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

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

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

S3DecoderLib: DBPF v.2. Типы данных

Формат DBPF2 и его декодирование: Часть практическая, типы данных

 

[ Стабильный билд • Описание формата • Декодер и кодер • Декомпрессия сжатых блоков DBPF2 ]

 

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

DBPF2Decoder.pas, rev.130517

 

Типы данных

 

record TDBPF2Header – заголовок файла

Размер записи 96 байт, полей как видно много, но назначение большинства из них неизвестно, а если и известно, то неизвестно применение. Для декодирования файла важны два поля Sig и IndexEntryCount:
type
  TDBPF2Header = packed record
  // from http://www.simswiki.info/images/9/94/DBPF_File_Format_v2.0.png
    Sig: packed array[0..3] of BYTE; // 0x46504244 aka "DBPF"
    MajorVersion: DWORD; // 2
    MinorVersion: DWORD; // 0
    MajorUserVersion: DWORD; // 0 ???
    MinorUserVersion: DWORD; // 0 ???
    Flags: DWORD; // ???
    CreatedDateTimeStamp: DWORD; // 0 ???
    ModifiedDateTimeStamp: DWORD; // 0 ???
    IndexMajorVersion: DWORD; // 0 ???
    IndexEntryCount: DWORD; // число записей в индексной таблице
    IndexLocation: DWORD; // устарело
    IndexSize: DWORD; // размер индексной таблицы в байтах
    HoleIndexEntryCount: DWORD; // ???
    HoleIndexLocation: DWORD; // ???
    HoleIndexSize: DWORD; // ???
    IndexMinorVersion: DWORD; // всегда 3 ???
    IndexOffset: DWORD; // абсолютное смещение индексной таблицы
    Reserved: packed array[0..27] of BYTE;
  end; // TDBPF2Header record

Поля

Sig: packed array[0..3] of BYTE – сигнатура файла, содержит текст "DBPF" (или "DBPP" если заголовок шифрованный), при сравнении удобно сравнивать сигнатуру не побайтно, а сразу как 32-разрядное целое: ( PInt(@FHeader.Sig[0])^<>$46504244 ) для "DBPF" ( или с <>$50504244 для "DBPP");

IndexEntryCount: DWORD – число записей в индексной таблице;

MajorVersion, MinorVersion: DWORD – версия формата, 2.0;

IndexSize: DWORD – размер индексной таблицы в байтах, вычисляется довольно сложно потому, что размер индексной записи не фиксированный, а зависит от типа индекса (IndexType), точнее IndexType выступает как битовая маска – каждому полю записи соответствует свой бит и при установке его поле выносится перед всеми записями, а затем пропускается во всех записях. В общем случае IndexSize = 4 * (1 + число_установленных_бит_в_IndexType + (8 - число_установленных_бит_в_IndexType) * IndexEntryCount;

IndexOffset: DWORD – абсолютное смещение индексной таблицы от начала файла в байтах;

 

class TDBPF2Item – индексная запись

type
  TDBPF2Item = class
    private
      procedure SetInstance(v: UInt64); // запись 64bit экземпляра
      function GetInstance: UInt64; // чтение 64bit экземпляра
      function GetTGIName: string; // возвращает TGI как строку '%.8X-%.8X-%.8X%.8X'

    protected
      // from http://www.modthesims.info/wiki.php?title=Sims_3:DBPF
      FResourceType: DWORD; // тип ресурса, см. http://www.modthesims.info/wiki.php?title=Sims_3:PackedFileTypes
      FResourceGroup: DWORD; // группа, старший байт набор флагов???
      FInstanceHi: DWORD;
      FInstanceLo: DWORD; // экземпляр 32+32bit
      FOffset: DWORD; // абсолютное смещение данных с начала файла
      FPackedSize: DWORD; // в DBPF старший бит всегда 1, нужно делать and/or $7FFFFFFF/$80000000
      FMemSize: DWORD; // распакованный размер
      FCompressed: WORD; // сжатый блок: 0 - нет, 0xFFFF - да
      FUnknown: WORD; // всегда 1
      FStream: TStream; // ссылка на вторичный поток
      FOwner: TDBPF2Decoder; // ссылка на владельца записи
      FChanged: boolean; // запись изменена
      FWrapper: TDBPF2ItemDecoder;

   protected
      procedure UnCompress; // записывает в поток декомпрессированный блок

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

      procedure FreeStream; // освобождает вторичный поток
      procedure UnlinkStream; // удаляет ссылку на вторичный поток

      procedure Decode(AStream: TStream); overload; // декодирует данные записи
      procedure Decode(AWrapper: TDBPF2ItemDecoder); overload; // декодирует данные записи
      function Decoded: boolean; // проверяет запись на декодированность
      function Exists: boolean; // проверяет запись на наличие
      procedure SaveToFile(path: string; ext: string; template: string = '%s%.8X-%.8X-%.8X%.8X%s');
      // записывает в файл запись, запись должна быть не декодированная и не удаленная

      property ResourceType: DWORD read FResourceType write FResourceType; // тип ресурса
      property ResourceGroup: DWORD read FResourceGroup write FResourceGroup; // группа
      property InstanceHi: DWORD read FInstanceHi write FInstanceHi;
      property InstanceLo: DWORD read FInstanceLo write FInstanceLo; // экземпляр 32+32bit
      property Instance: UInt64 read GetInstance write SetInstance; // экземпляр 64bit
      property Offset: DWORD read FOffset; // абсолютное смещение данных с начала файла
      property PackedSize: DWORD read FPackedSize; // упакованный размер, старший бит сброшен
      property MemSize: DWORD read FMemSize; // распакованный размер
      property Compressed: WORD read FCompressed; // сжатый блок: 0 - нет, 0xFFFF - да
      property Stream: TStream read FStream write Decode; // ссылка на вторичный поток
      property TGIName: string read GetTGIName; // TGI как строка '%.8X-%.8X-%.8X%.8X'
      property Changed: boolean read FChanged write FChanged; // запись изменена
      property Wrapper: TDBPF2ItemDecoder read FWrapper write Decode; // обертка потока
  end; // TDBPF2Item class

Свойства

ResourceType: DWORD – тип ресурса, чтение/запись;

ResourceGroup: DWORD – группа, чтение/запись;

InstanceHi: DWORD – старшие 32 бит экземпляра, чтение/запись;

InstanceLo: DWORD – младшие 32 бит экземпляра, чтение/запись;

Instance: UInt64 – экземпляр (64 бит), чтение/запись;

Offset: DWORD – абсолютное смещение данных с начала файла, только чтение;

PackedSize: DWORD – упакованный размер, старший бит сброшен (в файле DBPF2 он установлен, но так с ним было бы неудобно работать, по этому при записи файла он должен быть приведен в соответствие), только чтение;

MemSize: DWORD – распакованный размер), только чтение;

