Skip to content

Latest commit

 

History

History
85 lines (63 loc) · 10.6 KB

File metadata and controls

85 lines (63 loc) · 10.6 KB
title Embedded Libraries
nav_order 11

10. Embedded Libraries

The solution ships five in-house libraries that replace external tools (maxcso, psxpackager), add CloneCD support, and cover Alcohol 120% and UltraISO images. All five multi-target net10.0;net8.0, are packable, and expose internals to BatchConvertToCHD.Tests via InternalsVisibleTo. A sixth in-house library, CHDSharp, is consumed as a NuGet package and is covered in §10.4.

Library Purpose Replaces
CCDSharp CloneCD .ccd/.img/.sub parsing + CUE/BIN conversion — (new capability)
CSOSharp CSO/CISO decompression (deflate/zlib + LZ4) maxcso.exe
PBPSharp PlayStation PBP extraction + SFO/TOC parsing psxpackager.exe
Alcohol120Sharp Alcohol 120% .mds/.mdf parsing, subchannel stripping, split-volume joining, cue writing — (new capability)
UltraIsoSharp UltraISO ISZ decompression back to the plain image — (new capability)

10.1 CCDSharp

Purpose: read CloneCD disc-image sets (.ccd descriptor + .img data + optional .sub subchannel) and convert them to CUE/BIN for chdman.

  • Main type: CcdConverterParse(inputFile) returns a parsed disc model (DiscImage with ImgFilePath, subchannel info, track table); ConvertToCueBin(inputFile, tempCuePath) writes the CUE/BIN pair.
  • Integration: ProcessCcdFileForConversionAsync (MainWindow.xaml.cs:1702) parses the .ccd, converts to CUE/BIN in a temp dir, then converts the cue with chdman. On success the .ccd/.img/.sub/.cdt set is deleted when "delete originals" is enabled.
  • Archive extractions skip .img files that belong to a .ccd set to avoid double conversion (MainWindow.xaml.cs:1562–1573).
  • Failure messages are prefixed "CCDSharp: Conversion error" and are excluded from bug reports.
  • Reference sources live under References/ (ccd2cue-master, ccd2iso-main, myccd2cue-main) — third-party material used to build the library, not part of the build.
  • Testing note: the test project does not reference CCDSharp, so there are currently no CCDSharp unit tests (see Testing).

10.2 CSOSharp

Purpose: read and decompress CISO (Compressed ISO, .cso) images.

  • Main type: CsoFileOpen(path/stream, out CsoFile) returns a CsoError; exposes UncompressedSize, block metadata, ReadBlock, ExtractToIso(path, progress?, token), and a seekable CsoStream implementing the stream contract.
  • Supports v1 and v2 headers, deflate/zlib and LZ4 compression (K4os.Compression.LZ4 dependency).
  • Integration: ArchiveService.ExtractCsoAsync (Services/ArchiveService.cs:52) decompresses to a temp ISO for the conversion pipeline.
  • Error enum: CsoError { None, FileNotFound, InvalidHeader, UnsupportedVersion, InvalidBlockSize, ... }.
  • Tests: CsoFileTests, CsoStreamTests, CsoHeaderTests, plus byte-for-byte integration tests against real .cso/.iso pairs (CsoFileIntegrationTests).

10.3 PBPSharp

