ZiPatch File Structure
From FFXIV Classic Wiki
All ZiPatch files for FINAL FANTASY XIV share the same overall structure. This format was later expanded in 2012 for DRAGON QUEST X and FINAL FANTASY XIV: A Realm Reborn, which are more similar in their DAT structure. Many of the block types found in this version were deprecated, but still remain in the executable for A Realm Reborn.
ZiPatch Header
91 5A 49 50 41 54 43 48 0D 0A 1A 0A ‘ZIPATCH....
The ZiPatch File Header is followed immediately by n blocks, which each carry specific instructions.
Block Structure
[StructLayout(LayoutKind.Sequential, Pack=4)] struct Block { int _dataSize; // Little Endian byte[] _data; // data.Length is dataSize + 4 (inclusive of block type identifier) [MarshalAs(UnmanagedType.ByValArray, SizeConst=4)] byte[] _crc; // crc is a standard CRC32 checksum (RFC 1952) of data }
The block type identifier is indicated by the slice of data[0..3]. Analysis of ffxivupdater.exe indicates the following block types as valid:
FHDR // File Header; observed APLY // Unknown; observed APFS // Unknown; not observed ETRY // Entry File; observed ADIR // Add Directory; observed DELD // Delete Directory; observed
File Header
The File Header block is a summary of the changes that will take place as a result of applying the ZiPatch.
[StructLayout(LayoutKind.Sequential, Pack=4, Size=20)] struct FileHeader { [MarshalAs(UnmanagedType.ByValArray, SizeConst=4)] byte[] _version; // version format is unknown, but may be major/minor. Analysis of ffxivupdater.exe indicates the string FileHeaderV2. 00 00 02 00 observed [MarshalAs(UnmanagedType.ByValArray, SizeConst=4)] byte[] _result; // DIFF or HIST observed int _numEntryFile; // Little Endian int _numAddDirectory; // Little Endian int _numDeleteDirectory; // Little Endian }