Skip to content

Latest commit

 

History

History
1413 lines (1177 loc) · 74.3 KB

release-notes.md

File metadata and controls

1413 lines (1177 loc) · 74.3 KB

Release Notes

1.9.1

Release date: 2026-11-08.

Patch release: reliable releases and a clearer GUI. There are no library API or archive-format changes; the package remains compatible with 1.9.0.

GUI

  • Folder pickers no longer surface Avalonia's Directory must exist exception as an application error when the selected folder was deleted (or became inaccessible) while the native dialog was open. The GUI now explains that the path is not an existing folder and suggests choosing another folder or typing the path directly.
  • Picker and browse failures now marshal their log messages to the UI thread, so a handled picker error can no longer trigger a second InvalidOperationException from DataContext access on a thread-pool thread.
  • Removed the now-redundant nested picker-failure guards and added regression coverage for the Avalonia exception contract.

Release engineering and distribution

  • Tag pushes reliably create the GitHub release again; workflow_dispatch dry runs still build and smoke-test the bundles without publishing.
  • The release SBOM tool is pinned to Microsoft.Sbom.DotNetTool 4.1.13.
  • Docker base images are pinned by digest, and GHCR write permission is scoped to the Docker build job.
  • Packaging manifests are generated from GitHub REST API release digests (including the refreshed 1.9.0 manifests), and the Homebrew cask uses the current macOS dependency form.

Tests

  • Full suite: 2315 passed / 1 opt-in skip on net10.0 (three new GUI folder-picker regression tests); 2239 passed / 1 opt-in skip on net8.0/net9.0.

1.9.0

Release date: 2026-11-08.

The most advanced XISO management release. 1.9.0 combines the reviewed public-API cleanup (FAC-01), the beyond-reference feature pass (BRF-01…BRF-13), the distribution and shell-integration track (DST-01…DST-05) and a full documentation refresh. net8.0, net9.0 and net10.0 remain supported.

Breaking change: StfsSharp compatibility facades removed

  • Removed XISOSharp.GodHeader, XISOSharp.StfsHeader, XISOSharp.StfsPackage, XISOSharp.BlockDevice.GodBlockDevice and the matching XISOSharp.Models records/enums (GodTitleInfo, GodVolumeInfo, StfsEntry, StfsPackageInfo, StfsPackageKind, StfsTitleInfo, StfsValidationIssue, StfsValidationReport). Consumers use StfsSharp types directly.
  • Kept XisoChecksum.ComputeStfsChecksum/ComputeStfsChecksumHex as StfsSharp-backed helpers. The internal GodVolumeBlockDevice adapter keeps XisoImageSource/OpenRead/OpenBlockDevice working for GOD/SVOD inputs.
  • Package validation now compares against 1.8.0; the reviewed CP0001 suppressions cover exactly the facade type removals.
  • Downstream consumers migrated to the hybrid split: SimpleXisoDrive uses XISOSharp for mounting/XDVDFS and StfsSharp directly for GOD/SVOD resolution; XISO Studio uses XISOSharp for reads, StfsSharp directly for GOD metadata and CCISharp directly for CCI validation (XRP-04).

New inspection and archival tools

  • Parallel collection verbs (BRF-06): --jobs 1..64 now also runs multi-image checksum, hash, -V/audit and --batch extract/list/tree/rewrite over images in parallel. Per-image output is captured and replayed in input order, JSON arrays stay ordered, and scoped Logger counters keep each image's summary exact.
  • Redump DAT verification (BRF-09): XisoDat.Parse/Verify and verify-dat <dat> <image>... [--json] match whole images against a Redump-style XML DAT (game/rom size + MD5/SHA-1/CRC32) and report verified, ambiguous, not-in-DAT and missing entries. No DAT source is bundled.
  • Disc-layout inspector (BRF-01): XisoDiscInfo.Read and disc-info/--disc-info report XGD type/subtype and wave, video L0/L1 and game-partition byte/sector ranges, PFI presence and layer break, embedded or sectors.txt security-sector ranges, Redump-size matching and consistency warnings. Containers report the game-partition view and mark video fields unavailable.
  • Skeleton overlay (BRF-02): XisoSkeleton.Apply and apply-skeleton/--apply-skeleton restore file data into a --petrify skeleton, verifying the optional .hash; Petrify→Apply reproduces the original image byte-for-byte. Skeleton creation now preserves the system preamble and 0xFF file-tail padding.
  • Per-file hash sidecars (BRF-05): XisoReader.ComputeFileHashSidecar and file-hashes generate SHA-1 (default), SHA-256 or MD5 sidecars for ISO/split/CISO/CCI/GOD/STFS/ZAR; verify-hashes detects all three digest lengths and accepts the same containers.
  • Redump/XGD size helper: XisoDiscInfo.IsKnownRedumpSize.

Xbox 360 metadata and executables

  • Embedded default.xex metadata (BRF-03): GOD headers and XBLA/XBLIG STFS packages merge XDBF/XSRC publisher, developer, genre, description and thumbnail presence into title-info/TitleInfo, in text and --json.
  • Thumbnail export (BRF-04): xex-image --type thumbnail writes the XDBF 0x8000 PNG payload (image or loose .xex input).
  • Loose executables (BRF-08): --xex-info, --xbe-info and --xbe-image accept a single .xex/.xbe file with the same parser and JSON shape as the image-plus-path form.
  • ZAR level (BRF-07): --zar-level 1..22 for --zar, --compress and convert --format zar; level 6 remains byte-identical.

Name and determinism policy

  • Create-time link policy (BRF-12): --symlink-mode follow|skip|reject for -c, --pack, build-image and apply-skeleton. follow is the historical behavior (file links pack their target, directory reparse points are skipped); skip omits both; reject fails with the link path. Cyclic directory links always terminate.
  • Actionable host-I/O diagnostics (BRF-13): HostIoDiagnostics names the path, operation and likely fix for permission-denied, long-path, sharing, existing-destination, illegal-name and full-disk failures. Extraction exceptions and CLI modes use the same detail, so raw Permission denied or Invalid argument no longer reaches the user alone.
  • Xbox filename rules (BRF-10): XisoNameRules exposes the 42-character component limit and Latin-1 contract. --strict-names fails before writing; the default warns. Supported for create, --pack, --copy-in, build-image and Apply; +, !, spaces and Latin-1 names round-trip.
  • Deterministic packing (BRF-11): --deterministic is an alias for --file-time 0 and is accepted for create, --pack, rewrite and build-image; repeated packs are byte-identical. Rewrites now accept an explicit fileTime so --deterministic -r writes FILETIME 0 instead of preserving the source timestamp.

Distribution and shell integration

  • winget, Scoop and Homebrew manifests (DST-03): the release assets are described by generated manifests under packaging/. The repository root is also a Scoop bucket (bucket/xisosharp.json), and scripts/update-packaging.ps1 -Version <version> refreshes every manifest and SHA-256 value from a published GitHub release.
  • Shell completions and man page (DST-04): PowerShell, bash, zsh and fish completions live in docs/completions/, and xisosharp(1) in docs/man/. CI parses each script, checks that every CLI flag is completable, and renders/lints the man page.
  • Container image (DST-05): Dockerfile builds a framework-dependent CLI image. docker.yml smoke-tests -v, create/list/extract and publishes ghcr.io/purelogiccode/xisosharp:<version> plus :latest on tag pushes.
  • Optional signing (DST-01/DST-02): NuGet author signing runs when the signing secrets exist; Windows bundles can be Authenticode-signed and verified, and macOS bundles codesigned/notarized, behind repository variables. Unsigned builds remain the default.
  • CI validation: packaging-smoke (completions/man page), packaging-windows (winget/Scoop validation) and package-install-smoke (winget, Scoop and Homebrew installs).

Review fixes

  • Deterministic rewrites now write the fixed FILETIME again (DecodeXiso/Rewrite gained additive fileTime overloads).
  • Redump DAT parsing skips size-only entries that can never be content-verified, and duplicate detection no longer depends on a |-joined key.
  • Host-I/O diagnostics map the Unix EWOULDBLOCK sharing error in addition to EBUSY and EEXIST.

Tests

New suites cover the disc inspector, skeleton overlay, embedded XEX metadata, thumbnail export, hash sidecars across containers, ZAR levels, loose executables, name rules, deterministic packing, parallel collection verbs, Redump DAT verification, symlink modes and host-I/O diagnostics. The full suite is 2312 passed / 1 opt-in skip on net10.0 and 2239 passed / 1 opt-in skip on net8.0/net9.0.

1.8.0

Release date: 2026-11-07.

Hardening and Xbox 360 GUI release. No existing public API is removed and all read/write behavior is unchanged; the package validates against 1.7.0.

