The CMP format is how most files in the games Cosmo's Cosmic Adventures, Duke Nukem II, and Major Stryker are stored, albeit with varying file extensions (Cosmo prefers VOL and STN, while Major Stryker uses MS1, MS2 and MS3.)
Duke Nukem II will check the current directory first for files, and fall back to the CMP file if none are found. This means files inside the CMP can be easily overridden by simply placing their replacements as normal files in the game directory.
Cosmo's Cosmic Adventures and Major Stryker will check the archive files first and fall back to the game directory if the desired file could not be found in the archives. For Cosmo's Cosmic Adventures, you can simply rename or remove the archive files to force the game to use external files from the game directory. Major Stryker checks for the presence of the archive files and will malfunction if the archives are missing, so you must either pack all your files into the archives or create "empty" archives to force the game to use the external files from the game directory.
There is no known signature for this format. One method to identify files is to read in the file entries (as there is a fixed maximum of these in the original files, all 4000 bytes must be present for the file to be valid) and confirm that each filename only consists of ASCII characters or nulls, and each file offset plus its size is less than the total size of the CMP file. It is extremely unlikely that this method would incorrectly identify a file.
An additional check may be to examine the offset of the first file. This should always be 0xFA0 (4000), as the FAT is always 4000 bytes. However the actual number of bytes read from the FAT differs from game to game.
|Game||FAT size||File entries|
|Cosmo's Cosmic Adventures||960||48|
|Duke Nukem II||4000||200|
The first 4000 bytes of the file consists of file entries, with the remainder containing the data. Each file entry consists of the filename, its offset and its size. This slightly unusual configuration (storing both the offset and the size) means it is possible (in theory) for two different files to share the same data, and to insert "hidden" data between files.
A file entry is laid out as follows.
|char cFilename||Filename (8.3 style), only NULL-terminated if there is enough room|
|UINT32LE iOffset||File offset from start of group file|
|UINT32LE iSize||File size|
The 4000 bytes available leaves enough room for 200 files. Unused file entries are NULL. The first entry where cFilename starts with a 0 byte marks the end of the FAT. The very last file entry seems to contain an ASCII decimal number closely related to the number of files, however this appears to be debugging information generated by the tool that created the file, as that data is never used by any game.
Implementation Restrictions & Bugs
- All file names in the archive must be in upper case
- When searching for a file name, the first match in the FAT is used.
- Cosmo & Stryker: The code checks 1 more file entry than it reads from the file, so make sure the last entry read from the file has cFilename set to 0's.
- Cosmo & Stryker: Only the first 11 characters of the file names are compared, so FILENAME.001 and FILENAME.002 will be considered identical.
- Duke 2: String comparison actually only checks if one string is the prefix of the other. For example, if there is a file named "L" in the archive (at the beginning of the FAT), the game will always read that file when it tries to acces any file that starts with "L" (like L1.MNI to L8.MNI).
The following tools are able to work with files in this format.
|Name||Platform||Extract files?||Decompress on extract?||Create new?||Modify?||Compress on insert?||Access hidden data?||Edit metadata?||Notes|