Skip to the content.

Legacy formats

All legacy formats are decoded to the canonical ISO view through IBlobReader. Detection is by magic bytes (see CLI reference). Layout details below follow Dolphin’s DiscIO sources.

GCZ

A compressed GameCube image, invented by GCZTool and supported by Dolphin. The header is 32 bytes; all integers little-endian.

0x00  magic                  u32 — 0xB10BC001 (bytes 01 C0 0B B1)
0x08  compressed_data_size   u64 — size of the data area after the tables
0x10  disc_size              u64 — uncompressed ISO size
0x18  block_size             u32 — 0x4000 for standard images
0x1C  num_blocks             u32
0x20  block pointer table:   8 bytes per block
      { u64 LE offset | bit 63 = uncompressed flag }
      (offset relative to the start of the compressed data; bit 63 set = block stored
       uncompressed, clear = deflate-compressed)
      then the hash table:   u32 LE Adler-32 per block

Header area total = 0x20 + 12 · num_blocks; the size fields are validated in ulong so a header with the top bit set cannot wrap past the bounds check. Each 0x4000-byte block of ISO data is deflate-compressed independently; blocks with size 0 decode as zeroes. RVZSharp decompresses with the BCL ZLibStream.

CISO / WBI

A simple block-compressed format used by old homebrew tools.

0x0000  magic       "CISO"
0x0004  block_size  u32 LE — 0x8000 for standard images
0x0008  block map   0x7FF8 bytes — 1 byte per block: 1 = block present, 0 = zero-fill
0x8000  present blocks, concatenated in order

The decoded length is always 0x7FF8 × block_size (the map covers 0x7FF8 blocks, regardless of the file_size other tools write). Present blocks are served sequentially; absent blocks decode as zeroes.

WBFS

The Wii Backup File System container (a FAT-like structure in the file). Header is 512 bytes; multi-byte integers big-endian.

0x000  magic            "WBFS"
0x004  hd_sector_count  u32 BE — total sectors of the raw device image
0x008  hd_sector_shift  u8  — raw sector size = 1 << shift
0x009  cluster_shift    u8  — cluster size  = 1 << shift (≥ 0x8000; 2 MiB for standard files)
0x00A  disc_table[0]    u8  — slot 0 present?
0x00C  disc_table…      disc offsets in raw sectors
0x100  disc info table  (DiscHeaderSize = 256 bytes)
…     disc tables:     the wlba table at `raw_sector_size + 0x100`:
        u16 BE cluster index per 2 MiB cluster of the disc

TGC

“Tiny GameCube” images: the disc without its empty tail, plus a header. RVZSharp follows Dolphin: the virtual image is the file minus the TGC header (Length = file.Length − tgc_header_size), and reads are served with three on-the-fly patches. Header fields are u32 big-endian, except the magic — the one field Dolphin reads without byte-swapping (the on-disk bytes are the little-endian form of 0xA2380FAE):

0x000  magic                 AE 0F 38 A2
0x008  tgc_header_size       (removed from the front when decoding)
0x010  fst_real_offset       offset of the FST within the file
0x014  fst_size
0x01C  dol_real_offset
0x024  file_area_real_offset
0x034  file_area_virtual_offset

Read patches:

No decompression is involved — reads are served straight from the file with the patches applied, and hostile header values are clamped before any allocation.

NFS

Wii U–era encrypted images (the “EGGS” container). The whole image is AES-128-CBC encrypted with a console key; data is organised in LBA ranges. Header is 0x200 bytes; multi-byte integers big-endian.

0x000  magic        "EGGS"
0x010  range count  u32 BE (capped at 61)
0x014  LBA ranges:  { start u32 BE, num u32 BE } × count,
       each unit = one 0x8000-byte block

Decoding: