UFO:AFTERMATH

Unofficial Virtual File System Format Specification Version 0.1

Disclaimer

UFO:Aftermath is a trademark of Altar interactive. This document is not a product of Altar interactive, who should not be associated with it. Nor will they provide any support for it. You may use this document freely as long as you dont take out a fee for it. None of the information contained is guaranteed to be correct. The author can not be held responsible for any consequences related to the use or misuse of the information contained herein.

Description

VFS-files are basically raw images of a FAT-style file system. As such they are easy to change dynamically but suffers from fragmentation. That a game uses a file system this way is very unusual.

A VFS consists of these four segements:

Name:Size:
header
fat table
root directory
clusters
sizeof(header)
clustercount*sizeof(fat_entry)
maxrootfiles*sizeof(file_entry)
clustersize*clustercount

The header describes the file system. It contains version information, sizes and limits of the systems and an md5 checksum. The header is followed by the fat table, which has one entry for each cluster. The entry describes if the cluster is used, and at what cluster the file that own it continues. The root directory is a fixed-size area that contains the file entries for the root files/directories. Directories are normal files that contains sequences of file_entry. And last are the clusters.

Structures

struct header
{
  float  version             // 1.0
  uint32 clustersize
  uint32 clustercount
  uint32 maxrootfiles        // 32 in save games, 64 otherwise
  uint32 zero                // could be that maxrootfiles is 64bit
  uint32 filenamelength      // always 64
  uint32 windowsize          // for compressed data, always 50000
  char   md5sum[16]          // calculated from offset 44 to EOF
  uint32 versionstringlength // always 256
  char   versionstring[256]
  uint32 usedclusters
}

struct file_entry
{
  char   name[64]             // padded with '\0'
  char   unknown1[4]
  uint32 type                 // 1=file,2=directory,9=compressed file
  char   unknown2[4]          // always 0xFFFFFFFF
  uint32 startcluster         // one-based
  uint32 size
  uint32 size_uncompressed    // 0 if uncompressed
}

struct fat_entry
{
  uint32 usage                // 0=unused,1=used
  uint32 nextcluster          // 0xFFFFFFFF to signal end cluster
}

Compressed streams

The compressed files, type 9, are series of compressed chunks. The compression library is used is regular zlib. Each uncompressed chunk is at most the size of windowsize from the header. Before each chunk is a marker, uint32, that describes the size of the chunk. Then follows the compressed data. On some files the last marker is repeated after the last chunk, this is probably caused by a bug in the generator tool.

Notes

Note that there is often garbage in the blocks that comprise directories, these are the result of reused buffers during the creation of the vfs. Always respect the size given in the entry and dont rely on unused entries being zeroed out. Except in the root directory where there is no other options.

In the type field of file_entry the gap between 2 and 9 could be the result of bit 3 being a flag the signals compression, this way, theoretically there can be compressed directories.

Cluster indices range from 1 and up to and including clustercount

Future

There is still alot of loose ends.


sigget@europe.com