Skip to the content.

Architecture

┌────────────────────────────────────────────────────────────────────┐
│                          CLI (RVZSharp.Cli)                        │
│            header │ verify │ convert │ extract  —  Blob.Open     │
└───────────────┬────────────────────────────────────────────────────┘
                │ IBlobReader
┌───────────────▼────────────────────────────────────────────────────┐
│                         Library (RVZSharp)                         │
│                                                                     │
│  Blobs ── RvzReader ── Chunks/Compression/Packing/Wii  (read path)  │
│  Blobs ── RvzWriter/WiaWriter ── WiaRvzWriter core     (write path) │
│  Blobs ── GczWriter / CisoWriter / WbfsWriter / TgcWriter (writers) │
│  Blobs ── DiscHasher / DiscVerifier ── Wii hash trees   (verify)    │
└────────────────────────────────────────────────────────────────────┘

Module map

Module Files Responsibility
Blobs/ Blob, BlobType, IBlobReader, PlainBlob, GczBlob, CisoBlob, WbfsBlob, TgcBlob, NfsBlob Format detection and per-format random-access decoding to ISO bytes
Models/ DiscInfo, DiscFileInfo, WiaFileHead, WiaDisc, WiaPartEntry, WiaRawDataEntry, GroupEntry, HashExceptionEntry, DiscHashes, WiaRvzFormat, CompressionType Data models, container structs (RVZ/WIA), option records and enums
Chunks/ ChunkDecoder, TableParser Group decompression, exception-list parsing, table loading
Compression/ CompressionCodecFactory, CompressionEncoderFactory, ICompressionDecoder, ICompressionEncoder, codecs, Lzma/ (vendored 7-Zip decoder) Read-side decompression and write-side compression
Packing/ RvzPackingDecoder, RvzPackingEncoder, LaggedFibonacciGenerator, LaggedFibonacciPrng RVZ junk packing: segment streams and PRNG seed recovery
Wii/ PartitionRegionBuilder, WiiHashCalculator, WiiVolume, WiiPartitionExtractor, PartitionReader Wii partition encryption, hash tree, exceptions, ticket title-key decryption, decrypted partition views
Files/ DiscFileSystem GameCube/Wii FST parsing, case-insensitive lookup, file data streaming
Verification/ DiscVerifier Dolphin VolumeVerifier equivalent: partition headers, TMD/H3 tables and the h0/h1/h2/h3 hash tree walk
IO/ LruCache, MultiPartStream, BlobCopy, Crc32, SectionStream, ParallelExecution Decoded-unit caching, split-file streams, copy/hash helpers and exception-preserving parallel loops

Read path

IBlobReader (any format)          canonical ISO bytes
        │
        ▼
RvzReader.Open                    validates file head + disc struct hashes,
                                  loads partition/raw/group tables (hash-checked)
        │
        ▼
ReadAt(position)                  finds the data area covering `position`
        │
        ├─ raw area ──► group by chunk ──► decompress ──► unpack segments (if packed)
        │                                                         │
        └─ partition area ─► chunk payload (decrypted data)        │
                             + hash exceptions                     │
                             │                                     │
                             ▼                                     ▼
                     PartitionRegionBuilder                RvzPackingDecoder
                     (recompute h0/h1/h2, apply            (LFG PRNG, seed +
                     exceptions, AES-128-CBC               skip offset % 0x8000)
                     re-encrypt, zero-fill tail)

Key points:

Write path

IBlobReader (any format)                    Stream (RVZ/WIA out)
        │                                        ▲
        ▼                                        │
WiiVolume detection ──► data areas in disc order │
   (Wii magic, 0x60/0x61 flags, partition table) │
        │                                        │
        ├─ raw area ──► chunk payload            │
        │              │                         │
        │              ▼                         │
        │        RvzPackingEncoder (junk scan,   │
        │        GetSeed, segment stream; RVZ)   │
        │              │                         │
        ├─ partition area ─► WiiPartitionExtractor
        │   (decrypt region, diff hash tree ──► exceptions,
        │    split/merge into chunks; one exception list
        │    per 2 MiB region a chunk covers)
        │              │
        │              ▼
        │        pack (RVZ) + compress each group
        │        (zero group when all-zero and no exceptions;
        │         WIA always stores the codec output)
        │              │
        ▼              ▼
tables (partition = plain, raw + group = compressed;
        RVZ 12-byte / WIA 8-byte group entries)
layout iteration until the group-table size converges
        │
        ▼
file head (SHA-1 over disc struct, sizes, head hash)

Key points:

Verification

DiscVerifier.Verify (Dolphin: VolumeVerifier) parses each partition header, validates the TMD structure and the H3 table against the TMD content hash, then walks every data sector: it decrypts the hash area (zero IV) and data (IV = ciphertext at 0x3D0) with the plaintext partition key (WiiVolume.GetPartitions, which prefers the container’s key and otherwise common-key decrypts the ticket’s title key), recomputes h0 from the 31 data blocks, compares the embedded h1/h2 slots and the h3 entry, and reports every mismatch with a severity. GameCube discs have no hash trees and are reported valid.

Design decisions

Decision Rationale
Dolphin C++ is the layout truth References/dolphin-master/ — the RVZ/WIA formats were invented there; the Go reader and docs/WiaAndRvz.md are cross-checks
Canonical ISO view for all formats one consumer (CLI, writer) works for every container
GCZ uses BCL ZLibStream (read) and SharpZipLib Deflater (write) GCZ is deflate; SharpZipLib is already a dependency for bzip2, and Deflater can be reset per block like Dolphin’s deflateReset
Parallel decode serializes only file reads RVZ/WIA chunks and partition regions are independent; workers read stored bytes under a lock (short I/O) and decompress from memory in parallel, then write in disc order — byte-identical output, near-linear speedup for LZMA/LZMA2
FST offsets are read from the decrypted view Dolphin’s GetFSTOffset is a partition-relative (decrypted) read; PartitionReader provides that view for the parser, the writer’s split point and extract
LZMA decoder is vendored 7-Zip compact, self-contained, no external native code
LZMA-SDK for encoding pure-managed public-domain encoder (runtime dependency, version 22.1.1)
Writer stores partitions decrypted + exceptions the defining RVZ space optimization; identical to Dolphin
Junk packing is best-effort GetSeed fails cleanly on non-PRNG data and the writer falls back to literal bytes — output stays valid
Chunk sizes per Dolphin powers of two from 32 KiB to 2 MiB, or multiples of 2 MiB above that
PURGE only in WIA output PURGE is a WIA-only method (WiaWriter); RVZ output rejects it and RVZ readers reject PURGE containers

Format-version handling

WiaFileHead carries version (written 0x01000000) and version_compatible (0x00030000 for RVZ, 0x00080000 for WIA). The reader accepts a file when ImplementedVersion >= VersionCompatible, so newer readers can open older files and vice versa.