Pure C# CHD (Compressed Hunks of Data) reader — V1–V5, all 10 codecs, parent/child chaining, 100% byte-for-byte match with MAME chdman.
Fork of RomVault/CHDSharp by Gordon Jefferyes — extended with Zstd, AVHuff, parallel verification, async APIs, metadata support, and a comprehensive test suite.
- CD/GD-ROM track (TOC) parsing — Full track layout, sector types, pregap/postgap, GD-ROM support (incl. legacy
CHGTlittle-endian CDDA) viaTracks/IsLittleEndianAudio/GenerateCueSheet()/ExportToc() UnitBytesproperty — Derives sector size from metadata for all CHD versions (HDD 512B, CD 2448B, V5 header)- New enums —
ChdTrackType(Mode1, Mode2, Audio, etc.) andChdSubType(None, Normal, Raw) - Centralized versioning — All 7 projects share version
1.2.0viaDirectory.Build.props - Deterministic builds — Reproducible byte-for-byte builds with embedded SourceLink
- Embedded debug symbols — Easier NuGet debugging with
<DebugType>embedded</DebugType> - Companion library —
CHDSharpEncoderwith CRC16, SHA1, and Deflate support - Code refactoring — Consistent code style across the entire codebase
dotnet add package CHDSharpTargets net8.0, net9.0, and net10.0. Zero native dependencies — every codec (zlib, lzma, huffman, flac, zstd, AVHuff) is implemented in pure C#, with Zstd backed by the managed ZstdSharp.Port.
using CHDSharp;
using CHDSharp.Models;
// Quick check: is this a valid CHD?
if (Chd.IsChdFile("game.chd", out uint version))
Console.WriteLine($"Detected V{version}");
// Full verification (parallel, deep decompress every hunk)
using var stream = File.OpenRead("game.chd");
var result = Chd.CheckFile(stream, "game.chd", deepCheck: true);
Console.WriteLine(result.IsSuccess
? $"V{result.Version} SHA1: {result.Sha1Hex}"
: $"Error: {result.Error.GetMessage()}");
// Random access — open once, read hunks or byte ranges on demand
var err = ChdFile.Open("game.chd", out var chd);
using (chd)
{
// Inspect metadata (game name, disc label, etc.)
foreach (var meta in chd.Metadata)
Console.WriteLine(meta); // e.g. "GAME: gauntlet"
// Parse CD/GD-ROM track layout (TOC)
if (chd.Tracks is { } tracks)
foreach (var track in tracks)
Console.WriteLine($"Track {track.TrackNumber}: {track.GetTypeString()}");
// Read hunk #42
var hunk = new byte[chd.HunkBytes];
chd.ReadHunk(42, hunk);
// Read arbitrary byte range (crosses hunk boundaries)
var buf = new byte[1024];
chd.Read(offset: 0x10000, buf, 0, buf.Length);
// Or decompress the entire image at once
chd.ReadAllBytes(out var image);
}
// Child (differential) CHD with its parent
var childResult = Chd.CheckFileWithParent("child.chd", "parent.chd");
// Async API
var (_, asyncChd) = await ChdFile.OpenAsync("game.chd");
await using (asyncChd)
{
await asyncChd.ReadHunkAsync(0, hunk);
}# Verify all .chd files in directories (recursive)
CHDSharpCli D:\CHD
# Verify paths from a text file
CHDSharpCli --list chd_paths.txt
# Random-access self-test on a single CHD
CHDSharpCli --random game.chd
# Verify a child CHD against its parent
CHDSharpCli --parent child.chd parent.chd
# Print CD/GD-ROM table of contents
CHDSharpCli --toc game.chd
# Generate CUE sheet for CD CHDs
CHDSharpCli --cue game.chd
# Classify CHD media type
CHDSharpCli --classify game.chd- Read any CHD — V1–V5 headers, all internal map formats (self-dedup, CRC16/32, compressed/uncompressed, RLE)
- All 10 codecs — zlib, lzma, huffman, flac, zstd, AVHuff + CD variants (
cdzl,cdlz,cdfl,cdzs) - Random-access API —
ReadHunk()andRead()with hunk-caching;EnumerateHunks()for sequential streaming - Async API —
OpenAsync,ReadHunkAsync,ReadAsync,IAsyncDisposable - Parallel verification — multi-threaded
CheckFilewith bounded memory, configurable thread count - Parent/child chaining — transparent differential CHD support with wrong-parent detection
- Track info — parse CD/GD-ROM table of contents (track types, sector sizes, pregap/postgap, frame offsets)
- Metadata — expose game name, disc labels, and other CHD header metadata
- 100% chdman match — cross-checked against
chdman info,verify, andextractraw(MAME 0.288) - Pluggable logging —
Microsoft.Extensions.Loggingintegration; silent by default
| Version | Header | Map | Status |
|---|---|---|---|
| V1 | 76 bytes | Self-hunk dedup | ✅ |
| V2 | 80 bytes | Self-hunk dedup | ✅ |
| V3 | 120 bytes | CRC32 map, self-hunk | ✅ |
| V4 | 108 bytes | CRC32 map, parent chain | ✅ |
| V5 | 124 bytes | CRC16 / compressed / RLE, parent/unit chain | ✅ |
| Codec | FourCC | CD Variant | |
|---|---|---|---|
| Zlib (Deflate) | zlib |
cdzl |
✅ |
| LZMA | lzma |
cdlz |
✅ |
| Huffman | huff |
— | ✅ |
| FLAC | flac |
cdfl |
✅ |
| Zstd | zstd |
cdzs |
✅ |
| AVHuff | avhu |
— | ✅ |
| Feature | libchdr 0.3.0 (C) | CHDSharp (C#) |
|---|---|---|
| V1–V5 headers | ✅ | ✅ |
| zlib, lzma, huffman, flac | ✅ | ✅ |
| Zstd (zstd, cdzs) | ✗ | ✅ |
| AVHuff | ✗ | ✅ |
| Parent/child chains | ✅ | ✅ |
| Random access | ✅ | ✅ |
| Async API | ✗ | ✅ |
| Metadata reading | ✗ | ✅ |
| Parallel verification | ✗ | ✅ |
| Pluggable logging | ✗ | ✅ |
| CHD creation | ✗ | ✗ |
| Native dependencies | zlib, lzma, flac | none |
By default the library is silent. Set Chd.LoggerFactory before any other call to enable logging with any ILoggerFactory-compatible provider:
using Serilog;
using Serilog.Extensions.Logging;
Chd.LoggerFactory = new SerilogLoggerFactory(
new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console()
.CreateLogger());The full wiki lives in docs/ — format reference, codecs, API reference, verification, extraction, performance, testing, and troubleshooting.
See the CHDSharpLib README for the complete Chd, ChdFile, ChdResult, ChdHeaderInfo, ChdMetadataEntry, and ChdError API reference, including all Open overloads, the full header DTO read (Chd.ReadHeader), performance tuning (Chd.TaskCount), and usage patterns.
The test infrastructure has three tiers:
| Project | Type | Description |
|---|---|---|
CHDSharpTest |
xUnit | Unit tests (header/API, CRC checksums) + corpus tests against 29 deterministic CHD files (V1–V5, all codecs & map types) |
CHDSharpTester |
WPF | Interactive batch verification cross-checked against chdman — header info, deep verify, SHA1, random-access extraction, codec decode, parent/child chains |
CHDSharpTestGen |
Console | Deterministic corpus generator (builds source images, runs vintage chdman binaries, produces the CHDSharpTest/TestData/ corpus) |
# Regenerate corpus (requires chdman binaries in CHDSharpTest/chdman/)
dotnet run --project CHDSharpTestGen
# Run unit + corpus tests
dotnet test
# Interactive chdman cross-check
dotnet run --project CHDSharpTestergit clone https://github.com/purelogiccode/CHDSharp.git
cd CHDSharp
dotnet build -c Release
# NuGet package
dotnet pack -c Release CHDSharpLib/Requires .NET 8.0 SDK or later. Works on Windows, Linux, and macOS.
MIT License — see LICENSE.
Gordon Jefferyes (@gjefferyes) — the original author of RomVault/CHDSharp, which this project is forked from. Gordon built the foundational C# CHD reader (V1–V5 headers, zlib/lzma/huffman/flac codecs, and a custom LZMA/FLAC stack) that this project extends with Zstd, AVHuff, parallel verification, async APIs, metadata support, and comprehensive testing.
- MAME — CHD format specification and
chdmanreference implementation - libchdr — C reference library by Romain Tisseraud
- ZstdSharp.Port — pure C# Zstd decompressor by Oleg Stepanischev
- Donate: support the developer
- ⭐ Star this repo on GitHub