TVFS: Difference between revisions

From wowdev
Jump to navigation Jump to search
 
Line 60: Line 60:
     int8_t PartialEKey [FileManifestHeader.eKeySize];
     int8_t PartialEKey [FileManifestHeader.eKeySize];
     int32_BE_t CompressedLength;
     int32_BE_t CompressedLength;
     int32_t EstOffset;        // Offset to the EstEntry, shown as int32_t but is of variable length based on estTableSize in header. See [[#Note_on_Container_file/ESPec_table_field_sizes|this note]].
     int32_BE_t EstOffset;        // Offset to the EstEntry, shown as int32_t but is of variable length based on estTableSize in header. See [[#Note_on_Container_file/ESPec_table_field_sizes|this note]].
     int32_BE_t Length;
     int32_BE_t Length;
     int8_t CKey [16];
     int8_t CKey [16];

Latest revision as of 00:41, 2 September 2023

TVFS (TACT Virtual File System) appeared back with the release of Warcraft III Reforged and has been used in various Call of Duty titles, Diablo 4 as well as World of Warcraft.

Its VFS manifests (from TACT's buildconfigs) are supposed to supplement or even replace the old root manifest format in some cases.

File manifest

TVFS file manifests are listed in buildconfig under vfs-* keys. Information about this format is based on CascLib's implementation.

Header

Header should always be at least 38/0x26 bytes. estTableOffset and estTableSize are optional and only set if flags & 2.

struct {
/*0x00*/  char magic[4];                // Always TVFS
/*0x04*/  char version;                 // Format version. Always 1.
/*0x05*/  char headerSize;              // Header size in bytes.
/*0x06*/  char eKeySize;                // EKey size in bytes. Should be 9.
/*0x07*/  char patchKeySize;            // PatchKey size in bytes. Should be 9.
/*0x08*/  uint32_BE_t flags;            // FileManifestFlags, see below.
/*0x0C*/  uint32_BE_t pathTableOffset;  // Offset to the path table.
/*0x10*/  uint32_BE_t pathTableSize;    // Size of the path table.
/*0x14*/  uint32_BE_t vfsTableOffset;   // Offset to the VFS table.
/*0x18*/  uint32_BE_t vfsTableSize;     // Size of the VFS table.
/*0x1C*/  uint32_BE_t cftTableOffset;   // Offset to the container file table.
/*0x20*/  uint32_BE_t cftTableSize;     // Size of the container file table, also used to calculate size of offests to this table (see below).
/*0x24*/  uint16_BE_t maxDepth;         // The maximum depth of the path prefix tree stored in the path table,
/*0x26*/  uint32_BE_t estTableOffset;   // Offset to ESpec table. Only present if write support (flags & 2) is enabled.
/*0x2A*/  uint32_BE_t estTableSize;     // Size of ESpec table. Only present if write support (flags & 2) is enabled. Also used to calculate size of offests to this table (see below).
} FileManifestHeader;

Note on Container file/ESPec table field sizes

Most current implementations also add 2 'virtual' fields to the header that contain the sizes of the offsets at VfsSpanEntry.CtfOffset and CftEntry.EstOffset respectively. Offsets into either tables grow based on the table's size.

Tables shorter than 0xff will have offsets the size of 1 byte, tables over 0xff will have 2 byte offsets, over 0xffff 3 byte offsets and over 0xffffff maxing out at 4 byte offsets.

Sample code for calculating those can be found in CascLib here.

FileManifestFlags

enum FileManifestFlags {
 INCLUDE_CKEY       =     0x1,  // Include C-key in content file record.
 WRITE_SUPPORT      =     0x2,  // Write support. Include a table of encoding specifiers. This is required for writing files to the underlying storage. This bit is implied by the patch-support bit.
 PATCH_SUPPORT      =     0x4,  // Patch support. Include patch records in the content file records.
 LOWERCASE_MANIFEST =     0x8,  // Lowercase manifest. All paths in the path table have been converted to ASCII lowercase (i.e. [A-Z] converted to [a-z]).
};

Path table

Starts with the root directory and recursively contains directories/files.

TODO structure

NodeFlags

enum NodeFlags {
 PATH_SEPARATOR_PRE  =     0x1,  // There is path separator before the name.
 PATH_SEPARATOR_POST =     0x2,  // There is path separator after the name.
 NODE_VALUE          =     0x4,  // The NodeValue in path table entry is valid.
};

Container file table

struct CftEntry
{
   int8_t PartialEKey [FileManifestHeader.eKeySize];
   int32_BE_t CompressedLength;
   int32_BE_t EstOffset;         // Offset to the EstEntry, shown as int32_t but is of variable length based on estTableSize in header. See this note.
   int32_BE_t Length;
   int8_t CKey [16];
};

TODO

VFS table

struct VfsSpanEntry
{
   int32_BE_t ContentOffset;
   int32_BE_t ContentLength;
   int32_BE_t CftOffset;       // Offset to the CftEntry, shown as int32_t but is of variable length based on cftTableSize in header. See this note.
};

TODO

ESpec table

List of null-terminated Encoding Specification strings.