Compressed: WORD – признак того, что блок сжат $0000 - нет, $FFFF – да, чтение/запись;

Stream: TStream – ссылка на вторичный поток, чтение/запись;

TGIName: string – TGI (Type-Group-Instance) как строка, в формате '%.8X-%.8X-%.8X%.8X', только чтение;

 

Методы

constructor Create(AOwner: TDBPF2File) – конструктор класса, как аргумент получает декодер, индексной таблице которого принадлежит запись;

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

 

procedure FreeStream – освобождает вторичный поток (вызывает его Free), то же что и Stream:= nil, но работает быстрее, при попытке освободить поток для записи которой нет в исходном файле – помечает запись как удаленную;

procedure UnlinkStream – удаляет ссылку на вторичный поток, но не удаляет его, необходимо вызывать ее, а не FreeStream, если поток использовался в добавлялся в другой TDBPF2Decoder;

procedure Decode(AStream: TStream) – декодирует запись, то же что и Stream:= AStream, но работает быстрее, если запись уже декодирована, то вначале освобождает старый вторичный поток;

генерирует исключения:

EDBPF2UnCompressionError(csUnCompressionIdError) – 'Неверный заголовок сжатого блока', если Id записи не равен $FB;

EDBPF2UnCompressionError(csUnCompressionSizeError) – 'Неверный размер сжатого блока', если PackedSize записи не равен указанному в ее индексной таблице или декомпессированному объему;

function Decoded: boolean – возвращает true, если запись уже декодирована;

function Exists: boolean – проверяет запись на наличие, возвращает false если запись удалена;

procedure SaveToFile(path: string; ext: string; template: string = '%s%.8X-%.8X-%.8X%.8X%s') – записывает запись в файл без ее предварительного декодирования, параметры: путь, расширение файла, формат имени файла (по умолчанию – {путь)\TGI{расширение})

 

array TDBPF2Items – массив записей

type
  TDBPF2Items = packed array of TDBPF2Item; // массив записей

Прочие типы

 

Исключения

type
  EDBPF2DecoderError = class (Exception); // базовый класс ошибки декодера
  EDBPF2HeaderError = class (EDBPF2DecoderError); // ошибка заголовка
  EDBPF2UnCompressionError = class (EDBPF2DecoderError); // ошибка декомпрессии
  EDBPF2DecriptionError = class (EDBPF2DecoderError); // ошибка дешифрации
Категория: S3DecoderLib | Добавил: crazylab (27.09.2013)
Просмотров: 402