102 Commits

Author SHA1 Message Date
Matt Nadareski
de17b0c59c Bump version 2026-11-11 17:41:51 +01:00
gmipf
1663345195 Add a UDF reader and wrapper (#100)
* Add a UDF reader

Reads the Volume Recognition Sequence, the Anchor Volume Descriptor
Pointer (sector 256, then the end of the volume), the Main or Reserve
Volume Descriptor Sequence, the File Set Descriptor and the directory
hierarchy. Type 1 and Metadata Partitions are mapped, Virtual and
Sparable partitions are not.

File Entries, Allocation Extent Descriptors and directories are read in
ascending sector order with wrap-around, adjacent sectors merged into
one request. FindFileEntry follows one path and reads only the
directories on it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Add a UDF wrapper

Prints the volume and file set structures and the directory hierarchy,
and extracts the files. CreateDiscImageWrapper tries UDF after ISO 9660
for a stream at offset 0, so discs with both file systems still open as
ISO 9660.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Treat the stream position as the start of the UDF volume

The UDF reader addresses logical sectors from the start of the stream,
so the wrapper hands it a view that starts at the current position and
keeps that offset, like the other wrappers. CreateDiscImageWrapper no
longer skips UDF for a stream that is not at offset 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Address review comments on the UDF code

- Move the descriptor tag check to UDFExtensions, with tests
- Parse Volume Structure Descriptors in their own method
- Use the existing extensions for numbers, the partition type identifier
  and printing entity identifiers
- Use Array.Exists in IsSafeName
- Make Extract non-virtual and remove the printing test
- Use collection expressions and string interpolation

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Parse File Identifier Descriptors in their own method

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Add a TODO to use the CRC from Hashing

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 17:18:23 +01:00
Matt Nadareski
5c3184baa7 Add .NET 11 support 2026-11-11 12:02:16 +01:00
gmipf
9e39a0cf16 Close the cabinet files opened for a cabinet set (#105)
* Close the cabinet files opened for a cabinet set

MicrosoftCabinet.Extract opened the cabinet file again for the set,
together with the previous and next cabinets, and never closed any of
them, so they stayed open until their streams were finalized.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keep the original comment on the previous cabinet

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 14:19:16 -04:00
gmipf
11f9bf9fd9 Stop writing after the last file of a cabinet folder (#107)
* Stop writing after the last file of a cabinet folder

When the last data block of a folder held the end of two or more files,
WriteData still wrote the rest of the block after EndFile had closed the
last file, which threw an ObjectDisposedException. It now returns there,
as it already does when the first file in a block ends the folder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Simplify the console check in the cabinet extraction test

Extract catches the ObjectDisposedException and only writes it to
Console.Error, so the test still reads the console, but without the
try/finally. It now fails with the whole exception as its message.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 09:46:10 -04:00
gmipf
373cf2d752 Replace invalid filename characters in Wise dialog names (#106)
The file of a custom dialog is named after the dialog name from the
script, which is free text. On Windows, a name like "Install under NT?"
is not a valid filename, so writing the file threw an IOException and
stopped the extraction.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 21:32:34 -04:00
gmipf
dc18951d0b Close the Wise script and the multipart file after extraction (#104)
* Look for the Wise overlay header before opening the file again

ExtractWiseOverlay (and ExtractWise for NE) opened a second stream on
the executable for multi-part Wise installers before checking for a
Wise overlay header at all. For any other executable that stream was
never closed, so the file stayed open until the stream was finalized.
On Windows such a file cannot be deleted, so an extraction folder that
contains it is left behind in TEMP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Close the Wise script and the multipart file after extraction

ExtractWiseOverlay (and ExtractWise for NE) never closed WiseScript.bin,
which it opens from the output directory, nor the stream with the
installer and its parts, so these files stayed open until their streams
were finalized.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keep the original block that opens the multipart file

Close the multipart stream with a separate using declaration after the
block instead of rewriting it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 21:30:32 -04:00
gmipf
29b9d27c33 Look for the Wise overlay header before opening the file again (#103)
ExtractWiseOverlay (and ExtractWise for NE) opened a second stream on
the executable for multi-part Wise installers before checking for a
Wise overlay header at all. For any other executable that stream was
never closed, so the file stayed open until the stream was finalized.
On Windows such a file cannot be deleted, so an extraction folder that
contains it is left behind in TEMP.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 09:50:21 -04:00
gmipf
f6ade446c6 Locate the PKZIP file data instead of reading it into the model (#102)
* Locate the PKZIP file data instead of reading it into the model

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keep only the offset of the PKZIP file data

The length is the compressed size from the local file header or the ZIP64
extended field, which the printer already shows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keep the file data property as a comment for documentation

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 21:04:01 -04:00
Matt Nadareski
3798dbcb47 Bump version 2026-08-31 19:15:36 -04:00
Matt Nadareski
2a70a9a20e Update IO to 2.3.0 2026-08-28 13:11:31 -04:00
Matt Nadareski
6f92f85f5d Convert BFPK writing to use GrindCore zlib 2026-08-27 14:01:50 -04:00
Matt Nadareski
b7851601a4 Convert GCZ writing to use GrindCore zlib 2026-08-27 13:59:38 -04:00
Matt Nadareski
cb2a96c413 Convert GCZ to use GrindCore zlib 2026-08-27 13:57:49 -04:00
Matt Nadareski
69c0843a0d Convert GZip to use GrindCore zlib 2026-08-27 13:56:09 -04:00
Matt Nadareski
0171ea9da7 Convert IS-CAB to use GrindCore zlib 2026-08-27 13:53:23 -04:00
Matt Nadareski
e493af25e0 Convert CExe to use GrindCore zlib 2026-08-27 12:37:26 -04:00
Matt Nadareski
62427576e9 Convert SGA to use GrindCore zlib 2026-08-27 12:30:01 -04:00
Matt Nadareski
e80ea00872 Update packages 2026-08-27 09:36:42 -04:00
Matt Nadareski
1d76967a08 Ignore bad IS-CAB group names 2026-07-19 21:09:59 -04:00
Matt Nadareski
b9ffd61252 Bump version 2026-07-10 13:29:35 -04:00
Matt Nadareski
b4e1f6b729 Update packages, relax requirements 2026-07-10 11:23:17 -04:00
Matt Nadareski
451fc0b394 Bump version 2026-07-06 09:57:11 -04:00
HeroponRikiBestest
79ca9f617e Add sim parsing for Steam2 sim/sid installers (#95)
* Add model for sim file

* Add sim parsing for steam2 installer set

* First round of fixes
2026-07-06 09:21:17 -04:00
Matt Nadareski
a602686551 Trim path separators from start of filenames on extract 2026-07-05 23:28:24 -04:00
Matt Nadareski
4083aed12f Some filenames in MS-CAB start with one or more separators 2026-07-01 10:18:20 -04:00
Matt Nadareski
88aae0dd26 Bump version 2026-06-12 08:56:35 -04:00
Matt Nadareski
499fc44004 Ensure a 2-byte read is possible 2026-06-07 21:56:17 -04:00
Matt Nadareski
481020bd08 Move useful helper to a better place 2026-05-22 09:24:03 -04:00
Matt Nadareski
5642f601a3 Minor cleanup 2026-05-21 10:38:38 -04:00
Deterous
b42a12f051 Recursive InfoPrint for ISO9660 and XDVDFS (#94)
* Recursive InfoPrint for XDVDFS / XboxISO

* Cleanup, full file paths

* Add safety

* Recursive ISO9660 printing

* Naive decode filename

* comment
2026-05-21 10:32:20 -04:00
Matt Nadareski
a5879b46f1 Slightly more cleanup around IS-CAB and printing 2026-05-18 19:52:44 -04:00
Matt Nadareski
9a14cc2620 Fix major issues in IS-CAB 2026-05-18 19:23:35 -04:00
Matt Nadareski
a777df13db Take directory into account for IS-CAB 2026-05-18 13:35:59 -04:00
Matt Nadareski
78d7bc310f Add placebo recursive flag for now 2026-05-18 10:24:30 -04:00
Matt Nadareski
a2d15f301b Move it around 2026-05-14 20:52:12 -04:00
Matt Nadareski
d3c9849908 Attempt to fix detection issues 2026-05-14 20:08:32 -04:00
Matt Nadareski
249c51933b Update packages 2026-05-14 09:25:26 -04:00
Matt Nadareski
cf586f7af2 Add Nintendo Disc extensions tests 2026-05-12 22:47:19 -04:00
Matt Nadareski
b805c91cb3 Add notes and reconfigure based on IO porting 2026-05-12 21:55:11 -04:00
Matt Nadareski
2a0e8e2eb0 First round of cleanup for DolphinLib additions 2026-05-12 20:33:53 -04:00
Dimensional
49aa6895b6 Dolphin lib (#85)
* Add GCZ, WIA/RVZ, and NintendoDisc (GameCube/Wii) format support

Port of DolphinIsoLib into SabreTools.Serialization architecture:
- Data.Models: GCZ/, WIA/, NintendoDisc/ model subdirectories (15 files)
- Serialization.Readers: GCZ, WIA, NintendoDisc readers
- Serialization.Writers: GCZ, WIA writers (structural metadata; full round-trip TODO)
- Wrappers: NintendoDisc, GCZ, WIA wrappers with Encryption partial class
- Wrappers: WiaRvzCompressionHelper (BZip2/LZMA/LZMA2/Zstd, net462+ guarded)
- WrapperType + WrapperFactory: GCZ, WIA, NintendoDisc entries added

GetInnerWrapper() decompression and NintendoDisc.Extraction FST extraction
are stubbed with TODO comments pending full implementation.

* Implement GetInnerWrapper for GCZ and WIA, full NintendoDisc extraction

* Add GCZ/WIA/RVZ write pipeline and Nintendo disc compression helpers

* Add WIA/RVZ table decompression, NintendoDisc/GCZ printing, NintendoDisc detection for .iso files

* Fix NintendoDisc header layout, GC magic, and add embedded disc header to WIA/GCZ printing

- Fix GCMagicWord: 0xC23D3C1F -> 0xC2339F3D (confirmed from Dolphin DiscUtils.h)
- Fix disc header field layout to match Dolphin's confirmed offsets:
  MakerCode is bytes 4-5 of the 6-char GameId (no separate field at 0x006),
  DiscNumber at 0x006, DiscVersion at 0x007, unused region is 14 bytes (0x00A-0x017)
- Update NintendoDisc reader: derive MakerCode from GameId[4..5], fix skip count
- Add ParseDiscHeaderOnly() to reader for partial (short) stream parsing
- Guard DisableHash/DisableEnc reads at the 0x080 boundary for 128-byte embedded headers
- Guard DOL/FST skip for streams shorter than full 0x440 boot block
- Fix WrapperFactory: NintendoDisc magic detection now precedes .iso -> ISO9660 fallback
- Add GameId-prefix heuristic in WrapperFactory for GC discs lacking magic word
- Add GameId-prefix platform fallback in reader for GC discs without GCMagicWord
- Add DiscHeader property to WIA wrapper (parsed from Header2.DiscHeader bytes)
- Add DiscHeader property to GCZ wrapper (decompresses first block only)
- Add ReadDiscHeader() helper to GCZ for lightweight first-block decompression
- Print embedded disc header (Game ID, Maker, Disc/Rev, Title) in WIA.Printing.cs and GCZ.Printing.cs

* Fix Wii partition extraction: correct IV, FST size shift, partition naming

- Block decryption: IV is at raw block offset 0x3D0 (still-encrypted),
  matching Dolphin/DolphinIsoLib WiiPartitionDecryptor.DecryptBlock exactly.
- FST size field at boot.bin 0x428 is also stored >>2 on Wii; apply <<2
  to get true byte size.
- Partition folder naming now matches DolphinIsoLib WiiDiscExtractor exactly:
  type 0->GM+n, 1->UP+n, 2->CH+n, printable ASCII unknown->raw 4-char string,
  non-printable->P{index}. SSBB VC channels extract as HA8E, HA9E, etc.
- ExtractionTool peek buffer increased from 16 to 32 bytes.

Verified: SSBB GM0 extracts 5524 files, boot.bin/fst.bin byte-identical
to Dolphin reference extraction.

* Fix FST extraction: create zero-byte files instead of skipping them

Files with fileSize=0 in the FST were silently skipped. Now they are
created as empty files, matching Dolphin/DolphinIsoLib behavior.

Verified: SSBB now extracts 5958 files with 0 missing, 0 extra,
0 size mismatches, and 0 hash mismatches vs DolphinIsoLib reference.

* Add GCZ/WIA/RVZ virtual stream extraction via NintendoDisc wrapper

* Address PR #85 review comments (Copilot + mnadareski)

* Address PR #85 review comments

* Replace custom endian helpers and SHA1 with SabreTools.IO equivalents

* Update GCZ.Printing.cs

* Update NintendoDisc.Printing.cs

* Update WIA.Printing.cs

* Add WIA/RVZ Wii partition crypto round-trip support

- Add AesCbc internal helper (BouncyCastle AES-CBC encrypt/decrypt)
- Add NintendoDisc.CommonKeyProvider hook for injectable test keys
- Fix sha1.Terminate() missing in all three ComputeSha1 helpers in WIA.cs
- Fix Wii partition dataOff alignment to 0x8000 boundary
- Add WIA.EncryptWiiGroup (internal) for re-encrypting plaintext groups
- Add WIA.DumpIso to WIA.Writing.cs (WIA/RVZ -> flat ISO conversion)
- Add WiaVirtualStream on-demand group decompression
- Add _preDecryptedReader bypass on NintendoDisc for WIA extraction path
- Add WIATests.cs with Wii crypto round-trip test using synthetic data
- Move DumpIso from WIA.Extraction.cs to WIA.Writing.cs
- Bump DumpIso read buffer from 1 MiB to 2 MiB (aligns to WIA chunk size)
- Add InternalsVisibleTo SabreTools.Wrappers.Test in csproj

* Remove hardcoded Wii common keys from NintendoDisc.Encryption

- Delete the embedded WiiCommonKeyRetail and WiiCommonKeyKorean byte
  arrays from NintendoDisc.Encryption.cs.
- Make CommonKeyProvider public so any caller (not just tests) can
  inject keys; DecryptTitleKey now returns null when no key is
  available for the requested index rather than falling back to
  hardcoded values.
- Add NintendoDiscEncryptionTests.cs:
    - Argument guard and no-provider tests for DecryptTitleKey.
    - Fake-key round-trip test (encrypt then decrypt with injected key).
    - Integration test that reads TestData/NintendoDisc/keys.json,
      verifies each key against hardcoded SHA256 constants, and skips
      silently if the file is absent or the keys do not match.
    - LoadKeyProvider helper (named JSON format, index-keyed).
- Add [Collection(NintendoDisc)] to both NintendoDiscEncryptionTests
  and WIATests to prevent parallel access to the static
  CommonKeyProvider from racing between test classes.
- Add TestData/NintendoDisc/keys.json.example documenting the
  expected key file format.
- Add Newtonsoft.Json reference to SabreTools.Wrappers.Test.csproj.

* Didn't actually commit the changes. My bad. Fixed.

* Edited a comment

* Added in XUnit outputs that show up in Test Viewer in VS

---------

Co-authored-by: Matt Nadareski <mnadareski@outlook.com>
2026-05-12 10:41:32 -04:00
Matt Nadareski
9ed671f595 Editorconfig cleanup 2026-04-28 09:26:49 -04:00
Deterous
a2b9db3afd PC Engine CD-ROM Header Support (#91) 2026-04-28 09:24:36 -04:00
Matt Nadareski
49ea4302b6 Add mostly-working version of JSON printing to older .NET 2026-04-27 18:56:10 -04:00
Matt Nadareski
59f76b1036 Editorconfig cleanup 2026-04-27 13:28:23 -04:00
Deterous
6fa3631c80 Add Opera FileSystem support (#90)
* Add Opera FileSystem support

* Fix tests
2026-04-27 13:24:30 -04:00
Matt Nadareski
b24f96ac0f Fix documentation 2026-04-25 21:51:42 -04:00
Matt Nadareski
201af08f5f Document alternative TGZ layout 2026-04-25 21:45:53 -04:00
Deterous
c179cf410b XboxISO separate functions for partition extraction (#89)
* XboxISO funcs for partition extraction

* Add new parameter with default
2026-04-19 23:59:39 -04:00