At a glance

Magic
none - a 12-byte sync pattern opens every sector; files are found through ISO9660
Where on disc
the whole .bin image; the Primary Volume Descriptor sits at LBA 16
Stride
2352 bytes per sector, 2048 of them file content at byte 24
Parser
crates/iso (raw.rs sector reader, iso9660.rs walker, write.rs EDC/ECC re-encode, relayout.rs)
Confidence
Confirmed - textbook CD-ROM XA / ECMA-130 geometry; every disc-gated test in the workspace reads through it
Used by
extraction pipeline, disc patcher, in-browser ROM patcher

Overview

A CD image (.bin) is a flat run of sectors addressed by LBA - the logical block address, a sector number counting from the start of the disc. "Mode2/2352" names the sector flavour PlayStation discs use: mode 2 of the CD-ROM XA standard, stored as full 2352-byte raw sectors rather than pre-stripped 2048-byte ones. Reading a file means knowing its start LBA and peeling the 2048 user-data bytes out of each sector.

Two things live on top of that geometry:

  • ISO9660 - the standard CD filesystem that turns sector numbers into the 45 named files on the disc.
  • Relayout - growing a file by whole sectors, which the official PAL discs did to fit longer translated dialogue and which a community language pack needs when its text does not fit in place.

Sector layout

Each sector is 2352 bytes. Only the 2048-byte slice in the middle is file content; the rest is the sync mark and address the drive uses to find the sector, a subheader (meaningful for streamed XA audio and video), and the error-detection and error-correction codes that let a scratched disc still read.

One 2352-byte Mode 2 Form 1 sector: sync, header, subheader, 2048 bytes of user data, then EDC and ECC 0 sync 12 B 12 header 4 B MSF 16 subheader 8 B 24 user data (file content) 2048 B 2072 EDC 4 B 2076 ECC 276 B 2352 sizes not to scale - the user-data slice is 87% of the sector
One raw sector. RawDisc::read_sector(lba) returns only the 2048-byte user-data slice at byte 24.
BytesSizeFieldMeaning
0..1212syncSync pattern 00 FF FF FF FF FF FF FF FF FF FF 00
12..164headerM:S:F address (BCD minutes:seconds:frames, lba + 150) + mode byte
16..248subheaderfile / channel / submode / coding (the XA streaming fields)
24..20722048user datathe file content ISO9660 and every game format see
2072..2352280EDC + ECCerror detection + correction (Form 1 only; Form 2 XA audio sectors carry no ECC)

RawDisc::read_sector(lba) returns just the user-data slice; read_user_data(lba, count, buf) reads a contiguous run.

const SECTOR_SIZE: usize = 2352;
const USER_DATA_OFFSET: usize = 24;
const USER_DATA_SIZE: usize = 2048;

ISO9660 walk

On top of the sector layer sits ISO9660, the standard CD filesystem - it turns "sector 16" into named files and directories. The layout is textbook:

  • Primary Volume Descriptor at LBA 16.
  • Root directory record at PVD offset 156.
  • Each directory record begins with a length byte; records pad to even lengths.

The walker (crates/iso/src/iso9660.rs) is iterative and yields stable-sorted file paths. The Legend of Legaia (USA) disc produces 45 files:

CDNAME.TXT  DMY.DAT  PROT.DAT  SCUS_942.54  SYSTEM.CNF
MOV/MV1.STR ... MV6.STR
XA/XA1.XA  ... XA34.XA
FileWhat it isPage
PROT.DATthe main asset archive - nearly every texture, model, script, sound bank and code overlay is one of its 1233 numbered entriesPROT.DAT TOC
SCUS_942.54the game's main executable (the resident half of the engine; the rest lives in overlays inside PROT.DAT)Ghidra tooling
CDNAME.TXTa developer-left name map for the archive's entriesCDNAME map
DMY.DATa sibling archive of developer test fixtures, no game contentDMY.DAT
MOV/MV*.STRthe pre-rendered movies - PSX MDEC video in the Iki bitstream, not the common STRv2 layout; decoder crates/mdecFMV table, cutscenes
XA/XA*.XAstreamed voice and audio in standard CD-XA Mode 2 Form 2; crates/xa demuxes per (file_no, ch_no) straight off the raw sectorsXA audio
History: the XA "non-standard interleave"

