mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-02-07 05:44:39 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe95b894d7 | ||
|
|
38a2712a8f | ||
|
|
d1ea091574 | ||
|
|
6bc812fc2f | ||
|
|
61b89fbd72 | ||
|
|
a2c065bdf2 | ||
|
|
88479f674b | ||
|
|
5edbacde74 | ||
|
|
67fc51224b | ||
|
|
101f3294b4 | ||
|
|
6c5622f732 | ||
|
|
f2a6fe1445 | ||
|
|
b0b593443f | ||
|
|
9b05185add | ||
|
|
17316da536 | ||
|
|
f3ca4dd989 | ||
|
|
e2b7bdac8c |
@@ -27,7 +27,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.4.10" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.4.11" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
253
SabreTools.Serialization/Deserializers/CHD.cs
Normal file
253
SabreTools.Serialization/Deserializers/CHD.cs
Normal file
@@ -0,0 +1,253 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.Models.CHD;
|
||||
|
||||
namespace SabreTools.Serialization.Deserializers
|
||||
{
|
||||
// TODO: Expand this to full CHD files eventually
|
||||
public class CHD : BaseBinaryDeserializer<Header>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Header? Deserialize(Stream? data)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead)
|
||||
return null;
|
||||
|
||||
// If the offset is out of bounds
|
||||
if (data.Position < 0 || data.Position >= data.Length)
|
||||
return null;
|
||||
|
||||
// Cache the current offset
|
||||
int initialOffset = (int)data.Position;
|
||||
|
||||
// Determine the header version
|
||||
uint version = GetVersion(data);
|
||||
|
||||
// Read and return the current CHD
|
||||
return version switch
|
||||
{
|
||||
1 => ParseHeaderV1(data),
|
||||
2 => ParseHeaderV2(data),
|
||||
3 => ParseHeaderV3(data),
|
||||
4 => ParseHeaderV4(data),
|
||||
5 => ParseHeaderV5(data),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the matching CHD version, if possible
|
||||
/// </summary>
|
||||
/// <returns>Matching version, 0 if none</returns>
|
||||
private static uint GetVersion(Stream data)
|
||||
{
|
||||
// Read the header values
|
||||
byte[] tagBytes = data.ReadBytes(8);
|
||||
string tag = Encoding.ASCII.GetString(tagBytes);
|
||||
uint length = data.ReadUInt32BigEndian();
|
||||
uint version = data.ReadUInt32BigEndian();
|
||||
|
||||
// Seek back to start
|
||||
data.SeekIfPossible();
|
||||
|
||||
// Check the signature
|
||||
if (!string.Equals(tag, Constants.SignatureString, StringComparison.Ordinal))
|
||||
return 0;
|
||||
|
||||
// Match the version to header length
|
||||
#if NET472_OR_GREATER || NETCOREAPP
|
||||
return (version, length) switch
|
||||
{
|
||||
(1, Constants.HeaderV1Size) => version,
|
||||
(2, Constants.HeaderV2Size) => version,
|
||||
(3, Constants.HeaderV3Size) => version,
|
||||
(4, Constants.HeaderV4Size) => version,
|
||||
(5, Constants.HeaderV5Size) => version,
|
||||
_ => 0,
|
||||
};
|
||||
#else
|
||||
return version switch
|
||||
{
|
||||
1 => length == Constants.HeaderV1Size ? version : 0,
|
||||
2 => length == Constants.HeaderV2Size ? version : 0,
|
||||
3 => length == Constants.HeaderV3Size ? version : 0,
|
||||
4 => length == Constants.HeaderV4Size ? version : 0,
|
||||
5 => length == Constants.HeaderV5Size ? version : 0,
|
||||
_ => 0,
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a V1 header
|
||||
/// </summary>
|
||||
private static HeaderV1? ParseHeaderV1(Stream data)
|
||||
{
|
||||
var header = new HeaderV1();
|
||||
|
||||
byte[] tagBytes = data.ReadBytes(8);
|
||||
header.Tag = Encoding.ASCII.GetString(tagBytes);
|
||||
if (header.Tag != Constants.SignatureString)
|
||||
return null;
|
||||
|
||||
header.Length = data.ReadUInt32BigEndian();
|
||||
if (header.Length != Constants.HeaderV1Size)
|
||||
return null;
|
||||
|
||||
header.Version = data.ReadUInt32BigEndian();
|
||||
header.Flags = (Flags)data.ReadUInt32BigEndian();
|
||||
header.Compression = (CompressionType)data.ReadUInt32BigEndian();
|
||||
if (header.Compression > CompressionType.CHDCOMPRESSION_ZLIB)
|
||||
return null;
|
||||
|
||||
header.HunkSize = data.ReadUInt32BigEndian();
|
||||
header.TotalHunks = data.ReadUInt32BigEndian();
|
||||
header.Cylinders = data.ReadUInt32BigEndian();
|
||||
header.Heads = data.ReadUInt32BigEndian();
|
||||
header.Sectors = data.ReadUInt32BigEndian();
|
||||
header.MD5 = data.ReadBytes(16);
|
||||
header.ParentMD5 = data.ReadBytes(16);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a V2 header
|
||||
/// </summary>
|
||||
private static HeaderV2? ParseHeaderV2(Stream data)
|
||||
{
|
||||
var header = new HeaderV2();
|
||||
|
||||
byte[] tagBytes = data.ReadBytes(8);
|
||||
header.Tag = Encoding.ASCII.GetString(tagBytes);
|
||||
if (header.Tag != Constants.SignatureString)
|
||||
return null;
|
||||
|
||||
header.Length = data.ReadUInt32BigEndian();
|
||||
if (header.Length != Constants.HeaderV2Size)
|
||||
return null;
|
||||
|
||||
header.Version = data.ReadUInt32BigEndian();
|
||||
header.Flags = (Flags)data.ReadUInt32BigEndian();
|
||||
header.Compression = (CompressionType)data.ReadUInt32BigEndian();
|
||||
if (header.Compression > CompressionType.CHDCOMPRESSION_ZLIB)
|
||||
return null;
|
||||
|
||||
header.HunkSize = data.ReadUInt32BigEndian();
|
||||
header.TotalHunks = data.ReadUInt32BigEndian();
|
||||
header.Cylinders = data.ReadUInt32BigEndian();
|
||||
header.Heads = data.ReadUInt32BigEndian();
|
||||
header.Sectors = data.ReadUInt32BigEndian();
|
||||
header.MD5 = data.ReadBytes(16);
|
||||
header.ParentMD5 = data.ReadBytes(16);
|
||||
header.BytesPerSector = data.ReadUInt32BigEndian();
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a V3 header
|
||||
/// </summary>
|
||||
private static HeaderV3? ParseHeaderV3(Stream data)
|
||||
{
|
||||
var header = new HeaderV3();
|
||||
|
||||
byte[] tagBytes = data.ReadBytes(8);
|
||||
header.Tag = Encoding.ASCII.GetString(tagBytes);
|
||||
if (header.Tag != Constants.SignatureString)
|
||||
return null;
|
||||
|
||||
header.Length = data.ReadUInt32BigEndian();
|
||||
if (header.Length != Constants.HeaderV3Size)
|
||||
return null;
|
||||
|
||||
header.Version = data.ReadUInt32BigEndian();
|
||||
header.Flags = (Flags)data.ReadUInt32BigEndian();
|
||||
header.Compression = (CompressionType)data.ReadUInt32BigEndian();
|
||||
if (header.Compression > CompressionType.CHDCOMPRESSION_ZLIB_PLUS)
|
||||
return null;
|
||||
|
||||
header.TotalHunks = data.ReadUInt32BigEndian();
|
||||
header.LogicalBytes = data.ReadUInt64BigEndian();
|
||||
header.MetaOffset = data.ReadUInt64BigEndian();
|
||||
header.MD5 = data.ReadBytes(16);
|
||||
header.ParentMD5 = data.ReadBytes(16);
|
||||
header.HunkBytes = data.ReadUInt32BigEndian();
|
||||
header.SHA1 = data.ReadBytes(20);
|
||||
header.ParentSHA1 = data.ReadBytes(20);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a V4 header
|
||||
/// </summary>
|
||||
private static HeaderV4? ParseHeaderV4(Stream data)
|
||||
{
|
||||
var header = new HeaderV4();
|
||||
|
||||
byte[] tagBytes = data.ReadBytes(8);
|
||||
header.Tag = Encoding.ASCII.GetString(tagBytes);
|
||||
if (header.Tag != Constants.SignatureString)
|
||||
return null;
|
||||
|
||||
header.Length = data.ReadUInt32BigEndian();
|
||||
if (header.Length != Constants.HeaderV4Size)
|
||||
return null;
|
||||
|
||||
header.Version = data.ReadUInt32BigEndian();
|
||||
header.Flags = (Flags)data.ReadUInt32BigEndian();
|
||||
header.Compression = (CompressionType)data.ReadUInt32BigEndian();
|
||||
if (header.Compression > CompressionType.CHDCOMPRESSION_AV)
|
||||
return null;
|
||||
|
||||
header.TotalHunks = data.ReadUInt32BigEndian();
|
||||
header.LogicalBytes = data.ReadUInt64BigEndian();
|
||||
header.MetaOffset = data.ReadUInt64BigEndian();
|
||||
header.HunkBytes = data.ReadUInt32BigEndian();
|
||||
header.SHA1 = data.ReadBytes(20);
|
||||
header.ParentSHA1 = data.ReadBytes(20);
|
||||
header.RawSHA1 = data.ReadBytes(20);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a V5 header
|
||||
/// </summary>
|
||||
private static HeaderV5? ParseHeaderV5(Stream data)
|
||||
{
|
||||
var header = new HeaderV5();
|
||||
|
||||
byte[] tagBytes = data.ReadBytes(8);
|
||||
header.Tag = Encoding.ASCII.GetString(tagBytes);
|
||||
if (header.Tag != Constants.SignatureString)
|
||||
return null;
|
||||
|
||||
header.Length = data.ReadUInt32BigEndian();
|
||||
if (header.Length != Constants.HeaderV5Size)
|
||||
return null;
|
||||
|
||||
header.Version = data.ReadUInt32BigEndian();
|
||||
header.Compressors = new uint[4];
|
||||
for (int i = 0; i < header.Compressors.Length; i++)
|
||||
{
|
||||
header.Compressors[i] = data.ReadUInt32BigEndian();
|
||||
}
|
||||
|
||||
header.LogicalBytes = data.ReadUInt64BigEndian();
|
||||
header.MapOffset = data.ReadUInt64BigEndian();
|
||||
header.MetaOffset = data.ReadUInt64BigEndian();
|
||||
header.HunkBytes = data.ReadUInt32BigEndian();
|
||||
header.UnitBytes = data.ReadUInt32BigEndian();
|
||||
header.RawSHA1 = data.ReadBytes(20);
|
||||
header.SHA1 = data.ReadBytes(20);
|
||||
header.ParentSHA1 = data.ReadBytes(20);
|
||||
|
||||
return header;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SabreTools.IO.Extensions;
|
||||
@@ -447,14 +448,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
var fileGroup = new FileGroup();
|
||||
|
||||
fileGroup.NameOffset = data.ReadUInt32();
|
||||
|
||||
fileGroup.ExpandedSize = data.ReadUInt32();
|
||||
fileGroup.Reserved0 = data.ReadBytes(4);
|
||||
fileGroup.CompressedSize = data.ReadUInt32();
|
||||
fileGroup.Reserved1 = data.ReadBytes(4);
|
||||
fileGroup.Reserved2 = data.ReadBytes(2);
|
||||
fileGroup.Attribute1 = data.ReadUInt16();
|
||||
fileGroup.Attribute2 = data.ReadUInt16();
|
||||
fileGroup.Attributes = (FileGroupAttributes)data.ReadUInt16();
|
||||
|
||||
// TODO: Figure out what data lives in this area for V5 and below
|
||||
if (majorVersion <= 5)
|
||||
@@ -462,19 +458,19 @@ namespace SabreTools.Serialization.Deserializers
|
||||
|
||||
fileGroup.FirstFile = data.ReadUInt32();
|
||||
fileGroup.LastFile = data.ReadUInt32();
|
||||
fileGroup.UnknownOffset = data.ReadUInt32();
|
||||
fileGroup.Var4Offset = data.ReadUInt32();
|
||||
fileGroup.Var1Offset = data.ReadUInt32();
|
||||
fileGroup.UnknownStringOffset = data.ReadUInt32();
|
||||
fileGroup.OperatingSystemOffset = data.ReadUInt32();
|
||||
fileGroup.LanguageOffset = data.ReadUInt32();
|
||||
fileGroup.HTTPLocationOffset = data.ReadUInt32();
|
||||
fileGroup.FTPLocationOffset = data.ReadUInt32();
|
||||
fileGroup.MiscOffset = data.ReadUInt32();
|
||||
fileGroup.Var2Offset = data.ReadUInt32();
|
||||
fileGroup.TargetDirectoryOffset = data.ReadUInt32();
|
||||
fileGroup.Reserved3 = data.ReadBytes(2);
|
||||
fileGroup.Reserved4 = data.ReadBytes(2);
|
||||
fileGroup.Reserved5 = data.ReadBytes(2);
|
||||
fileGroup.Reserved6 = data.ReadBytes(2);
|
||||
fileGroup.Reserved7 = data.ReadBytes(2);
|
||||
fileGroup.OverwriteFlags = (FileGroupFlags)data.ReadUInt32();
|
||||
fileGroup.Reserved = new uint[4];
|
||||
for (int i = 0; i < fileGroup.Reserved.Length; i++)
|
||||
{
|
||||
fileGroup.Reserved[i] = data.ReadUInt32();
|
||||
}
|
||||
|
||||
// Cache the current position
|
||||
long currentPosition = data.Position;
|
||||
@@ -512,15 +508,19 @@ namespace SabreTools.Serialization.Deserializers
|
||||
component.IdentifierOffset = data.ReadUInt32();
|
||||
component.DescriptorOffset = data.ReadUInt32();
|
||||
component.DisplayNameOffset = data.ReadUInt32();
|
||||
component.Reserved0 = data.ReadUInt16();
|
||||
component.ReservedOffset0 = data.ReadUInt32();
|
||||
component.ReservedOffset1 = data.ReadUInt32();
|
||||
component.Status = (ComponentStatus)data.ReadUInt16();
|
||||
component.PasswordOffset = data.ReadUInt32();
|
||||
component.MiscOffset = data.ReadUInt32();
|
||||
component.ComponentIndex = data.ReadUInt16();
|
||||
component.NameOffset = data.ReadUInt32();
|
||||
component.ReservedOffset2 = data.ReadUInt32();
|
||||
component.ReservedOffset3 = data.ReadUInt32();
|
||||
component.ReservedOffset4 = data.ReadUInt32();
|
||||
component.Reserved1 = data.ReadBytes(32);
|
||||
component.CDRomFolderOffset = data.ReadUInt32();
|
||||
component.HTTPLocationOffset = data.ReadUInt32();
|
||||
component.FTPLocationOffset = data.ReadUInt32();
|
||||
component.Guid = new Guid[2];
|
||||
for (int i = 0; i < component.Guid.Length; i++)
|
||||
{
|
||||
component.Guid[i] = data.ReadGuid();
|
||||
}
|
||||
component.CLSIDOffset = data.ReadUInt32();
|
||||
component.Reserved2 = data.ReadBytes(28);
|
||||
component.Reserved3 = data.ReadBytes(majorVersion <= 5 ? 2 : 1);
|
||||
@@ -533,10 +533,10 @@ namespace SabreTools.Serialization.Deserializers
|
||||
component.SubComponentsCount = data.ReadUInt16();
|
||||
component.SubComponentsOffset = data.ReadUInt32();
|
||||
component.NextComponentOffset = data.ReadUInt32();
|
||||
component.ReservedOffset5 = data.ReadUInt32();
|
||||
component.ReservedOffset6 = data.ReadUInt32();
|
||||
component.ReservedOffset7 = data.ReadUInt32();
|
||||
component.ReservedOffset8 = data.ReadUInt32();
|
||||
component.OnInstallingOffset = data.ReadUInt32();
|
||||
component.OnInstalledOffset = data.ReadUInt32();
|
||||
component.OnUninstallingOffset = data.ReadUInt32();
|
||||
component.OnUninstalledOffset = data.ReadUInt32();
|
||||
|
||||
// Cache the current position
|
||||
long currentPosition = data.Position;
|
||||
|
||||
@@ -39,6 +39,7 @@ namespace SabreTools.Serialization
|
||||
Wrapper.BFPK item => item.PrettyPrint(),
|
||||
Wrapper.BSP item => item.PrettyPrint(),
|
||||
Wrapper.CFB item => item.PrettyPrint(),
|
||||
Wrapper.CHD item => item.PrettyPrint(),
|
||||
Wrapper.CIA item => item.PrettyPrint(),
|
||||
Wrapper.GCF item => item.PrettyPrint(),
|
||||
Wrapper.InstallShieldCabinet item => item.PrettyPrint(),
|
||||
@@ -83,6 +84,7 @@ namespace SabreTools.Serialization
|
||||
Wrapper.BFPK item => item.ExportJSON(),
|
||||
Wrapper.BSP item => item.ExportJSON(),
|
||||
Wrapper.CFB item => item.ExportJSON(),
|
||||
Wrapper.CHD item => item.ExportJSON(),
|
||||
Wrapper.CIA item => item.ExportJSON(),
|
||||
Wrapper.GCF item => item.ExportJSON(),
|
||||
Wrapper.InstallShieldCabinet item => item.ExportJSON(),
|
||||
@@ -167,6 +169,16 @@ namespace SabreTools.Serialization
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Export the item information as pretty-printed text
|
||||
/// </summary>
|
||||
private static StringBuilder PrettyPrint(this Wrapper.CHD item)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
CHD.Print(builder, item.Model);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Export the item information as pretty-printed text
|
||||
/// </summary>
|
||||
|
||||
161
SabreTools.Serialization/Printers/CHD.cs
Normal file
161
SabreTools.Serialization/Printers/CHD.cs
Normal file
@@ -0,0 +1,161 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using SabreTools.Models.CHD;
|
||||
using SabreTools.Serialization.Interfaces;
|
||||
|
||||
namespace SabreTools.Serialization.Printers
|
||||
{
|
||||
public class CHD : IPrinter<Header>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public void PrintInformation(StringBuilder builder, Header model)
|
||||
=> Print(builder, model);
|
||||
|
||||
public static void Print(StringBuilder builder, Header header)
|
||||
{
|
||||
builder.AppendLine("CHD Header Information:");
|
||||
builder.AppendLine("-------------------------");
|
||||
|
||||
if (header == null)
|
||||
{
|
||||
builder.AppendLine("No header");
|
||||
builder.AppendLine();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (header)
|
||||
{
|
||||
case HeaderV1 v1:
|
||||
Print(builder, v1);
|
||||
break;
|
||||
case HeaderV2 v2:
|
||||
Print(builder, v2);
|
||||
break;
|
||||
case HeaderV3 v3:
|
||||
Print(builder, v3);
|
||||
break;
|
||||
case HeaderV4 v4:
|
||||
Print(builder, v4);
|
||||
break;
|
||||
case HeaderV5 v5:
|
||||
Print(builder, v5);
|
||||
break;
|
||||
default:
|
||||
builder.AppendLine("Unrecognized header type");
|
||||
builder.AppendLine();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void Print(StringBuilder builder, HeaderV1 header)
|
||||
{
|
||||
builder.AppendLine(header.Tag, $"Tag");
|
||||
builder.AppendLine(header.Length, $"Length");
|
||||
builder.AppendLine(header.Version, $"Version");
|
||||
builder.AppendLine($" Flags: {header.Flags} (0x{header.Flags:X})");
|
||||
builder.AppendLine($" Compression: {header.Compression} (0x{header.Compression:X})");
|
||||
builder.AppendLine(header.HunkSize, $"Hunk size");
|
||||
builder.AppendLine(header.TotalHunks, $"Total hunks");
|
||||
builder.AppendLine(header.Cylinders, $"Cylinders");
|
||||
builder.AppendLine(header.Heads, $"Heads");
|
||||
builder.AppendLine(header.Sectors, $"Sectors");
|
||||
builder.AppendLine(header.MD5, $"MD5");
|
||||
builder.AppendLine(header.ParentMD5, $"Parent MD5");
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
private static void Print(StringBuilder builder, HeaderV2 header)
|
||||
{
|
||||
builder.AppendLine(header.Tag, $"Tag");
|
||||
builder.AppendLine(header.Length, $"Length");
|
||||
builder.AppendLine(header.Version, $"Version");
|
||||
builder.AppendLine($" Flags: {header.Flags} (0x{header.Flags:X})");
|
||||
builder.AppendLine($" Compression: {header.Compression} (0x{header.Compression:X})");
|
||||
builder.AppendLine(header.HunkSize, $"Hunk size");
|
||||
builder.AppendLine(header.TotalHunks, $"Total hunks");
|
||||
builder.AppendLine(header.Cylinders, $"Cylinders");
|
||||
builder.AppendLine(header.Heads, $"Heads");
|
||||
builder.AppendLine(header.Sectors, $"Sectors");
|
||||
builder.AppendLine(header.MD5, $"MD5");
|
||||
builder.AppendLine(header.ParentMD5, $"Parent MD5");
|
||||
builder.AppendLine(header.BytesPerSector, $"Bytes per sector");
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
private static void Print(StringBuilder builder, HeaderV3 header)
|
||||
{
|
||||
builder.AppendLine(header.Tag, $"Tag");
|
||||
builder.AppendLine(header.Length, $"Length");
|
||||
builder.AppendLine(header.Version, $"Version");
|
||||
builder.AppendLine($" Flags: {header.Flags} (0x{header.Flags:X})");
|
||||
builder.AppendLine($" Compression: {header.Compression} (0x{header.Compression:X})");
|
||||
builder.AppendLine(header.TotalHunks, $"Total hunks");
|
||||
builder.AppendLine(header.LogicalBytes, $"Logical bytes");
|
||||
builder.AppendLine(header.MetaOffset, $"Meta offset");
|
||||
builder.AppendLine(header.MD5, $"MD5");
|
||||
builder.AppendLine(header.ParentMD5, $"Parent MD5");
|
||||
builder.AppendLine(header.HunkBytes, $"Hunk bytes");
|
||||
builder.AppendLine(header.SHA1, $"SHA-1");
|
||||
builder.AppendLine(header.ParentSHA1, $"Parent SHA-1");
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
private static void Print(StringBuilder builder, HeaderV4 header)
|
||||
{
|
||||
builder.AppendLine(header.Tag, $"Tag");
|
||||
builder.AppendLine(header.Length, $"Length");
|
||||
builder.AppendLine(header.Version, $"Version");
|
||||
builder.AppendLine($" Flags: {header.Flags} (0x{header.Flags:X})");
|
||||
builder.AppendLine($" Compression: {header.Compression} (0x{header.Compression:X})");
|
||||
builder.AppendLine(header.TotalHunks, $"Total hunks");
|
||||
builder.AppendLine(header.LogicalBytes, $"Logical bytes");
|
||||
builder.AppendLine(header.MetaOffset, $"Meta offset");
|
||||
builder.AppendLine(header.HunkBytes, $"Hunk bytes");
|
||||
builder.AppendLine(header.SHA1, $"SHA-1");
|
||||
builder.AppendLine(header.ParentSHA1, $"Parent SHA-1");
|
||||
builder.AppendLine(header.RawSHA1, $"Raw SHA-1");
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
private static void Print(StringBuilder builder, HeaderV5 header)
|
||||
{
|
||||
builder.AppendLine(header.Tag, $"Tag");
|
||||
builder.AppendLine(header.Length, $"Length");
|
||||
builder.AppendLine(header.Version, $"Version");
|
||||
|
||||
// TODO: Remove this hack when actual compressor names are supported
|
||||
// builder.AppendLine(header.Compressors, $"Compressors");
|
||||
string compressorsLine = "Compressors: ";
|
||||
if (header.Compressors == null)
|
||||
{
|
||||
compressorsLine += "[NULL]";
|
||||
}
|
||||
else
|
||||
{
|
||||
var compressors = new List<string>();
|
||||
for (int i = 0; i < header.Compressors.Length; i++)
|
||||
{
|
||||
uint compressor = header.Compressors[i];
|
||||
byte[] compressorBytes = BitConverter.GetBytes(compressor);
|
||||
Array.Reverse(compressorBytes);
|
||||
string compressorString = Encoding.ASCII.GetString(compressorBytes);
|
||||
compressors.Add(compressorString);
|
||||
}
|
||||
|
||||
compressorsLine += string.Join(", ", [.. compressors]);
|
||||
}
|
||||
builder.AppendLine(compressorsLine);
|
||||
|
||||
builder.AppendLine(header.LogicalBytes, $"Logical bytes");
|
||||
builder.AppendLine(header.MapOffset, $"Map offset");
|
||||
builder.AppendLine(header.MetaOffset, $"Meta offset");
|
||||
builder.AppendLine(header.HunkBytes, $"Hunk bytes");
|
||||
builder.AppendLine(header.UnitBytes, $"Unit bytes");
|
||||
builder.AppendLine(header.RawSHA1, $"Raw SHA-1");
|
||||
builder.AppendLine(header.SHA1, $"SHA-1");
|
||||
builder.AppendLine(header.ParentSHA1, $"Parent SHA-1");
|
||||
builder.AppendLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -315,27 +315,19 @@ namespace SabreTools.Serialization.Printers
|
||||
builder.AppendLine(fileGroup.NameOffset, " Name offset");
|
||||
builder.AppendLine(fileGroup.Name, " Name");
|
||||
builder.AppendLine(fileGroup.ExpandedSize, " Expanded size");
|
||||
builder.AppendLine(fileGroup.Reserved0, " Reserved 0");
|
||||
builder.AppendLine(fileGroup.CompressedSize, " Compressed size");
|
||||
builder.AppendLine(fileGroup.Reserved1, " Reserved 1");
|
||||
builder.AppendLine(fileGroup.Reserved2, " Reserved 2");
|
||||
builder.AppendLine(fileGroup.Attribute1, " Attribute 1");
|
||||
builder.AppendLine(fileGroup.Attribute2, " Attribute 2");
|
||||
builder.AppendLine($" Attributes: {fileGroup.Attributes} (0x{fileGroup.Attributes:X})");
|
||||
builder.AppendLine(fileGroup.FirstFile, " First file");
|
||||
builder.AppendLine(fileGroup.LastFile, " Last file");
|
||||
builder.AppendLine(fileGroup.UnknownOffset, " Unknown offset");
|
||||
builder.AppendLine(fileGroup.Var4Offset, " Var 4 offset");
|
||||
builder.AppendLine(fileGroup.Var1Offset, " Var 1 offset");
|
||||
builder.AppendLine(fileGroup.UnknownStringOffset, " Unknown string offset");
|
||||
builder.AppendLine(fileGroup.OperatingSystemOffset, " Operating system offset");
|
||||
builder.AppendLine(fileGroup.LanguageOffset, " Language offset");
|
||||
builder.AppendLine(fileGroup.HTTPLocationOffset, " HTTP location offset");
|
||||
builder.AppendLine(fileGroup.FTPLocationOffset, " FTP location offset");
|
||||
builder.AppendLine(fileGroup.MiscOffset, " Misc. offset");
|
||||
builder.AppendLine(fileGroup.Var2Offset, " Var 2 offset");
|
||||
builder.AppendLine(fileGroup.TargetDirectoryOffset, " Target directory offset");
|
||||
builder.AppendLine(fileGroup.Reserved3, " Reserved 3");
|
||||
builder.AppendLine(fileGroup.Reserved4, " Reserved 4");
|
||||
builder.AppendLine(fileGroup.Reserved5, " Reserved 5");
|
||||
builder.AppendLine(fileGroup.Reserved6, " Reserved 6");
|
||||
builder.AppendLine(fileGroup.Reserved7, " Reserved 7");
|
||||
builder.AppendLine($" Overwrite flags: {fileGroup.OverwriteFlags} (0x{fileGroup.OverwriteFlags:X})");
|
||||
builder.AppendLine(fileGroup.Reserved, " Reserved");
|
||||
}
|
||||
builder.AppendLine();
|
||||
}
|
||||
@@ -366,16 +358,16 @@ namespace SabreTools.Serialization.Printers
|
||||
builder.AppendLine(component.DescriptorOffset, " Descriptor offset");
|
||||
builder.AppendLine(component.DisplayNameOffset, " Display name offset");
|
||||
builder.AppendLine(component.DisplayName, " Display name");
|
||||
builder.AppendLine(component.Reserved0, " Reserved 0");
|
||||
builder.AppendLine(component.ReservedOffset0, " Reserved offset 0");
|
||||
builder.AppendLine(component.ReservedOffset1, " Reserved offset 1");
|
||||
builder.AppendLine($" Status: {component.Status} (0x{component.Status:X})");
|
||||
builder.AppendLine(component.PasswordOffset, " Password offset");
|
||||
builder.AppendLine(component.MiscOffset, " Misc. offset");
|
||||
builder.AppendLine(component.ComponentIndex, " Component index");
|
||||
builder.AppendLine(component.NameOffset, " Name offset");
|
||||
builder.AppendLine(component.Name, " Name");
|
||||
builder.AppendLine(component.ReservedOffset2, " Reserved offset 2");
|
||||
builder.AppendLine(component.ReservedOffset3, " Reserved offset 3");
|
||||
builder.AppendLine(component.ReservedOffset4, " Reserved offset 4");
|
||||
builder.AppendLine(component.Reserved1, " Reserved 1");
|
||||
builder.AppendLine(component.CDRomFolderOffset, " CD-ROM folder offset");
|
||||
builder.AppendLine(component.HTTPLocationOffset, " HTTP location offset");
|
||||
builder.AppendLine(component.FTPLocationOffset, " FTP location offset");
|
||||
builder.AppendLine(component.Guid, " GUIDs");
|
||||
builder.AppendLine(component.CLSIDOffset, " CLSID offset");
|
||||
builder.AppendLine(component.CLSID, " CLSID");
|
||||
builder.AppendLine(component.Reserved2, " Reserved 2");
|
||||
@@ -406,10 +398,10 @@ namespace SabreTools.Serialization.Printers
|
||||
builder.AppendLine(component.SubComponentsCount, " Sub-components count");
|
||||
builder.AppendLine(component.SubComponentsOffset, " Sub-components offset");
|
||||
builder.AppendLine(component.NextComponentOffset, " Next component offset");
|
||||
builder.AppendLine(component.ReservedOffset5, " Reserved offset 5");
|
||||
builder.AppendLine(component.ReservedOffset6, " Reserved offset 6");
|
||||
builder.AppendLine(component.ReservedOffset7, " Reserved offset 7");
|
||||
builder.AppendLine(component.ReservedOffset8, " Reserved offset 8");
|
||||
builder.AppendLine(component.OnInstallingOffset, " On installing offset");
|
||||
builder.AppendLine(component.OnInstalledOffset, " On installed offset");
|
||||
builder.AppendLine(component.OnUninstallingOffset, " On uninstalling offset");
|
||||
builder.AppendLine(component.OnUninstalledOffset, " On uninstalled offset");
|
||||
}
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>1.6.8</Version>
|
||||
<Version>1.6.9</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
@@ -45,9 +45,9 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="SabreTools.ASN1" Version="1.3.3" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="1.2.1" />
|
||||
<PackageReference Include="SabreTools.IO" Version="1.4.12" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.4.10" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="1.2.2" />
|
||||
<PackageReference Include="SabreTools.IO" Version="1.4.13" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.4.11" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -204,5 +204,14 @@ namespace SabreTools.Serialization
|
||||
string valueString = (value == null ? "[NULL]" : string.Join(", ", value.Select(u => u.ToString()).ToArray()));
|
||||
return sb.AppendLine($"{prefixString}: {valueString}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Append a line containing a UInt64[] value to a StringBuilder
|
||||
/// </summary>
|
||||
public static StringBuilder AppendLine(this StringBuilder sb, Guid[]? value, string prefixString)
|
||||
{
|
||||
string valueString = (value == null ? "[NULL]" : string.Join(", ", value.Select(g => g.ToString()).ToArray()));
|
||||
return sb.AppendLine($"{prefixString}: {valueString}");
|
||||
}
|
||||
}
|
||||
}
|
||||
121
SabreTools.Serialization/Wrappers/CHD.cs
Normal file
121
SabreTools.Serialization/Wrappers/CHD.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using System.IO;
|
||||
using SabreTools.Models.CHD;
|
||||
|
||||
namespace SabreTools.Serialization.Wrappers
|
||||
{
|
||||
public class CHD : WrapperBase<Header>
|
||||
{
|
||||
#region Descriptive Properties
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string DescriptionString => "MAME Compressed Hunks of Data";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extension Properties
|
||||
|
||||
/// <summary>
|
||||
/// Internal MD5 hash, if available
|
||||
/// </summary>
|
||||
public byte[]? MD5
|
||||
{
|
||||
get
|
||||
{
|
||||
return Model switch
|
||||
{
|
||||
HeaderV1 v1 => v1.MD5,
|
||||
HeaderV2 v2 => v2.MD5,
|
||||
HeaderV3 v3 => v3.MD5,
|
||||
HeaderV4 v4 => null,
|
||||
HeaderV5 v5 => null,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal SHA1 hash, if available
|
||||
/// </summary>
|
||||
public byte[]? SHA1
|
||||
{
|
||||
get
|
||||
{
|
||||
return Model switch
|
||||
{
|
||||
HeaderV1 v1 => null,
|
||||
HeaderV2 v2 => null,
|
||||
HeaderV3 v3 => v3.SHA1,
|
||||
HeaderV4 v4 => v4.SHA1,
|
||||
HeaderV5 v5 => v5.SHA1,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <inheritdoc/>
|
||||
public CHD(Header? model, byte[]? data, int offset)
|
||||
: base(model, data, offset)
|
||||
{
|
||||
// All logic is handled by the base class
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public CHD(Header? model, Stream? data)
|
||||
: base(model, data)
|
||||
{
|
||||
// All logic is handled by the base class
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a CHD header from a byte array and offset
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array representing the archive</param>
|
||||
/// <param name="offset">Offset within the array to parse</param>
|
||||
/// <returns>A CHD header wrapper on success, null on failure</returns>
|
||||
public static CHD? Create(byte[]? data, int offset)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data == null)
|
||||
return null;
|
||||
|
||||
// If the offset is out of bounds
|
||||
if (offset < 0 || offset >= data.Length)
|
||||
return null;
|
||||
|
||||
// Create a memory stream and use that
|
||||
var dataStream = new MemoryStream(data, offset, data.Length - offset);
|
||||
return Create(dataStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a CHD header from a Stream
|
||||
/// </summary>
|
||||
/// <param name="data">Stream representing the archive</param>
|
||||
/// <returns>An CHD header on success, null on failure</returns>
|
||||
public static CHD? Create(Stream? data)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead)
|
||||
return null;
|
||||
|
||||
var header = Deserializers.CHD.DeserializeStream(data);
|
||||
if (header == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
return new CHD(header, data);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using SabreTools.Models.N3DS;
|
||||
|
||||
namespace SabreTools.Serialization.Wrappers
|
||||
{
|
||||
@@ -74,5 +75,36 @@ namespace SabreTools.Serialization.Wrappers
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// TODO: Hook these up for external use
|
||||
#region Currently Unused Extensions
|
||||
|
||||
#region Ticket
|
||||
|
||||
/// <summary>
|
||||
/// Denotes if the ticket denotes a demo or not
|
||||
/// </summary>
|
||||
public static bool IsDemo(Ticket? ticket)
|
||||
{
|
||||
if (ticket?.Limits == null || ticket.Limits.Length == 0)
|
||||
return false;
|
||||
|
||||
return ticket.Limits[0] == 0x0004;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Denotes if the max playcount for a demo
|
||||
/// </summary>
|
||||
public static uint PlayCount(Ticket ticket)
|
||||
{
|
||||
if (ticket?.Limits == null || ticket.Limits.Length == 0)
|
||||
return 0;
|
||||
|
||||
return ticket.Limits[1];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -177,7 +177,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// Get the directory index for the given file index
|
||||
/// </summary>
|
||||
/// <returns>Directory index if found, UInt32.MaxValue on error</returns>
|
||||
public uint GetFileDirectoryIndex(int index)
|
||||
public uint GetDirectoryIndexFromFile(int index)
|
||||
{
|
||||
FileDescriptor? descriptor = GetFileDescriptor(index);
|
||||
if (descriptor != null)
|
||||
@@ -293,23 +293,43 @@ namespace SabreTools.Serialization.Wrappers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the file group name at a given index, if possible
|
||||
/// Get the file group for the given file index, if possible
|
||||
/// </summary>
|
||||
public string? GetFileGroupName(int index)
|
||||
public FileGroup? GetFileGroupFromFile(int index)
|
||||
{
|
||||
if (Model.FileGroups == null)
|
||||
return null;
|
||||
|
||||
if (index < 0 || index >= Model.FileGroups.Length)
|
||||
if (index < 0 || index >= FileCount)
|
||||
return null;
|
||||
|
||||
var fileGroup = Model.FileGroups[index];
|
||||
if (fileGroup == null)
|
||||
return null;
|
||||
for (int i = 0; i < FileGroupCount; i++)
|
||||
{
|
||||
var fileGroup = GetFileGroup(i);
|
||||
if (fileGroup == null)
|
||||
continue;
|
||||
|
||||
return fileGroup.Name;
|
||||
if (fileGroup.FirstFile > index || fileGroup.LastFile < index)
|
||||
continue;
|
||||
|
||||
return fileGroup;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the file group name at a given index, if possible
|
||||
/// </summary>
|
||||
public string? GetFileGroupName(int index)
|
||||
=> GetFileGroup(index)?.Name;
|
||||
|
||||
/// <summary>
|
||||
/// Get the file group name at a given file index, if possible
|
||||
/// </summary>
|
||||
public string? GetFileGroupNameFromFile(int index)
|
||||
=> GetFileGroupFromFile(index)?.Name;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SabreTools.Models.N3DS;
|
||||
|
||||
namespace SabreTools.Serialization.Wrappers
|
||||
{
|
||||
@@ -74,5 +76,178 @@ namespace SabreTools.Serialization.Wrappers
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// TODO: Hook these up for external use
|
||||
#region Currently Unused Extensions
|
||||
|
||||
#region ExeFSFileHeader
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a file header represents a CODE block
|
||||
/// </summary>
|
||||
public static bool IsCodeBinary(ExeFSFileHeader? header)
|
||||
{
|
||||
if (header == null)
|
||||
return false;
|
||||
|
||||
return header.FileName == ".code\0\0\0";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region NCCHHeaderFlags
|
||||
|
||||
/// <summary>
|
||||
/// Get if the NoCrypto bit is set
|
||||
/// </summary>
|
||||
public static bool PossiblyDecrypted(NCCHHeaderFlags flags)
|
||||
{
|
||||
if (flags == null)
|
||||
return false;
|
||||
|
||||
#if NET20 || NET35
|
||||
return (flags.BitMasks & BitMasks.NoCrypto) != 0;
|
||||
#else
|
||||
return flags.BitMasks.HasFlag(BitMasks.NoCrypto);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region NCSDHeader
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for Executable Content (CXI)
|
||||
/// </summary>
|
||||
public static PartitionTableEntry? ExecutableContent(NCSDHeader? header)
|
||||
{
|
||||
if (header?.PartitionsTable == null)
|
||||
return null;
|
||||
|
||||
return header.PartitionsTable[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for E-Manual (CFA)
|
||||
/// </summary>
|
||||
public static PartitionTableEntry? EManual(NCSDHeader? header)
|
||||
{
|
||||
if (header?.PartitionsTable == null)
|
||||
return null;
|
||||
|
||||
return header.PartitionsTable[1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for Download Play Child container (CFA)
|
||||
/// </summary>
|
||||
public static PartitionTableEntry? DownloadPlayChildContainer(NCSDHeader? header)
|
||||
{
|
||||
if (header?.PartitionsTable == null)
|
||||
return null;
|
||||
|
||||
return header.PartitionsTable[2];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for New3DS Update Data (CFA)
|
||||
/// </summary>
|
||||
public static PartitionTableEntry? New3DSUpdateData(NCSDHeader? header)
|
||||
{
|
||||
if (header?.PartitionsTable == null)
|
||||
return null;
|
||||
|
||||
return header.PartitionsTable[6];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for Update Data (CFA)
|
||||
/// </summary>
|
||||
public static PartitionTableEntry? UpdateData(NCSDHeader? header)
|
||||
{
|
||||
if (header?.PartitionsTable == null)
|
||||
return null;
|
||||
|
||||
return header.PartitionsTable[7];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Backup Write Wait Time (The time to wait to write save to backup after the card is recognized (0-255
|
||||
/// seconds)).NATIVE_FIRM loads this flag from the gamecard NCSD header starting with 6.0.0-11.
|
||||
/// </summary>
|
||||
public static byte BackupWriteWaitTime(NCSDHeader? header)
|
||||
{
|
||||
if (header?.PartitionFlags == null)
|
||||
return default;
|
||||
|
||||
return header.PartitionFlags[(int)NCSDFlags.BackupWriteWaitTime];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media Card Device (1 = NOR Flash, 2 = None, 3 = BT) (SDK 3.X+)
|
||||
/// </summary>
|
||||
public static MediaCardDeviceType MediaCardDevice3X(NCSDHeader? header)
|
||||
{
|
||||
if (header?.PartitionFlags == null)
|
||||
return default;
|
||||
|
||||
return (MediaCardDeviceType)header.PartitionFlags[(int)NCSDFlags.MediaCardDevice3X];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media Platform Index (1 = CTR)
|
||||
/// </summary>
|
||||
public static MediaPlatformIndex MediaPlatformIndex(NCSDHeader? header)
|
||||
{
|
||||
if (header?.PartitionFlags == null)
|
||||
return default;
|
||||
|
||||
return (MediaPlatformIndex)header.PartitionFlags[(int)NCSDFlags.MediaPlatformIndex];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media Type Index (0 = Inner Device, 1 = Card1, 2 = Card2, 3 = Extended Device)
|
||||
/// </summary>
|
||||
public static MediaTypeIndex MediaTypeIndex(NCSDHeader? header)
|
||||
{
|
||||
if (header?.PartitionFlags == null)
|
||||
return default;
|
||||
|
||||
return (MediaTypeIndex)header.PartitionFlags[(int)NCSDFlags.MediaTypeIndex];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media Unit Size i.e. u32 MediaUnitSize = 0x200*2^flags[6];
|
||||
/// </summary>
|
||||
public static uint MediaUnitSize(Cart cart)
|
||||
{
|
||||
return MediaUnitSize(cart.Header);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media Unit Size i.e. u32 MediaUnitSize = 0x200*2^flags[6];
|
||||
/// </summary>
|
||||
public static uint MediaUnitSize(NCSDHeader? header)
|
||||
{
|
||||
if (header?.PartitionFlags == null)
|
||||
return default;
|
||||
|
||||
return (uint)(0x200 * Math.Pow(2, header.PartitionFlags[(int)NCSDFlags.MediaUnitSize]));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media Card Device (1 = NOR Flash, 2 = None, 3 = BT) (Only SDK 2.X)
|
||||
/// </summary>
|
||||
public static MediaCardDeviceType MediaCardDevice2X(NCSDHeader? header)
|
||||
{
|
||||
if (header?.PartitionFlags == null)
|
||||
return default;
|
||||
|
||||
return (MediaCardDeviceType)header.PartitionFlags[(int)NCSDFlags.MediaCardDevice2X];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
case WrapperType.BSP: return BSP.Create(data);
|
||||
case WrapperType.BZip2: return null; // TODO: Implement wrapper
|
||||
case WrapperType.CFB: return CFB.Create(data);
|
||||
case WrapperType.CHD: return CHD.Create(data);
|
||||
case WrapperType.CIA: return CIA.Create(data);
|
||||
case WrapperType.Executable: return CreateExecutableWrapper(data);
|
||||
case WrapperType.GCF: return GCF.Create(data);
|
||||
@@ -218,6 +219,13 @@ namespace SabreTools.Serialization.Wrappers
|
||||
|
||||
#endregion
|
||||
|
||||
#region CHD
|
||||
|
||||
if (magic.StartsWith(new byte?[] { 0x4D, 0x43, 0x6F, 0x6D, 0x70, 0x72, 0x48, 0x44 }))
|
||||
return WrapperType.CHD;
|
||||
|
||||
#endregion
|
||||
|
||||
#region CIA
|
||||
|
||||
if (extension.Equals("cia", StringComparison.OrdinalIgnoreCase))
|
||||
|
||||
@@ -41,6 +41,11 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// </summary>
|
||||
CFB,
|
||||
|
||||
/// <summary>
|
||||
/// MAME Compressed Hunks of Data
|
||||
/// </summary>
|
||||
CHD,
|
||||
|
||||
/// <summary>
|
||||
/// CTR Importable Archive
|
||||
/// </summary>
|
||||
|
||||
@@ -17,8 +17,6 @@ namespace Test
|
||||
if (options == null)
|
||||
{
|
||||
Options.DisplayHelp();
|
||||
Console.WriteLine("Press enter to close the program...");
|
||||
Console.ReadLine();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user