All notable changes to RomForge are documented here. This project follows Semantic Versioning.
- Re-archiving now verifies the newly-written archive by reading it back and checking its CRC before marking the ROM re-archived, catching a corrupted write instead of trusting it. The verified CRC also warms the scan cache, so a "Scan Folder" run right after a re-archive no longer recomputes CRCs it already just confirmed.
- No user-facing changes. Build-time static analysis (Roslynator and .NET IDE style rules) is now enforced, catching issues that were previously invisible locally until CI ran a separate analysis pass.
- Re-archiving large ROMs no longer exhausts system memory and stalls the machine. 7-Zip was splitting large inputs into multiple blocks and encoding them in parallel, each encoder holding its own dictionary-sized allocation, so peak memory tracked the size of the ROM rather than the dictionary — a 4 GB 3DS cart could reach roughly 42 GB in a single job. Compression now uses a single encoder with a capped dictionary, holding memory flat at about 2.6 GB per job at any ROM size, with no measurable increase in archive size.
- "Re-Archive All" no longer re-packs the entire library on every run. DATs that store the ROM extension with a leading dot produced archive entries with a doubled dot ("Name..3ds"), which never matched on re-scan, so those ROMs stayed re-archive targets forever. Archives written by earlier versions are genuinely misnamed and will each be re-archived once, after which they settle as "Good".
- Memory throttling now applies to every compression path. Previously only bulk re-archive was throttled, so a single re-archive, a single trim and a bulk trim each ran unthrottled and could claim a full memory budget at the same time.
- Dictionary size and concurrency now adapt to the amount of memory available, so a single job can no longer exceed the entire memory budget on machines with less RAM.
- "Trim" is now correctly disabled while a bulk re-archive is running, matching the other operations.
- Cancelling a bulk re-archive no longer crashes in-flight files with a
NullReferenceException - "Rename All" no longer runs its work before the progress window appears, then flashes the window closed instantly
- Re-archiving large ROMs (e.g. 3DS) concurrently is now also throttled by estimated memory usage, not just CPU core count, to prevent exhausting system memory
- "Rename All" no longer reports success while changing nothing for ROMs whose only problem was a misnamed internal archive entry; the outer-filename rename and the internal entry name are now tracked separately, so these ROMs are correctly routed to Re-Archive instead. A re-scan is required to reclassify ROMs stored under the previous version.
- ROMs re-archived before the archive entry-naming fix could still show as "Good" despite having a garbage internal archive entry name; RomForge now detects the mismatch and requires a re-archive to clear it
- ROMs are now always renamed as "release - title", regardless of what naming template a DAT's own config specifies
- Fixed a bug where re-archiving or trimming a ROM could give its internal archive entry a corrupted name (a leftover random extension) when the ROM's real extension is empty
- The "Updating DAT" and "Downloading Images" dialogs now show which DAT they're working on, instead of a generic title
- Replaced the SharpCompress + external
7zzCLI archiving engine with SevenZipSharper, a bundled native library — RomForge no longer needs Homebrew'ssevenzippackage installed for compression to work - Re-archiving now tunes the 7z dictionary size to each ROM, improving compression ratios
- Fixed a data-loss bug where re-archiving a ROM to its own filename could destroy it if the app was interrupted mid-operation
- Patched a high-severity vulnerability in a bundled SQLite component (GHSA-2m69-gcr7-jv3q)
- The status bar now shows the running app version, with a link to the GitHub releases page; an "About RomForge…" menu item shows the same info
- Scan results are no longer wiped to "Missing" when a DAT's ROM folder is on an offline or not-yet-mounted external drive at startup
- Re-archiving or trimming a ROM no longer risks losing it if the destination becomes unreachable mid-operation (e.g. a drive unmounts) — the compressed copy is recovered to a dedicated folder instead of being silently discarded
- Deleting an entire ROM subfolder while its drive stays online is now correctly detected and reported, instead of being silently ignored
- In-app update check: RomForge now checks GitHub for a newer release at startup and lets you know when an update is available
- A DAT menu command to download any missing box-art on demand, with a live "X of Y" progress log you can cancel
- Updated the Avalonia UI toolkit to 12.1.0 and set the application name shown in the macOS menu bar
- Cancelling a re-archive no longer crashes the app
- Re-archiving now replaces a stale destination archive instead of appending to it, closing a path that could silently corrupt a ROM
- Preferences writes are serialized, so two settings changes in quick succession can no longer overwrite each other and lose a setting
- Hardened the re-archive status database against concurrent-write races that could drop a persisted re-archive mark
- Download missing box-art: after a DAT update, RomForge fetches only the images you don't already have and shows a live log with an "X of Y" counter that you can cancel
- A ROM is now only counted "Good" once RomForge has re-archived it — a freshly scanned, coincidentally-correct file no longer shows as good before it has been rewritten
First stable release.
- Settings screen (File → Settings…, ⌘,): global default archive format and a default destination folder for unverified ROMs
- Native macOS menu bar and a right-click context menu on the game list, plus a streamlined toolbar and status filter chips
- Signed and notarized macOS build — the app now launches without a Gatekeeper warning
- Reworked per-game match status into composable flags, so multiple issues on one ROM are tracked and shown together
- Fixed a zip-slip path-traversal weakness when extracting archives
Initial release.
- Import and manage OfflineList-format DAT files (ZIP-wrapped or raw XML)
- Scan ROM folders and match against DAT entries by CRC32
- Visual match status per game: Verified, Missing, Incorrectly Named, Wrong Archive Type, Untrimmed
- Sortable columns (release number, title, publisher, status) and per-status filter checkboxes
- Rename ROMs to DAT-expected filenames
- Re-archive ROMs between ZIP and 7z formats
- Trim ROMs (GBA/NDS padding removal)
- Auto-update DAT files from their configured update URL
- Scan cache keyed by folder path — only re-hashes files that have changed
- Status persistence via SQLite — game list survives restarts without re-scanning
- Multi-DAT support — open and switch between multiple DAT files in one session
- Progress dialog with cancellation for all long-running operations
- macOS, Windows, and Linux support via Avalonia UI