First round of cleanup for DolphinLib additions

This commit is contained in:
Matt Nadareski
2026-05-12 20:33:53 -04:00
parent 49aa6895b6
commit 2a0e8e2eb0
53 changed files with 3861 additions and 2586 deletions

View File

@@ -18,7 +18,7 @@ namespace SabreTools.Serialization.Writers
if (string.IsNullOrEmpty(path))
return false;
if (obj is null || !ValidateArchive(obj))
if (obj is null || !ValidateDiscImage(obj))
return false;
using var fs = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None);
@@ -35,41 +35,56 @@ namespace SabreTools.Serialization.Writers
if (stream is null || !stream.CanWrite)
return false;
if (obj is null || !ValidateArchive(obj))
if (obj is null || !ValidateDiscImage(obj))
return false;
// Header (32 bytes, little-endian)
stream.WriteLittleEndian(obj.Header.MagicCookie);
stream.WriteLittleEndian(obj.Header.SubType);
stream.WriteLittleEndian(obj.Header.CompressedDataSize);
stream.WriteLittleEndian(obj.Header.DataSize);
stream.WriteLittleEndian(obj.Header.BlockSize);
stream.WriteLittleEndian(obj.Header.NumBlocks);
WriteHeader(stream, obj.Header);
// Block pointer table (8 bytes per block, little-endian)
foreach (ulong ptr in obj.BlockPointers)
stream.WriteLittleEndian(ptr);
foreach (ulong pointer in obj.BlockPointers)
{
stream.WriteLittleEndian(pointer);
}
// Block hash table (4 bytes per block, little-endian)
foreach (uint hash in obj.BlockHashes)
{
stream.WriteLittleEndian(hash);
}
stream.Flush();
return true;
}
private static bool ValidateArchive(DiscImage obj)
/// <summary>
/// Write GczHeader data to the stream
/// </summary>
/// <param name="stream">Stream to write to</param>
public static void WriteHeader(Stream stream, GczHeader obj)
{
stream.WriteLittleEndian(obj.MagicCookie);
stream.WriteLittleEndian(obj.SubType);
stream.WriteLittleEndian(obj.CompressedDataSize);
stream.WriteLittleEndian(obj.DataSize);
stream.WriteLittleEndian(obj.BlockSize);
stream.WriteLittleEndian(obj.NumBlocks);
}
/// <summary>
/// Validate that disc image is writable
/// </summary>
private static bool ValidateDiscImage(DiscImage obj)
{
if (obj.Header is null)
return false;
if (obj.Header.MagicCookie != Constants.MagicCookie)
return false;
if (obj.Header.NumBlocks == 0)
return false;
if (obj.BlockPointers is null || obj.BlockPointers.Length != (int)obj.Header.NumBlocks)
if (obj.BlockPointers.Length != obj.Header.NumBlocks)
return false;
if (obj.BlockHashes is null || obj.BlockHashes.Length != (int)obj.Header.NumBlocks)
if (obj.BlockHashes.Length != obj.Header.NumBlocks)
return false;
return true;
}
}

View File

