TO:R Data Map

FileTable.bin: the game's file table

Source
docs/formats/filetable.md
SHA-256
fffe581e…96ca7a1a

The index of every game file, at the root of Data/. The game looks a file up here by group and file ID (or by a hash of its name), and gets back its path under Data/ and its size; it then reads exactly that many bytes from the file. So a rebuilt file that changes size needs its record here changed to match (Rebuilding). The file is not wrapped (no RotXor or ZIP, containers.md). It has fields no code reads and record kinds no record uses; Gibbed reads them as the PSP game's. Terms are as in the glossary.

Based on FileTable.bin, 2,627,476 bytes, SHA-256 a1a3dfbafd6d24b69b7db85a5bff9ef08c64cdedd3054e95717166905089a213. The game's loader in the unpacked executable, SHA-256 7b0230a11498f40396c9048345e7cfe0ef442cb7ca8faffc6f197920d2669599 (Ghidra and rea). Gibbed's FileTableFile.cs and FileTable/*.cs (reference_tools/Gibbed.LetUsClingTogether/projects/Gibbed.TacticsOgre.FileFormats/) and Gibbed.Reborn.RebuildFileTable/Program.cs.
Checked 2026-10-12
Method Static analysis of the loader and the read path with Ghidra 12.1.4, via rea and the decompiled code in local/exe/decomp/ (functions named by address below); disassembly with Xcode's objdump (LLVM); a single-file C# exploration program (exescan.cs, session scratchpad) that searches the executable for every call, jump or pointer to a given address; hex inspection; single-file C# exploration programs (filetable_check.cs, and ft.cs in the R31 review, session scratchpads) that walk the whole file as the loader does, check every count, offset, size and name hash against the file and Data/, and list each group's folders; Gibbed's source. 2026-10-12 (R18): the round trip, tor round-trip local/game/Data/FileTable.bin --docs docs, decoded the table with the layouts below, checked every count and offset against the Rebuilding rules, and rebuilt it from its rows byte for byte (1/1 file), with no decode problem reported; tor export and tor read-back (same as the original); the gate FileTableGivesEachFilesSizeAndTakesARebuiltOne (toolchain/tests/), which checks each file's size against Data/ and gives a rebuilt file a new size. The round trip confirms the layout and the Rebuilding rules, not what a field means: every fact about the loader is static analysis alone, so at most likely. No in-game tests yet.

Layout

The parts follow each other with no gaps, in this order (confirmed: the R18 round trip finds each part ending where the next begins, and the path records ending at the end of the file; so did the exploration program):

Part Starts at Record size Count
Header 0x0 0x44 1
Name records 0x44 8 name_count
Group records after the names 24 group_count
Range records after the groups 8 sum of the groups' range_count
File records file_records_offset 4 sum of the ranges' file_count
Path records path_records_offset variable, 8-aligned one per file record

Each part's count and offset in the shipped file are in its page's byte map (FileTable.bin).

The loader (0x1402b1490) reads only name_count, group_count, file_records_offset and path_records_offset. The fields no code reads are named by position, or as Gibbed reads them (guess).

Offset Size Type Name Meaning Confidence Source
0x00 2 u16 magic 0x1EF1. The loader doesn't check it; one file, so the data can't show it marks a format. guess Hex inspection; not read in 0x1402b1490. Gibbed FileTableFile (Signature).
0x02 2 u16 name_count Number of name records. likely 0x1402b1490 (count of 8-byte records from 0x44); hex inspection. Agrees with Gibbed.
0x04 2 u16 group_count Number of group records. likely 0x1402b1490 (stores it at slot +0x58, the bound of 0x1402b1350's search of 24-byte records); hex inspection. Gibbed dir_count.
0x06 2 u16 unk_0x06 4. Not read by the loader; Gibbed rejects any other value. — Hex inspection. Gibbed.
0x08 4 u32 file_records_offset Where the file records start: 0x44 + 8 × name_count + 24 × group_count + 8 × ranges. likely 0x1402b1490 (slot +0x78); 0x1402b1350 adds a range's offset to it; exploration program (the sum matches). Gibbed file_table_offset.
0x0C 4 u32 path_records_offset Where the path records start, right after the file records: file_records_offset + 4 × file records. Gibbed calls it the total size, which it was on the PSP, where the file ended there. likely 0x1402b1490 (slot +0x80); 0x1402b1340 adds 8 × path_offset to it; exploration program. Gibbed external_table_offset.
0x10 16 raw[16] title_id_1 ULJM05753, NUL-padded: a product code. Not read by the loader. guess Hex inspection. Gibbed (TitleId1, the PSP game's title ID).
0x20 16 raw[16] title_id_2 NPJH50348, NUL-padded: a product code. Not read by the loader. guess Hex inspection. Gibbed (TitleId2).
0x30 2 u16 unk_0x30 0. Gibbed rejects any other value. — Hex inspection. Gibbed.
0x32 1 u8 unk_0x32 0. Gibbed accepts 0 or 1. — Hex inspection. Gibbed.
0x33 1 u8 parental_level 5. Not read. guess Hex inspection. Gibbed's comment: used when writing save data on the PSP (PARENTAL_LEVEL in the SFO).
0x34 16 raw[16] install_data_key All zero. Not read. guess Hex inspection. Gibbed (InstallDataCryptoKey, the PSP's install-data key).

Name records

Let the game open a file by name: it hashes the name and looks the hash up here to get the file's group and file ID (0x1402af940, 0x1402b1700). If the hash isn't found, it opens the name as a path instead.

Offset Size Type Name Meaning Confidence Source
0x0 4 u32 name_hash FNV-1 32-bit hash of the name: start at 0x811C9DC5, and for each byte multiply by 0x01000193, then XOR the byte (sign-extended). likely 0x1402af940; exploration program (below).
0x4 2 u16 group_id The file's group ID. likely 0x1402b1700 returns it, 0x1402af940 opens by it. Gibbed dir_id.
0x6 2 u16 file_id The file's ID within the group. likely Same.

Group records

A group is the first of the two IDs a file is opened by. It isn't a folder: group 500 spans many menu/ folders and group 300 SaveThumb/common, ScreenShot, saveicon and system, while object/ is split over groups 20 and 30, event/scene/ over 901–909 and worldmap/ over 800 and 850 (exploration program ft.cs). No game string names it.

Offset Size Type Name Meaning Confidence Source
0x00 2 u16 id Group ID. The game finds a group by searching for it. In ascending order. likely 0x1402b1350; exploration program (ascending).
0x02 1 bool8 obfuscated 0 or 1: 1 only in group 2000 (movie/*.pmf, the files the game XORs with key 1, pmf.md). Not read when looking a file up. guess Exploration program (values); no reader in 0x1402b1350, 0x1402b1280, 0x1402b1650. Gibbed (IsEncrypted).
0x03 1 u8 offset_shift 4 in every group. Used only for record kinds 2 to 5: a file's data offset is the record's offset << offset_shift + base_offset. likely 0x1402b1280; exploration program. Gibbed block_shift (DataBlockSize).
0x04 4 u32 base_offset 0 in every group. Used only for record kinds 2 to 5, as above; the offset it gives is then dropped by 0x1402af860. likely 0x1402b1280; 0x1402b1490 sets it to 0 when mounting; exploration program. Gibbed data_base_offset.
0x08 1 u8 unk_0x08 0 in every group. The game finds no file in a group where this isn't 0. — 0x1402b1350; exploration program. Gibbed rejects non-zero.
0x09 1 bool8 in_install_data 0 in groups 2000, 2700 and 2750, 1 in the others. Not read when looking a file up. guess Exploration program. Gibbed (IsInInstallData).
0x0A 2 u16 range_count Number of this group's ranges. likely 0x1402b1350. Gibbed batch_count.
0x0C 2 u16 name_count Number of this group's name records; 0 for most. likely 0x1402b1650; exploration program. Agrees with Gibbed.
0x0E 2 u16 name_index Index of its first name record, 0xFFFF when it has none. likely 0x1402b1650. Agrees with Gibbed.
0x10 4 u32 range_records_offset Byte offset of its first range record from the start of the range records: 8 × the ranges of the groups before it. likely 0x1402b1350 (adds it to slot +0x70). Gibbed batch_table_offset.
0x14 4 u32 install_base_offset Differs per group: grows from 0 to 0xF4DA8000 in multiples of 0x8000. Not read when looking a file up. guess Exploration program. Gibbed (DataInstallBaseOffset).

Range records

A range is a run of consecutive file IDs in one group, sharing one record kind.

Offset Size Type Name Meaning Confidence Source
0x0 2 u16 base_file_id First file ID in the range. likely 0x1402b1350. Agrees with Gibbed.
0x2 2 u16 file_count Number of files; the range covers IDs base_file_id to base_file_id + file_count − 1. likely Same.
0x4 4 bits[0:28] file_record_offset Bits 0–28 of the u32 at 0x4: byte offset of the range's first file record from the start of the file records. likely 0x1402b1350 (& 0x1FFFFFFF, added to slot +0x78). Gibbed entry_offset.
0x4 4 bits[29:31] record_kind Bits 29–31 of the u32 at 0x4: the record kind, which sets the file record's size: 4, 0, 4, 6, 6 or 8 bytes for kinds 0 to 5. 0 in every range. likely 0x1402b1350 (size table at 0x140c9a9e4: 04 00 04 06 06 08); 0x1402b1280 switches on it; exploration program (every range is kind 0). Gibbed entry_kind.

File records

All of Reborn's file records are kind 0 (above): a 4-byte offset into the path records.

Offset Size Type Name Meaning Confidence Source
0x0 4 u32 path_offset Where the file's path record is, in 8-byte units: at path_records_offset + 8 × path_offset. Records vary in size, so this isn't a record index. likely 0x1402b1280, 0x1402b1340 (<< 3). Gibbed external_index.

Record kinds 2 to 5 hold an offset (shifted by the group's offset_shift) and a size, 2 or 4 bytes each, into one big data file. The game still reads them (0x1402b1280), but no record in Reborn's file uses them; Gibbed reads them as the PSP game's.

Path records

One record per file record.

Offset Size Type Name Meaning Confidence Source
0x0 n + 1 cstr path The file's path under Data/, with / separators, in ASCII, NUL-terminated. likely 0x1402b1340, 0x140295760 (opened under the game's data root); exploration program (paths).
n + 1 4 u32 size The file's size in bytes, right after the NUL, not aligned. The game reads this many bytes from the file. likely 0x1402b1280; exploration program (below).
n + 5 0 to 7 raw padding Zero bytes up to the next multiple of 8 from path_records_offset. likely Exploration program. Agrees with Gibbed.

How the game reads it

How the executable turns a file ID or name into bytes: it loads this table, looks the file up in it, and reads the file from Data/. The functions are in the names list.

Loading the table

Opening a file by ID

Opening a file by name

Reading the bytes

What the game does with the table's size once a file is open, and so what happens when the file on disk is a different size.

Decoded data

tor export writes the table as a folder payload.filetable/ with one .jsonl per kind of record (toolchain/README.md (../../toolchain/README.md#decoded-data)). The counts and offsets the Rebuilding rules derive aren't columns; they're in the file's .bin.

File Rows
header.jsonl One: every Header field but name_count, group_count, file_records_offset and path_records_offset.
names.jsonl One per name record.
groups.jsonl One per group record, every field but range_count, name_count, name_index and range_records_offset.
ranges.jsonl One per range record: group_id (its group's id), then every field but file_record_offset.
files.jsonl One per file record, with its path record: group_id, file_id (its range's base_file_id + its place in the range), path, size.

The view exe.file_opens joins files.jsonl to the executable's calls that open files (The indexes).

Rebuilding

What a rebuild needs. confirmed for unchanged rows: the table rebuilds byte for byte from its rows, with every count and offset derived as below (see Method).

Leads