.CMF - nbreeze/closers-rev GitHub Wiki
Introduction
.CMF is an archive format used exclusively in Closers to store all the game's files. If you have snooped around the game's files then you'll notice thousands of these archives right away. The format is public knowledge at this point and it hasn't changed much over the years aside from a signature change.
HEADER.CMF
does not follow this format.
Signature
The file begins with a signature wide string. This signature can be one of the following:
// N.K. .E.N.G.I.N.E. .C.O.M.B.I.N.E. .F.I.L.E. .v.e.r... .1...0...
4E 00 4B 00 20 00 45 00 4E 00 47 00 49 00 4E 00
45 00 20 00 43 00 4F 00 4D 00 42 00 49 00 4E 00
45 00 20 00 46 00 49 00 4C 00 45 00 20 00 76 00
65 00 72 00 2E 00 20 00 31 00 2E 00 30 00 00 00
// C.O.M.B.I.N.E. .F.I.L.E. .v.e.r...2.
43 00 4F 00 4D 00 42 00 49 00 4E 00 45 00 20 00
46 00 49 00 4C 00 45 00 20 00 76 00 65 00 72 00
2E 00 32 00
Entries
At file offset 0x64 (100) begins the list of entries stored in the file.
Next, there is an int32
specifying how many files are stored in the .CMF archive. We'll call this the entry count. After that, there is an array of file entry structures, with each structure specifying the filename, offset in data section of the archive, compression flag, and both compressed and uncompressed sizes.
struct CMFFileEntry {
wchar_t[256] fileName; // 512
unsigned int size_uncompressed; // 516
unsigned int size_compressed; // 520
unsigned int data_offset; // 524
unsigned int compressed; // 528
};
If compressed
is non-zero, then the file has been compressed with Zlib INFLATE.
:warning: The entry count and the entries themselves are encrypted. See the Decompiling page for more details.
Data
After the entries comes the actual files stored in the archive. If you want to be safe, you can easily determine the starting offset of the data section of the archive by doing this method:
DATA_SECTION_OFFSET = SIGNATURE_SECTION_SIZE + 4 + ( entry_count * sizeof(CMFFileEntry) )
...where SIGNATURE_SECTION_SIZE
is 100, or 0x64.
To get to a specific file, you need to use the data_offset
field of the CMFFileEntry
structure defined earlier. data_offset
is an offset that points to the start offset of the file, relative to DATA_SECTION_OFFSET
. Use data_offset + size_compressed
to get the ending offset of the file.