diff --git a/BurnOutSharp.Builders/N3DS.cs b/BurnOutSharp.Builders/N3DS.cs
index cc95b8cb..62abd79b 100644
--- a/BurnOutSharp.Builders/N3DS.cs
+++ b/BurnOutSharp.Builders/N3DS.cs
@@ -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;
}
+ ///
+ /// Parse a Stream into an RomFS header
+ ///
+ /// Stream to parse
+ /// Filled RomFS header on success, null on error
+ 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
}
}
diff --git a/BurnOutSharp.Models/N3DS/Cart.cs b/BurnOutSharp.Models/N3DS/Cart.cs
index 0d8afe13..c48751aa 100644
--- a/BurnOutSharp.Models/N3DS/Cart.cs
+++ b/BurnOutSharp.Models/N3DS/Cart.cs
@@ -34,5 +34,10 @@ namespace BurnOutSharp.Models.N3DS
/// ExeFS headers associated with each partition
///
public ExeFSHeader[] ExeFSHeaders { get; set; }
+
+ ///
+ /// RomFS headers associated with each partition
+ ///
+ public RomFSHeader[] RomFSHeaders { get; set; }
}
}
\ No newline at end of file
diff --git a/BurnOutSharp.Models/N3DS/RomFSHeader.cs b/BurnOutSharp.Models/N3DS/RomFSHeader.cs
index a951cd23..80ea79ad 100644
--- a/BurnOutSharp.Models/N3DS/RomFSHeader.cs
+++ b/BurnOutSharp.Models/N3DS/RomFSHeader.cs
@@ -5,8 +5,19 @@
/// used as external file storage.
///
///
+ /// TODO: Implement the other parts of the RomFS tree structure
public sealed class RomFSHeader
{
+ ///
+ /// Magic "IVFC"
+ ///
+ public string MagicString;
+
+ ///
+ /// Magic number 0x10000
+ ///
+ public uint MagicNumber;
+
///
/// Master hash size
///
diff --git a/BurnOutSharp.Wrappers/N3DS.cs b/BurnOutSharp.Wrappers/N3DS.cs
index c6778498..dc7acd8e 100644
--- a/BurnOutSharp.Wrappers/N3DS.cs
+++ b/BurnOutSharp.Wrappers/N3DS.cs
@@ -204,6 +204,13 @@ namespace BurnOutSharp.Wrappers
#endregion
+ #region RomFS Headers
+
+ ///
+ public Models.N3DS.RomFSHeader[] RomFSHeaders => _cart.RomFSHeaders;
+
+ #endregion
+
#endregion
#region Instance Variables
@@ -284,6 +291,7 @@ namespace BurnOutSharp.Wrappers
PrintPartitions();
PrintExtendedHeaders();
PrintExeFSHeaders();
+ PrintRomFSHeaders();
}
///
@@ -641,7 +649,7 @@ namespace BurnOutSharp.Wrappers
}
///
- /// Print ExeFS header header information
+ /// Print ExeFS header information
///
private void PrintExeFSHeaders()
{
@@ -688,6 +696,52 @@ namespace BurnOutSharp.Wrappers
Console.WriteLine();
}
+ ///
+ /// Print RomFS header information
+ ///
+ 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
}
}
\ No newline at end of file