Ocarina of Time, Majora's Mask, and all of their seperate versions & ports use an identical filesystem. The filesystem helps the game differentiate between compressed and decompressed data, and keep the files in order. It also allows for quick editing should something be misplaced. The filesystem (rather the file offset table part) begins right after the ROM creator and build date. If you would like to see for yourself, you can find the filesystem at the following offsets:
|Debug ROM||OoT NTSC 1.0||MM (U)||MM (J)|
If you, for some reason, have a different version, just search for "zelda@", and with any luck, you'll find it! An interesting note: the filename table refers to the file offset table as "dmadata". The file offset table also refers to itself, which is quite extraordinary.
File Offset Table
The file offset table begins exactly 0x30 bytes (48 bytes in decimal) from the creator/build date. The first entry of the file table is always the location 0x00000000 - 0x00001060, which is referred to as "makerom" in the filename table. This is not related to this article, but that file it the header for the N64 ROM. It contains region info, cart title, country, and boot code.
One entry for a file is 16 bytes (or 0x10 bytes; one line in a hex editor). You can split this up into 2 parts to find out the two offset pairs, and then you can split those two pairs in half to find the start/end offset for said pair. Here is a tiny diagram:
|Virtual Mapping (VRom)||Physical Mapping (Rom)|
The "virtual mapping" will contain the decompressed offset to the file. In essence, if all of the ROM's resources in a compressed rom were decompressed and stuck together, that's where the file would be. The "physical mapping" in these files will then either point to an uncompressed file, or a Yaz0 block (a file compressed with the Yaz0 algorithm), or no file at all (Majora's Mask).
- If a file is compressed, the start and end physical addresses will be set to the start/end of the file in rom.
- If a file is not compressed, the start physical address will point to rom, but the end address will be 0
- If a file does not exist, both start and end physical addresses will be FFFFFFFF.
<= COMPRESSED DATA => Offset 0x0001C1C0 in the debug ROM Virtual Mapping Physical Mapping 00A3A000 00A3EB80 009BA6B0 009BBA50 00A3F000 00A42300 009BBA50 009BD150 00A43000 00A4A780 009BD150 009C0310 <= DECOMPRESSED DATA => Offset 0x0001C1F0 in MM J Virtual Mapping Physical Mapping 00A4B000 00A4C310 009C0310 00000000 00A4C310 00A55660 009C1620 00000000 00A55660 00A68270 009CA970 00000000
As you can see in the decompressed data example, these three files are decompressed and mapped to a certain location, with their last pointer being set to 00000000. Since the file size of the file in the ROM is identical to the mapped one, the last pointer can be set to 00000000 without losing information. In short: the game calculates the size of the block via the virtual mapping (when dealing with decompressed data). In the compressed data example, however, the physical mapping points to a Yaz0 block in the ROM, which is then decompressed and mapped to the location in the first offset pair.
Since the debug ROM is in fact a debugger's ROM, the developers were nice enough to leave all of the filenames for OoT's resources intact. They can be found in the main code block or at offset 0xBE80. The filenames are separated by 1-4 null (0x00) bytes (for four-byte alignment), and they match up perfectly with the data referenced by the file offset table. The debug ROM is the only Zelda 64 game to have a complete file listing. Majora's Mask has one too (following a similar format), but it only lists the names of the scene files, and some of the scenes it refers to are removed.