Library

  • Source-filesystem packing (LIB-01): ISourceFilesystem is the read-side counterpart to IFilesystem. MemoryFilesystem implements both, and XisoWriter.CreateXiso/PackFromDirectory (sync and async) gain overloads that pack a custom store without host source paths. The output is byte-identical to the host-directory path and remains CWD-free under concurrent creates.
  • Per-call logging (LIB-02): IXisoLogger, XisoLogOptions and XisoLogScope route one operation's log output to an isolated sink. UnpackOptions.Log applies the same to extraction. Scopes are AsyncLocal-based, so concurrent operations can log to separate sinks; the static Logger facade is unchanged when no scope is active.
  • Sparse outputs (LIB-03): pre-sized writer and extraction outputs are marked sparse on NTFS (FSCTL_SET_SPARSE) and rely on file-system holes on Unix. CISO/CCI decompression and ZAR extraction skip all-zero chunks; every path keeps the dense fallback when sparse files are unavailable.
  • Property-style round-trips (LIB-04): deterministic seeded coverage for pack/extract, split/join, CISO, CCI and ISO/ZAR at empty, one-byte, sector-boundary and compression-threshold sizes.
  • Benchmarks (LIB-05/LIB-06): the end-to-end suite adds extract, CCI compress/decompress and 64 MiB random-read cases; docs/benchmarks.md records the methodology and an extract-xiso/xdvdfs/XboxKit comparison with a reproducible script.
  • Support policy (LIB-07): net8.0/net9.0 stay supported compatibility targets in 2.x (owner decision 2026-11-07); net10.0 is the primary target.
  • Package validation (LIB-08): the baseline moved from 1.4.4 to 1.7.0; the 1.4.4-era suppressions were retired.

CCISharp 1.1 integration

XISOSharp now references CCISharp 1.1.0:

  • CCI compression levels 10..12 select the managed LZ4-HC encoder (level 12 is the highest effort); levels 0..9 keep the existing fast encoder and byte output.
  • Single-file compress --format cci --jobs 1..64 compresses sectors on a bounded worker pool. Output is byte-identical to --jobs 1.
  • CCI readers accept multi-digit parts such as game.10.cci when the contiguous set starts at game.1.cci; the writer still emits .1.cci … .9.cci.
  • XisoCci.CompressToCci gains a jobs overload; the existing overload is unchanged and defaults to sequential compression.
  • Documentation, CLI help and the public-API baseline are updated. Existing level 0..9 CCI output and all read verbs are unchanged.

Docs and fixtures

  • DocFX link gate (DOC-01): the Pages site and API reference already publish from the library XML docs; a CI docs-links job now fails on broken local Markdown/HTML links.
  • Public synthetic corpus (DOC-02): XISOSharp.TestDataGenerator --corpus deterministically generates XISO, split ISO, CISO, CCI, ZAR, GOD/SVOD, XBLA/XBLIG STFS, XBE/XEX and corrupt fixtures plus a SHA-256 manifest. No game data is included, and PublicCorpusTests/BattleTests consume it.
  • Docs refresh (DOC-03): feature matrices, known limitations, library/CLI docs and READMEs updated for the hardening APIs and the Xbox 360 GUI.

GUI

  • Xbox 360 tab (GUI-01/GUI-02): open GOD/SVOD headers or .data folders, XBLA/XBLIG STFS packages and images; list/tree/extract/unpack/audit, with the same CLI verbs and byte-identical output as the command line. Drag/drop routes GOD/STFS inputs to the tab.
  • Title panel (GUI-03): parses title-info --json for XBE/XEX/GOD/STFS and shows title name, ID, region, disc and publisher/developer/genre fields.
  • XBE preview (GUI-04): renders logo, $$XTIMAGE title and $$XSIMAGE save assets through the same XbeAssets decoder as --xbe-image; missing or unsupported assets produce a clean message.
  • Parallel controls (GUI-05): extraction and CISO/CCI compression expose --jobs 1..64, and CCI levels 10..12 are selectable.

Full suite green on all three targets: 2144 passed / 1 opt-in skip on net8.0/net9.0 and 2217 passed / 1 opt-in skip on net10.0. Package validation against 1.7.0, dotnet format, InspectCode, AOT, fuzz and battle-interop are green on the release commit.

1.7.0

Release date: 2026-11-07.

StfsSharp extraction. The GOD/SVOD and single-file XBLA/XBLIG STFS readers now live in the standalone MIT package StfsSharp 1.0.0. XISOSharp consumes it as a NuGet dependency and keeps its historical public types as thin facades, so no read verb changes behavior:

  • GodHeader, StfsHeader and StfsPackage map the StfsSharp models to the existing XISOSharp records.
  • GodBlockDevice is an IBlockDevice adapter over StfsSharp.GodVolume.
  • XisoChecksum.ComputeStfsChecksum and the CLI/GUI paths are unchanged.
  • The facades were removed in XISOSharp 1.9.0; consumers use StfsSharp directly.

StfsSharp adds a standalone public surface for the moved readers: GodVolume/GodVolumeStream, StfsPackage.Open/ReadFileChunks, extraction progress (StfsProgress), safe-name policies, and deep hash-tree validation. Its suite covers synthetic packages, a deterministic mutation fuzzer, BenchmarkDotNet cases and optional real-corpus checks (XBLA, XBLIG and GOD/SVOD). No on-disk format behavior changed.

Full suite green on all three targets: 2101 passed / 1 opt-in skip (2102) on net8.0/net9.0 and 2165 passed / 1 opt-in skip (2166) on net10.0; InspectCode 0 warnings, dotnet format clean, package validation passes.

1.6.0

Release date: 2026-11-06

Phase 10 Tier A + read-only Tier B slice. This release adds Xbox 360 XDBF/XSRC title metadata, XBE logo/title/save image extraction, the FATX split cap, batch --delete-source, GOD/STFS title naming, read-only GOD/SVOD sector input, XBLA/XBLIG STFS package listing/extraction and SHA-1 hash-tree validation, parallel CISO compression/extraction, the safe-extract name policy, and CWD-free writer/reader concurrency. The standalone StfsSharp package extraction is planned for 1.7.0; CCISharp 1.1 (LZ4-HC and parallel CCI compression) remains a separate track.

Full suite green on all three targets: 2098 passed / 1 opt-in skip (2099) on net8.0/net9.0 and 2162 passed / 1 opt-in skip (2163) on net10.0.

