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

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

Реализация декодирования формата DBPF2 содержится в файле siS3DBPF2Decoder.pas

Статьи по теме

Заголовок файла

type
TDBPF2Header = packed record
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;

 

Размер записи 96 байт, полей как видно много, но назначение большинства из них неизвестно, а если и известно, то неизвестно применение.

Для декодирования файла важны два поля:

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 – абсолютное смещение индексной таблицы от начала файла в байтах;

Индексная запись

type
TDBPF2Item = class
...
protected
procedure UnCompress; // записывает в поток декомпрессированный блок
public
constructor Create(AOwner: TDBPF2File); // конструктор класса
destructor Destroy; override; // деструктор класса
procedure FreeStream; // освобождает вторичный поток
procedure UnlinkStream; // удаляет ссылку на вторичный поток
procedure Decode(AStream: TStream); // декодирует данные записи
function Decoded: boolean; // проверяет запись на декодированность
function Exists: boolean; // проверяет запись на наличие
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;
// ссылка на вторичный поток
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 – ссылка на вторичный поток, чтение/запись;

Методы

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

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

 

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

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

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

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

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

Прочие типы


Исключения

type
EDBPF2DecoderError = class (Exception); // базовый класс ошибки декодера
EDBPF2HeaderError = class (EDBPF2DecoderError); // ошибка заголовка
EDBPF2UnCompressionError = class (EDBPF2DecoderError); // ошибка декомпрессии
EDBPF2ItemIOError = class (EDBPF2DecoderError); // ошибка ввода-вывода

The Sims 3

The Sims 2

The Sims

MySims

Sims-игры

Даты релизов

the_sims_3_store_saleshymn_bunnersimovod_3simovod2Журнал «Симовод»Prosims - магазин сувениров