@@ -1,6 +1,8 @@
using System;
using System.IO;
using SabreTools.Data.Models.WIA;
using SabreTools.Numerics.Extensions;
using static SabreTools.Data.Models.WIA.Constants;
namespace SabreTools.Serialization.Writers
{
@@ -18,7 +20,7 @@ namespace SabreTools.Serialization.Writers
if (string.IsNullOrEmpty(path))
return false;
if (obj is null || !ValidateArchive(obj))
if (obj is null || !ValidateDiscImage(obj))
return false;
using var fs = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None);
@@ -35,121 +37,170 @@ namespace SabreTools.Serialization.Writers
if (stream is null || !stream.CanWrite)
return false;
if (obj is null || !ValidateArchive(obj))
if (obj is null || !ValidateDiscImage(obj))
return false;
WriteHeader1(stream, obj.Header1);
WriteHeader2(stream, obj.Header2);
WriteWiaHeader1(stream, obj.Header1);
WriteWiaHeader2(stream, obj.Header2);
// Partition entries
if (obj.PartitionEntries != null)
if (obj.PartitionEntries is not null)
{
foreach (var pe in obj.PartitionEntries)
{
WritePartitionEntry(stream, pe);
}
}
// Raw data entries
foreach (var re in obj.RawDataEntries)
{
WriteRawDataEntry(stream, re);
}
// Group entries
if (obj.Header1.Magic == Constants.RvzMagic && obj.RvzGroupEntries != null)
if (obj.Header1.Magic == RvzMagic && obj.RvzGroupEntries is not null)
{
foreach (var ge in obj.RvzGroupEntries)
{
WriteRvzGroupEntry(stream, ge);
}
}
else if (obj.Header1.Magic != Constants.RvzMagic && obj.GroupEntries != null)
else if (obj.Header1.Magic != RvzMagic && obj.GroupEntries is not null)
{
foreach (var ge in obj.GroupEntries)
{
WriteWiaGroupEntry(stream, ge);
}
}
stream.Flush();
return true;
}
private static bool ValidateArchive(DiscImage obj)
/// <summary>
/// Write PartitionDataEntry data to the stream
/// </summary>
/// <param name="stream">Stream to write to</param>
public static void WritePartitionDataEntry(Stream stream, PartitionDataEntry obj)
{
if (obj.Header1 is null || obj.Header2 is null)
return false;
if (obj.Header1.Magic != Constants.WiaMagic && obj.Header1.Magic != Constants.RvzMagic)
stream.WriteBigEndian(obj.FirstSector);
stream.WriteBigEndian(obj.NumberOfSectors);
stream.WriteBigEndian(obj.GroupIndex);
stream.WriteBigEndian(obj.NumberOfGroups);
stream.Flush();
}
/// <summary>
/// Write PartitionEntry data to the stream
/// </summary>
/// <param name="stream">Stream to write to</param>
public static void WritePartitionEntry(Stream stream, PartitionEntry obj)
{
stream.Write(obj.PartitionKey);
WritePartitionDataEntry(stream, obj.DataEntry0);
WritePartitionDataEntry(stream, obj.DataEntry1);
stream.Flush();
}
/// <summary>
/// Write RawDataEntry data to the stream
/// </summary>
/// <param name="stream">Stream to write to</param>
public static void WriteRawDataEntry(Stream stream, RawDataEntry obj)
{
stream.WriteBigEndian(obj.DataOffset);
stream.WriteBigEndian(obj.DataSize);
stream.WriteBigEndian(obj.GroupIndex);
stream.WriteBigEndian(obj.NumberOfGroups);
stream.Flush();
}
/// <summary>
/// Write RvzGroupEntry data to the stream
/// </summary>
/// <param name="stream">Stream to write to</param>
public static void WriteRvzGroupEntry(Stream stream, RvzGroupEntry obj)
{
stream.WriteBigEndian(obj.DataOffset);
stream.WriteBigEndian(obj.DataSize);
stream.WriteBigEndian(obj.RvzPackedSize);
stream.Flush();
}
/// <summary>
/// Write WiaGroupEntry data to the stream
/// </summary>
/// <param name="stream">Stream to write to</param>
public static void WriteWiaGroupEntry(Stream stream, WiaGroupEntry obj)
{
stream.WriteBigEndian(obj.DataOffset);
stream.WriteBigEndian(obj.DataSize);
stream.Flush();
}
/// <summary>
/// Write WiaHeader1 data to the stream
/// </summary>
/// <param name="stream">Stream to write to</param>
public static void WriteWiaHeader1(Stream stream, WiaHeader1 obj)
{
stream.WriteLittleEndian(obj.Magic);
stream.WriteBigEndian(obj.Version);
stream.WriteBigEndian(obj.VersionCompatible);
stream.WriteBigEndian(obj.Header2Size);
stream.Write(obj.Header2Hash);
stream.WriteBigEndian(obj.IsoFileSize);
stream.WriteBigEndian(obj.WiaFileSize);
stream.Write(obj.Header1Hash);
stream.Flush();
}
/// <summary>
/// Write WiaHeader2 data to the stream
/// </summary>
/// <param name="stream">Stream to write to</param>
public static void WriteWiaHeader2(Stream stream, WiaHeader2 obj)
{
stream.WriteBigEndian((uint)obj.DiscType);
stream.WriteBigEndian((uint)obj.CompressionType);
stream.WriteBigEndian(obj.CompressionLevel);
stream.WriteBigEndian(obj.ChunkSize);
byte[] dh = obj.DiscHeader;
stream.Write(dh, 0, Math.Min(dh.Length, DiscHeaderStoredSize));
if (dh.Length < DiscHeaderStoredSize)
stream.Write(new byte[DiscHeaderStoredSize - dh.Length], 0, DiscHeaderStoredSize - dh.Length);
stream.WriteBigEndian(obj.NumberOfPartitionEntries);
stream.WriteBigEndian(obj.PartitionEntrySize);
stream.WriteBigEndian(obj.PartitionEntriesOffset);
stream.Write(obj.PartitionEntriesHash);
stream.WriteBigEndian(obj.NumberOfRawDataEntries);
stream.WriteBigEndian(obj.RawDataEntriesOffset);
stream.WriteBigEndian(obj.RawDataEntriesSize);
stream.WriteBigEndian(obj.NumberOfGroupEntries);
stream.WriteBigEndian(obj.GroupEntriesOffset);
stream.WriteBigEndian(obj.GroupEntriesSize);
stream.WriteByte(obj.CompressorDataSize);
byte[] prop = obj.CompressorData;
stream.Write(prop, 0, Math.Min(prop.Length, 7));
if (prop.Length < 7)
stream.Write(new byte[7 - prop.Length], 0, 7 - prop.Length);
stream.Flush();
}
/// <summary>
/// Validate that disc image is writable
/// </summary>
private static bool ValidateDiscImage(DiscImage obj)
{
if (obj.Header1.Magic != WiaMagic && obj.Header1.Magic != RvzMagic)
return false;
return true;
}
#region Write helpers
private static void WriteHeader1(Stream s, WiaHeader1 h)
{
s.WriteLittleEndian(h.Magic);
s.WriteBigEndian(h.Version);
s.WriteBigEndian(h.VersionCompatible);
s.WriteBigEndian(h.Header2Size);
s.Write(h.Header2Hash, 0, 20);
s.WriteBigEndian(h.IsoFileSize);
s.WriteBigEndian(h.WiaFileSize);
s.Write(h.Header1Hash, 0, 20);
}
private static void WriteHeader2(Stream s, WiaHeader2 h)
{
s.WriteBigEndian((uint)h.DiscType);
s.WriteBigEndian((uint)h.CompressionType);
s.WriteBigEndian(h.CompressionLevel);
s.WriteBigEndian(h.ChunkSize);
s.Write(h.DiscHeader, 0, 0x80);
s.WriteBigEndian(h.NumberOfPartitionEntries);
s.WriteBigEndian(h.PartitionEntrySize);
s.WriteBigEndian(h.PartitionEntriesOffset);
s.Write(h.PartitionEntriesHash, 0, 20);
s.WriteBigEndian(h.NumberOfRawDataEntries);
s.WriteBigEndian(h.RawDataEntriesOffset);
s.WriteBigEndian(h.RawDataEntriesSize);
s.WriteBigEndian(h.NumberOfGroupEntries);
s.WriteBigEndian(h.GroupEntriesOffset);
s.WriteBigEndian(h.GroupEntriesSize);
s.WriteByte(h.CompressorDataSize);
s.Write(h.CompressorData, 0, 7);
}
private static void WritePartitionDataEntry(Stream s, PartitionDataEntry e)
{
s.WriteBigEndian(e.FirstSector);
s.WriteBigEndian(e.NumberOfSectors);
s.WriteBigEndian(e.GroupIndex);
s.WriteBigEndian(e.NumberOfGroups);
}
private static void WritePartitionEntry(Stream s, PartitionEntry e)
{
s.Write(e.PartitionKey, 0, 16);
WritePartitionDataEntry(s, e.DataEntry0);
WritePartitionDataEntry(s, e.DataEntry1);
}
private static void WriteRawDataEntry(Stream s, RawDataEntry e)
{
s.WriteBigEndian(e.DataOffset);
s.WriteBigEndian(e.DataSize);
s.WriteBigEndian(e.GroupIndex);
s.WriteBigEndian(e.NumberOfGroups);
}
private static void WriteWiaGroupEntry(Stream s, WiaGroupEntry e)
{
// DataOffset stored as actual_offset >> 2
s.WriteBigEndian((uint)(e.DataOffset >> 2));
s.WriteBigEndian(e.DataSize);
}
private static void WriteRvzGroupEntry(Stream s, RvzGroupEntry e)
{
// DataOffset stored as actual_offset >> 2
s.WriteBigEndian((uint)(e.DataOffset >> 2));
s.WriteBigEndian(e.DataSize);
s.WriteBigEndian(e.RvzPackedSize);
}
#endregion
}
}

View File

@@ -46,6 +46,9 @@ namespace SabreTools.Serialization.Writers
return true;
}
/// <summary>
/// Validate that Volume is writable
/// </summary>
public static bool ValidateVolume(Volume? obj)
{
// If the data is invalid