Library

  • Concurrent creation and extraction: XisoWriter.CreateXiso/PackFromDirectory resolve the source to absolute host paths, keep byte/file progress in per-operation state and take no process-wide lock. Concurrent creates run independently and never change the process working directory; output is byte-identical. A caller-supplied inRoot without HostPath is resolved once against the caller's CWD. XisoReader.Extract/UnpackImage extract through a rooted LocalFilesystem instead of Directory.SetCurrentDirectory, so concurrent extracts are independent too; UnpackImage(..., IFilesystem) still accepts any custom destination.
  • FATX-safe split default: Constants.FatxMaxFileSize (0xFF000000, 4 GiB − 16 MiB) is now the default maximum part size for plain-ISO splits. An explicit --size above it is still honoured with a warning. CISO/CCI keep their 0xffbf6000 xdvdfs-compatible compression default.
  • Parallel CISO compression: CisoWriter.CompressToCso/CompressStream gain jobs overloads (1..64) that compress sector batches on a bounded worker pool and write payloads in sector order, so output is byte-identical to the sequential writer and progress stays ordered. MaxParallelism is the shared ceiling; CCI remains single-threaded until CCISharp 1.1.
  • Parallel extraction: UnpackOptions.MaxDegreeOfParallelism (1..64, default 1) queues independent files during the sequential tree walk and copies them on a bounded pool. Output is byte-identical to a sequential run; per-file FileAdded progress and completion logs stay in traversal order, and SkipExisting/ContinueOnError keep their semantics. Plain ISO sources are read positionally through RandomAccess; CISO/CCI/GOD/split and in-memory sources serialize reads, and destination filesystem calls are serialized so MemoryFilesystem and other non-thread-safe stores stay safe. UnpackOptions.MaxParallelism is the shared 64 ceiling.
  • GOD read-only sector input: GodBlockDevice maps a GOD/SVOD header plus its DataNNNN fragments into the decompressed sector view, so every read verb (list, tree, extract, checksum, hash, validate, sector-layout, ranges) accepts a GOD container. GodHeader.TryReadVolume/GodVolumeInfo expose the SVOD mapping, and XisoImageSource detects both a header file and its .data folder. In-place repair/copy-in/set-filetime/rewrite refuse GOD and ask for a decompress first.
  • GOD title metadata: GodHeader/GodTitleInfo read the plaintext XContent header of a GOD/SVOD container (title name, title ID, disc number/count) without mounting it. Names are sanitised for FATX and fall back to the hex title ID when empty.
  • XBLA/XBLIG header metadata: StfsHeader/StfsTitleInfo read the same XContent fields from single-file Xbox 360 STFS packages (XBLA 0x000D0000, XBLIG 0x00000002), which have no .data directory.
  • XBLA/XBLIG package listing and extraction: StfsPackage reads the STFS file table, follows contiguous and hash-chain block lists through the level-0/level-1/level-2 hash interleave, and exposes Entries, Find, ReadAllBytes, CopyTo and ExtractTo. StfsPackageInfo reports the XContent title fields and the volume layout. XisoChecksum.ComputeStfsChecksum uses the same sorted-path SHA3-256 tree hash as ISO and ZAR, so equivalent trees compare equal. Read-only: STFS writing/rebuilding stays out of scope.
  • STFS hash-tree validation: StfsPackage.Validate hashes every logical data block and compares it with its level-0 hash entry, walks each file's block chain for truncation/cycles, verifies every level-0 table against its level-1 parent (and level-1 tables against level 2), and checks the top hash and header hash in the volume descriptor. StfsValidationReport carries the counts and every mismatch as a StfsValidationIssue. Read-only: package signatures are not verified, and STFS writing/rebuilding remains out of scope.
  • Xbox 360 title metadata: XexDbdf reads the plaintext XDBF/XSTR/XSRC resources from the XEX header-section table. XexTitleInfo carries title name, publisher, developer, genre, description and optional thumbnail; GetXexTitleInfo exposes it directly. TitleInfo gains additive Kind (Xbe/Xex) and Xex properties, and GetTitleInfo resolves default.xbe → default.xex → default_mp.xbe.
  • XBE image assets: XbeAssets reads the logo bitmap and the $$XTIMAGE/$$XSIMAGE sections. DXT1/3/5, BGR24/BGRA32 and XPR0 payloads are decoded to PNG by the new BCL-only DxtDecoder/PngWriter; DDS is passed through or generated. XbeInfo gains HasLogoBitmap, HasTitleImage and HasSaveImage init properties.
  • Safe-extract name policy: ExtractNamePolicy (Reject default, Sanitize, Skip) and UnpackOptions.NamePolicy choose how hostile entry names are handled. Sanitize replaces unsafe characters with _ and adds ~N on collisions; Skip omits the entry (and a skipped directory's subtree). StfsPackage.ExtractTo and XisoZarchive.ExtractZar gained matching ExtractNamePolicy overloads. The existing overloads keep the fail-fast default.

CLI

  • GOD input: every read verb accepts a GOD header or its .data folder; decompress writes a plain ISO (named after the header title) and convert accepts GOD → .iso/.cci/.cso. Redump modes and in-place write verbs refuse GOD with a "decompress first" message.
  • XBLA/XBLIG STFS packages: -l, -t, -x, --unpack, checksum and -l/--json accept a single-file XBLA/XBLIG STFS package and read its file table directly. Extraction honours -d and --skip-existing; checksum uses the ISO/ZAR-compatible tree hash. compress, decompress, convert, rewrite and the raw redump modes refuse STFS with an "extract first" message. -V/audit verifies the package's SHA-1 hash tree (per-block hashes, level tables, top hash and header hash) and reports Files checked / Blocks checked / Hash tables / Result.
  • title-info accepts a GOD header or its .data folder, a single-file XBLA/XBLIG STFS package, or an XISO image's default.xbe/default.xex/ default_mp.xbe and reports the available title name, title ID, disc and version fields in text and --json form. Xbox 360 titles also report publisher, developer, genre, description and thumbnail presence.
  • --xbe-image <image> <path> --type logo|title|save -o out.png|out.dds extracts XBE artwork. --xbe-info --json adds hasLogoBitmap, hasTitleImage and hasSaveImage; --xex-info prints the XDBF title name, publisher, developer, genre and description when present.
  • --delete-source on batch compress, decompress, convert and split: deletes each source only after a successful conversion, requires -y/--yes (refused with -n/--no), removes every part of a split set, and reports the deleted count in the batch summary.
  • --jobs on CISO compression: compress/cso --jobs 1..64 compresses sectors on a bounded worker pool (default 1); output is byte-identical to the sequential writer. With --batch, --jobs still selects concurrent conversions; single-file CCI compression is single-threaded.
  • --jobs on extraction: -x and --unpack accept --jobs 1..64 (default 1) to copy independent files in parallel. Output is byte-identical, per-file FileAdded progress stays in traversal order, and --skip-existing/ --continue-on-error work unchanged. ZAR/STFS unpacking and non-extract modes reject the flag with a clear message.
  • --name-policy reject|sanitize|skip on -x/--unpack: choose fail-fast rejection (default), collision-safe sanitized names, or skipping hostile entries during ISO/CISO/CCI/GOD/ZAR/STFS extraction.
  • split warns when an explicit --size exceeds the conservative FATX cap.

Dependencies

  • CCISharp 1.0.1: the CCI reader now rejects oversized or hostile indexes with InvalidIndex instead of allocating a buffer sized by the part file. No API change.

Packaging

  • The CLI is no longer published as a NuGet dotnet tool (XISOSharp.Tool). XISOSharp (the library) remains the only NuGet package; get the CLI from the GitHub release bundles (release_<version>_<rid>.zip) or build it from source with publish-cli.ps1.

1.5.0

World-class library release. This merges the 1.5.0 development work (CCI, split ISO, ZAR input, traversal hardening, batch conversion, JSON, preallocation and explicit layout packing) with the Phase 9 productization work: an open-once XisoImage facade, full-image CRC32/MD5/SHA-1/SHA-256/SHA3-256, .hash verification, title metadata, Windows long-path/reserved-name hardening, ZAR extraction caps, mutation fuzzing, AOT smoke, 3-OS tests, a dotnet tool, SBOM and provenance.

Full suite green on all three targets: 1979 passed / 1 opt-in skip (1980) on net8.0/net9.0 and 2043 passed / 1 opt-in skip (2044) on net10.0.

Phase 9 — world-class library

  • XisoImage (XISOSharp): Open/OpenAsync, List/ListFlat, ReadFile/OpenReadStream, Extract/ExtractAsync, Validate, GetTitleInfo, ComputeImageHash, IDisposable/IAsyncDisposable.
  • Full-image hashes: XisoImageHash.Compute streams CRC32, MD5, SHA-1, SHA-256 and SHA3-256 in one pass through the decompressed view.
  • verify-hashes: verifies a --petrify/XboxKit .hash sidecar for ISO, CISO, CCI, split ISO and ZAR inputs.
  • Title metadata: title-info / XisoReader.GetTitleInfo find default.xbe and report title name, ID, region, disc and version.
  • Hardening: Windows longPathAware manifests, reserved device-name rejection/sanitization, ZAR extraction byte/entry caps, CISO malformed-index and alignment validation (found by the new mutation fuzzer).
  • Quality gates: 3-OS test matrix, dotnet format gate, AOT publish smoke, mutation fuzz job, 70% line / 60% branch coverage floors, package validation against 1.4.4 with a reviewed suppression baseline.
  • Packaging: XISOSharp.Tool dotnet tool, SBOM + build provenance on releases, community files and a console sample.

Layout packing (Phase 8)

Sector-layout packing release, plus the TOC hardening follow-up. Images can now be repacked at an explicit layout: XisoLayoutSpec accepts the JSON emitted by --sector-layout --json (or a compact path=sector text spec), fixes the sectors of matching files and directory tables, and allocates every other entry first-fit around the reserved extents. -c, --pack <dir> and build-image gain --layout <file>. The audit, sector-range, repair, salvage and ZAR walks now use the same explicit in-order table traversal as extract/list/rewrite, so MaxTocDepth bounds real subdirectory nesting only. The raw-sector redump modes also reject compressed and split containers up front, and the GUI ZAR tab converts a .zar back to a plain ISO. ZAR extraction is now depth-bounded, pre-sized and exact-length, and CISO compression reads split/container sources through the decompressed view instead of a joined temporary ISO.

Full suite green on all three targets: 1979 passed / 1 opt-in skip (1980) on net8.0/net9.0 and 2043 passed / 1 opt-in skip (2044) on net10.0.

Library

  • XisoLayoutSpec / XisoLayoutEntry (XISOSharp.Models): FromSectorLayout, Load (JSON/text auto-detect), Parse, ParseJson and ParseText. JSON accepts the full --sector-layout payload, a bare entries array, camelCase or PascalCase names, and startSector/sector aliases; the text form supports #/; comments, total-sectors=N and 0x hex sectors.
  • XisoWriter layout packing: CreateXiso, CreateXisoAsync, PackFromDirectory, PackFromDirectoryAsync and RemapFilesystem.BuildImage accept an optional layout. A two-pass planner validates every fixed extent (overlap, reserved system area, bounds, too-small extents), assigns the requested sectors, then seeds SectorAllocator so unplaced entries fill gaps first-fit.
  • Layout fidelity: a JSON layout round-trips an unchanged source tree byte-for-byte; TotalSectors is preserved (subject to the writer's final 64 KiB alignment); partition-relative sectors stay correct under prependSectors.
  • Strict/lenient paths: the compact text form rejects paths missing from the source tree; JSON extra entries are reserved (with a warning) so a subset repack cannot reuse their bytes.

TOC hardening (Phase 4 follow-up)

  • XisoReader.AuditWalk, XisoRanges.GetValidSectorsCore/CollectFileEntries, XisoRepairer.CollectWalk, XisoSalvager.SalvageWalk and XisoZarchive.ParseNode now walk each directory table with an explicit in-order stack (left subtree, entry, right siblings) instead of recursing on the left child. MaxTocDepth (64) bounds real subdirectory nesting only.
  • A 4,096-entry left-skewed table now audits, maps (--ranges, GetFileEntries), repairs a reserved-attribute bit on its deepest entry, salvages into a fresh image and packs to ZAR; cycles and out-of-table pointers still hit the existing named errors or report/drop gates.
  • The visited-offset set and MaxTocEntriesPerTable / MaxTocStackFrames backstops are unchanged; a shared (DAG) subtree now reports the same cycle error the reader has always raised.

ZAR validation (Phase 3 follow-up)

  • XisoValidator.ValidateConversion accepts a ZArchive (.zar) on either side: the tree comes from XisoZarchive.ListZar, and --validate-checksums hashes each name-tree entry through the new XisoZarchive.ComputeFileHash (no extraction to disk). ISO↔ZAR conversions can now be verified directly.
  • The CLI validate verb accepts .zar (including --json and --validate-report), matching the -l/-t/-x/checksum ZAR input support.
  • A .zar handed to a sector-only verb (-i, --ls, -V, --filetime, --sector-layout, --ranges, --repair, --copy-in/--copy-out, …) now reports a clean Error: naming the archive verbs instead of an unhandled NotSupportedException stack trace.

ZAR extraction hardening (Phase 3/7 follow-up)

  • XisoZarchive.ExtractZar now bounds directory nesting at Constants.MaxTocDepth, matching ListZar and ComputeZarChecksum; a malicious or corrupt archive fails with a named InvalidDataException instead of recursing until the stack overflows.
  • Each extracted destination is pre-sized from the name tree and copied with XisoFileCopier.CopyExact, so a truncated entry throws TruncatedCopyException instead of silently producing a short file. Failed or canceled entries delete their partial output (Windows-safe: the handle is closed first).

Direct CISO input (Phase 2 follow-up)

  • CisoWriter.CompressToCso reads split ISO, CISO and CCI sources through the seekable decompressed view from XisoImageSource instead of writing a joined temporary ISO first. Split output still goes through CisoSplitOutput.
  • The split-output collision guard now compares every source part (not just the entry path), so recompressing a split CISO/ISO set cannot truncate one of its own parts.

CLI

  • --layout <file> on -c <dir>, --pack <dir> and build-image; rejected for rewrite/extract/list modes and for --pack <iso>.
  • Help text and the misplaced-flag guard cover --layout.
  • --sector-layout --json game.iso > layout.json followed by -c game_dir out.iso --layout layout.json reproduces the source layout.
  • The raw-sector redump modes (--video, --random, --seed, --wipe, --trim, --petrify, --update, --zar) refuse .cso/.cci, split ISO and .zar inputs with a clear "decompress/convert/join first" message instead of parsing container bytes as an XISO.
  • Expected overwrite refusals (-n, redirected stdin) stay in the local log and no longer reach the bug-report API.
  • CCI split sets opened through any numbered part (.2.cci … .9.cci) name outputs after the game: extraction creates game/, rewrite writes game.iso, and compress derives game.cci instead of refusing the source as its own output. Plain ISO/CISO sets still strip only .1, and archive.1.zar keeps its number.

GUI

  • The ZAR tab is bidirectional: a .zar source runs convert and writes a plain ISO (output auto-derived next to the archive); an image source keeps the existing pack + overwrite/skip/auto-rename behavior. The output picker and labels follow the detected direction, and the self-test covers the new argv.

Tests

  • LayoutPackingTests (41): JSON/text parsing and validation, FromSectorLayout, byte-identical JSON round-trips, fixed-extent placement, first-fit gaps, reserved unmatched JSON extents, total-sector preservation, prepended partitions, case- insensitive paths, empty files/directories, build-image, and CLI -c/--pack/build-image end-to-end plus usage errors.
  • SectorAllocatorTests (+7 SeedUsedRanges cases): one-pass bulk seeding sorts/coalesces, rejects overlaps and out-of-bounds ranges, refuses to seed after allocations, handles null and zero-count ranges.
  • PathologicalTocTests (+5): the 4,096-entry left spine audits and maps, repairs its deepest entry, salvages to a passing image, and packs to a valid ZAR.
  • ZarValidateTests (10): ZAR↔ISO/CCI tree comparison, per-entry SHA-256/MD5 hashing (case-insensitive paths, missing/directory paths), missing-file and checksum-mismatch detection, CLI validate --json/--validate-report, and a clean sector-only rejection for .zar inputs.
  • ZarInputTests (+1): a 65-level name tree is rejected by both ListZar and ExtractZar with the depth message; the existing list/extract/checksum/ convert tests still pass with pre-sized, exact-length extraction.
  • CisoTests (+1): recompressing a CISO through CompressToCso now reads the decompressed view directly and round-trips to the same ISO hash.
  • RedumpInputGuardTests (11): every redump mode refuses .cci/.cso, split ISO and .zar inputs with the documented message, while a plain ISO still runs. CliCommandsTests.Convert, MainViewModelTests and the GUI self-test cover the ZAR→ISO direction/argv; OverwritePromptExtraTests asserts expected refusals carry NoBugReport. CisoAutoDetectTests.ReaderVerbs_CsoMatchIso and the split-ISO reader test now compare --ranges and sector-layout output.
  • XisoImageSourceTests (+7 part-suffix cases), CciAutoDetectTests.SecondCciPart_NamesOutputsAfterGameStem and XisoRepairerRefusalTests.Salvage_DefaultOutputPath_Naming cover numbered CCI part naming: extraction, rewrite, recompress and salvage from .2.cci all use the game stem; .10.cci/.0.cci stay ordinary names, and .1.zar keeps its number.
  • net8.0/net9.0 - 1980 tests (1979 passed, 1 opt-in skip); net10.0 - 2044 tests (2043 passed, 1 opt-in skip, adds the GUI tests).

JSON and I/O efficiency (Phase 7)

Machine-readable-output and I/O-efficiency release. Read-only verbs gain a stable --json schema (source-generated, trim/AOT-safe) with human logs moved to stderr, and extraction/creation now pre-size known-length destinations and use sequential-scan hints. -v/--version also reports the CCISharp, ZArchiveSharp, runtime and commit metadata.

Full suite green on all three targets: 1860 passed / 1 opt-in skip (1861) on net8.0/net9.0 and 1922 passed / 1 opt-in skip (1923) on net10.0.

Library

  • Preallocation / sequential I/O: new additive IFilesystem.CreateFile(string path, long? expectedLength) default member. LocalFilesystem opens with FileOptions.SequentialScan and applies SetLength before the first write; MemoryFilesystem preallocates its buffer; custom stores keep the old behavior through the default member. XisoReader.ExtractFile/CopyOutFile pass each entry's size, and plain-ISO sources open with SequentialScan.
  • XisoWriter pre-sizing: after the sector layout is computed, the output is sized once to the exact post-layout extent (plus any prepended partition) before the data phase. The final 64 KiB alignment padding and image bytes are unchanged.
  • Offset-aware read helpers: new overloads GetVolumeInfo(string, int?), GetVolumeInfo(Stream, string, int?), ListDirectory(string, string, int?), ListDirectory(Stream, string, string, int?) and GetSectorLayout(string, int?) probe the XISO header at an explicit Redump/XGD partition offset instead of the automatic candidates.
  • Container-aware ranges: XisoRanges.GetXisoRanges/GetFileEntries gained Stream overloads and open through XisoImageSource, so --ranges and range-based archival helpers read split ISO, CISO and CCI inputs.
  • Logger.RouteInfoToError: optional switch that sends Log/LogLine/ Flush to Error, keeping stdout free for machine-readable output.

CLI

  • --json on -i, -l, -t, --checksum/checksum, --sector-layout, --ranges, --filetime, --xex-info, --xbe-info, validate and -v/--version. Every document carries "schemaVersion": 1 and a command; list/tree wrap results in an images array (one document for multiple inputs), checksum returns a checksums array. JSON goes to stdout; banners/progress/warnings/errors go to stderr.
  • Serialization uses the source-generated JsonOutputContext (camelCase, nulls omitted), so the trimmed single-file CLI has no reflection fallback.
  • --json is rejected for mutating modes (extract, rewrite, create, compress/decompress, redump) with a clear error.
  • Version enrichment: -v keeps its historical first line, then prints XISOSharp, CCISharp, ZArchiveSharp, runtime, OS, architecture and the MinVer commit. -v --json emits the same data as a JSON document.
  • Help text documents --json, --version, and the new read-only schema.

Tests

  • CliJsonTests (12): every JSON payload parses, stdout/stderr are separated, multi-image list output stays one document, CCI input matches the ISO tree, checksum matches the library digest, validate reports summaries, version metadata is populated, and --json rejects extract mode.
  • XbeInfoTests/XexInfoTests: JSON payloads for --xbe-info/--xex-info (plus the existing end-to-end text checks).
  • PreallocationTests (5): LocalFilesystem pre-sizing, empty default, MemoryFilesystem capacity behavior, the default interface-member fallback, and extraction passing each entry size to a custom IFilesystem.
  • CliHelpFlagTests now asserts the enriched version output while keeping the first-line banner contract.
  • net8.0/net9.0 - 1861 tests (1860 passed, 1 opt-in skip); net10.0 - 1923 tests (1922 passed, 1 opt-in skip, adds the GUI tests).

1.4.5

Container-input, traversal-hardening and batch-conversion release. XISOSharp now reads CCI/CCIM images (via the new CCISharp 1.0.0 dependency), split plain-ISO sets (game.1.iso …), and ZArchive (.zar) inputs, and exposes one unified detection/open layer (XisoImageSource) for every sector-based format. The CLI gains compress --format cci, --cci-level/--cci-split, cci/uncci aliases, convert for ZAR ↔ ISO, ZAR-aware list/extract/checksum, and --batch conversion on compress, decompress, convert and split; the GUI gains a CISO/CCI format selector and routes .cci/.zar drops to the matching tab. The reader's directory walk is now an explicit in-order stack, so a pathological left-skewed table can no longer exhaust the process stack or trip the subdirectory depth cap.

Full suite green on all three targets: 1841 passed / 1 opt-in skip (1842) on net8.0/net9.0 and 1903 passed / 1 opt-in skip (1904) on net10.0.

Library

  • XisoImageSource (XisoImageFormat, XisoImageSourceInfo): extension-led detection with a CISO/CCIM magic sniff fallback; OpenRead/OpenBlockDevice return the decompressed/concatenated view for ISO, split ISO, CISO, CCI and their split variants. Plain files remain ISO candidates.
  • CCI/CCIM: XisoCci (CompressToCci, DecompressToIso, DeriveDefaultCciPath, DeriveDefaultIsoPath), CciBlockDevice, and CciNaming; backed by CCISharp 1.0.0 (MIT, pure managed, LZ4). Single-part and .1.cci … .9.cci sets are supported.
  • Split ISO input: SplitIsoFile/SplitIsoStream concatenate <base>.1.iso, .2.iso, … (multi-digit indices included); a missing middle part raises InvalidDataException instead of silently truncating.
  • ZAR input: XisoZarchive.ListZar, ExtractZar, ConvertZarToIso; XisoChecksum.ComputeZarChecksum/ComputeZarChecksumHex produce the same SHA3-256 tree hash as the equivalent ISO. Unsafe entry names are rejected.
  • Unified readers: XisoReader.OpenImageStream now routes CCI and split ISO through the factory; XisoChecksum opens every format through OpenBlockDevice. Output naming strips .cso/.cci/.1.* suffixes.
  • In-place guards: Repair, CopyIntoImage and SetFileTime refuse CISO and CCI containers with a clear "decompress first" error, even when the file is missing or corrupt.
  • Recompression: CisoWriter.CompressToCso and XisoCci.CompressToCci accept split ISO/CISO/CCI sources by materializing the decompressed image to a temporary ISO; directory sources still pack then compress.
  • StreamBlockDevice exposes any seekable stream as an IBlockDevice.
  • Pathological TOC traversal: TraverseXiso now walks each directory table with an explicit in-order stack instead of left-subtree recursion. MaxTocDepth bounds subdirectory nesting only; intra-table depth is bounded by MaxTocEntriesPerTable and Constants.MaxTocStackFrames (100k). A 4,096-entry left-skewed chain lists/trees/extracts/rewrites, and the rewrite checksum matches the balanced form. ContinueOnError still skips just the corrupt subtree.
  • Runtime dependencies are now ZArchiveSharp 1.4.0 and CCISharp 1.0.0.

CLI

  • compress --format cso|cci (default cso), --cci-level 0..9, --cci-split <bytes>; -l/--level and --split remain format-neutral.
  • cci alias for compress --format cci; uncci joins decompress.
  • Format-specific flag validation: --ciso-* is rejected for CCI output and --cci-* for CISO output.
  • decompress auto-detects CISO vs CCI (extension plus magic sniff).
  • convert <src.zar|src.iso> <out.iso|out.zar>; -l, -t, -x, --unpack and checksum accept .zar directly.
  • Batch conversion: --batch <dir> / --batch-recursive on compress, decompress, convert and split; --skip-existing resumes, --continue-on-error keeps going after a failed file (partial outputs are removed), --jobs 1..64 converts in parallel, and --output-name supports {name}/{ext}/{format}. Duplicate outputs and outputs that would clobber another input are refused before any write. convert --batch --format iso|zar covers both directions.
  • Help text and the GUI self-test cover the new flags.

GUI

  • Compress tab: Format selector (CISO/CCI); output/save dialog and split placeholder follow the selected format.
  • Picker filters and drop routing include .cci/.1.cci; a dropped .zar opens the Extract tab for list/extract/checksum, and compressed drops route to Decompress.
  • Decompress picker accepts CISO and CCI; collision guards use the matching default output naming.

Tests

  • XisoImageSourceTests: detection table for ISO/XISO/IMG/CISO/split CISO/ CCI/split CCI/split ISO, CCI round-trip, cross-part seeks, magic sniffing, suffix stripping and missing files.
  • CciAutoDetectTests: list/tree/extract/unpack/rewrite/checksum parity, default output naming, CCI decompression and the in-place refusal contracts.
  • SplitIsoAutoDetectTests: extract/list/checksum parity, split CISO/CCI recompression, default game/ naming and missing-middle-part errors.
  • CliCciTests: CCI compress/decompress, split sets, aliases, list and format-specific flag rejection.
  • ZarInputTests: ZAR listing/extraction/checksum/convert and CLI wiring.
  • PathologicalTocTests: 4,096-entry left-skewed, right-skewed, alternating and balanced tables; list/tree/extract/rewrite parity, a left self-cycle, and continue-on-error subtree skipping.
  • CliBatchConvertTests: CISO/CCI batch compress, batch decompress, ISO to ZAR convert, batch split, recursive discovery, naming templates (including subdirectories), duplicate-output refusal, --skip-existing resume, --continue-on-error partial-output cleanup, and parallel --jobs.
  • net8.0/net9.0 - 1842 tests (1841 passed, 1 opt-in skip); net10.0 - 1904 tests (1903 passed, 1 opt-in skip, adds the GUI tests).

1.4.4

Extraction-cleanup and static-analysis release. A failed or cancelled extraction no longer leaves a truncated destination file behind: ExtractFile/CopyOutFile delete the partial output through the new IFilesystem.DeleteFile member, which custom destination stores can override (the default keeps the previous no-op behavior). The solution is clean under JetBrains InspectCode - 0 errors and 0 warnings across every project - and dead members found by the inspection were removed from the Tester. Full suite green on all three targets: 1760 passed / 1 opt-in skip (1761) on net8.0/net9.0, 1821 passed / 1 opt-in skip (1822) on net10.0.

Library

  • Partial-destination cleanup: a copy that throws, reports truncation, or is cancelled removes the destination it wrote, so callers (drag-and-drop prep, batch extraction, resume runs) can never mistake a partial file for a complete one. Cleanup is best-effort and never masks the extraction error.
  • IFilesystem.DeleteFile: new member with a default no-op implementation - existing custom stores still compile and keep their partial content if they cannot delete. LocalFilesystem deletes from disk (a missing file is a no-op); MemoryFilesystem removes the stored snapshot.
  • Static-analysis cleanup across the library, CLI, GUI, Tester, benchmarks and tests: redundant default arguments, redundant casts and assignments, dead null guards, unused fields/properties, and simplified nullability in Logger.Out/Logger.Error (assigning null now stores TextWriter.Null, so the getters never return null). No output or format changes.

Tests

  • ExtractRobustnessTests: a truncated copy and a mid-write failure both leave no destination file, including through a custom IFilesystem.
  • XisoFilesystemTests: LocalFilesystem.DeleteFile removes files and treats a missing path as a no-op.
  • Suite: net8.0/net9.0 - 1761 tests (1760 passed, 1 opt-in skip); net10.0 - 1822 tests (1821 passed, 1 opt-in skip, adds the GUI tests).

1.4.3

Split CISO part sets honor the caller-chosen FileShare when opening images. CisoSplitFile.OpenParts was hardcoded to FileShare.Read, so XisoReader.OpenImageStream(path, FileShare.ReadWrite) and XisoExplorerOptions.Share reached plain ISOs and single-file .cso containers but not the individual *.1.cso part files - a split set held open by a writer (sync client, in-progress copy, antivirus) still failed with a sharing violation on Windows. The share mode now threads to every part. Defaults are unchanged (FileShare.Read). Full suite green on all three targets: 1758 passed / 1 opt-in skip (1759) on net8.0/net9.0, 1819 passed / 1 opt-in skip (1820) on net10.0.

Library

  • Split CISO share mode: CisoSplitFile.OpenParts(firstPart, share) accepts a share mode, and CisoBlockDevice threads the caller's FileShare through to every part file. XisoExplorerOptions.Share now covers plain ISOs, single .cso containers, and split *.1.cso part sets alike.

Tests

  • CisoOpenParts_HonorsCallerShareMode pins the share plumbing, including that the default stays read-shared; SplitCso_ExplorerWithReadWriteShare_ CoexistsWithWriterHoldingPart covers the end-to-end XisoExplorer flow with a writer holding the first part.

1.4.2

Deep-review hardening and GUI experience release. An 80-item review of the whole repository (path escapes, patch-layout collisions, CWD leaks, partial artifacts, CLI contract mismatches, vacuous tests, doc drift) is resolved, together with the follow-up regressions found while re-reviewing those fixes and a final pass over the fix commits. The desktop app gains Donate/About/Exit header actions, F8 window screenshots, and a startup update prompt backed by the same UpdateCore

  • 24-hour cache the CLI uses. Namespace note: UnpackOptions, ProcessRunResult, ExplorerNode, and XisoExplorerOptions moved from XISOSharp to XISOSharp.Models — add using XISOSharp.Models; when upgrading from 1.4.1. Targets remain net8.0 / net9.0 / net10.0; full suite green on all three (1818 tests on net10.0: 1817 passed, 1 opt-in skip; 1757 on net8.0/net9.0: 1756 passed, 1 opt-in skip). The suite runs fully sequentially (assembly-wide DisableTestParallelization) because create/extract mutate the process CWD.

Library

  • Path safety: crafted image names (separators, Windows drive-relative colons, any trailing dot/space) are rejected at extract on Windows or sanitized by repair/salvage; listing, tree, rewrite, and ZAR packing accept every structurally valid name on every host, matching the reference tool (the colon stays valid on Unix where the writer/patcher accept it).
  • Patching: the allocator reserves the optimized tag (sector 15), the ECMA-119 descriptor pair (16-17), and the layout-tool signature sector — also for header-only volumes; sector counts use 64-bit math; the root table size is recorded even when the table stays in place; a child offset that would encode the 0xFFFF empty-child sentinel fails instead of truncating.
  • Walkers: all child offsets are bounded by the recorded table size, the all-zero empty-table sentinel is honored, ./.. records are skipped consistently, truncated names fail instead of truncating the walk (including CollectFileEntries), and zero-size directory entries list as empty.
  • Writing/containers: CWD is restored on every path; a cwd source (-c . / -c ..) defaults its output next to the source instead of aborting on the same-leaf guard; relative -d resolves against the caller CWD; failed/cancelled runs delete partial .iso/.cso/.zar output (including the build-image remap writer, and closing split-part handles first on Windows) but never a pre-existing file the call did not create; CISO headers/indexes are validated; split part naming handles dotted bases; Latin1Encoding range checks are overflow-safe.
  • Repair/audit: a missing optimized tag is written at the disc offset for prepended images; path and device audits agree on trailing magic, empty-image tag probing, and an oversized root table (audit now matches extraction).
  • XisoPaths resolves both sides of an input==output check against one CWD snapshot; XisoExplorer.Dispose serializes with keep-open reads.

CLI

  • --silent is order-independent in every position, including with -v/ --help, and still requires --checksum; --file-time/--preserve-attrs/ --jobs/--policy are rejected outside their modes, and --jobs is rejected with --compress or a multi-mode redump run where it cannot take effect; --wipe/--trim honor -o; --is-optimized honors --skip-sectors; --ciso-split refuses a source named like its own first part.
  • -D deletes .old only after a fully successful (validated) rewrite, and a failed file no longer suppresses a later file's success or keeps its backup.
  • Help shows -o <output> for the redump modes instead of a positional second file (which is parsed as another input).
  • stdout/stderr are always UTF-8 instead of the host console code page, so Latin-1 filenames (café.txt) render and pipe identically on every platform (matching xdvdfs's UTF-8 output); the battle harness now decodes each tool with its real encoding (extract-xiso Latin-1; xdvdfs, xboxkit, and the CLI UTF-8) so non-ASCII names compare equal instead of collapsing to U+FFFD.

GUI

  • Donate/About/Exit header actions with an About dialog; F8 screenshots; startup update prompt (subscribed before probing so a fast show cannot hang it); tooltips.
  • Drag-and-drop routing fixed (only *.iso folders go to Batch; .zar drops go to Rebuild in single- and multi-item drops); Wipe/Trim pass -o before the image; CliStatus updates on the UI thread; settings persist again; screenshot environment warnings stay local and the fallback folder is tried for security exceptions.

Logging, bug reports, telemetry

  • Shared Serilog pipeline; expected operational warnings are tagged NoBugReport; the shared API key is double-Base64 encoded (ApiKeyStore); the dedupe map is bounded; ProcessRunner falls back to a stable working directory when the inherited CWD was deleted.

Tester

  • List comparison parses the real \name (N bytes) format and decodes extract-xiso's Latin-1 output; two empty parses fail instead of passing; remaining dead wrappers (RunQuietAsync) removed.

Docs & build

  • Drift fixed (test counts, --help, Release packing, battle default, coverage OS/figures, Tester CI, sequential-suite description, missing scripts, ConversionPlan.md, namespace samples); publish scripts stage into %TEMP% and merge instead of deleting the protected publish*/ trees, and publish-cli.ps1 -Zip requires an exact tag or -Version <x.y.z> so a pre-release run cannot overwrite a shipped release_*.zip; docs/ serves Pages (Docsify _sidebar.md) and syncs to the wiki (Home.md + _Sidebar.md) via .github/workflows/wiki.yml.

1.4.1

Dependency and legal maintenance release. ZArchiveSharp moves 1.3.0 → 1.4.0 (drop-in: upstream rewrote its pipeline layer as original MIT work with no public-surface, wire-format, or CLI changes), and the ZArchiveSharp notice is refreshed — the library, including the ZArchiveSharp.Pipeline pack/extract layer XISOSharp uses, is fully MIT. No XISOSharp API or CLI behavior changes; targets remain net8.0 / net9.0 / net10.0; full suite green on all three (1427 tests: 1426 passed, 1 opt-in skip, 0 failed).

Dependencies

  • ZArchiveSharp 1.3.0 → 1.4.0. Upstream highlights: original MIT pipeline layer (ZarPipeline, ZarPackEngine, ProcessRunner), stricter per-item batch isolation, and a robust stderr drain that no longer stalls on an inherited pipe. The public surface is unchanged, so ZAR output, CLI semantics, and exit codes are untouched.

License

  • LICENSE item 4 records ZArchiveSharp as fully MIT as of v1.4.0 (Copyright (c) 2026 PureLogicCode.com; lead developer Peterson Fernandes), including ZArchiveSharp.Pipeline.
  • The packaged library license (XISOSharp/LICENSE) is synced with the root LICENSE, so the NuGet package now carries the full third-party notices (extract-xiso BSD-4-clause, xdvdfs, XboxKit, ZArchiveSharp).

Docs

  • Root README.md and docs/building.md dependency references updated 1.3.0 → 1.4.0.

1.4.0

Integrity-audit release. The CLI's -V audit no longer fails a structurally sound image just because the optimized tag is missing: it reports the tag (Optimized: yes/no) and passes raw/unconverted dumps, while structural damage still fails. Audits now accept .cso images (previously compressed bytes were read as sectors), the library gains a requireOptimizedTag overload plus the AuditResult.IsOptimized property, and empty (zero-root) images report tag presence instead of always false. Targets remain net8.0 / net9.0 / net10.0; full suite green on all three (1427 tests: 1426 passed, 1 opt-in skip, 0 failed).

Library

Audit control and tag reporting

  • New overloads AuditXiso(string isoPath, bool requireOptimizedTag) and AuditXiso(IBlockDevice dev, string isoName, bool requireOptimizedTag). With requireOptimizedTag: false a missing tag is not an audit issue, so raw (unconverted) images audit as valid; the 1-arg overloads keep the original strict behavior (true).
  • New AuditResult.IsOptimized property reports whether the tag was found. The empty/zero-root early-return paths previously skipped the tag probe, so an image whose root fields are zero but whose tag is intact reported false; both the path and block-device overloads now probe and report it.
  • AuditXiso(string) now opens through OpenImageStream (CISO-aware) instead of a plain FileStream, matching GetVolumeInfo. A .cso input used to be audited as compressed bytes, producing bogus tree/bounds issues.

CLI

  • -V is an integrity audit: it prints Optimized: yes/no, a missing tag no longer fails the run, and raw/unconverted images exit 0. Use --is-optimized for the strict tag-only probe or --repair to write a missing tag. Help text updated.

Tests

  • 1427 tests across net8.0 / net9.0 / net10.0: 1426 passed, 1 opt-in skip (XISO_UPDATE_FIXTURE=1 fixture validator), 0 failed.
  • New: CliAuditTests (3 end-to-end -V runs: optimized, raw passing with Optimized: no, corrupt tree failing), AuditXisoTests integrity/tag/CISO cases (4, incl. plain-vs-CISO parity), and device empty-root tag coverage.

Dependencies

  • coverlet.collector 10.0.1 → 10.1.0 (Tests). No library dependency changes.

Docs

  • README.md, XISOSharp/README.md, XISOSharp.Cli/README.md, docs/cli.md, and docs/api-xisoreader.md document the integrity audit, the requireOptimizedTag overload, and IsOptimized; docs/troubleshooting.md and docs/getting-started.md refreshed; suite counts updated.
  • Release bundles now include WhatsNew.md next to README.md and LICENSE.

1.3.0

Correctness and maintenance release. The rewrite -o output name is now honored for real — including rooted/absolute paths — and a rewrite that fails to write reports an error instead of exiting 0. Wrapped exceptions carry their cause, the reference-binary interop tests resolve the current References/ drop again, and the bug-report wire format is locked by tests. Targets remain net8.0 / net9.0 / net10.0; full suite green on all three (1419 tests: 1418 passed, 1 opt-in skip, 0 failed).

Library

Rewrite output naming

  • XisoWriter.CreateXiso ignored inName in rewrite mode, so XisoReader.Rewrite(..., outputName:) (CLI -o) had no effect on the output filename. The name is now used verbatim: relative names resolve against the -d directory, and rooted names are kept intact. The Windows drive-letter strip used for legacy names no longer applies to a rooted -o, which turned C:\out\game.iso into :\out\game.iso and failed with a path-syntax error.
  • XisoReader.DecodeXiso (and therefore Rewrite) now returns the writer's non-zero result when the output cannot be written. Previously the writer logged the failure but the rewrite still reported success and returned 0.
  • Regression tests: Rewrite_WithAbsoluteOutputName_UsesProvidedName, Rewrite_UnwritableOutput_ReturnsError.

Exception causality

  • Wrapped rethrows embed the caught exception as InnerException (Meziantou MA0054): ProcessRunner timeout → TimeoutException, XisoReader truncated file copy → IOException, GUI MainViewModel output-verification failures → InvalidOperationException. Message text is unchanged, so existing diagnostics and exception filters keep working.

CLI

  • Rewrite (-r) now checks the decode result: a failed rewrite exits 1 and does not print successfully rewritten (the input stays at <name>.old, exactly as before the fix).
  • -o accepts relative and rooted paths and uses them as-is.

Logging

  • UpdateChecker debug-logs every previously silent catch (offline checks and API/cache failures stay below Warning, so they never file bug reports); GUI CliLocator.ProductVersion debug-logs unreadable CLI metadata.
  • BugReporter extracts ComposeReport and exposes BuildExceptionBlock to tests; new BugReportFormatTests (5) lock the Environment / Error / Exception sections required by the bug-report service.

Tests

  • 1419 tests across net8.0 / net9.0 / net10.0: 1418 passed, 1 opt-in skip (XISO_UPDATE_FIXTURE=1 fixture validator), 0 failed.
  • TestConditions resolves the compiled extract-xiso.exe from the current References/ drop (canonical References/extract-xiso.exe, dated drop root, or in-tree CMake build) instead of the removed 202505152050 artifact path; the legacy llCompat interop tests run and pass again.
  • RegenerateFixtureIso_WhenRequested renamed to ValidateFixtureIso_WhenRequested (it validates only; regeneration stays manual) — docs/testing.md updated.

Dependencies

  • Meziantou.Analyzer 3.0.257 → 3.0.290 (all projects), Avalonia 12.1.2 → 12.1.3 (GUI), QuestPDF 2026.8.0 → 2026.9.1 (Tester), Microsoft.NET.Test.Sdk 18.10.0 → 18.10.1 (Tests). No library dependency changes.

Docs

  • Badge rows (CI, NuGet version/downloads, release, .NET, platform/RIDs, license, docs site, per-project) added to the root, library, CLI, Tests, Tester, and docs READMEs; suite counts refreshed; -o rooted-path behavior documented in the CLI reference.

1.2.0

Additive release for VFS-consumer parity (SimpleXisoDrive/Dokan): the probe and read stack now accepts the rebuilt "sector-0" XISO layout (volume descriptor at the very start of the image instead of partition sector 32), and the in-place patcher, sector ranges, and ZAR packing understand it end-to-end. Targets remain net8.0 / net9.0 / net10.0; full suite green on all three (1412 tests: 1408 passed, 4 pre-existing skips, 0 failed).

Library

Rebuilt sector-0 XISO support

  • VerifyXiso (stream and block-device overloads), GetVolumeInfo, GetFileTimeRaw/SetFileTime (both overloads), and OffsetBlockDevice.Probe detect a volume descriptor at absolute offset 0. Such images report DiscLseek = 0 and DescriptorSector = 0; sector numbers stay partition-relative, so XisoExplorer, directory listing, and bounded file reads work unchanged on them.
  • XisoReader.TryFindHeaderBase resolves the descriptor base for callers that take a partition offset (standard sector-32 candidate first, then sector-0).
  • GetSectorLayout marks the detected descriptor sector as used instead of hardcoding partition sector 32, so SectorAllocator.FromLayout can no longer hand out the live header to the in-place patcher.
  • PatchVolumeHeaderRoot writes the relocated root pointer to the active header base (DiscLseek + DescriptorSector * 2048), fixing a silent-corruption path where CopyIn on a sector-0 image overwrote the descriptor or left the header pointing at the old root table.
  • XisoRanges.GetXisoRanges/GetFileEntries and XisoZarchive.CreateZar resolve the descriptor with the same helper; invalid images keep the historical fallback base and failure behavior.
  • XisoRedump.RebuildRedump rejects sector-0 inputs with an explicit error (repack to the standard sector-32 layout first) because a verbatim embed would place the descriptor at partition sector 0; HasXisoMagic recognizes sector-0 images so they keep working as .zar sidecar inputs.

Prompt cancellation in XboxPrng.TryGetSeed

  • The brute-force seed search now checks the cancellation token inside each worker's candidate chunk. A canceled search stops promptly instead of grinding through the rest of the chunk — removing the coverage-instrumented stall that tripped CI's 15-minute blame-hang watchdog on the net8.0 test host.

Tests

  • New XisoRebuiltSector0Tests (12 tests): probe/verify/volume-info parity, explorer listing + OpenReadStream, filetime read/write, block-device probe, sector layout used/free ranges, in-place add/replace/root-table-move, and GetXisoRanges/CreateZar round-trips on sector-0 images.

Docs

  • docs/xiso-format.md documents the rebuilt sector-0 variant; the api-xisoreader.md probe table, DescriptorSector contract, and the library/CLI READMEs cover the accepted layout and the Redump rebuild restriction.

CI

  • Test runs always publish a .trx artifact for post-mortems and skip hang-dump collection (--blame-hang-dump-type none); the instrumented seed-search stall that aborted the net8.0 job is gone (windows tests dropped from ~15 min to ~1.5 min per TFM).

1.1.0

Additive release for VFS-consumer parity (SimpleXisoDrive/Dokan): the public API gains bounded in-place file reads, a keep-open explorer mode, descriptor creation-time/sector surfacing, FileShare control, and Windows attribute mapping — no behavior change to existing APIs. Targets remain net8.0 / net9.0 / net10.0; full suite green on all three (1400 tests: 1396 passed, 4 pre-existing skips, 0 failed).

Library

Read file bytes in place — no extraction

  • XisoExplorer.OpenReadStream(string) / OpenReadStream(ExplorerNode) return a read-only, seekable Stream over a file's data extent inside the image. Reads are clamped to the entry's FileSize (not the image length), so a corrupt TOC cannot leak the next file's sectors; seeking at/past the end reads 0 bytes per Stream conventions; CISO/split-CISO images work transparently through the decompressed block device. No copy is made, so 4 GB files stream in place.
  • XisoReader.ReadFileBytes(isoPath, internalPath, Span<byte>, fileOffset) and the stream overload are one-shot conveniences over the same bounds; the stream overload leaves the caller's stream open, and missing paths/directories throw InvalidDataException.
  • A stateless explorer's read stream owns the image handle (dispose it); a keep-open explorer's read streams stay valid until the explorer is disposed.

Keep-open explorer mode

  • New XisoExplorerOptions { KeepOpen, Share } and XisoExplorer(string, XisoExplorerOptions): KeepOpen holds one image stream for the explorer's lifetime (metadata calls use the held stream), serializes operations with an internal lock, and Dispose() closes the stream — the mount/VFS shape that avoids re-opening the image for every lookup. KeepOpen: false stays byte-for-byte identical to 1.0.2.

FileShare control on image opens

  • XisoReader.OpenImageStream(path, FileShare) and XisoExplorerOptions.Share: plain-ISO streams pass the share mode through (default FileShare.Read, unchanged), and CISO inputs thread it to the container file. FileShare.ReadWrite lets a mounted image coexist with AV scanners or sync clients that open the .iso for write.

Volume descriptor timestamps and sector

  • VolumeInfo gains CreationTime (DateTimeOffset?, null when invalid; raw 0 maps to 1601-01-01), FileTimeRaw, and DescriptorSector (partition-relative sector 32 for every supported layout — the partition shift is DiscLseek; −1 when invalid) — all populated by the same probe GetVolumeInfo already performs, so no second open is needed. GetVolumeInfo agrees with GetFileTime for the same image.

Windows attribute mapping

  • New XisoAttributes.ToWindowsFileAttributes(byte): pure bit math mapping the raw XDVDFS attribute byte to System.IO.FileAttributes (ReadOnly always set; Directory/Hidden/System/Archive OR'd in; Normal when nothing else applies; reserved bits masked), matching SimpleXisoDrive's locked expectations.

GUI (Avalonia)

  • Modern dark theme: left navigation rail with an accent pill, card layout, green accent palette, rounded inputs and log console, and a dark native title bar on Windows.
  • New ZAR tab: packs an ISO/XISO/Redump image into a .zar (ZArchive/zstd, loadable in Xenia canary) with overwrite/skip/auto-rename collision policies; drop routing and tab-order shortcuts account for the new tab.

Fixes

  • XisoExplorer.OpenReadStream(string) and the keep-open constructor no longer leak the image handle when a lookup or probe throws.
  • BoundedSubStream rejects seeks before the window start with IOException (per Stream conventions) instead of reading preceding image bytes.
  • ReadFileBytes validates the path even when the buffer is empty.
  • GetVolumeInfo skips probe candidates past EOF instead of aborting, so a trimmed XGD3 image (smaller than the global candidate offset) is detected.

Docs

  • Library/Getting-Started quick samples for the VFS use case, and the Utilities page documents explorer options, the read-bounds contract, and XisoAttributes.

Dependencies

  • ZArchiveSharp NuGet dependency updated 1.0.2 → 1.3.0 (mount-friendly reader API, specific open-failure reasons; additive, no wire-format changes).

1.0.2

Release tag 1.0.2. Targets remain net8.0 / net9.0 / net10.0; full suite green on all three (1338 tests: 1334 passed, 4 pre-existing skips, 0 failed).

CLI

-v banner is XISOSharp-branded

-v (and the usage header) now prints XISOSharp v<version> for <win|linux|macos|cross-platform> - https://github.com/purelogiccode/XISOSharp instead of the extract-xiso compatibility line. The version is the MinVer build stamp with +build metadata trimmed, so it matches the package/assembly version. Constants.ExisoVersion is kept for provenance and the on-disk optimized tag (in!xiso!2.7.1 (01.11.14)) is unchanged, so image compatibility is unaffected. The extract-xiso BSD-4-clause acknowledgement remains in the shipped LICENSE.

Automatic update check

Every interactive launch compares the running version against the latest GitHub release — at most one request per 24 hours, cached at %LocalAppData%/XISOSharp/update-check.json. A newer release prints an [UPDATE] notice with the release page and the matching release_<version>_<rid>.zip asset, and on an interactive console you are offered to open the release page in your browser. The check is skipped for -q/-Q/-v runs and test hosts, never fails the run, and can be disabled with XISO_NO_UPDATE_CHECK=1.

New inspection verbs

--sector-layout (volume summary, per-file extents, used/free ranges), --ranges (system/bone vs file sector ranges), and --is-optimized (optimized-tag probe, --skip-sectors aware).

Interactive launch pause

Double-clicking XISOSharp.exe with no arguments prints usage and waits for a keypress instead of closing the console window. Scripts, pipes, test hosts, and XISO_NO_PAUSE=1 are never blocked.

Warning+ logs forwarded to the bug-report service

The shared Serilog pipeline in the CLI, GUI, and Tester forwards Warning-and-above events to the bug-report API with environment, error, and exception sections; opt out with XISO_DISABLE_BUGREPORT=1.

GUI (Avalonia)

  • CLI discovery fix for single-file bundles: ToolLocator now also probes the directory of the real executable (Environment.ProcessPath) after AppContext.BaseDirectory, since self-extracting bundles run from %TEMP%\.net\.... This resolves the "CLI not found" state when the GUI runs from a published bundle.
  • The legacy XISOSharp.Cli file-name fallback was removed; resolution is XISOSharp(.exe) only.
  • Status bar and log show a branded product label (XISOSharp <version>) read from the CLI binary's version metadata instead of echoing the -v banner.
  • The app icon is embedded in both the executable and the window.
  • Framework-dependent publish builds and stages the CLI beside the GUI automatically (previous attempts failed with NETSDK1151).

Library

  • ToolLocator is now the shared resolver/probe used by the GUI, Tester, and BattleTests: explicit override → app directory → process directory → PATH, with a bounded, tree-killed -v probe via ProcessRunner, plus a new ToolLocatorTests suite.
  • Constants.Banner reports the XISOSharp product version; the extract-xiso baseline constant is retained for provenance.

Repository & docs

  • GitHub Pages publishes the Docsify documentation, and a workflow syncs the wiki (sidebar included).
  • LICENSE now carries the full third-party notices (extract-xiso BSD-4-clause, xdvdfs, XboxKit, ZArchiveSharp); distributed bundles include LICENSE and README.md.
  • Docs and readmes refreshed for the branded banner, the new inspection verbs, update checks, the GUI bundle layout, and the shared tool locator.

Dependencies

No library dependency changes: ZArchiveSharp stays at 1.0.2, analyzer/Roslynator versions are unchanged from 1.0.1.

1.0.1

Release tag 1.0.1. Targets remain net8.0 / net9.0 / net10.0; full suite green on all three (1290 tests: 1286 passed, 4 pre-existing skips, 0 failed).

Fixes

Rewrite keeps zero-size directories as directories

Optimizing (-r / Rewrite) an image containing a zero-size directory entry — seen in the wild in e.g. Marvel vs Capcom 2 — used to write that entry back as a file (ARC attribute, file data) instead of a directory, breaking the game.

Cause: XisoReader.TraverseXiso in GenerateAvl mode only recursed into subdirectories with fileSize > 0 and left AvlNode.Subdirectory as null for zero-size ones; the writer treats null as "file". The fix assigns AvlNode.EmptySubdirectory, matching upstream extract-xiso build 202609111233, which fixed the same bug in traverse_xiso() (subdirectory left NULL instead of EMPTY_SUBDIRECTORY). See Rewrite mode and XISO Format.

SHA3-256 checksum works on OSes without native SHA3 support

XisoChecksum.ComputeImageChecksum used only the BCL IncrementalHash SHA3-256, which throws PlatformNotSupportedException on OSes without a SHA3 provider (Windows 10 CNG, OpenSSL 1.x) — all checksum tests failed there. New pure-managed FIPS 202 SHA3-256 (XISOSharp/Sha3.cs, no new dependencies, trim/AOT-safe) is now used as a fallback whenever SHA3_256.IsSupported is false; digests are identical either way (verified against OpenSSL 3.0, including rate-boundary sizes). See Checksums.

Dependencies

  • ZArchiveSharp 1.0.1 → 1.0.2, now consumed purely as a NuGet package — the sibling-checkout ProjectReference fallback was removed, so no side-by-side CSharp_ZArchiveSharp clone is needed to build. See Building.
  • Meziantou.Analyzer 3.0.235 → 3.0.236 (all projects), Avalonia.Diagnostics 11.3.21 → 11.3.22 (GUI, Debug-only). Dev-only, no runtime impact.

Documentation

  • Checksum docs (xdvdfs Compat, XisoReader, Utilities) describe the BCL/managed-fallback behavior.
  • Rewrite docs (XisoWriter) and the format reference (XISO Format) document the zero-size-directory handling and upstream parity.
  • Reference/build docs updated for the NuGet-only ZArchiveSharp consumption and the extract-xiso-build-202609111233 reference drop.
  • Library README intro no longer pins a single extract-xiso version number.

Internal (no behavior change)

Solution-wide Roslynator formatting cleanup (line wrapping, Fill(0) → Clear(), internal Sha3_256 → Sha3256 rename).

1.0.0

Initial NuGet release: pure-C# port of extract-xiso v2.7.1 (byte-identical output) extended with XboxKit archival workflows and xdvdfs packing (build-image remapping, CISO, SHA3-256 checksums). See the README for the full feature list.