Save file container format
This page describes the container format used by Arx Fatalis save files (.sav) as well as Arx Libertatis extensions to that format.
See Common file format types for a description of the type names used here.
Save files are stored in a generic container that maps names (arbitrary strings) to chunks of data. Arx Libertatis adds two extensions to the vanilla Arx Fatalis .sav format. The .sav container format can be read and written using the
SaveBlock class (
.sav files can be viewed, extracted and modified using arxsavetool.
The file header starts at byte position 0 - there is no magic number.
|u32||File table offset|
The file table offset is the location of the file table (in bytes) relative to the first byte after the header. Add 4 bytes to get the offset relative to the start of the file.
The file table starts with a file table header:
File table header
|u32||Number of file entries|
Currently, the following version numbers are defined.
||Version used in Arx Fatalis 1.21|
||Added support for different compression algorithms (Arx Libertatis extension)|
||Removed ".sav" suffix from internal filenames (Arx Libertatis extension)|
The file table is followed by the specified number of file entries. For save files with version
SAV_VERSION_LEGACY the first file entry should be ignored.
File table entries
Each file table entry is preceded by a null-terminated string - the file name. Versions older than
SAV_VERSION_NOEXT store file names case-insensitively and append ".sav". When loading such versions, the filename should be converted to lowercase and the ".sav" extension removed.
For versions older than
|u32||Stored (compressed) file size - This can be ignored and calculated from chunk sizes.|
|u32||Number of chunks - 0 means 1!|
|u32||Useless data. This can be safely ignored|
SAV_VERSION_DEFLATE and newer:
|u32||Uncompressed file size|
|u32||Number of chunks|
Currently, the following compression algorithms are defined.
||No compression. Data is stored as-is.|
||Data is compressed using the PKWARE implode library. Even-numbered bytes of the result are bitwise negated.|
||Data is compressed using the ZLIB deflate format.|
Code to decompress PKWARE implode-encoded data can be found in blast.c in the contrib directory of the zlib source.
Versions older than SAV_VERSION_DEFLATE always use the
ImplodeCrypt algorithm. To allow changing save files without decompressing all data, the value
0xffffffff may be used to indicate that the uncompressed size is not known if (and only if) the compression algorithm is
The rest of the file entry is a list of as many chunk offsets as specified. For versions older than
SAV_VERSION_DEFLATE, the actual number of chunks is always 1 or more, even if the file entry says 0. The concatenation of the chunks referenced by these offsets makes up the compressed file data.
The chunk offset is the location of the chunk data (in bytes) relative to the first byte after the header. Add 4 bytes to get the offset relative to the start of the file. The chunk size is given in bytes. There is no guarantee that all parts of the .sav file are used in chunks or the file table.