Skip to main content

UTF (Universal Tree Format)

Overview

Container file format used to store various assets in Freelancers. Little-endian byte order.

Freelancer uses UTF in these type of files:

  • .utf (audio library, etc)
  • .ale (particle effects library)
  • .vms (rigid mesh buffer library)
  • .3db (single-part rigid model)
  • .cmp (compound rigid model)
  • .dfm (compound deformable model)
  • .sph (simple sphere model)
  • .txm (texture library)
  • .mat (material library)

File begins with header block which is always 56 bytes.

NameTypeDescription
signatureuint32Magic bytes, string reads as "UTF ".
versionuint32Always 0x101.
treeOffsetuint32Absolute byte offset to tree block.
treeSizeuint32Tree byte size.
unusedEntryOffsetuint32Usually is 0.
entrySizeuint32Entry byte size is always 44. Freelancer will crash otherwise.
namesOffsetuint32Absolute byte offset to dictionary block.
namesSizeAllocateduint32Dictionary byte size allocated.
namesSizeUseduint32Dictionary used byte size. Must be equal or less than namesSizeAllocated.
dataOffsetuint32Absolute byte offset to data block.
unusedOffsetuint32Absolute byte offset to extra data (unused).
unusedSizeuint32Extra data byte size (unused).
filetimeuint64Windows 64-bit FILETIME.
  • Header is usually followed by entries but not always, some files have dictionary before entries.
  • Dictionary is a concatenated collection of ASCIIz strings (NUL-terminated ASCII strings).
  • Dictionary reserves first string as empty (i.e. first byte in dictionary block is 0x0). Entries with zero length name are ignored.

Entry

Each entry in tree block is 44 bytes.

NameTypeDescription
nextOffsetuint32Offset to next sibling in tree block.
nameOffsetuint32Offset to entry name in dictionary block.
attributesuint32File system attributes.
sharingAttributesuint32File system sharing attributes (unused).
childOffsetuint32Either offset to first child or to entry data.
dataSizeAllocateduint32Allocated data byte length.
dataSizeUseduint32Actual used data byte length.
dataSizeUncompresseduint32Uncompressed data byte length (unused).
createTimeuint32File creation timestamp.
accessTimeuint32File last access timestamp.
modifyTimeuint32File last modification timestamp.
  • Tree root entry name should be "/", but other names are possible.
  • For attributes see Win32 API dwFileAttributes. In short it should be either 0x80 for file or 0x10 for folder. It is not necessary, however, that all three bytes after the first here are zero, and, in fact, in some vanilla files, they are not.
  • When entry is a folder the childOffset points to first child byte offset, relative to treeOffset in header, and dataSize* are all zeroes.
  • When entry is a file the childOffset points to data block, relative to dataOffset in header, and dataSize* indicate file size.
  • Timestamps are DOS file timestamp, see: https://blogs.msdn.microsoft.com/oldnewthing/20030905-02/?p=42653