Каталог статей
Главная » Статьи » 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) | |
Просмотров: 1495 |