-
Notifications
You must be signed in to change notification settings - Fork 0
libchdr comparison
This page compares CHDSharp against the C reference library libchdr 0.3.0 (kept in References/libchdr-0.3.0), which CHDSharp uses as a parity baseline.
CHDSharp is a feature superset of libchdr 0.3.0: it implements everything libchdr does (plus AVHuff, which libchdr does not implement), adds verification, extraction, async APIs, and metadata support, and has zero native dependencies — where libchdr bundles zlib (miniz), LZMA SDK, zstd, and dr_flac, CHDSharp ships managed implementations.
CHDSharp vs the two other independent CHD implementations (chd-rs 0.3.4 and CHDlite 0.2.1, compared against their checked-in sources), MAME's reference chdman (0.288), and libchdr 0.3.0. The CHDSharp column covers the whole repo (reader + CHDSharpEncoder + CLI). ✅ = supported, 🟡 = partial, ❌ = not supported, — = not applicable (CLI).
| Capability | CHDSharp (this repo) | chd-rs 0.3.4 (Rust) | CHDlite 0.2.1 (C++) |
chdman (MAME 0.288) |
libchdr 0.3.0 (C) |
|---|---|---|---|---|---|
| Reading | |||||
| Read V1–V5 | ✅ | ✅ | 🟡 V3–V5 only (rejects V1/V2) | ✅ | ✅ |
| All 10 codecs (decode) | ✅ | ✅ | ✅ | ✅ (reference) | 🟡 9 of 10 (no AVHuff) |
| Parent/child chains (read) | ✅ | ✅ | ✅ | ✅ | ✅ |
| Per-hunk CRC16/CRC32 verification | ✅ always | 🟡 opt-in feature, off by default | ✅ always | ✅ always | 🟡 V5 CRC16 build option (on by default); V3/V4 CRC32 never checked |
| Full-image verify (rawsha1 + combined SHA1) | ✅ parallel | 🟡 raw SHA1 only | ✅ sequential | ✅ sequential | ❌ no verify function |
verify --fix (repair header hashes) |
✅ | ❌ | ✅ | ✅ | ❌ |
| Track/TOC parsing (CD/GD-ROM) | ✅ Tracks/ChdTrackInfo
|
🟡 tags recognized, no track model | ✅ | ✅ | ❌ |
| Metadata read | ✅ | ✅ | ✅ | ✅ | ✅ chd_get_metadata
|
| Writing | |||||
| Write V5 | ✅ (encoder) | ❌ read-only | ✅ | ✅ (reference) | ❌ read-only |
| All 10 codecs (encode) | 🟡 9 of 10 (avhu decode-only; chdman produces it only via createld, deliberately skipped) |
❌ | ✅ | ✅ | ❌ |
Uncompressed CHD (-c none) |
✅ byte-exact with chdman | 🟡 decode only | 🟡 core supports, CLI rejects | ✅ | 🟡 decode only |
Delta/parent CHD creation (-ip) |
✅ | ❌ | ✅ | ✅ | ❌ |
| CHD→CHD copy / re-compress | ✅ | ❌ | ✅ | ✅ | ❌ |
| Metadata write (addmeta/delmeta) | ✅ | ❌ | ✅ | ✅ | ❌ |
| Input formats | |||||
| CUE / GDI / ISO / TOC / NRG parsing | ✅ all five | — | ✅ all five | ✅ all five | ❌ |
| CUE style conversion / Redump match | ✅ | ❌ | ✅ | ✅ convertcue
|
❌ |
| API & reads | |||||
| Byte-range reads | ✅ Read(offset, ...)
|
✅ Read + Seek
|
✅ read_bytes
|
— | ❌ hunk-only chd_read
|
| LBA/MSF sector-addressed reads | ✅ ReadSector/ReadSectorMsf/ReadFrame + CdRomAddress
|
❌ | ✅ read_sector + msf_to_lba/lba_to_msf
|
— | ❌ |
| Thread-safe random access | ✅ ReadHunkConcurrent
|
❌ | ❌ | — | ❌ |
| Async I/O API | ✅ | ❌ | 🟡 async compress pump only | — | ❌ |
| Cancellation + progress reporting | ✅ on all long-running APIs | ❌ | 🟡 cancel + callbacks via C API | — | ❌ |
| Precache / multi-hunk LRU cache | ✅ both | ❌ | 🟡 single-hunk cache | — | 🟡 chd_precache, no hunk cache |
| Header-only DTO read | ✅ Chd.ReadHeader (libchdr parity) |
🟡 Header struct exposed |
🟡 via ChdReader
|
✅ info
|
✅ chd_read_header
|
| Performance & tooling | |||||
| Parallel verification | ✅ (default 8 workers) | ❌ | ❌ | ❌ | ❌ |
| Parallel encoding | ✅ (1–64 workers) | ❌ | ✅ (≤ 16, per-codec weighted queues) | ✅ (≤ 16 work-queue threads) | ❌ |
| Benchmarks | ✅ BenchmarkDotNet + chdman comparer | ✅ benches/
|
✅ benchmark_chd.cpp
|
— | 🟡 tests/benchmark.c (minimal timing harness) |
| Fuzzing / mutation testing | ✅ 3500-seed deterministic suite | ✅ cargo-fuzz target | ❌ | ❌ | 🟡 tests/fuzz.c (libFuzzer harness) |
| Extras | |||||
| Extraction (CUE/BIN, GDI, ISO) | ✅ | 🟡 raw dump only | ✅ | ✅ | ❌ |
| Platform/game detection | ✅ 11 systems (CHDlite parity) | ❌ | ✅ 11 systems | ❌ | ❌ |
| Multi-hash output (SHA-256/CRC32/XXH3) | ✅ SHA1/SHA256/CRC32/XXH3 | ❌ | ✅ SHA1/MD5/CRC32/SHA256/XXH3 | 🟡 SHA1/MD5 only | ❌ |
| Batch mode (folder scan) | ✅ | ❌ | ✅ | ❌ | ❌ |
| Native dependencies | none (pure C#) | none (pure-Rust crates) | zlib-ng / zstd / lzma / flac | zlib / lzma / flac | zlib (miniz) / LZMA SDK / zstd / dr_flac |
| Language | C# (.NET 8/9/10) | Rust | C++ | C++ (MAME) | C |
The same table is also in the repository README.
| Feature | libchdr 0.3.0 (C) | CHDSharp (C#) |
|---|---|---|
| CHD V1–V5 headers | ✅ | ✅ |
| V1/V2 maps (packed entries, self-dedup) | ✅ | ✅ |
| V3/V4 maps (CRC32, mini/self/parent hunks) | ✅ | ✅ |
| V5 compressed map (Huffman+RLE) | ✅ | ✅ |
| V5 uncompressed map | ✅ | ✅ |
| V5 unit-based parent references (incl. unaligned/straddling) | ✅ | ✅ |
zlib / cdzl
|
✅ (miniz) | ✅ (managed) |
lzma / cdlz
|
✅ (LZMA SDK) | ✅ (custom C# port) |
huff |
✅ | ✅ |
flac / cdfl
|
✅ (dr_flac) | ✅ (custom C# decoder) |
zstd / cdzs
|
✅ (zstd 1.5.7) | ✅ (ZstdSharp.Port) |
avhu (AVHuff) |
❌ (known limitation) | ✅ |
Secondary codec (ZLIB_PLUS type-6 hunks) |
❌ declared but unimplemented | ✅ |
| Per-hunk CRC32 verification (V3/V4) | ❌ stored, never checked | ✅ (honors NO_CRC) |
| Per-hunk CRC16 verification (V5) | ✅ (build option, default on) | ✅ |
| Full-image verification (SHA1/MD5/rawsha1) | ❌ no verify function | ✅ parallel |
| Combined metadata-SHA1 verification | ❌ | ✅ |
| Metadata query by tag/index/flags | ✅ chd_get_metadata
|
✅ GetMetadata + Metadata list |
| V1/V2 synthesized GDDD metadata | ✅ | ✅ |
chd_precache (whole file in RAM) |
✅ | ✅ Precache()
|
Random access (chd_read / ReadHunk, Read) |
✅ | ✅ |
| Byte-range reads | ❌ (hunk-only) | ✅ Read(offset, ...)
|
| Sector-addressed reads (LBA/MSF) | ❌ requested (#155) | ✅ ReadSector/ReadSectorMsf/ReadFrame + CdRomAddress
|
| Async API | ❌ | ✅ |
| Extraction (CUE/GDI/ISO/IMG/RAW) | ❌ | ✅ |
| TOC / track parsing | ❌ | ✅ Tracks/ChdTrackInfo
|
| Classification (cd/dvd/hdd/gd-rom) | ❌ | ✅ |
Custom IO (callbacks vs Stream) |
✅ core_file callbacks | ✅ Stream overloads |
| Thread-safe logging | ❌ | ✅ ILoggerFactory
|
| CHD creation | ❌ (commented out) | ✅ CHDSharpEncoder
|
| Native dependencies | zlib, lzma, flac, zstd | none |
To close the small gaps found during the comparison, the library gained:
-
GetMetadata(string? tag, uint index, out ChdMetadataEntry?)— mirrorschd_get_metadata(tag search, occurrence index, wildcard vianull/empty tag,Chderrmetadatanotfound). -
ChdMetadataEntry.Flags— exposes the metadata flags byte (libchdr'sresultflags). -
ChdFile.Precache()— mirrorschd_precache(whole compressed file in memory, idempotent, stream position restored). -
V1/V2 synthesized GDDD metadata — matches libchdr's behavior of fabricating
CYLS:…,HEADS:…,SECS:…,BPS:…from the obsolete header fields.
All four are covered by ParityFeaturesTests.
| Area | libchdr | CHDSharp | Why |
|---|---|---|---|
| V3/V4 CRC32 | never verified | verified (unless NO_CRC) | matches MAME semantics; catches corrupt files libchdr silently accepts |
V3/V4 ZLIB_PLUS type-6 hunks |
falls through, returns success with empty output | fully decoded (secondary codec) | correctness |
| AVHuff | unsupported (open fails or errors) | fully decoded | feature |
| Metadata errors |
CHDERR_METADATA_NOT_FOUND only |
also Chderrreaderror/Chderrinvaliddata surfaced |
diagnostics |
Open(Stream) IO failures |
returns errors | returns errors (never throws) | robustness |
-
FLAC: libchdr uses dr_flac 0.13.3 (battle-tested, full spec). CHDSharp's custom decoder covers everything CHD content uses — 16/24-bit, all channel modes incl. mid/side, fixed/LPC subframes (orders 1–32), all block sizes, Rice coding, CRC-8/16 — and rejects unsupported cases (e.g. 8/12/20-bit, custom sample-rate codes) that
chdmannever produces. The corpus includes FLAC, cdfl, and AVHuff-FLAC fixtures. - LZMA: both synthesize the fixed properties (lc=3, lp=0, pb=2, dict = hunk size) since CHD hunks are headerless; CHDSharp's port also supports LZMA2 and preset dictionaries internally.
- Zstd: libchdr uses zstd 1.5.7 native; CHDSharp uses ZstdSharp.Port 0.8.8 (pure C#). Both handle single-frame blocks correctly.
-
Use CHDSharp when you want a managed, dependency-free reader with verification, metadata, extraction, and modern .NET ergonomics (async, nullable,
IAsyncDisposable). - Use libchdr when you need a C library for embedding in C/C++ projects, or want the (extremely well-tested) native zstd/LZMA/FLAC stacks and do not need AVHuff, verification, or extraction.
CHDSharp
Format & internals
API & usage
Operations
Writing CHDs
Reference