Add RomFS header parsing/printing

This commit is contained in:
Matt Nadareski
2023-01-07 23:09:26 -08:00
parent c91691f79b
commit 3882db6fc6
4 changed files with 135 additions and 1 deletions

View File

@@ -161,6 +161,32 @@ namespace BurnOutSharp.Builders
#endregion
#region RomFS Headers
// Create the RomFS header table
cart.RomFSHeaders = new RomFSHeader[8];
// Iterate and build the RomFS headers
for (int i = 0; i < 8; i++)
{
// If we have an encrypted or invalid partition
if (cart.Partitions[i].MagicID != NCCHMagicNumber)
continue;
// Get the RomFS header offset
long offset = (cart.Header.PartitionsTable[i].Offset + cart.Partitions[i].RomFSOffsetInMediaUnits) * mediaUnitSize;
if (offset < 0 || offset >= data.Length)
continue;
// Seek to the RomFS header
data.Seek(offset, SeekOrigin.Begin);
// Parse the RomFS header
cart.RomFSHeaders[i] = ParseRomFSHeader(data);
}
#endregion
return cart;
}
@@ -647,6 +673,44 @@ namespace BurnOutSharp.Builders
return exeFSFileHeader;
}
/// <summary>
/// Parse a Stream into an RomFS header
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled RomFS header on success, null on error</returns>
private static RomFSHeader ParseRomFSHeader(Stream data)
{
// TODO: Use marshalling here instead of building
RomFSHeader romFSHeader = new RomFSHeader();
byte[] magicString = data.ReadBytes(4);
romFSHeader.MagicString = Encoding.ASCII.GetString(magicString).TrimEnd('\0');
if (romFSHeader.MagicString != RomFSMagicNumber)
return null;
romFSHeader.MagicNumber = data.ReadUInt32();
if (romFSHeader.MagicNumber != RomFSSecondMagicNumber)
return null;
romFSHeader.MasterHashSize = data.ReadUInt32();
romFSHeader.Level1LogicalOffset = data.ReadUInt64();
romFSHeader.Level1HashdataSize = data.ReadUInt64();
romFSHeader.Level1BlockSizeLog2 = data.ReadUInt32();
romFSHeader.Reserved1 = data.ReadBytes(4);
romFSHeader.Level2LogicalOffset = data.ReadUInt64();
romFSHeader.Level2HashdataSize = data.ReadUInt64();
romFSHeader.Level2BlockSizeLog2 = data.ReadUInt32();
romFSHeader.Reserved2 = data.ReadBytes(4);
romFSHeader.Level3LogicalOffset = data.ReadUInt64();
romFSHeader.Level3HashdataSize = data.ReadUInt64();
romFSHeader.Level3BlockSizeLog2 = data.ReadUInt32();
romFSHeader.Reserved3 = data.ReadBytes(4);
romFSHeader.Reserved4 = data.ReadBytes(4);
romFSHeader.OptionalInfoSize = data.ReadUInt32();
return romFSHeader;
}
#endregion
}
}

View File

@@ -34,5 +34,10 @@ namespace BurnOutSharp.Models.N3DS
/// ExeFS headers associated with each partition
/// </summary>
public ExeFSHeader[] ExeFSHeaders { get; set; }
/// <summary>
/// RomFS headers associated with each partition
/// </summary>
public RomFSHeader[] RomFSHeaders { get; set; }
}
}

View File

@@ -5,8 +5,19 @@
/// used as external file storage.
/// </summary>
/// <see href="https://www.3dbrew.org/wiki/RomFS"/>
/// TODO: Implement the other parts of the RomFS tree structure
public sealed class RomFSHeader
{
/// <summary>
/// Magic "IVFC"
/// </summary>
public string MagicString;
/// <summary>
/// Magic number 0x10000
/// </summary>
public uint MagicNumber;
/// <summary>
/// Master hash size
/// </summary>

View File

@@ -204,6 +204,13 @@ namespace BurnOutSharp.Wrappers
#endregion
#region RomFS Headers
/// <inheritdoc cref="Models.N3DS.Cart.RomFSHeaders"/>
public Models.N3DS.RomFSHeader[] RomFSHeaders => _cart.RomFSHeaders;
#endregion
#endregion
#region Instance Variables
@@ -284,6 +291,7 @@ namespace BurnOutSharp.Wrappers
PrintPartitions();
PrintExtendedHeaders();
PrintExeFSHeaders();
PrintRomFSHeaders();
}
/// <summary>
@@ -641,7 +649,7 @@ namespace BurnOutSharp.Wrappers
}
/// <summary>
/// Print ExeFS header header information
/// Print ExeFS header information
/// </summary>
private void PrintExeFSHeaders()
{
@@ -688,6 +696,52 @@ namespace BurnOutSharp.Wrappers
Console.WriteLine();
}
/// <summary>
/// Print RomFS header information
/// </summary>
private void PrintRomFSHeaders()
{
Console.WriteLine(" RomFS Header Information:");
Console.WriteLine(" -------------------------");
if (RomFSHeaders == null || RomFSHeaders.Length == 0)
{
Console.WriteLine(" No RomFS headers");
}
else
{
for (int i = 0; i < RomFSHeaders.Length; i++)
{
var romFSHeader = RomFSHeaders[i];
Console.WriteLine($" RomFS Header {i}");
if (romFSHeader == null)
{
Console.WriteLine($" Unrecognized RomFS data, no data can be parsed");
}
else
{
Console.WriteLine(value: $" Magic string: {romFSHeader.MagicString}");
Console.WriteLine(value: $" Magic number: {romFSHeader.MagicNumber}");
Console.WriteLine(value: $" Master hash size: {romFSHeader.MasterHashSize}");
Console.WriteLine(value: $" Level 1 logical offset: {romFSHeader.Level1LogicalOffset}");
Console.WriteLine(value: $" Level 1 hashdata size: {romFSHeader.Level1HashdataSize}");
Console.WriteLine(value: $" Level 1 block size: {romFSHeader.Level1BlockSizeLog2}");
Console.WriteLine(value: $" Reserved 1: {BitConverter.ToString(romFSHeader.Reserved1).Replace('-', ' ')}");
Console.WriteLine(value: $" Level 2 logical offset: {romFSHeader.Level2LogicalOffset}");
Console.WriteLine(value: $" Level 2 hashdata size: {romFSHeader.Level2HashdataSize}");
Console.WriteLine(value: $" Level 2 block size: {romFSHeader.Level2BlockSizeLog2}");
Console.WriteLine(value: $" Reserved 2: {BitConverter.ToString(romFSHeader.Reserved2).Replace('-', ' ')}");
Console.WriteLine(value: $" Level 3 logical offset: {romFSHeader.Level3LogicalOffset}");
Console.WriteLine(value: $" Level 3 hashdata size: {romFSHeader.Level3HashdataSize}");
Console.WriteLine(value: $" Level 3 block size: {romFSHeader.Level3BlockSizeLog2}");
Console.WriteLine(value: $" Reserved 3: {BitConverter.ToString(romFSHeader.Reserved3).Replace('-', ' ')}");
Console.WriteLine(value: $" Reserved 4: {BitConverter.ToString(romFSHeader.Reserved4).Replace('-', ' ')}");
Console.WriteLine(value: $" Optional info size: {romFSHeader.OptionalInfoSize}");
}
}
}
Console.WriteLine();
}
#endregion
}
}