From 008629b61fd4d58c13d468e02df22c63e108e966 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Mon, 9 Jan 2023 14:32:40 -0800 Subject: [PATCH] Add all but directory sectors --- BurnOutSharp.Builders/CFB.cs | 120 ++++++++++++++++++++++++-- BurnOutSharp.Models/CFB/Constants.cs | 2 + BurnOutSharp.Models/CFB/FileHeader.cs | 2 +- 3 files changed, 117 insertions(+), 7 deletions(-) diff --git a/BurnOutSharp.Builders/CFB.cs b/BurnOutSharp.Builders/CFB.cs index b95368ba..8d58f9fe 100644 --- a/BurnOutSharp.Builders/CFB.cs +++ b/BurnOutSharp.Builders/CFB.cs @@ -1,5 +1,6 @@ +using System; +using System.Collections.Generic; using System.IO; -using System.Text; using BurnOutSharp.Models.CFB; using BurnOutSharp.Utilities; using static BurnOutSharp.Models.CFB.Constants; @@ -68,9 +69,96 @@ namespace BurnOutSharp.Builders #endregion - // TODO: Implement FAT sector parsing - // TODO: Implement Mini FAT sector parsing - // TODO: Implement DIFAT sector parsing + #region FAT Sectors + + // Create a FAT sector table + var fatSectors = new List(); + + // Loop through and add the FAT sectors + for (int i = 0; i < fileHeader.NumberOfFATSectors; i++) + { + // Try to get the FAT sector offset + long offset = (long)(fileHeader.DIFAT[i] * Math.Pow(2, fileHeader.SectorShift)); + if (offset < 0 || offset >= data.Length) + return null; + + // Seek to the offset + data.Seek(offset, SeekOrigin.Begin); + + // Try to parse the sectors + var sectorNumbers = ParseSector(data, fileHeader.SectorShift); + if (sectorNumbers == null) + return null; + + // Add the sector shifts + fatSectors.AddRange(sectorNumbers); + } + + // Assign the FAT sectors table + binary.FATSectors = fatSectors.ToArray(); + + #endregion + + #region Mini FAT Sectors + + // Get the offset of the first mini FAT sector + long firstMiniFatOffset = (long)(fileHeader.FirstMiniFATSectorLocation * Math.Pow(2, fileHeader.SectorShift)); + if (firstMiniFatOffset < 0 || firstMiniFatOffset >= data.Length) + return null; + + // Seek to the first mini FAT sector + data.Seek(firstMiniFatOffset, SeekOrigin.Begin); + + // Create a mini FAT sector table + var miniFatSectors = new List(); + + // Loop through and add the mini FAT sectors + for (int i = 0; i < fileHeader.NumberOfMiniFATSectors; i++) + { + // Try to parse the sectors + var sectorNumbers = ParseSector(data, fileHeader.SectorShift); + if (sectorNumbers == null) + return null; + + // Add the sector shifts + miniFatSectors.AddRange(sectorNumbers); + } + + // Assign the mini FAT sectors table + binary.MiniFATSectors = miniFatSectors.ToArray(); + + #endregion + + #region DIFAT Sectors + + // Get the offset of the first DIFAT sector + long firstDifatOffset = (long)(fileHeader.FirstDIFATSectorLocation * Math.Pow(2, fileHeader.SectorShift)); + if (firstDifatOffset < 0 || firstDifatOffset >= data.Length) + return null; + + // Seek to the first DIFAT sector + data.Seek(firstDifatOffset, SeekOrigin.Begin); + + // Create a DIFAT sector table + var difatSectors = new List(); + + // Loop through and add the DIFAT sectors + for (int i = 0; i < fileHeader.NumberOfMiniFATSectors; i++) + { + // Try to parse the sectors + var sectorNumbers = ParseSector(data, fileHeader.SectorShift); + if (sectorNumbers == null) + return null; + + // Add the sector shifts + difatSectors.AddRange(sectorNumbers); + } + + // Assign the DIFAT sectors table + binary.DIFATSectors = difatSectors.ToArray(); + + #endregion + // TODO: Implement directory sector parsing return binary; @@ -86,8 +174,8 @@ namespace BurnOutSharp.Builders // TODO: Use marshalling here instead of building FileHeader header = new FileHeader(); - header.Signature = data.ReadBytes(8); - if (header.Signature != SignatureBytes) + header.Signature = data.ReadUInt64(); + if (header.Signature != SignatureUInt64) return null; header.CLSID = data.ReadGuid(); @@ -133,6 +221,26 @@ namespace BurnOutSharp.Builders return header; } + /// + /// Parse a Stream into a sector full of sector numbers + /// + /// Stream to parse + /// Sector shift from the header + /// Filled sector full of sector numbers on success, null on error + private static SectorNumber[] ParseSector(Stream data, ushort sectorShift) + { + // TODO: Use marshalling here instead of building + int sectorCount = (int)(Math.Pow(2, sectorShift) / sizeof(uint)); + SectorNumber[] sectorNumbers = new SectorNumber[sectorCount]; + + for (int i = 0; i < sectorNumbers.Length; i++) + { + sectorNumbers[i] = (SectorNumber)data.ReadUInt32(); + } + + return sectorNumbers; + } + #endregion } } diff --git a/BurnOutSharp.Models/CFB/Constants.cs b/BurnOutSharp.Models/CFB/Constants.cs index 59e93f01..3d15c16f 100644 --- a/BurnOutSharp.Models/CFB/Constants.cs +++ b/BurnOutSharp.Models/CFB/Constants.cs @@ -3,5 +3,7 @@ namespace BurnOutSharp.Models.CFB public static class Constants { public static readonly byte[] SignatureBytes = new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }; + + public const ulong SignatureUInt64 = 0xE11AB1A1E011CFD0; } } \ No newline at end of file diff --git a/BurnOutSharp.Models/CFB/FileHeader.cs b/BurnOutSharp.Models/CFB/FileHeader.cs index b8ea297a..931024e2 100644 --- a/BurnOutSharp.Models/CFB/FileHeader.cs +++ b/BurnOutSharp.Models/CFB/FileHeader.cs @@ -9,7 +9,7 @@ namespace BurnOutSharp.Models.CFB /// IOdentification signature for the compound file structure, and MUST be /// set to the value 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1. /// - public byte[] Signature; + public ulong Signature; /// /// Reserved and unused class ID that MUST be set to all zeroes (CLSID_NULL)