Early tooling reported a bespoke XA interleave. The interleave is the standard one; the apparent muxing scheme was damage from reading Form 2 sectors through a Form 1 (2048-byte) truncation. The demuxer reads raw 2352-byte sectors - see XA audio.

Full-ISO relayout

Growing a file by whole sectors - PROT.DAT, which the official PAL discs grew at mastering to fit longer localized dialogue - moves every file after it, so every on-disc reference to those files has to be rewritten. Legaia's disc makes this a small, well-bounded edit. Implementation: legaia_iso::relayout (generic ISO9660 + ECMA-130; embeds no game bytes).

The LBA reference graph

Two facts make the relayout safe (how we know):

  1. PROT.DAT's internal TOC is PROT.DAT-relative, not absolute disc LBAs. Entry 0's TOC start LBA is identical on every region's disc even though PROT.DAT sits at a different disc LBA per region. Growing an interior entry needs only an internal-TOC shift (PROT.DAT TOC), not a disc-wide cascade.
  2. No file is located by a hardcoded absolute LBA in the executable. Every file is found by ISO9660 name lookup; no post-PROT.DAT file's disc LBA appears as a literal in any USA or PAL executable.

When PROT.DAT grows by G sectors the cascade reduces to one rule: every ISO9660 LBA value > prot_lba gains +G; PROT.DAT's directory-record size gains +G*2048; the PVD volume-space size gains +G.

StructureLocationEdit
PVD volume spaceLBA 16, off 80 (LE) + 84 (BE)+= G
Path table (LE @18 + BE @20, incl. optional copies @19/@21)dir extentsextents > prot_lba += G
Directory records (root + every subdirectory extent)rec off +2 LBA / +10 sizeLBA > prot_lba += G; PROT.DAT size += G*2048
PROT internal TOCPROT.DAT byte 8+(j+2)*4entries after a grown one += cumulative G (PROT-relative)

Subdirectory extents that live after PROT.DAT (MOV and XA on the retail disc) relocate too, so their self . record and file records are patched at the extent's new position.

Per-sector mechanics of a relocation
  • Every sector after PROT.DAT moves +G: its 12-byte sync + 4-byte header are rewritten so the stored MSF address is BCD(lba+150) for the new position.
  • Form 1 EDC/ECC are computed with the header treated as zero (crates/iso/src/write.rs), so a pure relocation needs no EDC/ECC recompute - only the MSF header changes. Form 2 (XA) sectors carry no ECC.
  • EDC/ECC are recomputed only for sectors whose user data changes: the rebuilt PROT.DAT payload, the PVD, path tables and the directory extents.
  • The PROT entry index space is preserved (no entries added or removed), so index-keyed same-size edits still resolve after a relayout.

Consumers: DiscPatcher::grow_prot_entries and the translate import --allow-relayout localization path (translation tooling).

How we know

EvidenceAddress / sourceWhat it proves
ECMA-130 / CD-ROM XApublic standardSector geometry, EDC/ECC polynomial, MSF encoding
PROT.DAT openerFUN_8003E4E8The archive is found by ISO9660 name lookup, not by a hardcoded LBA
STR / XA path openerSCUS path-open helperMovies and audio are opened by path; no absolute LBA literal in any USA or PAL executable
USA vs PAL diffSCES_019.44/.45/.46The PAL discs are a per-entry +1-sector relayout of the same structure; PROT TOC entry 0 is identical across regions (PROT-relative)
Disc-gated round tripscrates/iso, crates/patcher/tests/*_real.rsEvery rewritten sector stays EDC/ECC-valid; relayout preserves the entry index space

Full page: docs/formats/disc.md.

See also