ZiPatch File Structure

From FFXIV Classic Wiki
Revision as of 19:07, 5 June 2019 by Deviltti (talk | contribs)
Jump to: navigation, search

ZiPatch Synopsis

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 to each other. 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, each of which 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; [00 00 00 01 00 00 00 04 00 00 00 01] and [00 00 00 02 00 00 00 04 00 00 00 01] 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
}