Purpose: parse PlayStation PBP (PSP/PSX eboot) containers and extract PlayStation disc images to CUE/BIN.

  • Main type: PbpFileOpen(path, out PbpFile) / Open(stream, ownsStream, out PbpFile); properties Header, SfoData, Discs (IReadOnlyList<PbpDiscInfo>), IsMultiDisc, Title, DiscId, Category.
  • Header: magic 0x50425000, 40-byte header with offsets for SFO/ICON0/ICON1/PIC0/PIC1/SND0/DATA.PSP/DATA.PSAR.
  • Disc detection: PSAR header PSISOIMG0000 → single disc; PSTITLEIMG000000 → multi-disc (reads 5 position slots at +0x200); anything else → PbpError.InvalidPsarHeader (the app treats this as "not a PlayStation disc image — PSP application, unsupported variant, or corrupt file" and skips informatively). The four "template" DWORDs of the PSTITLEIMG header (fixed values in popstation/PSX2PSP/iPoPS output) are not validated: pop-fe writes zeros there and its multi-disc PBPs parse from the position table alone.
  • PbpDiscInfoReadBlock, ExtractTo(stream, progress?, token), ExtractToBinCue(binPath, cuePath?, progress?, token); TOC parsed from the PSAR TOC (A0/A1/A2 markers, BCD track numbers, best effort — a bad TOC never aborts extraction). A disc container whose header parsed but that carries no ISO index entries throws NoIsoIndexException (public, derives from Exception) so callers can report the likely cause: a truncated or incomplete download.
  • Index entries (32 bytes at PSAR+0x4000, data at PSAR+0x100000) are read in both authoring layouts: the popstation/PSX2PSP/iPoPS layout writes the block size as a 32-bit int at bytes 4–7, the pop-fe layout writes a 16-bit size at bytes 4–5, a stored-flag byte at 6 (bit 0 = uncompressed block) and a SHA-1 at 8–23. Block offsets use 64-bit math so multi-gigabyte files cannot overflow. Corrupt entries are rejected with InvalidDataException (oversized lengths, stored blocks larger than a full 16-sector block).
  • Block decompression uses SharpZipLib's raw Inflater (the same decompressor the popstation reference implementation uses for PSAR blocks, windowBits −15); a block that fails raw inflation is retried as a zlib-wrapped stream (2-byte header + Adler-32, as written by tools using zlib.compress). Blocks flagged stored, or exactly one full block (16 × 0x930) in size, are copied verbatim. A failed block surfaces as PbpError.DecompressionError.
  • CueSheetWriter.GenerateCueSheet(binFileName, tocEntries) — emits FILE ... BINARY, TRACK nn MODE2/2352 (data) / AUDIO (audio), with INDEX 00 for audio tracks computed as track start minus 150-frame lead-in (clamped ≥ 0).
  • SFO model: SfoData (magic 0x46535000; GetString/GetUInt32; static Keys with BOOTABLE, CATEGORY, DISC_ID, DISC_VERSION, LICENSE, PARENTAL_LEVEL, PSP_SYSTEM_VER, REGION, TITLE), SfoEntry (formats 0x0204 string / 0x0404 uint32), TocEntry, TrackType { Data = 0x41, Audio = 0x01 }.
  • SFO parsing is best effort: a missing or corrupt PARAM.SFO (bad magic, malformed table, offsets beyond EOF) leaves Title/DiscId null with empty Entries instead of failing Open — none of the reference tools read the SFO when extracting disc images.
  • PbpError enum: None=0, InvalidHeader=1, FileNotFound=2, IoError=3, CorruptFile=4, InvalidPsarHeader=5, DiscOutOfRange=6, ResourceNotFound=7, DecompressionError=8, TruncatedPsar=9, InvalidSfo=10. TruncatedPsar is returned when the PSAR container parses but no ISO index follows (see NoIsoIndexException). InvalidSfo is retained for API compatibility but is no longer returned by Open (SFO problems are tolerated). The app maps these to targeted guidance ("most likely truncated or incomplete — re-download") instead of a generic corrupt-file message.
  • Block decompression uses SharpZipLib's raw Inflater (the same decompressor the popstation reference implementation uses for PSAR blocks), which tolerates a few streams the stricter .NET DeflateStream rejects; a failed block surfaces as PbpError.DecompressionError.
  • Integration: ExtractPbpToCueBinAsync (MainWindow.xaml.cs:2959) — multi-disc PBPs produce "{name} - Disc N.bin/.cue" sets; the result (PbpExtractionResult) carries ErrorCode + a human-readable Error so the caller can distinguish skippable conditions from real failures.
  • Tests: PbpFileTests, PbpHeaderTests, SfoDataTests, SfoEntryTests, TocEntryTests, CueSheetWriterTests, plus real-file integration tests (PbpFileIntegrationTests).

10.4 CHDSharp (NuGet)

Purpose: pure C# CHD (Compressed Hunks of Data) reading, verification, extraction, and creation — the engine behind the app's extraction and verification tabs.

  • Consumed as a NuGet package (CHDSharp v1.4.3), not a project reference; the app also bundles the project's CLI (CHDSharp.exe) and MAME's chdman.exe side by side, preferring the native-architecture binary on ARM64.
  • Capabilities: CHD V1–V5, all 10 compression codecs (zlib, lzma, huffman, flac, zstd, avhu + CD variants), parent/child chaining, parallel verification, and full CHD creation (createcd/createdvd/createhd/copy) with output that is byte-identical to chdman.
  • The byte-parity claim was validated by the (since-removed) CHDBattleTest battleground project — see Testing §11.6 — which reported zero mismatches against chdman 0.289 across decode, encode, and cross-verification battles on a 56-disc corpus.
  • In the conversion pipeline CHDSharp is the automatic fallback: the bundled chdman is the primary encoder, and a file that chdman cannot convert is retried with CHDSharp.exe — see Conversion Pipeline §5.3.
  • When the library cannot decode a CHD (corrupt file, A/V laserdisc), the app falls back to chdman for extraction — see Extraction & Verification.

10.5 Alcohol120Sharp

Purpose: turn an Alcohol 120% image (.mds descriptor + .mdf data, including split .i00/.i01 volumes) into something the encoder can read.

  • Main types: MdsParser (IsMdsFile, Parse), MdsDisc/MdsTrack (parsed model with sector-size classification), MdsInputPreparer (PrepareAsync → cue / DVD image / failure; StripSubchannelAsync, WriteCueAsync, FormatMsf), and SplitImageJoiner (TryGetVolumeSet, JoinAsync, GetTotalBytes for .001/.i00 volume sets).
  • The three preparation shapes (plain 2352, subchannel strip, ISO-as-DVD) and the recovered .mds layout are documented in Utilities Reference §8.12.
  • Integration: ProcessMdsFileForConversionAsync prepares the work set, then the conversion funnel takes the cue (or DVD image).
  • Tests: MdsTests.cs, SplitImageJoinerTests.cs.

10.6 UltraIsoSharp

Purpose: decompress UltraISO .isz images back to the plain images they were made from, per EZB Systems' ISZ File Format Specification 1.00.

  • Main types: IszHeader (packed 48-byte header with TryRead validation), IszDecoder (TryReadHeaderAsync, DecodeAsync), IszSegment/IszChunkType/IszDecodeResult.
  • Supports whole and multi-segment images, zlib / bzip2 / stored / zero-elided chunks; encryption is refused by name, truncation and damaged tables are reported rather than guessed at.
  • Integration: ResolveIszAsync decodes the ISZ to a temp image, which is then classified and converted like any other image.
  • Tests: IszHeaderTests.cs, IszDecoderTests.cs.