-
Notifications
You must be signed in to change notification settings - Fork 4
Dolphin lib #85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Dimensional
wants to merge
10
commits into
SabreTools:main
Choose a base branch
from
Dimensional:DolphinLib
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Dolphin lib #85
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
d944d50
Add GCZ, WIA/RVZ, and NintendoDisc (GameCube/Wii) format support
Dimensional 2915d24
Implement GetInnerWrapper for GCZ and WIA, full NintendoDisc extraction
Dimensional d598a7e
Add GCZ/WIA/RVZ write pipeline and Nintendo disc compression helpers
Dimensional c96fa2b
Add WIA/RVZ table decompression, NintendoDisc/GCZ printing, NintendoD…
Dimensional 242c0f7
Fix NintendoDisc header layout, GC magic, and add embedded disc heade…
Dimensional 53b9366
Fix Wii partition extraction: correct IV, FST size shift, partition n…
Dimensional c620499
Fix FST extraction: create zero-byte files instead of skipping them
Dimensional a6d1093
Add GCZ/WIA/RVZ virtual stream extraction via NintendoDisc wrapper
Dimensional d85e97c
Address PR #85 review comments (Copilot + mnadareski)
Dimensional 51d8a87
Address PR #85 review comments
Dimensional File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| namespace SabreTools.Data.Models.GCZ | ||
| { | ||
| /// <summary> | ||
| /// Represents a parsed GCZ (GameCube Zip) compressed disc image. | ||
| /// Contains header metadata and block lookup tables. | ||
| /// Actual compressed block data is accessed via the source stream. | ||
| /// </summary> | ||
| public class DiscImage | ||
| { | ||
| /// <summary> | ||
| /// GCZ file header | ||
| /// </summary> | ||
| public GczHeader Header { get; set; } = new(); | ||
|
|
||
| /// <summary> | ||
| /// Block pointer table (one entry per block). | ||
| /// Each value encodes both the offset of the block within the compressed data section | ||
| /// and a compression flag in the top bit: | ||
| /// <list type="bullet"> | ||
| /// <item>Top bit CLEAR → block is zlib/deflate-compressed at that offset.</item> | ||
| /// <item>Top bit SET → block is stored uncompressed at that offset.</item> | ||
| /// </list> | ||
| /// Offset is <c>value & ~UncompressedFlag</c>. | ||
| /// </summary> | ||
| public ulong[] BlockPointers { get; set; } = []; | ||
|
|
||
| /// <summary> | ||
| /// Adler-32 (stored as CRC32) hashes of the uncompressed block data, | ||
|
Dimensional marked this conversation as resolved.
|
||
| /// one per block. Used for integrity verification. | ||
| /// </summary> | ||
| public uint[] BlockHashes { get; set; } = []; | ||
|
|
||
| /// <summary> | ||
| /// Byte offset within the GCZ file where the compressed block data begins. | ||
| /// Computed as: <c>HeaderSize + (NumBlocks * 8) + (NumBlocks * 4)</c>. | ||
| /// </summary> | ||
| /// <remarks>Not parsed from stream; computed during deserialization.</remarks> | ||
| public long DataOffset { get; set; } | ||
|
Dimensional marked this conversation as resolved.
|
||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| namespace SabreTools.Data.Models.GCZ | ||
| { | ||
| public static class Constants | ||
| { | ||
| /// <summary>GCZ magic cookie (little-endian u32 at offset 0)</summary> | ||
| public const uint MagicCookie = 0xB10BC001; | ||
|
Dimensional marked this conversation as resolved.
|
||
|
|
||
| /// <summary>Size of the GCZ file header in bytes</summary> | ||
| public const int HeaderSize = 32; | ||
|
|
||
| // Valid GCZ block sizes (Dolphin-compatible) | ||
| public const uint BlockSize32K = 0x8000; | ||
| public const uint BlockSize64K = 0x10000; | ||
| public const uint BlockSize128K = 0x20000; | ||
| public const uint DefaultBlockSize = BlockSize32K; | ||
|
|
||
| /// <summary> | ||
| /// Top bit of a block-pointer value: when CLEAR the block is zlib/deflate compressed; | ||
| /// when SET the block is stored uncompressed. | ||
| /// </summary> | ||
| public const ulong UncompressedFlag = 0x8000000000000000; | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| namespace SabreTools.Data.Models.GCZ | ||
| { | ||
| /// <summary> | ||
| /// GCZ (GameCube Zip) file header — 32 bytes at the start of the file | ||
| /// </summary> | ||
| /// <see href="https://github.com/dolphin-emu/dolphin/blob/master/Source/Core/DiscIO/CompressedBlob.h"/> | ||
| public sealed class GczHeader | ||
| { | ||
| /// <summary> | ||
| /// Magic cookie identifying a GCZ file (0xB10BC001) | ||
| /// </summary> | ||
| public uint MagicCookie { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Sub-type; always 0 for GameCube / Wii disc images | ||
| /// </summary> | ||
| public uint SubType { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Total size of the compressed block data section in bytes | ||
| /// </summary> | ||
| public ulong CompressedDataSize { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Total decompressed (ISO) size in bytes | ||
| /// </summary> | ||
| public ulong DataSize { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Size of each uncompressed block in bytes (must be 32 KiB, 64 KiB, or 128 KiB) | ||
| /// </summary> | ||
| public uint BlockSize { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Number of blocks in the image | ||
| /// </summary> | ||
| public uint NumBlocks { get; set; } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| namespace SabreTools.Data.Models.NintendoDisc | ||
| { | ||
| public static class Constants | ||
| { | ||
| #region Disc identification magic values | ||
|
|
||
| /// <summary>Magic word present at offset 0x01C on GameCube discs</summary> | ||
| public const uint GCMagicWord = 0xC2339F3D; | ||
|
|
||
| /// <summary>Magic word present at offset 0x018 on Wii discs</summary> | ||
| public const uint WiiMagicWord = 0x5D1C9EA3; | ||
|
|
||
| #endregion | ||
|
|
||
| #region Disc header layout | ||
|
|
||
| // Offsets within the 0x440-byte boot block. | ||
| // Layout confirmed against Dolphin source (VolumeDisc.cpp / DiscUtils.h): | ||
| // 0x000–0x003 Title code (4 chars, e.g. "GAFE") | ||
| // 0x004–0x005 Maker code (2 chars, e.g. "01") — Dolphin Read(0x4, 2) | ||
| // 0x006 Disc number — Dolphin GetDiscNumber() Read(6) | ||
| // 0x007 Revision — Dolphin GetRevision() Read(7) | ||
| // 0x008 Audio streaming | ||
| // 0x009 Streaming buffer size | ||
| // 0x00A–0x017 Unused (14 bytes) | ||
| // 0x018 Wii magic (0x5D1C9EA3) | ||
| // 0x01C GC magic (0xC2339F3D) | ||
| // 0x020–0x07F Game title (0x60 bytes) | ||
| // 0x080 Disable hash verification | ||
| // 0x081 Disable disc encryption | ||
| public const int TitleCodeOffset = 0x000; | ||
| public const int TitleCodeLength = 4; | ||
| public const int MakerCodeOffset = 0x004; | ||
| public const int MakerCodeLength = 2; | ||
| /// <summary>Full 6-char game ID = TitleCode[4] + MakerCode[2]</summary> | ||
| public const int GameIdOffset = 0x000; | ||
| public const int GameIdLength = 6; | ||
| public const int DiscNumberOffset = 0x006; | ||
| public const int DiscVersionOffset = 0x007; | ||
| public const int AudioStreamingOffset = 0x008; | ||
| public const int StreamingBufferSizeOffset = 0x009; | ||
| public const int WiiMagicOffset = 0x018; | ||
| public const int GCMagicOffset = 0x01C; | ||
| public const int GameTitleOffset = 0x020; | ||
| public const int GameTitleLength = 0x060; | ||
| public const int DisableHashVerificationOffset = 0x080; | ||
| public const int DisableDiscEncryptionOffset = 0x081; | ||
| public const int DolOffsetField = 0x420; | ||
| public const int FstOffsetField = 0x424; | ||
| public const int FstSizeField = 0x428; | ||
| public const int DiscHeaderSize = 0x440; | ||
|
|
||
| #endregion | ||
|
|
||
| #region BI2 data | ||
|
|
||
| public const int Bi2Address = 0x000440; | ||
| public const int Bi2Size = 0x2000; | ||
|
|
||
| #endregion | ||
|
|
||
| #region Apploader | ||
|
|
||
| public const int ApploaderAddress = 0x002440; | ||
| public const int ApploaderCodeSizeOffset = 0x14; | ||
| public const int ApploaderTrailerSizeOffset = 0x18; | ||
| public const int ApploaderHeaderSize = 0x20; | ||
|
|
||
| #endregion | ||
|
|
||
| #region Wii-specific disc layout | ||
|
|
||
| public const int WiiPartitionTableAddress = 0x40000; | ||
| public const int WiiPartitionGroupCount = 4; | ||
| public const int WiiRegionDataAddress = 0x04E000; | ||
| public const int WiiRegionDataSize = 0x20; | ||
|
|
||
| #endregion | ||
|
|
||
| #region Wii partition header fields | ||
|
|
||
| // Offsets relative to partition start | ||
| public const int WiiTicketSize = 0x2A4; | ||
| public const int WiiTmdSizeAddress = 0x2A4; | ||
| public const int WiiTmdOffsetAddress = 0x2A8; | ||
| public const int WiiCertSizeAddress = 0x2AC; | ||
| public const int WiiCertOffsetAddress = 0x2B0; | ||
| public const int WiiH3OffsetAddress = 0x2B4; | ||
| public const int WiiH3Size = 0x18000; | ||
| public const int WiiDataOffsetAddress = 0x2B8; | ||
|
|
||
| #endregion | ||
|
|
||
| #region Wii block / group structure | ||
|
|
||
| public const int WiiBlockSize = 0x8000; | ||
| public const int WiiBlockHeaderSize = 0x0400; | ||
| public const int WiiBlockDataSize = 0x7C00; | ||
| public const int WiiBlocksPerGroup = 64; | ||
| public const int WiiGroupSize = WiiBlocksPerGroup * WiiBlockSize; | ||
| public const int WiiGroupDataSize = WiiBlocksPerGroup * WiiBlockDataSize; | ||
|
|
||
| #endregion | ||
|
|
||
| #region DVD sector size | ||
|
|
||
| public const int DvdSectorSize = 0x800; | ||
|
|
||
| #endregion | ||
|
|
||
| #region Wii ticket fields | ||
|
|
||
| // Offsets relative to ticket start | ||
| public const int TicketEncryptedTitleKeyOffset = 0x1BF; | ||
| public const int TicketTitleIdOffset = 0x1DC; | ||
| public const int TicketCommonKeyIndexOffset = 0x1F1; | ||
|
|
||
| #endregion | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| namespace SabreTools.Data.Models.NintendoDisc | ||
| { | ||
| /// <summary> | ||
| /// Represents a parsed GameCube or Wii disc image | ||
| /// </summary> | ||
| public class Disc | ||
|
mnadareski marked this conversation as resolved.
|
||
| { | ||
| /// <summary> | ||
| /// Disc boot block header (first 0x440 bytes) | ||
| /// </summary> | ||
| public DiscHeader Header { get; set; } = new(); | ||
|
|
||
| /// <summary> | ||
| /// Detected platform (GameCube or Wii) | ||
| /// </summary> | ||
| public Platform Platform { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Wii partition table entries (Wii discs only) | ||
| /// </summary> | ||
| public WiiPartitionTableEntry[]? PartitionTableEntries { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Wii region data at disc offset 0x4E000 (Wii discs only) | ||
| /// </summary> | ||
| public WiiRegionData? RegionData { get; set; } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| namespace SabreTools.Data.Models.NintendoDisc | ||
| { | ||
| /// <summary> | ||
| /// GameCube / Wii disc boot block header (first 0x440 bytes of the disc) | ||
| /// </summary> | ||
| /// <see href="https://wiibrew.org/wiki/Wii_disc"/> | ||
| public sealed class DiscHeader | ||
| { | ||
| /// <summary> | ||
| /// 6-character ASCII game ID (e.g. "GALE01") | ||
| /// </summary> | ||
| /// <remarks>6 bytes at offset 0x000</remarks> | ||
| public string GameId { get; set; } = string.Empty; | ||
|
|
||
| /// <summary> | ||
| /// 2-character ASCII maker / publisher code (e.g. "01") | ||
| /// </summary> | ||
| /// <remarks>Derived from GameId bytes at offset 0x004–0x005; not a separate on-disc field</remarks> | ||
| public string MakerCode { get; set; } = string.Empty; | ||
|
|
||
| /// <summary> | ||
| /// Zero-based disc number for multi-disc games | ||
| /// </summary> | ||
| public byte DiscNumber { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Disc version | ||
| /// </summary> | ||
| public byte DiscVersion { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Non-zero if audio streaming is enabled | ||
| /// </summary> | ||
| public byte AudioStreaming { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Audio streaming buffer size (in 16 KiB units) | ||
| /// </summary> | ||
| public byte StreamingBufferSize { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Wii magic word at offset 0x018 (0x5D1C9EA3 for Wii discs, 0 for GameCube) | ||
| /// </summary> | ||
| public uint WiiMagic { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// GameCube magic word at offset 0x01C (0xC2339F3D for GameCube discs) | ||
| /// </summary> | ||
| public uint GCMagic { get; set; } | ||
|
Dimensional marked this conversation as resolved.
|
||
|
|
||
| /// <summary> | ||
| /// Null-terminated ASCII game title (up to 0x60 bytes at offset 0x020) | ||
| /// </summary> | ||
| public string GameTitle { get; set; } = string.Empty; | ||
|
|
||
| /// <summary> | ||
| /// Non-zero to disable hash verification (GameCube only) | ||
| /// </summary> | ||
| public byte DisableHashVerification { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Non-zero to disable disc encryption (GameCube only) | ||
| /// </summary> | ||
| public byte DisableDiscEncryption { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Offset of the main DOL executable (no shift for GameCube; <<2 for Wii) | ||
| /// </summary> | ||
| public uint DolOffset { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Offset of the File System Table (no shift for GameCube; <<2 for Wii) | ||
| /// </summary> | ||
| public uint FstOffset { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Maximum size of the File System Table in bytes | ||
| /// </summary> | ||
| public uint FstSize { get; set; } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| namespace SabreTools.Data.Models.NintendoDisc | ||
| { | ||
| /// <summary> | ||
| /// Platform / console type for a Nintendo disc image | ||
| /// </summary> | ||
| public enum Platform | ||
| { | ||
| /// <summary>Platform could not be determined</summary> | ||
| Unknown = 0, | ||
|
|
||
| /// <summary>Nintendo GameCube</summary> | ||
| GameCube = 1, | ||
|
|
||
| /// <summary>Nintendo Wii</summary> | ||
| Wii = 2, | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Wii partition type | ||
| /// </summary> | ||
| public enum WiiPartitionType : uint | ||
| { | ||
| /// <summary>Game data partition (DATA)</summary> | ||
| Data = 0, | ||
|
|
||
| /// <summary>System update partition (UPDATE)</summary> | ||
| Update = 1, | ||
|
|
||
| /// <summary>Channel installer partition (CHANNEL)</summary> | ||
| Channel = 2, | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.