XISOSharp 1.2.0
Requires NuGet 5.0 or higher.
dotnet add package XISOSharp --version 1.2.0
NuGet\Install-Package XISOSharp -Version 1.2.0
<PackageReference Include="XISOSharp" Version="1.2.0" />
<PackageVersion Include="XISOSharp" Version="1.2.0" />
<PackageReference Include="XISOSharp" />
paket add XISOSharp --version 1.2.0
#r "nuget: XISOSharp, 1.2.0"
#:package XISOSharp@1.2.0
#addin nuget:?package=XISOSharp&version=1.2.0
#tool nuget:?package=XISOSharp&version=1.2.0
XISOSharp
A pure C# class library for creating, extracting, listing, and rewriting Xbox ISO (XISO) disc images. A direct conversion of the extract-xiso tool from C to C# — byte-identical output, no native dependencies — extended with the archival power of XboxKit (Redump video/filler/seed/wipe/trim/petrify/update/rebuild, ZAR) and the modern packing of xdvdfs (build-image remapping, CISO compress/decompress, checksums). All logic — including the AVL tree, Boyer-Moore search, XISO header verification, directory traversal, format rewriting, and media-enable patching — is ported directly from the reference C implementation.
Full documentation (getting started, CLI reference, archival workflows, library API) lives in the docs folder on GitHub.
Table of Contents
- Installation
- Supported Disc Formats
- Quick Start
- API Reference
- Data Types
- Usage Examples
- Auditing, Repairing, and Salvaging an XISO
- Error Handling
- Thread Safety
- Compatibility
- Performance
- License
Installation
dotnet add package XISOSharp
The package is strong-name signed and includes XML documentation, Source Link for debugging, and .snupkg symbol packages for all target frameworks.
Release history: Release Notes · What's New.
Supported Disc Formats
| Format | Description | Lseek Offset |
|---|---|---|
| RAW | Raw XISO (no offset) | 0 |
| Rebuilt (sector 0) | Rebuilt XISO without the 32-sector pad; descriptor at absolute offset 0 (DescriptorSector = 0) |
0 |
| GLOBAL | Retail/Xbox Live discs | 0x0FD90000 |
| XGD2 | Xbox 360 XGD2 discs (same as GLOBAL) | 0x0FD90000 |
| XGD3 | Xbox 360 XGD3 discs | 0x02080000 |
| XGD2 Hybrid | Xbox 360 hybrid discs | 0x89D80000 |
| XGD1 | Xbox 360 XGD1 discs | 0x18300000 |
The library automatically detects the disc format during verification by probing each known offset, plus the rebuilt sector-0 layout (descriptor at absolute offset 0). Standard images keep offset 0 zeroed, so the candidates never collide.
Quick Start
using XISOSharp;
// Extract all files from an XISO image
XisoReader.DecodeXiso("game.iso", "output_folder", ExtractMode.Extract, out _);
// List all files in an XISO image (prints to console)
XisoReader.DecodeXiso("game.iso", null, ExtractMode.List, out _);
// Create an XISO image from a directory
XisoWriter.CreateXiso("source_folder", "output_folder", null, null, out _, "game.iso", null);
API Reference
XisoReader
Static class for reading and processing XISO disc images.
DecodeXiso
Main entry point for processing an XISO image. Verifies the image header, then performs extraction, listing, or rewriting based on the specified mode.
public static int DecodeXiso(
string xisoPath,
string? outputPath,
ExtractMode mode,
out string? outIsoPath,
bool llCompat = false,
CancellationToken cancellationToken = default,
string? outputName = null,
int? skipSectors = null,
int? prependSectors = null)
| Parameter | Type | Description |
|---|---|---|
xisoPath |
string |
Path to the XISO file to process. |
outputPath |
string? |
Output directory for extraction or rewrite output. When null in extract mode, a directory named after the ISO is created. |
mode |
ExtractMode |
Operating mode: Extract, List, or Rewrite. |
outIsoPath |
out string? |
Receives the path to the output ISO file when in rewrite mode. |
llCompat |
bool |
If true, uses backwards-compatible (non-optimized) right-offset calculation. Defaults to false. |
cancellationToken |
CancellationToken |
Token to monitor for cancellation requests. |
outputName |
string? |
Custom output filename for rewrite mode. When null, the original filename with .iso extension is used. |
skipSectors |
int? |
Optional number of 2048-byte sectors to skip in the source file before the XISO filesystem begins (Redump-style images with a video partition). When set, offset probing is skipped and the header must be at skipSectors * 2048 + 0x10000. |
prependSectors |
int? |
Optional number of 2048-byte sectors to prepend to the output image in rewrite mode, leaving room for a video partition. Stored sector numbers remain partition-relative. Ignored in non-rewrite modes. |
Returns: 0 on success, non-zero on error.
Exceptions:
FileNotFoundException— input file does not existInvalidDataException— file is not a valid XISO imageIOException— read errorsExtractErrorException— non-fatal extraction error (see error code)
DecodeXisoAsync
Asynchronous wrapper around DecodeXiso that runs the synchronous engine on a thread pool thread.
public static async Task<(int Result, string? OutIsoPath)> DecodeXisoAsync(
string xisoPath,
string? outputPath,
ExtractMode mode,
bool llCompat = false,
CancellationToken cancellationToken = default)
Returns: A tuple containing Result (0 on success) and OutIsoPath (the output ISO path in rewrite mode).
Extract, UnpackImage, List, Tree, DecodeXiso, and DecodeXisoAsync
each have a Stream overload taking (Stream imageStream, string imageName, ...)
in place of the input path — for memory, network, or embedded-resource images.
The stream must be readable and seekable and is left open; imageName (typically
the file name) drives output naming and messages. Rewrite stays path-only.
using var image = new MemoryStream(File.ReadAllBytes("game.iso"));
int rc = XisoReader.UnpackImage(image, "game.iso", "./out"); // stream stays open
Destination filesystems (IFilesystem, TODO #7)
UnpackImage also accepts any IFilesystem destination in place of outputPath:
public static int UnpackImage(
string isoPath, IFilesystem filesystem,
CancellationToken cancellationToken = default, int? skipSectors = null,
UnpackOptions? options = null, IProgress<ProgressInfo>? progress = null)
public static int UnpackImage(
Stream imageStream, string imageName, IFilesystem filesystem,
CancellationToken cancellationToken = default, int? skipSectors = null,
UnpackOptions? options = null, IProgress<ProgressInfo>? progress = null)
Files land at the filesystem root (no ISO-named subdirectory, no process
working-directory changes) with the same per-file hardening as the disk path:
skip-existing resume probes the destination filesystem, truncated data and failed
writes throw the same ExtractFileException errors. Paths are
destination-root-relative, /-separated, case-insensitive; FileLength returns
-1 for unresolvable paths (never skipped, reports as truncated).
Built-in implementations:
| Type | Behavior |
|---|---|
LocalFilesystem(string? root = null) |
Local disk under root (cwd-relative when null, matching the legacy unpack); LocalFilesystem.Instance is the shared cwd-relative instance; parent directories are not auto-created |
MemoryFilesystem |
In-process byte snapshots committed when the unpack closes each file's stream; re-creating a file truncates it; parents auto-created; inspect via ReadAllBytes(path), FileNames, DirectoryNames |
var memory = new MemoryFilesystem();
XisoReader.UnpackImage("game.iso", memory);
byte[] defaultXbe = memory.ReadAllBytes("default.xbe"); // never touched the disk
XisoReader.UnpackImage("game.iso", new LocalFilesystem(@"D:\games\out")); // disk, no chdir
Image explorer (XisoExplorer, TODO #11)
UI-agnostic explorer over one .iso or .cso image (the engine behind the Tester's
Explore tab). The constructor probes the volume eagerly; by default every operation
opens and closes the image, so instances are safe for concurrent background use.
Pass XisoExplorerOptions { KeepOpen = true } to hold one stream for the explorer's
lifetime (VFS/mount mode), where operations are serialized by an internal lock and
Dispose() releases the stream. Paths are image-internal, /-separated,
case-insensitive.
public sealed class XisoExplorer : IDisposable
{
public XisoExplorer(string isoPath); // fail fast: ArgumentException / FileNotFoundException / XisoFormatException
public XisoExplorer(string isoPath, XisoExplorerOptions options); // KeepOpen / Share (FileShare)
public string IsoPath { get; }
public XisoExplorerOptions Options { get; }
public VolumeInfo Volume { get; }
public bool IsKeepOpen { get; }
public IReadOnlyList<ExplorerNode> ListChildren(string internalPath);
public ExplorerNode? GetNode(string internalPath); // synthetic "/" root; null when missing
public Stream OpenReadStream(string internalPath); // bounded to the file size; InvalidDataException on dir/missing
public Stream OpenReadStream(ExplorerNode node); // ArgumentException when the node is a directory
public void CopyOut(string internalPath, string destPath, UnpackOptions? options = null,
CancellationToken cancellationToken = default, IProgress<ProgressInfo>? progress = null);
public string? ComputeHashHex(string internalPath, HashAlgorithmName algorithm); // null when missing
public XexInfo? GetXexInfo(string internalPath); // null when missing/dir/not XEX2
public XbeInfo? GetXbeInfo(string internalPath); // null when missing/dir/not XBEH
public static string Combine(string directory, string name);
public static string Normalize(string? internalPath);
}
public sealed record XisoExplorerOptions
{
public bool KeepOpen { get; init; } // default false
public FileShare Share { get; init; } = FileShare.Read; // FileShare.ReadWrite for writer coexistence
}
public sealed record ExplorerNode(
string Name, string FullPath, bool IsDirectory, long Size, uint StartSector, byte Attributes);
var explorer = new XisoExplorer("game.iso");
foreach (var node in explorer.ListChildren("/sub"))
Console.WriteLine($"{node.FullPath} ({node.Size} B)");
explorer.CopyOut("/docs/readme.txt", "./readme.txt");
string? sha256 = explorer.ComputeHashHex("/default.xbe", HashAlgorithmName.SHA256);
// In-place reads (VFS/Dokan ReadFile hot path; no extraction, .cso-aware)
using Stream data = explorer.OpenReadStream("/default.xex");
data.Seek(0x100, SeekOrigin.Begin);
int n = data.Read(buffer); // 0 at/past the file end
int oneShot = XisoReader.ReadFileBytes("game.iso", "/default.xbe", buffer, fileOffset: 0);
// Keep-open mount mode: one held handle, serialized ops, read streams die with Dispose
using var mounted = new XisoExplorer("game.iso",
new XisoExplorerOptions { KeepOpen = true, Share = FileShare.ReadWrite });
VolumeInfo vol = mounted.Volume; // CreationTime, DescriptorSector, DiscFormat, ...
FileAttributes attrs = XisoAttributes.ToWindowsFileAttributes(mounted.GetNode("/default.xbe")!.Attributes);
Image splitting (XisoSplitter, TODO #17)
Splits a plain .iso into FATX-friendly parts and reassembles them (the
plain-ISO counterpart to CSO --ciso-split). Parts are a pure byte partition
at sector-aligned cut points (<base>.1.iso, <base>.2.iso, …), so
concatenation restores the image bit-for-bit. Inputs are pre-validated, the
joined output is post-validated, existing targets are refused, and partial
outputs are removed on failure/cancel.
public static class XisoSplitter
{
public const long DefaultPartSizeBytes = 4294967296L; // FATX 4 GiB cap
public static IReadOnlyList<string> Split(string isoPath, string outputBase, long partSizeBytes,
CancellationToken cancellationToken = default, IProgress<ProgressInfo>? progress = null);
public static IReadOnlyList<string> SplitHalves(string isoPath, string outputBase,
CancellationToken cancellationToken = default, IProgress<ProgressInfo>? progress = null);
public static string Join(string firstPartPath, string outputPath,
CancellationToken cancellationToken = default, IProgress<ProgressInfo>? progress = null);
public static string PartPath(string outputBase, int partIndex); // 0-based
public static bool IsSplitPath(string? path); // *.1.iso
}
// XisoReader facades: SplitXiso / SplitXisoHalves / JoinSplitXiso
// CLI: split [--size <bytes|half>] [--output <base>] <image>… / join [--output <file>] <first.1.iso>…
var parts = XisoReader.SplitXiso("game.iso", "game", XisoSplitter.DefaultPartSizeBytes);
XisoReader.JoinSplitXiso(parts[0], "rejoined.iso");
VerifyXiso
Low-level method that validates the XISO header and returns root directory metadata. Most users should use DecodeXiso instead.
public static (uint rootDirSector, uint rootDirSize, long discLseek) VerifyXiso(
Stream fs, string isoName, int? skipSectors = null)
| Parameter | Type | Description |
|---|---|---|
fs |
Stream |
Open stream positioned anywhere. |
isoName |
string |
Display name for error messages. |
skipSectors |
int? |
Optional number of 2048-byte sectors to skip from the start of the file before the XISO filesystem begins. When set, the header magic is verified at skipSectors * SectorSize + HeaderOffset and offset probing is skipped. Negative values throw ArgumentOutOfRangeException. |
Returns: Tuple of (rootDirSector, rootDirSize, discLseek).
Exceptions:
InvalidDataException— no valid XISO header found or trailing magic byte mismatchIOException— file too short to contain expected header dataExtractErrorException— root directory sector and size are both zero (empty ISO)
Tree
Recursively lists all files in an XISO image in a tree format, showing full paths and sizes.
public static int Tree(
string xisoPath,
bool llCompat = false,
CancellationToken cancellationToken = default)
GetVolumeInfo
Reads the XISO volume descriptor and returns metadata about the image without throwing on validation errors.
public static VolumeInfo GetVolumeInfo(string isoPath)
Returns: A VolumeInfo record containing IsValid, RootDirSector, RootDirSize, DiscLseek, DiscFormat (friendly layout name: RAW, GLOBAL (XGD2), XGD3, XGD2 Hybrid, XGD1, Unknown), FileLength, TotalSectors, CreationTime (descriptor FILETIME as DateTimeOffset?, from the same probe), FileTimeRaw, and DescriptorSector (partition-relative descriptor sector: 32 for standard layouts, 0 for rebuilt sector-0 images — the partition shift is DiscLseek; −1 when invalid).
ReadFileBytes
Reads up to buffer.Length bytes of a file's data starting at fileOffset without extracting to disk. The read is clamped to the entry's own FileSize (not the image length), so a corrupt TOC cannot leak the next file's sectors; an offset at/past the file end returns 0.
public static int ReadFileBytes(string isoPath, string internalPath, Span<byte> buffer, long fileOffset)
public static int ReadFileBytes(Stream imageStream, string imageName, string internalPath,
Span<byte> buffer, long fileOffset) // stream left open
Returns: Bytes actually read. Throws: InvalidDataException for a missing path or directory target; ArgumentOutOfRangeException for a negative offset.
ListDirectory
Returns metadata about all entries in the specified directory within an XISO image.
public static IReadOnlyList<EntryInfo> ListDirectory(string isoPath, string internalPath = "/")
| Parameter | Type | Description |
|---|---|---|
isoPath |
string |
Path to the XISO file. |
internalPath |
string |
Path within the ISO (e.g. "/" for root, "/subdir" for a subdirectory). |
Returns: List of EntryInfo records, each containing Name, IsDirectory, StartSector, FileSize, Attributes, LeftChildOffset, RightChildOffset.
GetEntryInfo
Returns metadata about a specific file or directory entry within an XISO image.
public static EntryInfo? GetEntryInfo(string isoPath, string internalPath)
Returns: An EntryInfo record, or null if the path does not exist.
CopyOut
Copies a single file or directory from an XISO image to the local filesystem. If the path points to a file, it is extracted to destPath. If the path points to a directory, all its contents are recursively extracted.
public static void CopyOut(string isoPath, string internalPath, string destPath)
Exceptions:
InvalidDataException— path does not exist in the XISOIOException— read or write errors
CopyIn
Copies a host file into an XISO image, modifying it in place: replaces the entry at internalPath when it exists, or adds it as a new file when only its parent directory exists. A .old backup of the pre-patch image is written first unless createBackup is false.
public static void CopyIn(string isoPath, string hostFile, string internalPath, bool createBackup = true)
Exceptions:
FileNotFoundException— host file does not existInvalidDataException— path malformed, parent missing, target is a directory, or data does not fit in free spaceXisoFormatException— not a valid XISO imageIOException— read or write errors
ComputeFileHash
Computes the hash of a single file within an XISO image.
public static byte[]? ComputeFileHash(string isoPath, string internalPath, HashAlgorithmName algorithm)
| Parameter | Type | Description |
|---|---|---|
isoPath |
string |
Path to the XISO file. |
internalPath |
string |
Path within the ISO (e.g. "/subdir/file.xbe"). |
algorithm |
HashAlgorithmName |
Hash algorithm to use (HashAlgorithmName.MD5 or HashAlgorithmName.SHA256). |
Returns: Hash bytes, or null if the file does not exist.
ComputeDirectoryHashes
Computes hashes for all files in a directory (or the entire image) within an XISO.
public static List<(string Path, byte[] Hash)> ComputeDirectoryHashes(
string isoPath, string internalPath, HashAlgorithmName algorithm)
Returns: List of (path, hash) tuples for all files.
GetXexInfo
Parses the Xbox 360 XEX2 header of a .xex file inside the image: module flags, header size, entry point, image base/size, load address, region, allowed media types, media/title IDs, version, platform, disc number/count, encryption and compression types. Path and Stream overloads.
public static XexInfo? GetXexInfo(string isoPath, string internalPath)
public static XexInfo? GetXexInfo(Stream imageStream, string imageName, string internalPath)
Returns: An XexInfo record, or null when the entry is missing, a directory, or not an XEX2 executable.
Exceptions:
FileNotFoundException— input file does not exist (path overload)XisoFormatException— not a valid XISO imageIOException— read errors
GetXbeInfo
Parses the original-Xbox XBEH header + certificate of a .xbe file inside the image — no reference tool does this: base address, entry point, section count, init flags, cert size/timestamp, title ID and UTF-16 title name (+ 16 alternate title IDs), allowed-media, region, and ratings bitmasks, disc number, version. All multi-byte fields are read little-endian (cert address is a load pointer: file offset = address − base). Path and Stream overloads.
public static XbeInfo? GetXbeInfo(string isoPath, string internalPath)
public static XbeInfo? GetXbeInfo(Stream imageStream, string imageName, string internalPath)
Returns: An XbeInfo record, or null when the entry is missing, a directory, not an XBEH executable, or the certificate is out of range, below base, truncated, or the wrong size.
Exceptions:
FileNotFoundException— input file does not exist (path overload)XisoFormatException— not a valid XISO imageIOException— read errors
AuditXiso
Performs a deep integrity audit of an XISO image. Validates the header, walks the entire directory tree, checks sector bounds, detects cycles, validates filenames and attributes, and verifies the optimized tag.
public static AuditResult AuditXiso(string isoPath)
| Parameter | Type | Description |
|---|---|---|
isoPath |
string |
Path to the XISO file to audit. |
Returns: An AuditResult record with IsValid, FilesChecked, DirsChecked, and Issues.
Exceptions:
FileNotFoundException— input file does not existIOException— read errors
Repair
Repairs the audit's safely-patchable (class-C) issues in place: reserved attribute bits (rewritten with MaskAttributes), a missing optimized tag (exact CreateXiso tag bytes at offset 31337), and path separators in filenames (length-preserving _ substitution; left alone on collision). Every patch is length-preserving — image size never changes. Pointers from corrupt records are not trusted (converges over bounded passes); truncation, structural, and refused classes are reported, never patched. A .old backup is written first unless createBackup is false.
public static RepairResult Repair(string isoPath, bool createBackup = true, bool dryRun = false)
Returns: A RepairResult record with Fixed, Remaining, BackupPath, DryRun, and Success (true when the image now passes the audit).
Exceptions:
FileNotFoundException— input file does not existInvalidDataException— CISO container or split part (decompress/reassemble first)XisoFormatException— not a valid XISO imageIOException— read or write errors
Salvage
Rebuilds a readable image from a corrupt one: a bounded walk reusing the auditor's hardening limits carries every entry reachable without tripping a truncation or structural gate into a staging directory, then repacks it via CreateXiso into a fresh plain .iso. The source is only read, never modified (CISO input allowed); the rebuilt image is re-audited.
public static SalvageResult Salvage(string sourcePath, string? outputPath = null)
outputPath defaults to the source's directory plus the source stem with a .salvaged.iso suffix; an existing file is overwritten and a missing parent directory is created.
Returns: A SalvageResult record with Copied, Skipped, OutputPath, and OutputIssues (Success when the rebuilt image passes the audit).
Exceptions:
FileNotFoundException— source file does not existXisoFormatException— not a valid XISO image, or the tree root itself is unreachableIOException— read or write errors, or repacking failed
GetFileTime / SetFileTime
Read and write the Windows FILETIME field of the volume descriptor (xdvdfs-compatible: 0 is 1601-01-01, the deterministic-image value). Path and IBlockDevice overloads for reading; the setter takes a raw value or a DateTimeOffset (see FileTimeHelper).
public static ulong GetFileTimeRaw(string isoPath, int? skipSectors = null)
public static DateTimeOffset GetFileTime(string isoPath, int? skipSectors = null)
public static ulong GetFileTimeRaw(IBlockDevice dev, string isoName = "memory", int? skipSectors = null)
public static DateTimeOffset GetFileTime(IBlockDevice dev, string isoName = "memory", int? skipSectors = null)
public static void SetFileTime(string isoPath, ulong fileTime, int? skipSectors = null)
public static void SetFileTime(string isoPath, DateTimeOffset dateTime, int? skipSectors = null)
Exceptions:
FileNotFoundException— input file does not exist (path overloads)XisoFormatException— not a valid XISO imageIOException— read or write errors
Static class for creating and rewriting XISO disc images.
CreateXiso
Creates a new XISO from a local directory, or rewrites an existing ISO using a pre-built AVL tree.
public static int CreateXiso(
string rootDirectory,
string? outputDirectory,
AvlNode? inRoot,
Stream? sourceStream,
out string? outIsoPath,
string? inName,
ProgressCallback? progressCallback = null,
CancellationToken cancellationToken = default,
int? prependSectors = null,
IReadOnlyList<string>? excludePatterns = null,
IProgress<ProgressInfo>? progress = null)
| Parameter | Type | Description |
|---|---|---|
rootDirectory |
string |
Source directory for creation, or base name for rewrite mode. |
outputDirectory |
string? |
Directory where the output ISO is written. When null, the current working directory is used. |
inRoot |
AvlNode? |
Pre-built AVL tree root. When null, the tree is generated from the file system. |
sourceStream |
Stream? |
Source ISO stream for reading file data in rewrite mode; null when creating from a file system. |
outIsoPath |
out string? |
Receives the full path of the created output ISO file. |
inName |
string? |
Explicit output filename. When null, the directory name plus .iso is used. |
progressCallback |
ProgressCallback? |
Optional callback invoked with (currentBytes, totalBytes) during write. |
cancellationToken |
CancellationToken |
Token to monitor for cancellation requests. |
prependSectors |
int? |
Optional number of 2048-byte sectors to prepend to the output image before the XISO filesystem begins, leaving room for a video partition. The placeholder area is zero-filled; stored sector numbers remain partition-relative. Negative values throw ArgumentOutOfRangeException. |
excludePatterns |
IReadOnlyList<string>? |
Optional glob patterns of files/directories to omit from the image when creating from a file system (see GlobMatcher). Excluded directories are not recursed into. When Logger.RemoveSystemUpdate is set, **/$SystemUpdate/** is implicitly added. Ignored in rewrite mode. |
Returns: 0 on success, 1 on error.
CreateXisoAsync
Asynchronous wrapper around CreateXiso.
public static async Task<(int Result, string? OutIsoPath)> CreateXisoAsync(
string rootDirectory,
string? outputDirectory,
AvlNode? inRoot,
Stream? sourceStream,
string? inName,
ProgressCallback? progressCallback = null,
CancellationToken cancellationToken = default)
Returns: A tuple containing Result (0 on success) and OutIsoPath.
Skip / Prepend Sectors (Redump-style images)
Xbox disc images (especially Redump dumps) contain a video partition followed by the
game partition (the XISO filesystem). When the game partition does not start at file
offset 0, pass the partition start to the read APIs via skipSectors:
// XGD1 Redump image: game partition starts at sector 0xC180 (0x18300000 bytes)
int result = XisoReader.Extract("game.iso", "output", llCompat: false, skipSectors: 0xC180);
When creating an image that must sit after a video partition, use prependSectors to leave
zero-filled space at the start of the file. The two options are symmetric, enabling
round-trip reconstruction:
// Write the game partition at the same offset it was read from
XisoWriter.CreateXiso(srcDir, outputDir, null, null, out _, "game.iso", null,
prependSectors: 0xC180);
Both parameters are also exposed on the CLI as --skip-sectors N and --prepend-sectors N.
GlobMatcher
Matches relative paths against shell-style glob patterns. Used by CreateXiso
excludePatterns; also available as a standalone utility.
var matcher = new GlobMatcher(["**/*.tmp", "**/node_modules/**"]);
bool excluded = matcher.IsMatch("sub/notes.tmp"); // true
Supported syntax (use / as the separator; matching is case-insensitive):
| Pattern | Meaning |
|---|---|
* |
Any characters within a single path segment |
? |
Exactly one character within a single path segment |
** |
As a complete segment: zero or more path segments. A trailing /** also matches the directory itself |
[abc], [a-z], [!abc] |
Character classes with optional !/^ negation |
\x |
Escapes the next character |
Patterns without a leading **/ are anchored to the source root. A trailing / is
treated as /**. On the CLI, patterns are passed via the repeatable -X <glob> flag;
-s implicitly adds **/$SystemUpdate/** (create side matches entries named exactly
$SystemUpdate, unlike the extract-side -s check which uses substring matching).
Logger
Static class providing configurable text output. All output is thread-safe and can be redirected.
Properties
| Property | Type | Default | Description |
|---|---|---|---|
Out |
TextWriter |
Console.Out |
Writer for normal output. Set to TextWriter.Null to discard. |
Error |
TextWriter |
Console.Error |
Writer for error output. Set to TextWriter.Null to discard. |
Fields
| Field | Type | Default | Description |
|---|---|---|---|
Quiet |
bool |
false |
When true, suppresses all non-error output. |
RealQuiet |
bool |
false |
When true, suppresses all output including errors. |
Warned |
bool |
false |
Set to true when a warning is issued during processing. |
TotalBytes |
long |
0 |
Cumulative bytes written across the current operation. |
TotalFiles |
int |
0 |
Cumulative files processed in the current operation. |
TotalBytesAllIsos |
long |
0 |
Cumulative bytes across all processed ISO images. |
TotalFilesAllIsos |
int |
0 |
Cumulative file count across all processed ISO images. |
RemoveSystemUpdate |
bool |
false |
When true, files in $SystemUpdate folders are skipped. |
MediaEnable |
bool |
true |
When true, .xbe files are automatically patched for media-enable during creation/rewrite. |
XboxDiscLseek |
long |
0 |
Disc lseek offset detected during verification, used in rewrite mode. |
Methods
// Writes a formatted message to Out (unless Quiet is true).
public static void Log(string message, params object?[] args)
// Writes a line to Out (unless Quiet is true). No format arguments.
public static void LogLine(string message)
// Flushes Out (unless Quiet is true).
public static void Flush()
// Writes a formatted error message to Error (unless RealQuiet is true).
public static void LogErr(string message, params object?[] args)
AvlTree
Static class providing AVL (Adelson-Velsky/Landis) balanced binary search tree operations. Used internally for XISO directory indexing but exposed for advanced scenarios.
AvlCompareKey
Compares two strings case-insensitively using ASCII rules.
public static int AvlCompareKey(string lhs, string rhs)
AvlFetch
Looks up a node in the AVL tree by filename.
public static AvlNode? AvlFetch(AvlNode? root, string filename)
Returns: The matching AvlNode or null if not found.
AvlInsert
Inserts a node into the AVL tree, rebalancing as needed. Duplicate filenames are rejected.
public static AvlResult AvlInsert(ref AvlNode? root, AvlNode node)
Returns:
AvlResult.AvlBalanced— tree grew tallerAvlResult.NoErr— insertion completed without height changeAvlResult.AvlError— duplicate key
AvlTraverseDepthFirst
Traverses the AVL tree depth-first in the specified order.
public static int AvlTraverseDepthFirst(
AvlNode? root,
TraversalCallback callback,
object? context,
AvlTraversalMethod method,
int depth)
Returns: 0 if the full traversal completed, or the non-zero value returned by the callback (early termination).
FreeTree
Frees an entire AVL tree by clearing all node references so the garbage collector can reclaim memory.
public static void FreeTree(AvlNode? root)
BoyerMoore
Implements the Boyer-Moore string search algorithm for efficient pattern matching in byte arrays. Used internally for media-enable patching of .xbe files.
public class BoyerMoore
{
public BoyerMoore(byte[] pattern, int alphabetSize = 256)
public void Init()
public int Search(byte[] text, int startIndex, int length)
public int Search(byte[] text)
public void Done()
}
| Member | Description |
|---|---|
| Constructor | Initializes a new pattern matcher with the given pattern and alphabet size. |
Init() |
Builds the bad-character and good-suffix shift tables. Must be called before Search. |
Search(byte[], int, int) |
Searches for the pattern within a subrange of the text buffer. Returns the index of the first match, or -1. Throws InvalidOperationException if Init was not called (or after Done). |
Search(byte[]) |
Searches the entire text buffer starting at offset 0. Same InvalidOperationException contract. |
Done() |
Releases the shift tables. Re-initialize before searching again. |
FileTimeHelper
Static helper for converting between .NET timestamps and Windows FILETIME values.
public static class FileTimeHelper
{
public static void WriteFileTimeNow(Span<byte> destination)
}
Writes the current UTC time as a Windows FILETIME (two little-endian 32-bit words, 8 bytes total) into the destination span. Used internally for writing timestamps into XISO headers.
Constants
Static class containing all magic values, offsets, and constants used by the XISO format. See the IntelliSense tooltips or XML documentation for detailed descriptions.
Key constants include:
| Constant | Value | Description |
|---|---|---|
HeaderData |
"MICROSOFT*XBOX*MEDIA" |
XISO header magic string |
HeaderOffset |
0x10000 |
Offset of XISO header from start of image |
SectorSize |
2048 |
One sector = 2 KB |
RootDirectorySector |
0x108 |
Sector index of root directory table |
GlobalLseekOffset |
0x0FD90000 |
Sector offset for GLOBAL layout |
Xgd2LseekOffset |
0x0FD90000 |
Sector offset for XGD2 layout (same as Global) |
Xgd3LseekOffset |
0x02080000 |
Sector offset for XGD3 layout |
Xgd1LseekOffset |
0x18300000 |
Sector offset for XGD1 layout |
ReadWriteBufferSize |
0x00200000 |
2 MB buffer for file copy operations |
ExisoVersion |
"2.7.1 (01.11.14)" |
extract-xiso baseline this port tracks (provenance only; not printed) |
Banner |
— | Startup banner: XISOSharp product version (MinVer stamp) + platform + repository URL |
NumSectors(uint size) |
— | Computes the number of sectors required to hold size bytes |
Data Types
Enums
ExtractMode
Operating mode for XISO image processing.
| Value | Description |
|---|---|
GenerateAvl |
Build the AVL tree directory structure without writing an output file. |
Extract |
Extract files from the XISO image to disk. |
List |
List the contents of the XISO image to the logger. |
Rewrite |
Rewrite the XISO image with an optimized AVL directory structure. |
Tree |
Recursively list all files with sizes in a tree format. |
Verify |
Deep-audit the XISO image: validate header, walk tree, check sector bounds, detect cycles. |
ExtractError
Error codes for non-fatal extraction failures.
| Value | Code | Description |
|---|---|---|
ErrEndOfSector |
-5001 |
Unexpected end of sector while reading a directory entry chain. |
ErrIsoRewritten |
-5002 |
XISO image has already been rewritten (optimized format detected). |
ErrIsoNoFiles |
-5003 |
XISO image references no files in its directory table. |
ErrFileTruncated |
-5004 |
File data ends before the reported size (truncated image or entry pointing past end of image). |
ErrFileWrite |
-5005 |
Destination file or directory could not be created or written. |
ErrExtractFailed |
-5006 |
End-of-run summary of a ContinueOnError run: one or more files failed (message lists each). |
AvlResult
Result codes returned by AVL tree insertion.
| Value | Description |
|---|---|
NoErr |
Operation completed successfully without requiring rebalancing. |
AvlError |
An error occurred during the operation (e.g., duplicate key). |
AvlBalanced |
Operation completed and the tree was rebalanced. |
AvlTraversalMethod
Traversal order when walking an AVL tree.
| Value | Description |
|---|---|
Prefix |
Pre-order: visit node before children. |
Infix |
In-order: visit left child, then node, then right child. |
Postfix |
Post-order: visit children before node. |
AvlSkew
Skew direction of an AVL tree node.
| Value | Description |
|---|---|
NoSkew |
Node is balanced (subtrees have equal height). |
LeftSkew |
Left subtree is taller. |
RightSkew |
Right subtree is taller. |
Records
VolumeInfo
Metadata about an XISO volume descriptor.
| Property | Type | Description |
|---|---|---|
IsValid |
bool |
Whether the volume magic is valid. |
RootDirSector |
uint |
Sector index of the root directory table. |
RootDirSize |
uint |
Size of the root directory table in bytes. |
DiscLseek |
long |
Disc lseek offset detected during probing. |
DiscFormat |
string |
Friendly disc-layout identity from DiscLseek (RAW, GLOBAL (XGD2), XGD3, XGD2 Hybrid, XGD1, Unknown; Unknown when invalid). |
FileLength |
long |
Total size of the ISO file in bytes. |
TotalSectors |
long |
Total number of sectors in the ISO. |
CreationTime |
DateTimeOffset? |
Descriptor FILETIME as UTC time (null when invalid; raw 0 = 1601-01-01); agrees with XisoReader.GetFileTime. |
FileTimeRaw |
ulong |
Raw FILETIME field as stored in the descriptor. |
DescriptorSector |
int |
Partition-relative descriptor sector: 32 for standard layouts, 0 for rebuilt sector-0 images (the partition shift is DiscLseek); -1 when invalid. |
EntryInfo
Metadata about a single directory entry within an XISO image.
| Property | Type | Description |
|---|---|---|
Name |
string |
Filename of the entry. |
IsDirectory |
bool |
Whether this entry is a directory. |
StartSector |
uint |
Sector index where the entry's data begins. |
FileSize |
uint |
Size of the file data in bytes (0 for directories). |
Attributes |
byte |
Raw attribute byte (see Constants for flag definitions). |
LeftChildOffset |
ushort |
Left child offset in the directory tree (0 if none). |
RightChildOffset |
ushort |
Right child offset in the directory tree (0 if none). |
AuditResult
Result of a deep integrity audit of an XISO image.
| Property | Type | Description |
|---|---|---|
IsValid |
bool |
Whether the image passed all checks. |
FilesChecked |
int |
Number of file entries audited. |
DirsChecked |
int |
Number of directory entries audited. |
Issues |
IReadOnlyList<string> |
List of human-readable issues found during the audit. |
RepairResult
Outcome of an in-place repair pass (Repair).
| Property | Type | Description |
|---|---|---|
Fixed |
IReadOnlyList<string> |
Applied (or dry-run would-be) fixes. |
Remaining |
IReadOnlyList<string> |
Post-repair audit issues; empty when the image passes. |
BackupPath |
string? |
Path of the .old pre-repair backup, or null when none was written. |
DryRun |
bool |
Whether this was a preview pass that changed nothing. |
Success |
bool |
True when Remaining is empty. |
SalvageResult
Outcome of a salvage rebuild (Salvage).
| Property | Type | Description |
|---|---|---|
Copied |
IReadOnlyList<string> |
Carried image-internal paths (directories carry a trailing /). |
Skipped |
IReadOnlyList<string> |
Dropped entries with reasons. |
OutputPath |
string |
Path of the rebuilt plain .iso image. |
OutputIssues |
IReadOnlyList<string> |
Re-audit issues of the rebuilt image. |
Success |
bool |
True when the rebuilt image passes the audit. |
XexInfo
Xbox 360 XEX2 header of an executable inside the image (GetXexInfo).
| Property | Type | Description |
|---|---|---|
ModuleFlags |
uint |
Module flags. |
HeaderSize |
uint |
Header size in bytes. |
EntryPoint |
uint |
Entry point address. |
ImageBaseAddress |
uint |
Image base address. |
ImageSize |
uint |
Image size in bytes. |
LoadAddress |
uint |
Load address. |
Region |
uint |
Region bitmask. |
AllowedMediaTypes |
uint |
Allowed-media bitmask. |
MediaId |
uint |
Media ID. |
TitleId |
uint |
Title ID. |
Version |
uint |
Version. |
Platform |
byte |
Platform byte. |
DiscNumber |
byte |
Disc number of a multi-disc title. |
DiscCount |
byte |
Total disc count. |
EncryptionType |
ushort |
Encryption type. |
CompressionType |
ushort |
File compression type (0 = none, 1 = basic, 2 = normal, 3 = delta). |
XbeInfo
Original-Xbox XBEH header + certificate of an executable inside the image (GetXbeInfo).
| Property | Type | Description |
|---|---|---|
BaseAddress |
uint |
Image base address (retail: 0x00010000). |
EntryPoint |
uint |
Entry point address. |
SectionCount |
uint |
Number of section headers. |
InitFlags |
uint |
Init flags (e.g. 0x01 mount utility drive). |
CertSize |
uint |
Certificate size in bytes (retail: 464, 0x1D0). |
CertTimeDate |
uint |
Certificate timestamp (raw DWORD). |
TitleId |
uint |
Title ID from the certificate. |
TitleName |
string |
Title name from the certificate (UTF-16, up to 40 chars). |
AlternateTitleIds |
uint[] |
Alternate title IDs (16 entries, usually zero). |
AllowedMedia |
uint |
Allowed-media bitmask (0x01 hard disk … 0x80 media board). |
GameRegion |
uint |
Game-region bitmask (0x01 NA, 0x02 JP, 0x04 RoW). |
GameRatings |
uint |
Game-ratings bitmask (ESRB etc.). |
DiskNumber |
uint |
Disc number of a multi-disc title. |
Version |
uint |
Game version from the certificate. |
Classes
AvlNode
Node in an AVL balanced binary search tree. Used to index XISO directory entries by filename.
| Field | Type | Description |
|---|---|---|
Offset |
uint |
Byte offset of this node's directory entry within its parent sector. |
DirStart |
long |
Start byte position of the directory table this node belongs to. |
Filename |
string |
Filename (case-insensitive key for the AVL tree). |
FileSize |
uint |
Size of the file in bytes, or size of the directory entry table for directories. |
StartSector |
uint |
Sector index where the file data or subdirectory table begins. |
Subdirectory |
AvlNode? |
Root of an AVL tree containing the children of this directory node, or EmptySubdirectory. |
OldStartSector |
uint |
Original sector position before rewrite. |
Skew |
AvlSkew |
Current balance state of this node. |
Left |
AvlNode? |
Left child in the AVL tree. |
Right |
AvlNode? |
Right child in the AVL tree. |
EmptySubdirectory |
static AvlNode |
Singleton sentinel representing an empty subdirectory. |
DirEntry
Represents an on-disk directory entry in the XISO filesystem.
| Field | Type | Description |
|---|---|---|
Left |
DirEntry? |
Left child directory entry in the on-disk tree. |
Parent |
DirEntry? |
Parent directory entry. |
AvlNode |
AvlNode? |
Associated AVL node that indexes this entry by filename. |
Filename |
string |
Filename of the file or directory. |
FilenameLength |
byte |
Length of the filename in bytes (ASCII). |
ROffset |
ushort |
Right-child offset (in DWORDs) within the directory sector. |
Attributes |
byte |
File attribute flags (e.g., Constants.AttributeDir, Constants.AttributeArc). |
FileSize |
uint |
Size of the file in bytes, or size of the directory entry table for directories. |
StartSector |
uint |
Sector index where the file data or subdirectory begins. |
CreateList
Describes a source directory and optional output name for creating an XISO image. Entries can be chained for batch creation.
| Property | Type | Description |
|---|---|---|
Path |
string |
Source directory path whose contents will be packed into the XISO. |
Name |
string? |
Optional output filename. When null, the directory name is used. |
Next |
CreateList? |
Next entry in a linked list of creation tasks, or null. |
Delegates
ProgressCallback
public delegate void ProgressCallback(long currentValue, long finalValue);
Invoked during extraction/creation to report progress.
currentValue— number of bytes processed so farfinalValue— total number of bytes to process (may be0if unknown)
TraversalCallback
public delegate int TraversalCallback(AvlNode node, object? context, int depth);
Invoked for each node during an AVL tree traversal.
node— the current tree node being visitedcontext— arbitrary context object passed to the traversaldepth— current depth within the tree (0 = root)- Returns:
0to continue traversal; any non-zero value stops the traversal
Exceptions
ExtractErrorException
Thrown when a non-fatal extraction error occurs.
public class ExtractErrorException : Exception
{
public ExtractError ErrorCode { get; }
public ExtractErrorException(ExtractError code)
}
| Member | Type | Description |
|---|---|---|
ErrorCode |
ExtractError |
The specific error code that caused this exception. |
ExtractFileException
Per-file extraction failure carrying the full error context: which entry failed,
where it lives in the image, where it was going on disk, and the underlying
cause as InnerException. Message reads
Failed to extract "<entry>" (sector N, M bytes) -> "<dest>": <reason>.
Collected across a ContinueOnError run and summarized as ErrExtractFailed.
public sealed class ExtractFileException : ExtractErrorException
{
public string InternalPath { get; }
public string DestPath { get; }
public uint StartSector { get; }
public long FileSize { get; }
public long BytesRead { get; }
}
XisoFormatException
Thrown when an XISO image has an invalid format — missing or corrupt header magic, truncated image, or sector pointers that exceed file bounds.
public class XisoFormatException : IOException
{
public XisoFormatException(string message)
}
XisoEmptyException
Thrown when an XISO image is structurally valid but contains no files.
public class XisoEmptyException : ExtractErrorException
{
public XisoEmptyException()
}
XisoFileTooLargeException
Thrown when a file exceeds the maximum size supported by the XISO format (4 GB, the 32-bit unsigned integer limit).
public class XisoFileTooLargeException : IOException
{
public string FileName { get; }
public long FileSize { get; }
}
Usage Examples
Extracting Files from an XISO
using XISOSharp;
var result = XisoReader.DecodeXiso(
xisoPath: "game.iso",
outputPath: "extracted_files",
mode: ExtractMode.Extract,
outIsoPath: out _,
llCompat: false);
if (result == 0)
Console.WriteLine("Extraction completed successfully.");
With a custom progress callback:
XisoReader.DecodeXiso(
"game.iso", "output", ExtractMode.Extract, out _,
llCompat: false,
cancellationToken: CancellationToken.None);
// Access stats after completion:
Console.WriteLine($"Processed {Logger.TotalFiles} files, {Logger.TotalBytes} bytes");
Listing Files in an XISO
using XISOSharp;
// Lists all files in the XISO to the configured Logger output
XisoReader.DecodeXiso("game.iso", null, ExtractMode.List, out _);
Output appears on Logger.Out (defaults to Console.Out) and includes filename, size, and starting sector for each entry.
Rewriting an XISO
Rewriting rebuilds the directory structure into an optimized AVL layout, reducing fragmentation and potentially improving read performance on original Xbox hardware.
XisoReader.DecodeXiso(
xisoPath: "game.iso",
outputPath: "rewritten",
mode: ExtractMode.Rewrite,
outIsoPath: out var rewrittenPath,
llCompat: false);
Console.WriteLine($"Rewritten ISO written to: {rewrittenPath}");
// Optionally delete the original after successful rewrite
if (File.Exists(rewrittenPath))
File.Delete("game.iso");
Creating an XISO from a Directory
using XISOSharp;
var result = XisoWriter.CreateXiso(
rootDirectory: "my_game_files",
outputDirectory: "output",
inRoot: null, // Null to generate AVL tree from filesystem
sourceStream: null, // Null when creating from filesystem
outIsoPath: out var isoPath,
inName: "my_game.iso",
progressCallback: null,
cancellationToken: CancellationToken.None);
if (result == 0)
Console.WriteLine($"ISO created at: {isoPath}");
Auditing, Repairing, and Salvaging an XISO
No reference tool repairs images — these APIs diagnose and recover corrupt ones:
using XISOSharp;
// Diagnose: header, tag, full tree walk, sector bounds, cycles, names
AuditResult audit = XisoReader.AuditXiso("game.iso");
if (!audit.IsValid)
foreach (var issue in audit.Issues)
Console.WriteLine($" - {issue}");
// Repair what is safely patchable in place (keeps game.iso.old unless disabled)
RepairResult repaired = XisoReader.Repair("game.iso");
Console.WriteLine($"fixed {repaired.Fixed.Count}, remaining {repaired.Remaining.Count}");
// Truncated / structurally damaged: rebuild reachable entries into a fresh image
SalvageResult salvaged = XisoReader.Salvage("game.iso"); // -> game.salvaged.iso
Console.WriteLine($"carried {salvaged.Copied.Count}, dropped {salvaged.Skipped.Count}");
Progress Reporting
The ProgressCallback delegate provides real-time progress during creation and extraction:
void OnProgress(long current, long total)
{
if (total > 0)
{
var pct = (double)current / total * 100;
Console.Write($"\rProgress: {pct:F1}% ({current:N0} / {total:N0} bytes)");
}
else
{
Console.Write($"\rBytes written: {current:N0}");
}
}
XisoWriter.CreateXiso(
"source", "output", null, null, out _,
inName: "game.iso",
progressCallback: OnProgress);
Cancellation Support
Both DecodeXiso and CreateXiso accept a CancellationToken:
var cts = new CancellationTokenSource();
// Cancel after 30 seconds
cts.CancelAfter(TimeSpan.FromSeconds(30));
try
{
XisoReader.DecodeXiso("large.iso", "output", ExtractMode.Extract, out _,
cancellationToken: cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Operation was cancelled.");
}
Async overloads are also available:
var cts = new CancellationTokenSource();
var (result, outPath) = await XisoReader.DecodeXisoAsync(
"game.iso", "output", ExtractMode.Extract,
cancellationToken: cts.Token);
Suppressing Output
Configure Logger.Quiet or Logger.RealQuiet before calling any API:
// Suppress informational output, keep errors
Logger.Quiet = true;
// Suppress ALL output including errors
Logger.RealQuiet = true;
XisoReader.DecodeXiso("game.iso", "output", ExtractMode.Extract, out _);
Reset them after processing if you need normal output for subsequent operations.
Disabling Media-Enable Patching
By default, .xbe files are automatically patched to bypass media-check on modified Xbox consoles. Disable this behavior:
Logger.MediaEnable = false;
XisoWriter.CreateXiso("source", "output", null, null, out _, "game.iso", null);
Skipping System Update Folders
Logger.RemoveSystemUpdate = true;
XisoReader.DecodeXiso("game.iso", "output", ExtractMode.Extract, out _);
When enabled, any files within a $SystemUpdate folder are excluded from extraction and creation.
Redirecting Log Output
Send log output to a file or custom TextWriter:
using var logWriter = new StreamWriter("xiso.log");
Logger.Out = logWriter;
Logger.Error = logWriter;
XisoReader.DecodeXiso("game.iso", "output", ExtractMode.Extract, out _);
logWriter.Flush();
Graphical Progress (WPF / Blazor)
The ProgressCallback delegate integrates naturally into GUI frameworks:
// WPF example
var progress = new Progress<(long current, long total)>(p =>
{
Dispatcher.Invoke(() =>
{
if (p.total > 0)
progressBar.Value = (double)p.current / p.total * 100;
statusLabel.Text = $"{p.current:N0} / {p.total:N0} bytes";
});
});
await Task.Run(() =>
{
XisoReader.DecodeXiso("game.iso", "output", ExtractMode.Extract, out _,
cancellationToken: tokenSource.Token);
});
Error Handling
The library uses a combination of return codes and exceptions:
| Mechanism | Usage |
|---|---|
Return code (int) |
0 = success, non-zero = failure. Returned by DecodeXiso and CreateXiso. |
ExtractErrorException |
Thrown for non-fatal extraction errors. Check ErrorCode for the specific error. |
ExtractFileException |
Per-file extraction failure (entry, sector, expected/actual bytes, OS cause as inner). |
XisoFormatException |
Thrown when an XISO image has an invalid format (corrupt header, truncated, bad sector pointers). |
XisoEmptyException |
Thrown when an XISO image contains no files. |
XisoFileTooLargeException |
Thrown when a file exceeds the 4 GB XISO format limit. |
InvalidDataException |
Thrown when a requested path does not exist within the XISO. |
IOException |
Thrown for file read/write errors. |
FileNotFoundException |
Thrown when the input file does not exist. |
OperationCanceledException |
Thrown when a CancellationToken is triggered. |
Example:
try
{
var result = XisoReader.DecodeXiso("game.iso", "output", ExtractMode.Extract, out _);
if (result != 0)
Console.Error.WriteLine("Operation failed.");
}
catch (ExtractErrorException ex)
{
Console.Error.WriteLine($"Extract error: {ex.ErrorCode} - {ex.Message}");
}
catch (InvalidDataException ex)
{
Console.Error.WriteLine($"Invalid XISO: {ex.Message}");
}
Thread Safety
The core processing engine is not thread-safe for concurrent operations on the same file. However:
- Each call to
DecodeXisoorCreateXisois self-contained and safe to call from different threads when processing different files. Loggeris safe for concurrent access across multiple operations.- Async overloads (
DecodeXisoAsync,CreateXisoAsync) run the synchronous engine on a thread pool thread viaTask.Run, which is safe for UI thread responsiveness.
Compatibility
| Target | Version |
|---|---|
| .NET 8 | net8.0 |
| .NET 9 | net9.0 |
| .NET 10 | net10.0 |
The library targets net8.0, net9.0, and net10.0. Its only runtime dependency beyond the .NET runtime is ZArchiveSharp (for ZAR archive support); everything else is BCL-only.
Performance
- 2 MB read/write buffer for file copy operations, configurable via
Constants.ReadWriteBufferSize. - Boyer-Moore search for efficient
.xbemedia-enable pattern matching. - AVL balanced tree for O(log n) directory lookups during create/rewrite.
- Synchronous I/O for maximum throughput; async overloads are provided for UI responsiveness, not I/O concurrency.
- The library produces byte-identical output to the original C
extract-xisotool (reference build202609111233).
License
MIT License — see the LICENSE file included in the package for full terms.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- ZArchiveSharp (>= 1.3.0)
-
net8.0
- ZArchiveSharp (>= 1.3.0)
-
net9.0
- ZArchiveSharp (>= 1.3.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.