Четверг, 23.11.2017, 06:26
Приветствую Вас Гость

Каталог статей

Главная » Статьи » S3DecoderLib

S3DecoderLib: Sims3Pack. Реализация декодера

Формат Sims3Pack и его декодирование: Часть практическая, реализация декодера

 

[ Стабильный билд • Описание формата • Типы данных ]

 

Програмный модуль и версия

S3PackDecoder.pas, rev.120825

 

Типы данных

 

class TS3PackDecoder – реализация декодера

Декодер представляет собой наследника класса TComponent и может (и должен во избежание багов с парсером xml) устанавливаться на форму. Для работы с исходным файлом используется первичный поток, в его качестве допустим любой (естественно неабстрактный) потомок TStream; он должен быть создан и файл загружен в него – сделано это для того чтобы не привязываться к размещению исходного файла. Для освобождения первичного потока нельзя использовать его "родные" методы, для этого используется метод FreeStream декодера.
type
  TS3PackDecoder = class(TComponent)
    private
      FCount: integer; // число записей в индекной таблице
      FHeader: TS3PackHeader; // заголовок файла
      FItems: TS3PackItems; // параметры файлов в архиве
      FStream: TStream; // поток чтения
      FXMLDecoder: TXMLDocument; // парсер xml
      FPackageName: string; // имя пакета
      FPackageDescription: string; // описание пакета

    protected
      function Alloc: TS3PackItem; // добавляет запись в индексную таблицу и возвращает ее

    public
      constructor Create(AOwner: TComponent); override; // конcтруктор класса
      destructor Destroy; override; // деструктор класса

      procedure FreeStream; // освобождает вторичные потоки, освобождает первичный поток
      procedure Decode(AReader: TStream); // связывает поток декодирования, декодирует индексную таблицу

      property Items: TS3PackItems read FItems; // декодированная индексная таблица
      property Count: integer read FCount; // число записей в индекной таблице
      property Header: TS3PackHeader read FHeader; // заголовок файла
      property PackageName: string read FPackageName; // имя пакета
      property PackageDescription: string read FPackageDescription; // описание пакета
  end; // TS3PackDecoder class

Свойства

Items: TS3PackItems – массив записей по каждому из файлов в пакете, только чтение;

Count: integer – число файлов в пакете, только чтение;

Header: TS3PackHeader – заголовок пакета, содержит те самые 17 байт, категорически не рекомендуется лезть в него грязными руками (чистыми, кстати, тоже) – свойство информационное для отладки, только

чтение;

PackageName: string, имя пакета, если есть русская локализация, то берется из LocalizedNames\ru-RU, иначе какая есть (обычно английская) из DisplayName манифеста, только чтение;

PackageDescription: string, описание пакета, если есть русская локализация, то берется из LocalizedDescriptions\ru-RU, иначе какая есть (обычно английская) из Description манифеста, только чтение;

 

Методы

constructor Create(AOwner: TComponent) – конструктор класса;

destructor Destroy – виртуальный деструктор, освобождает все связанные потоки (и первичный и вторичные) – естественно вместо него лучше использовать метод Free;

procedure FreeStream – освобождает вторичные потоки, освобождает первичный поток, после его вызова нельзя использовать остальные поля и методы для данного файла, для освобождения потока нельзя использовать его "родные" методы;

procedure Decode(AReader: TStream) – связывает поток декодирования с декодером, декодирует индексную таблицу, должен вызывается первым, все остальные поля и методы используются после нее, до ее вызова состояние полей неопределенно, кроме Count, который равен 0;

function Alloc: TS3PackItem – защищенный метод, увеличивает индексную запись на один элемент и вызывает его конструктор;

 

Пример использования

Практическое использование может быть, например, такое:
procedure TfrmMain.btnSims3PackClick(Sender: TObject);
var
  i: integer;
begin
  if not dlgOpenS3Pack.Execute then exit;

  lstLog.Clear;
  S3PackDecoder.Decode(
    TFileStream.Create(dlgOpenS3Pack.FileName, fmOpenRead)); // (1)

  AddDebug('file=%s', [dlgOpenS3Pack.FileName]); // (2)
  AddDebug('name=%s', [S3PackDecoder.PackageName]);
  AddDebug('description=%s', [S3PackDecoder.PackageDescription]);
  AddDebug('-------------------', []);

  barProgress.Max:= S3PackDecoder.Count-1;
  Application.ProcessMessages;

  for i:= 0 to S3PackDecoder.Count-1 do with S3PackDecoder.Items do begin // (3)
    AddDebug('name=%s', [FileName]); // (4)
    AddDebug('  offset=%.6Xh, size=%.6Xh, type=%s', [Offset, Length, ContentType]);
    Decode(TMemoryStream.Create); // (5)
    Stream.SaveToFile('unpack\'+FileName);
    FreeStream;
    barProgress.Position:= i;
    Application.ProcessMessages;
  end;
  S3PackDecoder.FreeStream; // (6)
end;

 

В примере, выбранный пользователем файл:

1) открывается и декодируется;

2) в лог добавляются данные манифеста;

3) затем для каждой записи:

4) - в лог добавляются данные о ней;

5) - она декодируется и сохраняется на диск;

6) первичный поток закрывается;

Пример довольно условный, т.к. для записи на диск TFileStream подходит лучше – зато иллюстрирует правильное создание, доступ и уничтожение вторичных потоков. Обратите внимание на необходимость использования вызова Application.ProcessMessages в теле цикла декодирования, в случае его отсутствия при больших файлах заметна "заморозка" программы.

Категория: S3DecoderLib | Добавил: crazylab (27.09.2013)
Просмотров: 123