This rolls up everything since 4.0 into one stable release. Two new tools, full 3DS reversibility, faster archive browsing, and DAT matching that finally works for more than just CHDs.
If you've been on a 4.1.0 beta, there's nothing new here over 4.1.0-beta-4. This is just the stable cut.
What's new
PSP / PS2: CSO / ZSO / DAX (the fifth tool)
Compress PSP and PS2 .iso disc images to every format maxcso writes, and back. Five modes: CSO v1 (the universal default), CSO v2 (better block alignment for newer emulators), ZSO (lz4, faster to decode), DAX (the legacy PSP format), and decompress back to .iso.
PPSSPP and PCSX2 read these directly, so you don't need to decompress before playing. The round trip is byte-for-byte lossless, verify runs maxcso's --crc, and you can convert straight out of a ZIP / 7z / RAR. No keys needed.
Handheld ROMs: GB / GBC / GBA / NDS (the sixth tool)
Compress Game Boy, Game Boy Color, Game Boy Advance, and Nintendo DS dumps (.gb / .gbc / .gba / .nds) to a plain .7z or .zip, and extract them back. Three modes: 7z (LZMA2, smallest), zip (deflate, most compatible), and extract.
The round trip reproduces the original ROM byte-for-byte, checked by SHA-1 on real dumps. On my sample set GBA dumps shrank by about half and GB/GBC by roughly two thirds. Output names keep the ROM extension in front of the archive suffix (Game.gba → Game.gba.7z) so extraction is deterministic and same-name ROMs from different platforms never collide. Fast / Default / Max effort presets, with Max as the default.
3DS is now fully reversible
3DS used to be compress-only. Now there's a decompress mode that restores the original ROM from a Z3DS container (.zcci → .cci, .zcia → .cia, .z3ds → .3ds, and the two new ones below), and the round trip is byte-identical. The old "keep your sources" caveat is gone.
Two new input formats: .cxi (CTR Executable Image) and .3dsx (homebrew), mapping to .zcxi / .z3dsx. Both are experimental, like .cia.
This rides on a new upstream fork, pacnpal/z3ds_compress, which adds the decompression mode and the two new formats. Direction is always forced with an explicit flag, so it never guesses from a magic header.
Decompress a CHD straight out of an archive
A .chd packed inside a .zip / .7z / .rar now shows up when you browse into the archive, and you can extract it back to a disc image in place. Before, an archived .chd was hidden and you had to unzip by hand first. Recompression from inside an archive stays off on purpose, since re-CHD-ing a finished .chd is a pointless round trip.
Archive browsing is now global
Browsing into a compressed ROM archive used to say "Empty folder" even though the badge claimed it had contents. The contained ROM was invisible. Same idea behind the archived .chd fix above. The archive browser now lists any known source file inside a container, so a single-ROM archive shows its ROM and an archived .chd shows up too. Visible files that would be recursive to re-convert (a ROM already in its archive) are shown for inspection but not offered for in-place conversion.
Faster listings in archive-heavy folders
Browsing a folder with thousands of archives used to open and parse every single one on the request thread, twice each, so a big folder could take around 40 seconds to list and the whole UI looked frozen behind it. The listing now returns right away and the per-archive badges (member counts, "N converted", verify eligibility) fill in a moment later in the background. There's a new shared archive-member cache underneath, so each archive gets opened at most once per change across the whole app.
DAT matching now covers every format, not just CHD
The background library scan used to only find .chd files. Now it discovers every tool's output: Dolphin (.rvz / .wia / .gcz), 3DS, Switch, and plain .iso / .bin, and it primes the DAT-match cache for all of them.
Compressed Dolphin images now match Redump DATs. Matching uses each tool's embedded or derivable content hash, so chdman reports the CHD's SHA1 and Dolphin reports the reconstructed disc SHA1 from dolphin-tool verify. That's the hash Redump records for GameCube/Wii discs, so .rvz / .wia / .gcz match without the container bytes being identical. The heavy disc-hashing pass is capped and cancellable so it can't run away.
Tool-neutral priority and timeout settings
The process priority and timeout knobs used to be chdman-only. They govern every tool, so they now have tool-neutral names (COMPRESSATORIUM_TOOL_NICE, COMPRESSATORIUM_TOOL_IOPRIO_CLASS, COMPRESSATORIUM_TOOL_VERIFY_TIMEOUT, and friends). The old CHD_* names still work as aliases, so nothing breaks. You can also override a single tool with COMPRESSATORIUM_<TOOL>_*. Switch and 3DS verify runs are now bounded by the verify timeout too, where before they ran unbounded.
Fixes
- Handheld ROM Verify/Info only shows on single-ROM archives. The tool claims
.7z/.zip, so it used to offer Verify/Info on any archive by extension, including unrelated multi-file zips. It now checks the members and only offers those actions when the archive holds exactly one handheld ROM (#146). - Delete-on-verify no longer leaks verification records. Deleting a non-CHD verify-class source (
.rvz,.nsz,.z3ds, and so on) after verifying used to leave a stale record pointing at a file that no longer existed. The clear is now tool-wide (#130). - Stale or failed hashes no longer poison the match cache. A transient hash failure gets recorded as a non-cacheable error instead of a false "unmatched", and a forced rescan clears it.
Notes
- New tools need their binaries in the image. CSO builds maxcso from source in a dedicated Docker stage, and Handheld ROM reuses the
7zalready in the image (no new build stage). The 3DS binary was rebuilt from the new fork, which now builds with CMake. - Both new tools and the 3DS modes are available in the Web UI and the REST API, with live progress, single and batch verify, and file-info.
Full per-section detail, including the internals and test coverage, is in docs/RELEASE_NOTES.md.