From e36822a19c06f7e2060938e87fbe10637fac0288 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Thu, 31 Jul 2025 08:57:35 -0400 Subject: [PATCH] Add more extension properties; clean up --- SabreTools.Serialization/Wrappers/BSP.cs | 17 +- SabreTools.Serialization/Wrappers/CFB.cs | 4 - SabreTools.Serialization/Wrappers/CHD.cs | 20 +- SabreTools.Serialization/Wrappers/GCF.cs | 7 +- .../Wrappers/InstallShieldCabinet.cs | 49 +- SabreTools.Serialization/Wrappers/LZKWAJ.cs | 32 +- SabreTools.Serialization/Wrappers/LZSZDD.cs | 11 +- SabreTools.Serialization/Wrappers/Nitro.cs | 54 +- .../Wrappers/PortableExecutable.cs | 475 ++++++++---------- SabreTools.Serialization/Wrappers/Quantum.cs | 31 +- SabreTools.Serialization/Wrappers/VBSP.cs | 17 +- SabreTools.Serialization/Wrappers/VPK.cs | 15 +- SabreTools.Serialization/Wrappers/WAD3.cs | 17 +- SabreTools.Serialization/Wrappers/XZP.cs | 24 +- 14 files changed, 375 insertions(+), 398 deletions(-) diff --git a/SabreTools.Serialization/Wrappers/BSP.cs b/SabreTools.Serialization/Wrappers/BSP.cs index a42051c9..2dacbb1b 100644 --- a/SabreTools.Serialization/Wrappers/BSP.cs +++ b/SabreTools.Serialization/Wrappers/BSP.cs @@ -12,6 +12,13 @@ namespace SabreTools.Serialization.Wrappers #endregion + #region Extension Properties + + /// + public BspLumpEntry[]? Lumps => Model.Header?.Lumps; + + #endregion + #region Constructors /// @@ -86,12 +93,12 @@ namespace SabreTools.Serialization.Wrappers public bool ExtractAllLumps(string outputDirectory) { // If we have no lumps - if (Model.Header?.Lumps == null || Model.Header.Lumps.Length == 0) + if (Lumps == null || Lumps.Length == 0) return false; // Loop through and extract all lumps to the output bool allExtracted = true; - for (int i = 0; i < Model.Header.Lumps.Length; i++) + for (int i = 0; i < Lumps.Length; i++) { allExtracted &= ExtractLump(i, outputDirectory); } @@ -108,15 +115,15 @@ namespace SabreTools.Serialization.Wrappers public bool ExtractLump(int index, string outputDirectory) { // If we have no lumps - if (Model.Header?.Lumps == null || Model.Header.Lumps.Length == 0) + if (Lumps == null || Lumps.Length == 0) return false; // If the lumps index is invalid - if (index < 0 || index >= Model.Header.Lumps.Length) + if (index < 0 || index >= Lumps.Length) return false; // Read the data - var lump = Model.Header.Lumps[index]; + var lump = Lumps[index]; var data = ReadFromDataSource(lump.Offset, lump.Length); if (data == null) return false; diff --git a/SabreTools.Serialization/Wrappers/CFB.cs b/SabreTools.Serialization/Wrappers/CFB.cs index c78fcdc7..b47cc79e 100644 --- a/SabreTools.Serialization/Wrappers/CFB.cs +++ b/SabreTools.Serialization/Wrappers/CFB.cs @@ -391,10 +391,6 @@ namespace SabreTools.Serialization.Wrappers /// Ordered list of sector numbers, null on error public byte[]? GetMiniFATSectorChainData(SectorNumber startingSector) { - // Ignore invalid data - if (Model?.Header == null) - return null; - // Validate the mini stream data if (MiniStreamData == null) return null; diff --git a/SabreTools.Serialization/Wrappers/CHD.cs b/SabreTools.Serialization/Wrappers/CHD.cs index 81c99897..8a7b2972 100644 --- a/SabreTools.Serialization/Wrappers/CHD.cs +++ b/SabreTools.Serialization/Wrappers/CHD.cs @@ -52,24 +52,8 @@ namespace SabreTools.Serialization.Wrappers } } - /// - /// CHD version - /// - public int Version - { - get - { - return Model switch - { - HeaderV1 => 1, - HeaderV2 => 2, - HeaderV3 => 3, - HeaderV4 => 4, - HeaderV5 => 5, - _ => 0, - }; - } - } + /// + public uint Version => Model.Version; #endregion diff --git a/SabreTools.Serialization/Wrappers/GCF.cs b/SabreTools.Serialization/Wrappers/GCF.cs index 069ff9f8..aec5c662 100644 --- a/SabreTools.Serialization/Wrappers/GCF.cs +++ b/SabreTools.Serialization/Wrappers/GCF.cs @@ -143,6 +143,9 @@ namespace SabreTools.Serialization.Wrappers } } + /// + public uint BlockSize => Model.DataBlockHeader?.BlockSize ?? 0; + #endregion #region Instance Variables @@ -283,7 +286,7 @@ namespace SabreTools.Serialization.Wrappers { long dataBlockOffset = DataBlockOffsets[dataBlockIndex++]; dataBlockOffsets.Add(dataBlockOffset); - blockEntrySize -= Model.DataBlockHeader?.BlockSize ?? 0; + blockEntrySize -= BlockSize; } } @@ -314,7 +317,7 @@ namespace SabreTools.Serialization.Wrappers long fileSize = file.Size; for (int i = 0; i < dataBlockOffsets.Count; i++) { - int readSize = (int)Math.Min(Model.DataBlockHeader?.BlockSize ?? 0, fileSize); + int readSize = (int)Math.Min(BlockSize, fileSize); var data = ReadFromDataSource((int)dataBlockOffsets[i], readSize); if (data == null) return false; diff --git a/SabreTools.Serialization/Wrappers/InstallShieldCabinet.cs b/SabreTools.Serialization/Wrappers/InstallShieldCabinet.cs index 92e27f87..1a19f6ad 100644 --- a/SabreTools.Serialization/Wrappers/InstallShieldCabinet.cs +++ b/SabreTools.Serialization/Wrappers/InstallShieldCabinet.cs @@ -24,21 +24,33 @@ namespace SabreTools.Serialization.Wrappers /// Only used in multi-file public InstallShieldCabinet? Next { get; set; } + /// + public Component[]? Components => Model.Components; + /// /// Number of components in the cabinet set /// - public int ComponentCount => Model.Components?.Length ?? 0; + public int ComponentCount => Components?.Length ?? 0; /// /// Number of directories in the cabinet set /// public ushort DirectoryCount => Model.Descriptor?.DirectoryCount ?? 0; + /// + public string[]? DirectoryNames => Model.DirectoryNames; + /// /// Number of files in the cabinet set /// public uint FileCount => Model.Descriptor?.FileCount ?? 0; + /// + public FileDescriptor[]? FileDescriptors => Model.FileDescriptors; + + /// + public FileGroup[]? FileGroups => Model.FileGroups; + /// /// Number of file groups in the cabinet set /// @@ -249,13 +261,13 @@ namespace SabreTools.Serialization.Wrappers /// public string? GetComponentName(int index) { - if (Model.Components == null) + if (Components == null) return null; - if (index < 0 || index >= Model.Components.Length) + if (index < 0 || index >= ComponentCount) return null; - var component = Model.Components[index]; + var component = Components[index]; if (component?.Identifier == null) return null; @@ -271,13 +283,13 @@ namespace SabreTools.Serialization.Wrappers /// public string? GetDirectoryName(int index) { - if (Model.DirectoryNames == null) + if (DirectoryNames == null) return null; - if (index < 0 || index >= Model.DirectoryNames.Length) + if (index < 0 || index >= DirectoryNames.Length) return null; - return Model.DirectoryNames[index]; + return DirectoryNames[index]; } /// @@ -302,10 +314,7 @@ namespace SabreTools.Serialization.Wrappers /// public bool FileIsValid(int index) { - if (Model.Descriptor == null) - return false; - - if (index < 0 || index > Model.Descriptor.FileCount) + if (index < 0 || index > FileCount) return false; FileDescriptor? descriptor = GetFileDescriptor(index); @@ -345,13 +354,13 @@ namespace SabreTools.Serialization.Wrappers /// public FileDescriptor? GetFileDescriptor(int index) { - if (Model.FileDescriptors == null) + if (FileDescriptors == null) return null; - if (index < 0 || index >= Model.FileDescriptors.Length) + if (index < 0 || index >= FileDescriptors.Length) return null; - return Model.FileDescriptors[index]; + return FileDescriptors[index]; } /// @@ -424,13 +433,13 @@ namespace SabreTools.Serialization.Wrappers /// public FileGroup? GetFileGroup(int index) { - if (Model.FileGroups == null) + if (FileGroups == null) return null; - if (index < 0 || index >= Model.FileGroups.Length) + if (index < 0 || index >= FileGroups.Length) return null; - return Model.FileGroups[index]; + return FileGroups[index]; } /// @@ -438,10 +447,10 @@ namespace SabreTools.Serialization.Wrappers /// public FileGroup? GetFileGroup(string name) { - if (Model.FileGroups == null) + if (FileGroups == null) return null; - return Array.Find(Model.FileGroups, fg => fg != null && string.Equals(fg.Name, name)); + return Array.Find(FileGroups, fg => fg != null && string.Equals(fg.Name, name)); } /// @@ -449,7 +458,7 @@ namespace SabreTools.Serialization.Wrappers /// public FileGroup? GetFileGroupFromFile(int index) { - if (Model.FileGroups == null) + if (FileGroups == null) return null; if (index < 0 || index >= FileCount) diff --git a/SabreTools.Serialization/Wrappers/LZKWAJ.cs b/SabreTools.Serialization/Wrappers/LZKWAJ.cs index 79ab1d70..81ce0e57 100644 --- a/SabreTools.Serialization/Wrappers/LZKWAJ.cs +++ b/SabreTools.Serialization/Wrappers/LZKWAJ.cs @@ -13,6 +13,22 @@ namespace SabreTools.Serialization.Wrappers #endregion + #region Extension Properties + + /// + public KWAJCompressionType CompressionType => Model.Header?.CompressionType ?? KWAJCompressionType.NoCompression; + + /// + public ushort DataOffset => Model.Header?.DataOffset ?? 0; + + /// + public string? FileName => Model.HeaderExtensions?.FileName; + + /// + public string? FileExtension => Model.HeaderExtensions?.FileExtension; + + #endregion + #region Constructors /// @@ -87,17 +103,17 @@ namespace SabreTools.Serialization.Wrappers public bool Extract(string outputDirectory) { // Get the length of the compressed data - long compressedSize = Length - Model.Header!.DataOffset; - if (compressedSize < Model.Header.DataOffset) + long compressedSize = Length - DataOffset; + if (compressedSize < DataOffset) return false; // Read in the data as an array - byte[]? contents = ReadFromDataSource(Model.Header.DataOffset, (int)compressedSize); + byte[]? contents = ReadFromDataSource(DataOffset, (int)compressedSize); if (contents == null) return false; // Get the decompressor - var decompressor = Decompressor.CreateKWAJ(contents, Model.Header!.CompressionType); + var decompressor = Decompressor.CreateKWAJ(contents, CompressionType); if (decompressor == null) return false; @@ -106,11 +122,9 @@ namespace SabreTools.Serialization.Wrappers return false; // Create the full output path - string filename = "tempfile"; - if (Model.HeaderExtensions?.FileName != null) - filename = Model.HeaderExtensions.FileName; - if (Model.HeaderExtensions?.FileExtension != null) - filename += $".{Model.HeaderExtensions.FileExtension}"; + string filename = FileName ?? "tempfile"; + if (FileExtension != null) + filename += $".{FileExtension}"; // Ensure directory separators are consistent if (Path.DirectorySeparatorChar == '\\') diff --git a/SabreTools.Serialization/Wrappers/LZSZDD.cs b/SabreTools.Serialization/Wrappers/LZSZDD.cs index 7b700167..0c65f2e4 100644 --- a/SabreTools.Serialization/Wrappers/LZSZDD.cs +++ b/SabreTools.Serialization/Wrappers/LZSZDD.cs @@ -13,6 +13,13 @@ namespace SabreTools.Serialization.Wrappers #endregion + #region Extension Properties + + /// + public char LastChar => Model.Header?.LastChar ?? '\0'; + + #endregion + #region Constructors /// @@ -151,7 +158,7 @@ namespace SabreTools.Serialization.Wrappers if (extension.Length == 1) { if (extension == "_" || extension == "$") - return $"{Path.GetFileNameWithoutExtension(input)}.{char.ToLower(Model.Header!.LastChar)}"; + return $"{Path.GetFileNameWithoutExtension(input)}.{char.ToLower(LastChar)}"; return Path.GetFileNameWithoutExtension(input); } @@ -161,7 +168,7 @@ namespace SabreTools.Serialization.Wrappers return Path.GetFileNameWithoutExtension(input); // Handle replacing characters - char c = (char.IsUpper(input[0]) ? char.ToLower(Model.Header!.LastChar) : char.ToUpper(Model.Header!.LastChar)); + char c = (char.IsUpper(input[0]) ? char.ToLower(LastChar) : char.ToUpper(LastChar)); string text2 = extension.Substring(0, extension.Length - 1) + c; return Path.GetFileNameWithoutExtension(input) + "." + text2; } diff --git a/SabreTools.Serialization/Wrappers/Nitro.cs b/SabreTools.Serialization/Wrappers/Nitro.cs index 5cd3705d..41fdfe0a 100644 --- a/SabreTools.Serialization/Wrappers/Nitro.cs +++ b/SabreTools.Serialization/Wrappers/Nitro.cs @@ -19,6 +19,12 @@ namespace SabreTools.Serialization.Wrappers /// public CommonHeader? CommonHeader => Model.CommonHeader; + /// + public uint GameCode => Model.CommonHeader?.GameCode ?? 0; + + /// + public byte[]? SecureArea => Model.SecureArea; + #endregion #region Encryption process variables @@ -138,15 +144,15 @@ namespace SabreTools.Serialization.Wrappers private void EncryptARM9(byte[] tableData) { // If the secure area is invalid, nothing can be done - if (Model.SecureArea == null) + if (SecureArea == null) return; // Point to the beginning of the secure area int readOffset = 0; // Grab the first two blocks - uint p0 = Model.SecureArea.ReadUInt32(ref readOffset); - uint p1 = Model.SecureArea.ReadUInt32(ref readOffset); + uint p0 = SecureArea.ReadUInt32(ref readOffset); + uint p1 = SecureArea.ReadUInt32(ref readOffset); // Perform the initialization steps Init1(tableData); @@ -162,13 +168,13 @@ namespace SabreTools.Serialization.Wrappers uint size = 0x800 - 8; while (size > 0) { - p0 = Model.SecureArea.ReadUInt32(ref readOffset); - p1 = Model.SecureArea.ReadUInt32(ref readOffset); + p0 = SecureArea.ReadUInt32(ref readOffset); + p1 = SecureArea.ReadUInt32(ref readOffset); Encrypt(ref p1, ref p0); - Model.SecureArea.Write(ref writeOffset, p0); - Model.SecureArea.Write(ref writeOffset, p1); + SecureArea.Write(ref writeOffset, p0); + SecureArea.Write(ref writeOffset, p1); size -= 8; } @@ -177,8 +183,8 @@ namespace SabreTools.Serialization.Wrappers readOffset = 0; writeOffset = 0; - p0 = Model.SecureArea.ReadUInt32(ref readOffset); - p1 = Model.SecureArea.ReadUInt32(ref readOffset); + p0 = SecureArea.ReadUInt32(ref readOffset); + p1 = SecureArea.ReadUInt32(ref readOffset); if (p0 == 0xE7FFDEFF && p1 == 0xE7FFDEFF) { @@ -190,8 +196,8 @@ namespace SabreTools.Serialization.Wrappers Init1(tableData); Encrypt(ref p1, ref p0); - Model.SecureArea.Write(ref writeOffset, p0); - Model.SecureArea.Write(ref writeOffset, p1); + SecureArea.Write(ref writeOffset, p0); + SecureArea.Write(ref writeOffset, p1); } /// @@ -260,7 +266,7 @@ namespace SabreTools.Serialization.Wrappers private void DecryptARM9(byte[] tableData) { // If the secure area is invalid, nothing can be done - if (Model.SecureArea == null) + if (SecureArea == null) return; // Point to the beginning of the secure area @@ -268,8 +274,8 @@ namespace SabreTools.Serialization.Wrappers int writeOffset = 0; // Grab the first two blocks - uint p0 = Model.SecureArea.ReadUInt32(ref readOffset); - uint p1 = Model.SecureArea.ReadUInt32(ref readOffset); + uint p0 = SecureArea.ReadUInt32(ref readOffset); + uint p1 = SecureArea.ReadUInt32(ref readOffset); // Perform the initialization steps Init1(tableData); @@ -286,8 +292,8 @@ namespace SabreTools.Serialization.Wrappers p1 = 0xE7FFDEFF; } - Model.SecureArea.Write(ref writeOffset, p0); - Model.SecureArea.Write(ref writeOffset, p1); + SecureArea.Write(ref writeOffset, p0); + SecureArea.Write(ref writeOffset, p1); // Ensure alignment readOffset = 0x08; @@ -297,13 +303,13 @@ namespace SabreTools.Serialization.Wrappers uint size = 0x800 - 8; while (size > 0) { - p0 = Model.SecureArea.ReadUInt32(ref readOffset); - p1 = Model.SecureArea.ReadUInt32(ref readOffset); + p0 = SecureArea.ReadUInt32(ref readOffset); + p1 = SecureArea.ReadUInt32(ref readOffset); Decrypt(ref p1, ref p0); - Model.SecureArea.Write(ref writeOffset, p0); - Model.SecureArea.Write(ref writeOffset, p1); + SecureArea.Write(ref writeOffset, p0); + SecureArea.Write(ref writeOffset, p1); size -= 8; } @@ -341,15 +347,15 @@ namespace SabreTools.Serialization.Wrappers public bool? CheckIfDecrypted(out string? message) { // Return empty if the secure area is undefined - if (Model.SecureArea == null) + if (SecureArea == null) { message = "Secure area is undefined. Cannot be encrypted or decrypted."; return null; } int offset = 0; - uint firstValue = Model.SecureArea.ReadUInt32(ref offset); - uint secondValue = Model.SecureArea.ReadUInt32(ref offset); + uint firstValue = SecureArea.ReadUInt32(ref offset); + uint secondValue = SecureArea.ReadUInt32(ref offset); // Empty secure area standard if (firstValue == 0x00000000 && secondValue == 0x00000000) @@ -439,7 +445,7 @@ namespace SabreTools.Serialization.Wrappers private void Init1(byte[] tableData) { Buffer.BlockCopy(tableData, 0, _cardHash, 0, 4 * (1024 + 18)); - _arg2 = [Model.CommonHeader!.GameCode, Model.CommonHeader.GameCode >> 1, Model.CommonHeader.GameCode << 1]; + _arg2 = [GameCode, GameCode >> 1, GameCode << 1]; Init2(); Init2(); } diff --git a/SabreTools.Serialization/Wrappers/PortableExecutable.cs b/SabreTools.Serialization/Wrappers/PortableExecutable.cs index c912fb5f..db1aa344 100644 --- a/SabreTools.Serialization/Wrappers/PortableExecutable.cs +++ b/SabreTools.Serialization/Wrappers/PortableExecutable.cs @@ -21,100 +21,32 @@ namespace SabreTools.Serialization.Wrappers #region Extension Properties /// - /// Header padding data, if it exists + /// Dictionary of debug data /// - public byte[]? HeaderPaddingData + public Dictionary? DebugData { get { lock (_sourceDataLock) { - // If we already have cached data, just use that immediately - if (_headerPaddingData != null) - return _headerPaddingData; + // Use the cached data if possible + if (_debugData != null && _debugData.Count != 0) + return _debugData; - // TODO: Don't scan the known header data as well + // If we have no resource table, just return + if (DebugDirectoryTable == null || DebugDirectoryTable.Length == 0) + return null; - // If any required pieces are missing - if (Model.Stub?.Header == null) - return []; - if (Model.SectionTable == null) - return []; - - // Populate the raw header padding data based on the source - uint headerStartAddress = Model.Stub.Header.NewExeHeaderAddr; - uint firstSectionAddress = uint.MaxValue; - foreach (var s in Model.SectionTable) - { - if (s == null || s.PointerToRawData == 0) - continue; - if (s.PointerToRawData < headerStartAddress) - continue; - - if (s.PointerToRawData < firstSectionAddress) - firstSectionAddress = s.PointerToRawData; - } - - // Check if the header length is more than 0 before reading data - int headerLength = (int)(firstSectionAddress - headerStartAddress); - if (headerLength <= 0) - _headerPaddingData = []; - else - _headerPaddingData = ReadFromDataSource((int)headerStartAddress, headerLength); - - // Cache and return the header padding data, even if null - return _headerPaddingData; + // Otherwise, build and return the cached dictionary + ParseDebugTable(); + return _debugData; } } } - /// - /// Header padding strings, if they exist - /// - public List? HeaderPaddingStrings - { - get - { - lock (_sourceDataLock) - { - // If we already have cached data, just use that immediately - if (_headerPaddingStrings != null) - return _headerPaddingStrings; - - // TODO: Don't scan the known header data as well - - // If any required pieces are missing - if (Model.Stub?.Header == null) - return []; - if (Model.SectionTable == null) - return []; - - // Populate the header padding strings based on the source - uint headerStartAddress = Model.Stub.Header.NewExeHeaderAddr; - uint firstSectionAddress = uint.MaxValue; - foreach (var s in Model.SectionTable) - { - if (s == null || s.PointerToRawData == 0) - continue; - if (s.PointerToRawData < headerStartAddress) - continue; - - if (s.PointerToRawData < firstSectionAddress) - firstSectionAddress = s.PointerToRawData; - } - - // Check if the header length is more than 0 before reading strings - int headerLength = (int)(firstSectionAddress - headerStartAddress); - if (headerLength <= 0) - _headerPaddingStrings = []; - else - _headerPaddingStrings = ReadStringsFromDataSource((int)headerStartAddress, headerLength, charLimit: 3); - - // Cache and return the header padding data, even if null - return _headerPaddingStrings; - } - } - } + /// + public Models.PortableExecutable.DebugDirectoryEntry[]? DebugDirectoryTable + => Model.DebugTable?.DebugDirectoryTable; /// /// Entry point data, if it exists @@ -156,6 +88,105 @@ namespace SabreTools.Serialization.Wrappers } } + /// + /// Header padding data, if it exists + /// + public byte[]? HeaderPaddingData + { + get + { + lock (_sourceDataLock) + { + // If we already have cached data, just use that immediately + if (_headerPaddingData != null) + return _headerPaddingData; + + // TODO: Don't scan the known header data as well + + // If any required pieces are missing + if (Stub?.Header == null) + return []; + if (SectionTable == null) + return []; + + // Populate the raw header padding data based on the source + uint headerStartAddress = Stub.Header.NewExeHeaderAddr; + uint firstSectionAddress = uint.MaxValue; + foreach (var s in SectionTable) + { + if (s == null || s.PointerToRawData == 0) + continue; + if (s.PointerToRawData < headerStartAddress) + continue; + + if (s.PointerToRawData < firstSectionAddress) + firstSectionAddress = s.PointerToRawData; + } + + // Check if the header length is more than 0 before reading data + int headerLength = (int)(firstSectionAddress - headerStartAddress); + if (headerLength <= 0) + _headerPaddingData = []; + else + _headerPaddingData = ReadFromDataSource((int)headerStartAddress, headerLength); + + // Cache and return the header padding data, even if null + return _headerPaddingData; + } + } + } + + /// + /// Header padding strings, if they exist + /// + public List? HeaderPaddingStrings + { + get + { + lock (_sourceDataLock) + { + // If we already have cached data, just use that immediately + if (_headerPaddingStrings != null) + return _headerPaddingStrings; + + // TODO: Don't scan the known header data as well + + // If any required pieces are missing + if (Stub?.Header == null) + return []; + if (SectionTable == null) + return []; + + // Populate the header padding strings based on the source + uint headerStartAddress = Stub.Header.NewExeHeaderAddr; + uint firstSectionAddress = uint.MaxValue; + foreach (var s in SectionTable) + { + if (s == null || s.PointerToRawData == 0) + continue; + if (s.PointerToRawData < headerStartAddress) + continue; + + if (s.PointerToRawData < firstSectionAddress) + firstSectionAddress = s.PointerToRawData; + } + + // Check if the header length is more than 0 before reading strings + int headerLength = (int)(firstSectionAddress - headerStartAddress); + if (headerLength <= 0) + _headerPaddingStrings = []; + else + _headerPaddingStrings = ReadStringsFromDataSource((int)headerStartAddress, headerLength, charLimit: 3); + + // Cache and return the header padding data, even if null + return _headerPaddingStrings; + } + } + } + + /// + public Models.PortableExecutable.OptionalHeader? OptionalHeader => Model.OptionalHeader; + /// /// Address of the overlay, if it exists /// @@ -426,6 +457,12 @@ namespace SabreTools.Serialization.Wrappers } } + /// + public Models.PortableExecutable.SectionHeader[]? SectionTable => Model.SectionTable; + + /// + public Models.MSDOS.Executable? Stub => Model.Stub; + /// /// Stub executable data, if it exists /// @@ -439,12 +476,12 @@ namespace SabreTools.Serialization.Wrappers if (_stubExecutableData != null) return _stubExecutableData; - if (Model.Stub?.Header?.NewExeHeaderAddr == null) + if (Stub?.Header?.NewExeHeaderAddr == null) return null; // Populate the raw stub executable data based on the source int endOfStubHeader = 0x40; - int lengthOfStubExecutableData = (int)Model.Stub.Header.NewExeHeaderAddr - endOfStubHeader; + int lengthOfStubExecutableData = (int)Stub.Header.NewExeHeaderAddr - endOfStubHeader; _stubExecutableData = ReadFromDataSource(endOfStubHeader, lengthOfStubExecutableData); // Cache and return the stub executable data, even if null @@ -453,31 +490,6 @@ namespace SabreTools.Serialization.Wrappers } } - /// - /// Dictionary of debug data - /// - public Dictionary? DebugData - { - get - { - lock (_sourceDataLock) - { - // Use the cached data if possible - if (_debugData != null && _debugData.Count != 0) - return _debugData; - - // If we have no resource table, just return - if (Model.DebugTable?.DebugDirectoryTable == null - || Model.DebugTable.DebugDirectoryTable.Length == 0) - return null; - - // Otherwise, build and return the cached dictionary - ParseDebugTable(); - return _debugData; - } - } - } - /// /// Dictionary of resource data /// @@ -1003,13 +1015,13 @@ namespace SabreTools.Serialization.Wrappers private void ParseDebugTable() { // If there is no debug table - if (Model.DebugTable?.DebugDirectoryTable == null) + if (DebugDirectoryTable == null || DebugDirectoryTable.Length == 0) return; // Loop through all debug table entries - for (int i = 0; i < Model.DebugTable.DebugDirectoryTable.Length; i++) + for (int i = 0; i < DebugDirectoryTable.Length; i++) { - var entry = Model.DebugTable.DebugDirectoryTable[i]; + var entry = DebugDirectoryTable[i]; uint address = entry.PointerToRawData; uint size = entry.SizeOfData; @@ -1446,19 +1458,19 @@ namespace SabreTools.Serialization.Wrappers public int FindEntryPointSectionIndex() { // If the section table is missing - if (Model.SectionTable == null) + if (SectionTable == null) return -1; // If the address is missing - if (Model.OptionalHeader?.AddressOfEntryPoint == null) + if (OptionalHeader?.AddressOfEntryPoint == null) return -1; // If we don't have an entry point - if (Model.OptionalHeader.AddressOfEntryPoint.ConvertVirtualAddress(Model.SectionTable) == 0) + if (OptionalHeader.AddressOfEntryPoint.ConvertVirtualAddress(SectionTable) == 0) return -1; // Otherwise, find the section it exists within - return Model.OptionalHeader.AddressOfEntryPoint.ContainingSectionIndex(Model.SectionTable); + return OptionalHeader.AddressOfEntryPoint.ContainingSectionIndex(SectionTable); } /// @@ -1470,7 +1482,7 @@ namespace SabreTools.Serialization.Wrappers public Models.PortableExecutable.SectionHeader? GetFirstSection(string? name, bool exact = false) { // If we have no sections - if (SectionNames == null || SectionNames.Length == 0 || Model.SectionTable == null || Model.SectionTable.Length == 0) + if (SectionNames == null || SectionNames.Length == 0 || SectionTable == null || SectionTable.Length == 0) return null; // If the section doesn't exist @@ -1483,7 +1495,7 @@ namespace SabreTools.Serialization.Wrappers return null; // Return the section - return Model.SectionTable[index]; + return SectionTable[index]; } /// @@ -1495,7 +1507,7 @@ namespace SabreTools.Serialization.Wrappers public Models.PortableExecutable.SectionHeader? GetLastSection(string? name, bool exact = false) { // If we have no sections - if (SectionNames == null || SectionNames.Length == 0 || Model.SectionTable == null || Model.SectionTable.Length == 0) + if (SectionNames == null || SectionNames.Length == 0 || SectionTable == null || SectionTable.Length == 0) return null; // If the section doesn't exist @@ -1508,7 +1520,7 @@ namespace SabreTools.Serialization.Wrappers return null; // Return the section - return Model.SectionTable[index]; + return SectionTable[index]; } /// @@ -1519,15 +1531,15 @@ namespace SabreTools.Serialization.Wrappers public Models.PortableExecutable.SectionHeader? GetSection(int index) { // If we have no sections - if (Model.SectionTable == null || Model.SectionTable.Length == 0) + if (SectionTable == null || SectionTable.Length == 0) return null; // If the section doesn't exist - if (index < 0 || index >= Model.SectionTable.Length) + if (index < 0 || index >= SectionTable.Length) return null; // Return the section - return Model.SectionTable[index]; + return SectionTable[index]; } /// @@ -1539,7 +1551,7 @@ namespace SabreTools.Serialization.Wrappers public byte[]? GetFirstSectionData(string? name, bool exact = false) { // If we have no sections - if (SectionNames == null || SectionNames.Length == 0 || Model.SectionTable == null || Model.SectionTable.Length == 0) + if (SectionNames == null || SectionNames.Length == 0 || SectionTable == null || SectionTable.Length == 0) return null; // If the section doesn't exist @@ -1560,7 +1572,7 @@ namespace SabreTools.Serialization.Wrappers public byte[]? GetLastSectionData(string? name, bool exact = false) { // If we have no sections - if (SectionNames == null || SectionNames.Length == 0 || Model.SectionTable == null || Model.SectionTable.Length == 0) + if (SectionNames == null || SectionNames.Length == 0 || SectionTable == null || SectionTable.Length == 0) return null; // If the section doesn't exist @@ -1580,19 +1592,19 @@ namespace SabreTools.Serialization.Wrappers public byte[]? GetSectionData(int index) { // If we have no sections - if (SectionNames == null || SectionNames.Length == 0 || Model.SectionTable == null || Model.SectionTable.Length == 0) + if (SectionNames == null || SectionNames.Length == 0 || SectionTable == null || SectionTable.Length == 0) return null; // If the section doesn't exist - if (index < 0 || index >= Model.SectionTable.Length) + if (index < 0 || index >= SectionTable.Length) return null; // Get the section data from the table - var section = Model.SectionTable[index]; + var section = SectionTable[index]; if (section == null) return null; - uint address = section.VirtualAddress.ConvertVirtualAddress(Model.SectionTable); + uint address = section.VirtualAddress.ConvertVirtualAddress(SectionTable); if (address == 0) return null; @@ -1625,7 +1637,7 @@ namespace SabreTools.Serialization.Wrappers public List? GetFirstSectionStrings(string? name, bool exact = false) { // If we have no sections - if (SectionNames == null || SectionNames.Length == 0 || Model.SectionTable == null || Model.SectionTable.Length == 0) + if (SectionNames == null || SectionNames.Length == 0 || SectionTable == null || SectionTable.Length == 0) return null; // If the section doesn't exist @@ -1646,7 +1658,7 @@ namespace SabreTools.Serialization.Wrappers public List? GetLastSectionStrings(string? name, bool exact = false) { // If we have no sections - if (SectionNames == null || SectionNames.Length == 0 || Model.SectionTable == null || Model.SectionTable.Length == 0) + if (SectionNames == null || SectionNames.Length == 0 || SectionTable == null || SectionTable.Length == 0) return null; // If the section doesn't exist @@ -1666,19 +1678,19 @@ namespace SabreTools.Serialization.Wrappers public List? GetSectionStrings(int index) { // If we have no sections - if (SectionNames == null || SectionNames.Length == 0 || Model.SectionTable == null || Model.SectionTable.Length == 0) + if (SectionNames == null || SectionNames.Length == 0 || SectionTable == null || SectionTable.Length == 0) return null; // If the section doesn't exist - if (index < 0 || index >= Model.SectionTable.Length) + if (index < 0 || index >= SectionTable.Length) return null; // Get the section data from the table - var section = Model.SectionTable[index]; + var section = SectionTable[index]; if (section == null) return null; - uint address = section.VirtualAddress.ConvertVirtualAddress(Model.SectionTable); + uint address = section.VirtualAddress.ConvertVirtualAddress(SectionTable); if (address == 0) return null; @@ -1706,6 +1718,41 @@ namespace SabreTools.Serialization.Wrappers #region Tables + /// + /// Get the table based on index, if possible + /// + /// Index of the table to check for + /// Table on success, null on error + public Models.PortableExecutable.DataDirectory? GetTable(int index) + { + // If the table doesn't exist + if (OptionalHeader == null || index < 0 || index > 16) + return null; + + return index switch + { + 1 => OptionalHeader.ExportTable, + 2 => OptionalHeader.ImportTable, + 3 => OptionalHeader.ResourceTable, + 4 => OptionalHeader.ExceptionTable, + 5 => OptionalHeader.CertificateTable, + 6 => OptionalHeader.BaseRelocationTable, + 7 => OptionalHeader.Debug, + 8 => null, // Architecture Table + 9 => OptionalHeader.GlobalPtr, + 10 => OptionalHeader.ThreadLocalStorageTable, + 11 => OptionalHeader.LoadConfigTable, + 12 => OptionalHeader.BoundImport, + 13 => OptionalHeader.ImportAddressTable, + 14 => OptionalHeader.DelayImportDescriptor, + 15 => OptionalHeader.CLRRuntimeHeader, + 16 => null, // Reserved + + // Should never be possible + _ => null, + }; + } + /// /// Get the table data based on index, if possible /// @@ -1714,85 +1761,22 @@ namespace SabreTools.Serialization.Wrappers public byte[]? GetTableData(int index) { // If the table doesn't exist - if (Model.OptionalHeader == null || index < 0 || index > 16) + if (OptionalHeader == null || index < 0 || index > 16) return null; + // Get the table from the optional header + var table = GetTable(index); + // Get the virtual address and size from the entries - uint virtualAddress = 0, size = 0; - switch (index) - { - case 1: - virtualAddress = Model.OptionalHeader.ExportTable?.VirtualAddress ?? 0; - size = Model.OptionalHeader.ExportTable?.Size ?? 0; - break; - case 2: - virtualAddress = Model.OptionalHeader.ImportTable?.VirtualAddress ?? 0; - size = Model.OptionalHeader.ImportTable?.Size ?? 0; - break; - case 3: - virtualAddress = Model.OptionalHeader.ResourceTable?.VirtualAddress ?? 0; - size = Model.OptionalHeader.ResourceTable?.Size ?? 0; - break; - case 4: - virtualAddress = Model.OptionalHeader.ExceptionTable?.VirtualAddress ?? 0; - size = Model.OptionalHeader.ExceptionTable?.Size ?? 0; - break; - case 5: - virtualAddress = Model.OptionalHeader.CertificateTable?.VirtualAddress ?? 0; - size = Model.OptionalHeader.CertificateTable?.Size ?? 0; - break; - case 6: - virtualAddress = Model.OptionalHeader.BaseRelocationTable?.VirtualAddress ?? 0; - size = Model.OptionalHeader.BaseRelocationTable?.Size ?? 0; - break; - case 7: - virtualAddress = Model.OptionalHeader.Debug?.VirtualAddress ?? 0; - size = Model.OptionalHeader.Debug?.Size ?? 0; - break; - case 8: // Architecture Table - virtualAddress = 0; - size = 0; - break; - case 9: - virtualAddress = Model.OptionalHeader.GlobalPtr?.VirtualAddress ?? 0; - size = Model.OptionalHeader.GlobalPtr?.Size ?? 0; - break; - case 10: - virtualAddress = Model.OptionalHeader.ThreadLocalStorageTable?.VirtualAddress ?? 0; - size = Model.OptionalHeader.ThreadLocalStorageTable?.Size ?? 0; - break; - case 11: - virtualAddress = Model.OptionalHeader.LoadConfigTable?.VirtualAddress ?? 0; - size = Model.OptionalHeader.LoadConfigTable?.Size ?? 0; - break; - case 12: - virtualAddress = Model.OptionalHeader.BoundImport?.VirtualAddress ?? 0; - size = Model.OptionalHeader.BoundImport?.Size ?? 0; - break; - case 13: - virtualAddress = Model.OptionalHeader.ImportAddressTable?.VirtualAddress ?? 0; - size = Model.OptionalHeader.ImportAddressTable?.Size ?? 0; - break; - case 14: - virtualAddress = Model.OptionalHeader.DelayImportDescriptor?.VirtualAddress ?? 0; - size = Model.OptionalHeader.DelayImportDescriptor?.Size ?? 0; - break; - case 15: - virtualAddress = Model.OptionalHeader.CLRRuntimeHeader?.VirtualAddress ?? 0; - size = Model.OptionalHeader.CLRRuntimeHeader?.Size ?? 0; - break; - case 16: // Reserved - virtualAddress = 0; - size = 0; - break; - } + uint virtualAddress = table?.VirtualAddress ?? 0; + uint size = table?.Size ?? 0; // If there is no section table - if (Model.SectionTable == null) + if (SectionTable == null) return null; // Get the physical address from the virtual one - uint address = virtualAddress.ConvertVirtualAddress(Model.SectionTable); + uint address = virtualAddress.ConvertVirtualAddress(SectionTable); if (address == 0 || size == 0) return null; @@ -1822,85 +1806,22 @@ namespace SabreTools.Serialization.Wrappers public List? GetTableStrings(int index) { // If the table doesn't exist - if (Model.OptionalHeader == null || index < 0 || index > 16) + if (OptionalHeader == null || index < 0 || index > 16) return null; + // Get the table from the optional header + var table = GetTable(index); + // Get the virtual address and size from the entries - uint virtualAddress = 0, size = 0; - switch (index) - { - case 1: - virtualAddress = Model.OptionalHeader.ExportTable?.VirtualAddress ?? 0; - size = Model.OptionalHeader.ExportTable?.Size ?? 0; - break; - case 2: - virtualAddress = Model.OptionalHeader.ImportTable?.VirtualAddress ?? 0; - size = Model.OptionalHeader.ImportTable?.Size ?? 0; - break; - case 3: - virtualAddress = Model.OptionalHeader.ResourceTable?.VirtualAddress ?? 0; - size = Model.OptionalHeader.ResourceTable?.Size ?? 0; - break; - case 4: - virtualAddress = Model.OptionalHeader.ExceptionTable?.VirtualAddress ?? 0; - size = Model.OptionalHeader.ExceptionTable?.Size ?? 0; - break; - case 5: - virtualAddress = Model.OptionalHeader.CertificateTable?.VirtualAddress ?? 0; - size = Model.OptionalHeader.CertificateTable?.Size ?? 0; - break; - case 6: - virtualAddress = Model.OptionalHeader.BaseRelocationTable?.VirtualAddress ?? 0; - size = Model.OptionalHeader.BaseRelocationTable?.Size ?? 0; - break; - case 7: - virtualAddress = Model.OptionalHeader.Debug?.VirtualAddress ?? 0; - size = Model.OptionalHeader.Debug?.Size ?? 0; - break; - case 8: // Architecture Table - virtualAddress = 0; - size = 0; - break; - case 9: - virtualAddress = Model.OptionalHeader.GlobalPtr?.VirtualAddress ?? 0; - size = Model.OptionalHeader.GlobalPtr?.Size ?? 0; - break; - case 10: - virtualAddress = Model.OptionalHeader.ThreadLocalStorageTable?.VirtualAddress ?? 0; - size = Model.OptionalHeader.ThreadLocalStorageTable?.Size ?? 0; - break; - case 11: - virtualAddress = Model.OptionalHeader.LoadConfigTable?.VirtualAddress ?? 0; - size = Model.OptionalHeader.LoadConfigTable?.Size ?? 0; - break; - case 12: - virtualAddress = Model.OptionalHeader.BoundImport?.VirtualAddress ?? 0; - size = Model.OptionalHeader.BoundImport?.Size ?? 0; - break; - case 13: - virtualAddress = Model.OptionalHeader.ImportAddressTable?.VirtualAddress ?? 0; - size = Model.OptionalHeader.ImportAddressTable?.Size ?? 0; - break; - case 14: - virtualAddress = Model.OptionalHeader.DelayImportDescriptor?.VirtualAddress ?? 0; - size = Model.OptionalHeader.DelayImportDescriptor?.Size ?? 0; - break; - case 15: - virtualAddress = Model.OptionalHeader.CLRRuntimeHeader?.VirtualAddress ?? 0; - size = Model.OptionalHeader.CLRRuntimeHeader?.Size ?? 0; - break; - case 16: // Reserved - virtualAddress = 0; - size = 0; - break; - } + uint virtualAddress = table?.VirtualAddress ?? 0; + uint size = table?.Size ?? 0; // If there is no section table - if (Model.SectionTable == null) + if (SectionTable == null) return null; // Get the physical address from the virtual one - uint address = virtualAddress.ConvertVirtualAddress(Model.SectionTable); + uint address = virtualAddress.ConvertVirtualAddress(SectionTable); if (address == 0 || size == 0) return null; diff --git a/SabreTools.Serialization/Wrappers/Quantum.cs b/SabreTools.Serialization/Wrappers/Quantum.cs index 45dc2138..140cb9b2 100644 --- a/SabreTools.Serialization/Wrappers/Quantum.cs +++ b/SabreTools.Serialization/Wrappers/Quantum.cs @@ -12,6 +12,22 @@ namespace SabreTools.Serialization.Wrappers #endregion + #region Extension Properties + + /// + public long CompressedDataOffset => Model.CompressedDataOffset; + + /// + public ushort FileCount => Model.Header?.FileCount ?? 0; + + /// + public FileDescriptor[] FileList => Model.FileList ?? []; + + /// + public Header? Header => Model.Header; + + #endregion + #region Constructors /// @@ -76,19 +92,6 @@ namespace SabreTools.Serialization.Wrappers #endregion - #region Extension Properties - - /// - public long CompressedDataOffset => Model.CompressedDataOffset; - - /// - public ushort FileCount => Model.Header?.FileCount ?? 0; - - /// - public FileDescriptor[] FileList => Model.FileList ?? []; - - #endregion - #region Extraction /// @@ -121,7 +124,7 @@ namespace SabreTools.Serialization.Wrappers public bool ExtractFile(int index, string outputDirectory) { // If we have no files - if (Model.Header == null || FileCount == 0 || FileList == null || FileList.Length == 0) + if (Header == null || FileCount == 0 || FileList == null || FileList.Length == 0) return false; // If we have an invalid index diff --git a/SabreTools.Serialization/Wrappers/VBSP.cs b/SabreTools.Serialization/Wrappers/VBSP.cs index 0bfbd4f3..dd316866 100644 --- a/SabreTools.Serialization/Wrappers/VBSP.cs +++ b/SabreTools.Serialization/Wrappers/VBSP.cs @@ -12,6 +12,13 @@ namespace SabreTools.Serialization.Wrappers #endregion + #region Extension Properties + + /// + public VbspLumpEntry[]? Lumps => Model.Header?.Lumps; + + #endregion + #region Constructors /// @@ -86,12 +93,12 @@ namespace SabreTools.Serialization.Wrappers public bool ExtractAllLumps(string outputDirectory) { // If we have no lumps - if (Model.Header?.Lumps == null || Model.Header.Lumps.Length == 0) + if (Lumps == null || Lumps.Length == 0) return false; // Loop through and extract all lumps to the output bool allExtracted = true; - for (int i = 0; i < Model.Header.Lumps.Length; i++) + for (int i = 0; i < Lumps.Length; i++) { allExtracted &= ExtractLump(i, outputDirectory); } @@ -108,15 +115,15 @@ namespace SabreTools.Serialization.Wrappers public bool ExtractLump(int index, string outputDirectory) { // If we have no lumps - if (Model.Header?.Lumps == null || Model.Header.Lumps.Length == 0) + if (Lumps == null || Lumps.Length == 0) return false; // If the lumps index is invalid - if (index < 0 || index >= Model.Header.Lumps.Length) + if (index < 0 || index >= Lumps.Length) return false; // Read the data - var lump = Model.Header.Lumps[index]; + var lump = Lumps[index]; var data = ReadFromDataSource(lump.Offset, lump.Length); if (data == null) return false; diff --git a/SabreTools.Serialization/Wrappers/VPK.cs b/SabreTools.Serialization/Wrappers/VPK.cs index 96d9a70d..cf1b6efe 100644 --- a/SabreTools.Serialization/Wrappers/VPK.cs +++ b/SabreTools.Serialization/Wrappers/VPK.cs @@ -45,7 +45,7 @@ namespace SabreTools.Serialization.Wrappers // Get the archive count ushort archiveCount = 0; - foreach (var di in Model.DirectoryItems ?? []) + foreach (var di in DirectoryItems ?? []) { if (di.DirectoryEntry == null) continue; @@ -71,6 +71,9 @@ namespace SabreTools.Serialization.Wrappers } } + /// + public Models.VPK.DirectoryItem[]? DirectoryItems => Model.DirectoryItems; + #endregion #region Instance Variables @@ -156,12 +159,12 @@ namespace SabreTools.Serialization.Wrappers public bool ExtractAll(string outputDirectory) { // If we have no directory items - if (Model.DirectoryItems == null || Model.DirectoryItems.Length == 0) + if (DirectoryItems == null || DirectoryItems.Length == 0) return false; // Loop through and extract all files to the output bool allExtracted = true; - for (int i = 0; i < Model.DirectoryItems.Length; i++) + for (int i = 0; i < DirectoryItems.Length; i++) { allExtracted &= ExtractFile(i, outputDirectory); } @@ -178,15 +181,15 @@ namespace SabreTools.Serialization.Wrappers public bool ExtractFile(int index, string outputDirectory) { // If we have no directory items - if (Model.DirectoryItems == null || Model.DirectoryItems.Length == 0) + if (DirectoryItems == null || DirectoryItems.Length == 0) return false; // If the directory item index is invalid - if (index < 0 || index >= Model.DirectoryItems.Length) + if (index < 0 || index >= DirectoryItems.Length) return false; // Get the directory item - var directoryItem = Model.DirectoryItems[index]; + var directoryItem = DirectoryItems[index]; if (directoryItem.DirectoryEntry == null) return false; diff --git a/SabreTools.Serialization/Wrappers/WAD3.cs b/SabreTools.Serialization/Wrappers/WAD3.cs index a6a4d97f..fc90fe85 100644 --- a/SabreTools.Serialization/Wrappers/WAD3.cs +++ b/SabreTools.Serialization/Wrappers/WAD3.cs @@ -11,6 +11,13 @@ namespace SabreTools.Serialization.Wrappers #endregion + #region Extension Properties + + /// + public Models.WAD3.DirEntry[]? DirEntries => Model.DirEntries; + + #endregion + #region Constructors /// @@ -85,12 +92,12 @@ namespace SabreTools.Serialization.Wrappers public bool ExtractAllLumps(string outputDirectory) { // If we have no lumps - if (Model.DirEntries == null || Model.DirEntries.Length == 0) + if (DirEntries == null || DirEntries.Length == 0) return false; // Loop through and extract all lumps to the output bool allExtracted = true; - for (int i = 0; i < Model.DirEntries.Length; i++) + for (int i = 0; i < DirEntries.Length; i++) { allExtracted &= ExtractLump(i, outputDirectory); } @@ -107,15 +114,15 @@ namespace SabreTools.Serialization.Wrappers public bool ExtractLump(int index, string outputDirectory) { // If we have no lumps - if (Model.DirEntries == null || Model.DirEntries.Length == 0) + if (DirEntries == null || DirEntries.Length == 0) return false; // If the lumps index is invalid - if (index < 0 || index >= Model.DirEntries.Length) + if (index < 0 || index >= DirEntries.Length) return false; // Read the data -- TODO: Handle uncompressed lumps (see BSP.ExtractTexture) - var lump = Model.DirEntries[index]; + var lump = DirEntries[index]; var data = ReadFromDataSource((int)lump.Offset, (int)lump.Length); if (data == null) return false; diff --git a/SabreTools.Serialization/Wrappers/XZP.cs b/SabreTools.Serialization/Wrappers/XZP.cs index a9ff4bca..b58409b5 100644 --- a/SabreTools.Serialization/Wrappers/XZP.cs +++ b/SabreTools.Serialization/Wrappers/XZP.cs @@ -12,6 +12,16 @@ namespace SabreTools.Serialization.Wrappers #endregion + #region Extension Properties + + /// + public Models.XZP.DirectoryEntry[]? DirectoryEntries => Model.DirectoryEntries; + + /// + public Models.XZP.DirectoryItem[]? DirectoryItems => Model.DirectoryItems; + + #endregion + #region Constructors /// @@ -86,12 +96,12 @@ namespace SabreTools.Serialization.Wrappers public bool ExtractAll(string outputDirectory) { // If we have no directory entries - if (Model.DirectoryEntries == null || Model.DirectoryEntries.Length == 0) + if (DirectoryEntries == null || DirectoryEntries.Length == 0) return false; // Loop through and extract all files to the output bool allExtracted = true; - for (int i = 0; i < Model.DirectoryEntries.Length; i++) + for (int i = 0; i < DirectoryEntries.Length; i++) { allExtracted &= ExtractFile(i, outputDirectory); } @@ -108,20 +118,20 @@ namespace SabreTools.Serialization.Wrappers public bool ExtractFile(int index, string outputDirectory) { // If we have no directory entries - if (Model.DirectoryEntries == null || Model.DirectoryEntries.Length == 0) + if (DirectoryEntries == null || DirectoryEntries.Length == 0) return false; // If we have no directory items - if (Model.DirectoryItems == null || Model.DirectoryItems.Length == 0) + if (DirectoryItems == null || DirectoryItems.Length == 0) return false; // If the directory entry index is invalid - if (index < 0 || index >= Model.DirectoryEntries.Length) + if (index < 0 || index >= DirectoryEntries.Length) return false; // Get the associated directory item - var directoryEntry = Model.DirectoryEntries[index]; - var directoryItem = Array.Find(Model.DirectoryItems, di => di?.FileNameCRC == directoryEntry.FileNameCRC); + var directoryEntry = DirectoryEntries[index]; + var directoryItem = Array.Find(DirectoryItems, di => di?.FileNameCRC == directoryEntry.FileNameCRC); if (directoryItem == null) return false;