Add ExeFS header parsing

This commit is contained in:
Matt Nadareski
2023-01-07 22:44:31 -08:00
parent bf6f3bad46
commit 9a1bbd7e0d
3 changed files with 83 additions and 2 deletions

View File

@@ -106,6 +106,9 @@ namespace BurnOutSharp.Builders
#endregion
// Cache the media unit size for further use
long mediaUnitSize = (uint)(0x200 * Math.Pow(2, header.PartitionFlags[(int)NCSDFlags.MediaUnitSize]));
#region Extended Headers
// Create the extended header table
@@ -119,7 +122,6 @@ namespace BurnOutSharp.Builders
continue;
// Get the extended header offset
long mediaUnitSize = (uint)(0x200 * Math.Pow(2, header.PartitionFlags[(int)NCSDFlags.MediaUnitSize]));
long offset = (cart.Header.PartitionsTable[i].Offset * mediaUnitSize) + 0x200;
if (offset < 0 || offset >= data.Length)
continue;
@@ -133,7 +135,32 @@ namespace BurnOutSharp.Builders
#endregion
// TODO: Parse ExeFS file entries (decrypted only)
#region ExeFS Headers
// Create the ExeFS header table
cart.ExeFSHeaders = new ExeFSHeader[8];
// Iterate and build the ExeFS 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 ExeFS header offset
long offset = (cart.Header.PartitionsTable[i].Offset + cart.Partitions[i].ExeFSOffsetInMediaUnits) * mediaUnitSize;
if (offset < 0 || offset >= data.Length)
continue;
// Seek to the ExeFS header
data.Seek(offset, SeekOrigin.Begin);
// Parse the ExeFS header
cart.ExeFSHeaders[i] = ParseExeFSHeader(data);
}
#endregion
// TODO: Parse ExeFS filename table (decrypted only)
return cart;
@@ -579,6 +606,49 @@ namespace BurnOutSharp.Builders
return arm9AccessControl;
}
/// <summary>
/// Parse a Stream into an ExeFS header
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled ExeFS header on success, null on error</returns>
private static ExeFSHeader ParseExeFSHeader(Stream data)
{
// TODO: Use marshalling here instead of building
ExeFSHeader exeFSHeader = new ExeFSHeader();
exeFSHeader.FileHeaders = new ExeFSFileHeader[10];
for (int i = 0; i < 10; i++)
{
exeFSHeader.FileHeaders[i] = ParseExeFSFileHeader(data);
}
exeFSHeader.Reserved = data.ReadBytes(0x20);
exeFSHeader.FileHashes = new byte[10][];
for (int i = 0; i < 10; i++)
{
exeFSHeader.FileHashes[i] = data.ReadBytes(0x20);
}
return exeFSHeader;
}
/// <summary>
/// Parse a Stream into an ExeFS file header
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled ExeFS file header on success, null on error</returns>
private static ExeFSFileHeader ParseExeFSFileHeader(Stream data)
{
// TODO: Use marshalling here instead of building
ExeFSFileHeader exeFSFileHeader = new ExeFSFileHeader();
byte[] fileName = data.ReadBytes(8);
exeFSFileHeader.FileName = Encoding.ASCII.GetString(fileName).TrimEnd('\0');
exeFSFileHeader.FileOffset = data.ReadUInt32();
exeFSFileHeader.FileSize = data.ReadUInt32();
return exeFSFileHeader;
}
#endregion
}
}

View File

@@ -29,5 +29,10 @@ namespace BurnOutSharp.Models.N3DS
/// NCCH extended headers
/// </summary>
public NCCHExtendedHeader[] ExtendedHeaders { get; set; }
/// <summary>
/// ExeFS headers associated with each partition
/// </summary>
public ExeFSHeader[] ExeFSHeaders { get; set; }
}
}

View File

@@ -22,5 +22,11 @@
/// Reserved
/// </summary>
public byte[] Reserved;
/// <summary>
/// File hashes (10 hashes maximum, 32 bytes each, one for each header)
/// </summary>
/// <remarks>SHA-256 hashes</remarks>
public byte[][] FileHashes;
}
}