diff --git a/BurnOutSharp.Builders/InstallShieldCabinet.cs b/BurnOutSharp.Builders/InstallShieldCabinet.cs index e8d3a780..2d125c65 100644 --- a/BurnOutSharp.Builders/InstallShieldCabinet.cs +++ b/BurnOutSharp.Builders/InstallShieldCabinet.cs @@ -82,30 +82,30 @@ namespace BurnOutSharp.Builders #endregion - #region Cabinet Descriptor + #region Descriptor - // Get the cabinet descriptor offset - uint cabinetDescriptorOffset = commonHeader.CabDescriptorOffset; - if (cabinetDescriptorOffset < 0 || cabinetDescriptorOffset >= data.Length) + // Get the descriptor offset + uint descriptorOffset = commonHeader.DescriptorOffset; + if (descriptorOffset < 0 || descriptorOffset >= data.Length) return null; - // Seek to the cabinet descriptor - data.Seek(cabinetDescriptorOffset, SeekOrigin.Begin); + // Seek to the descriptor + data.Seek(descriptorOffset, SeekOrigin.Begin); - // Try to parse the cabinet descriptor - var cabinetDescriptor = ParseCabinetDescriptor(data); - if (cabinetDescriptor == null) + // Try to parse the descriptor + var descriptor = ParseDescriptor(data); + if (descriptor == null) return null; - // Set the cabinet descriptor - cabinet.CabinetDescriptor = cabinetDescriptor; + // Set the descriptor + cabinet.Descriptor = descriptor; #endregion #region File Descriptor Offsets // Get the file table offset - uint fileTableOffset = commonHeader.CabDescriptorOffset + cabinetDescriptor.FileTableOffset; + uint fileTableOffset = commonHeader.DescriptorOffset + descriptor.FileTableOffset; if (fileTableOffset < 0 || fileTableOffset >= data.Length) return null; @@ -115,9 +115,9 @@ namespace BurnOutSharp.Builders // Get the number of file table items uint fileTableItems; if (GetMajorVersion(commonHeader) <= 5) - fileTableItems = cabinetDescriptor.DirectoryCount + cabinetDescriptor.FileCount; + fileTableItems = descriptor.DirectoryCount + descriptor.FileCount; else - fileTableItems = cabinetDescriptor.DirectoryCount; + fileTableItems = descriptor.DirectoryCount; // Create and fill the file table cabinet.FileDescriptorOffsets = new uint[fileTableItems]; @@ -131,12 +131,12 @@ namespace BurnOutSharp.Builders #region Directory Descriptors // Create and fill the directory descriptors - cabinet.DirectoryDescriptors = new FileDescriptor[cabinetDescriptor.DirectoryCount]; - for (int i = 0; i < cabinetDescriptor.DirectoryCount; i++) + cabinet.DirectoryDescriptors = new FileDescriptor[descriptor.DirectoryCount]; + for (int i = 0; i < descriptor.DirectoryCount; i++) { // Get the directory descriptor offset - uint offset = cabinetDescriptorOffset - + cabinetDescriptor.FileTableOffset + uint offset = descriptorOffset + + descriptor.FileTableOffset + cabinet.FileDescriptorOffsets[i]; // If we have an invalid offset @@ -156,22 +156,22 @@ namespace BurnOutSharp.Builders #region File Descriptors // Create and fill the file descriptors - cabinet.FileDescriptors = new FileDescriptor[cabinetDescriptor.FileCount]; - for (int i = 0; i < cabinetDescriptor.FileCount; i++) + cabinet.FileDescriptors = new FileDescriptor[descriptor.FileCount]; + for (int i = 0; i < descriptor.FileCount; i++) { // Get the file descriptor offset uint offset; if (GetMajorVersion(commonHeader) <= 5) { - offset = cabinetDescriptorOffset - + cabinetDescriptor.FileTableOffset - + cabinet.FileDescriptorOffsets[cabinetDescriptor.DirectoryCount + i]; + offset = descriptorOffset + + descriptor.FileTableOffset + + cabinet.FileDescriptorOffsets[descriptor.DirectoryCount + i]; } else { - offset = cabinetDescriptorOffset - + cabinetDescriptor.FileTableOffset - + cabinetDescriptor.FileTableOffset2 + offset = descriptorOffset + + descriptor.FileTableOffset + + descriptor.FileTableOffset2 + (uint)(i * 0x57); } @@ -183,7 +183,7 @@ namespace BurnOutSharp.Builders data.Seek(offset, SeekOrigin.Begin); // Create and add the file descriptor - FileDescriptor fileDescriptor = ParseFileDescriptor(data, GetMajorVersion(commonHeader), cabinetDescriptorOffset + cabinetDescriptor.FileTableOffset); + FileDescriptor fileDescriptor = ParseFileDescriptor(data, GetMajorVersion(commonHeader), descriptorOffset + descriptor.FileTableOffset); cabinet.FileDescriptors[i] = fileDescriptor; } @@ -193,15 +193,15 @@ namespace BurnOutSharp.Builders // Create and fill the file group offsets cabinet.FileGroupOffsets = new Dictionary(); - for (int i = 0; i < cabinetDescriptor.FileGroupOffsets.Length; i++) + for (int i = 0; i < descriptor.FileGroupOffsets.Length; i++) { // Get the file group offset - uint offset = cabinetDescriptor.FileGroupOffsets[i]; + uint offset = descriptor.FileGroupOffsets[i]; if (offset == 0) continue; // Adjust the file group offset - offset += commonHeader.CabDescriptorOffset; + offset += commonHeader.DescriptorOffset; if (offset < 0 || offset >= data.Length) continue; @@ -209,21 +209,21 @@ namespace BurnOutSharp.Builders data.Seek(offset, SeekOrigin.Begin); // Create and add the offset - OffsetList offsetList = ParseOffsetList(data, GetMajorVersion(commonHeader), cabinetDescriptorOffset); - cabinet.FileGroupOffsets[cabinetDescriptor.FileGroupOffsets[i]] = offsetList; + OffsetList offsetList = ParseOffsetList(data, GetMajorVersion(commonHeader), descriptorOffset); + cabinet.FileGroupOffsets[descriptor.FileGroupOffsets[i]] = offsetList; // If we have a nonzero next offset uint nextOffset = offsetList.NextOffset; while (nextOffset != 0) { // Get the next offset to read - uint internalOffset = nextOffset + commonHeader.CabDescriptorOffset; + uint internalOffset = nextOffset + commonHeader.DescriptorOffset; // Seek to the file group offset data.Seek(internalOffset, SeekOrigin.Begin); // Create and add the offset - offsetList = ParseOffsetList(data, GetMajorVersion(commonHeader), cabinetDescriptorOffset); + offsetList = ParseOffsetList(data, GetMajorVersion(commonHeader), descriptorOffset); cabinet.FileGroupOffsets[nextOffset] = offsetList; // Set the next offset @@ -235,43 +235,55 @@ namespace BurnOutSharp.Builders #region File Groups + // Create the file groups array + cabinet.FileGroups = new FileGroup[cabinet.FileGroupOffsets.Count]; + // Create and fill the file groups - List fileGroups = new List(); + int fileGroupId = 0; foreach (var kvp in cabinet.FileGroupOffsets) { // Get the offset OffsetList list = kvp.Value; if (list == null) + { + fileGroupId++; continue; + } + + // If we have an invalid offset + if (list.DescriptorOffset <= 0) + { + fileGroupId++; + continue; + } /// Seek to the file group - data.Seek(list.DescriptorOffset + cabinetDescriptorOffset, SeekOrigin.Begin); + data.Seek(list.DescriptorOffset + descriptorOffset, SeekOrigin.Begin); // Try to parse the file group - FileGroup fileGroup = ParseFileGroup(data, GetMajorVersion(commonHeader), cabinetDescriptorOffset); + var fileGroup = ParseFileGroup(data, GetMajorVersion(commonHeader), descriptorOffset); + if (fileGroup == null) + return null; // Add the file group - fileGroups.Add(fileGroup); + cabinet.FileGroups[fileGroupId++] = fileGroup; } - // Set the file groups - cabinet.FileGroups = fileGroups.ToArray(); - #endregion #region Component Offsets // Create and fill the component offsets cabinet.ComponentOffsets = new Dictionary(); - for (int i = 0; i < cabinetDescriptor.ComponentOffsets.Length; i++) + for (int i = 0; i < descriptor.ComponentOffsets.Length; i++) { // Get the component offset - uint offset = cabinetDescriptor.ComponentOffsets[i]; + uint offset = descriptor.ComponentOffsets[i]; if (offset == 0) continue; // Adjust the component offset - offset += commonHeader.CabDescriptorOffset; + offset += commonHeader.DescriptorOffset; if (offset < 0 || offset >= data.Length) continue; @@ -279,21 +291,21 @@ namespace BurnOutSharp.Builders data.Seek(offset, SeekOrigin.Begin); // Create and add the offset - OffsetList offsetList = ParseOffsetList(data, GetMajorVersion(commonHeader), cabinetDescriptorOffset); - cabinet.ComponentOffsets[cabinetDescriptor.ComponentOffsets[i]] = offsetList; + OffsetList offsetList = ParseOffsetList(data, GetMajorVersion(commonHeader), descriptorOffset); + cabinet.ComponentOffsets[descriptor.ComponentOffsets[i]] = offsetList; // If we have a nonzero next offset uint nextOffset = offsetList.NextOffset; while (nextOffset != 0) { // Get the next offset to read - uint internalOffset = nextOffset + commonHeader.CabDescriptorOffset; + uint internalOffset = nextOffset + commonHeader.DescriptorOffset; // Seek to the file group offset data.Seek(internalOffset, SeekOrigin.Begin); // Create and add the offset - offsetList = ParseOffsetList(data, GetMajorVersion(commonHeader), cabinetDescriptorOffset); + offsetList = ParseOffsetList(data, GetMajorVersion(commonHeader), descriptorOffset); cabinet.ComponentOffsets[nextOffset] = offsetList; // Set the next offset @@ -305,30 +317,44 @@ namespace BurnOutSharp.Builders #region Components + // Create the components array + cabinet.Components = new Component[cabinet.ComponentOffsets.Count]; + // Create and fill the components - List components = new List(); + int componentId = 0; foreach (KeyValuePair kvp in cabinet.ComponentOffsets) { // Get the offset OffsetList list = kvp.Value; if (list == null) + { + componentId++; continue; + } + + // If we have an invalid offset + if (list.DescriptorOffset <= 0) + { + componentId++; + continue; + } // Seek to the component - data.Seek(list.DescriptorOffset + cabinetDescriptorOffset, SeekOrigin.Begin); + data.Seek(list.DescriptorOffset + descriptorOffset, SeekOrigin.Begin); // Try to parse the component - Component component = ParseComponent(data, GetMajorVersion(commonHeader), cabinetDescriptorOffset); + var component = ParseComponent(data, GetMajorVersion(commonHeader), descriptorOffset); + if (component == null) + return null; // Add the component - components.Add(component); + cabinet.Components[componentId++] = component; } - // Set the components - cabinet.Components = components.ToArray(); - #endregion + // TODO: Parse setup types + return cabinet; } @@ -348,8 +374,8 @@ namespace BurnOutSharp.Builders commonHeader.Version = data.ReadUInt32(); commonHeader.VolumeInfo = data.ReadUInt32(); - commonHeader.CabDescriptorOffset = data.ReadUInt32(); - commonHeader.CabDescriptorSize = data.ReadUInt32(); + commonHeader.DescriptorOffset = data.ReadUInt32(); + commonHeader.DescriptorSize = data.ReadUInt32(); return commonHeader; } @@ -403,38 +429,50 @@ namespace BurnOutSharp.Builders } /// - /// Parse a Stream into a cabinet descriptor + /// Parse a Stream into a descriptor /// /// Stream to parse - /// Filled cabinet descriptor on success, null on error - private static CabDescriptor ParseCabinetDescriptor(Stream data) + /// Filled descriptor on success, null on error + private static Descriptor ParseDescriptor(Stream data) { - CabDescriptor cabDescriptor = new CabDescriptor(); + Descriptor descriptor = new Descriptor(); - cabDescriptor.Reserved0 = data.ReadBytes(0x0C); - cabDescriptor.FileTableOffset = data.ReadUInt32(); - cabDescriptor.Reserved1 = data.ReadBytes(0x04); - cabDescriptor.FileTableSize = data.ReadUInt32(); - cabDescriptor.FileTableSize2 = data.ReadUInt32(); - cabDescriptor.DirectoryCount = data.ReadUInt32(); - cabDescriptor.Reserved2 = data.ReadBytes(0x08); - cabDescriptor.FileCount = data.ReadUInt32(); - cabDescriptor.FileTableOffset2 = data.ReadUInt32(); - cabDescriptor.Reserved3 = data.ReadBytes(0x0E); + descriptor.StringsOffset = data.ReadUInt32(); + descriptor.Reserved0 = data.ReadBytes(4); + descriptor.ComponentListOffset = data.ReadUInt32(); + descriptor.FileTableOffset = data.ReadUInt32(); + descriptor.Reserved1 = data.ReadBytes(4); + descriptor.FileTableSize = data.ReadUInt32(); + descriptor.FileTableSize2 = data.ReadUInt32(); + descriptor.DirectoryCount = data.ReadUInt16(); + descriptor.Reserved2 = data.ReadBytes(4); + descriptor.Reserved3 = data.ReadBytes(2); + descriptor.Reserved4 = data.ReadBytes(4); + descriptor.FileCount = data.ReadUInt32(); + descriptor.FileTableOffset2 = data.ReadUInt32(); + descriptor.ComponentTableInfoCount = data.ReadUInt16(); + descriptor.ComponentTableOffset = data.ReadUInt32(); + descriptor.Reserved5 = data.ReadBytes(4); + descriptor.Reserved6 = data.ReadBytes(4); - cabDescriptor.FileGroupOffsets = new uint[MAX_FILE_GROUP_COUNT]; - for (int i = 0; i < cabDescriptor.FileGroupOffsets.Length; i++) + descriptor.FileGroupOffsets = new uint[MAX_FILE_GROUP_COUNT]; + for (int i = 0; i < descriptor.FileGroupOffsets.Length; i++) { - cabDescriptor.FileGroupOffsets[i] = data.ReadUInt32(); + descriptor.FileGroupOffsets[i] = data.ReadUInt32(); } - cabDescriptor.ComponentOffsets = new uint[MAX_COMPONENT_COUNT]; - for (int i = 0; i < cabDescriptor.ComponentOffsets.Length; i++) + descriptor.ComponentOffsets = new uint[MAX_COMPONENT_COUNT]; + for (int i = 0; i < descriptor.ComponentOffsets.Length; i++) { - cabDescriptor.ComponentOffsets[i] = data.ReadUInt32(); + descriptor.ComponentOffsets[i] = data.ReadUInt32(); } - return cabDescriptor; + descriptor.SetupTypesOffset = data.ReadUInt32(); + descriptor.SetupTableOffset = data.ReadUInt32(); + descriptor.Reserved7 = data.ReadBytes(4); + descriptor.Reserved8 = data.ReadBytes(4); + + return descriptor; } /// @@ -483,14 +521,33 @@ namespace BurnOutSharp.Builders fileGroup.NameOffset = data.ReadUInt32(); - // Skip bytes based on the version - if (majorVersion <= 5) - _ = data.ReadBytes(0x48); - else - _ = data.ReadBytes(0x12); + fileGroup.ExpandedSize = data.ReadUInt32(); + fileGroup.Reserved0 = data.ReadBytes(4); + fileGroup.CompressedSize = data.ReadUInt32(); + fileGroup.Reserved1 = data.ReadBytes(4); + fileGroup.Reserved2 = data.ReadBytes(2); + fileGroup.Attribute1 = data.ReadUInt16(); + fileGroup.Attribute2 = data.ReadUInt16(); - fileGroup.FirstFile = data.ReadUInt16(); + // TODO: Figure out what data lives in this area for V5 and below + if (majorVersion <= 5) + data.Seek(0x36, SeekOrigin.Current); + + fileGroup.FirstFile = data.ReadUInt32(); fileGroup.LastFile = data.ReadUInt32(); + fileGroup.UnknownOffset = data.ReadUInt32(); + fileGroup.Var4Offset = data.ReadUInt32(); + fileGroup.Var1Offset = data.ReadUInt32(); + fileGroup.HTTPLocationOffset = data.ReadUInt32(); + fileGroup.FTPLocationOffset = data.ReadUInt32(); + fileGroup.MiscOffset = data.ReadUInt32(); + fileGroup.Var2Offset = data.ReadUInt32(); + fileGroup.TargetDirectoryOffset = data.ReadUInt32(); + fileGroup.Reserved3 = data.ReadBytes(2); + fileGroup.Reserved4 = data.ReadBytes(2); + fileGroup.Reserved5 = data.ReadBytes(2); + fileGroup.Reserved6 = data.ReadBytes(2); + fileGroup.Reserved7 = data.ReadBytes(2); // Cache the current position long currentPosition = data.Position; @@ -525,20 +582,64 @@ namespace BurnOutSharp.Builders { Component component = new Component(); + component.IdentifierOffset = data.ReadUInt32(); + component.DescriptorOffset = data.ReadUInt32(); + component.DisplayNameOffset = data.ReadUInt32(); + component.Reserved0 = data.ReadBytes(2); + component.ReservedOffset0 = data.ReadUInt32(); + component.ReservedOffset1 = data.ReadUInt32(); + component.ComponentIndex = data.ReadUInt16(); component.NameOffset = data.ReadUInt32(); - - // Skip bytes based on the version - if (majorVersion <= 5) - _ = data.ReadBytes(0x6C); - else - _ = data.ReadBytes(0x6B); - + component.ReservedOffset2 = data.ReadUInt32(); + component.ReservedOffset3 = data.ReadUInt32(); + component.ReservedOffset4 = data.ReadUInt32(); + component.Reserved1 = data.ReadBytes(32); + component.CLSIDOffset = data.ReadUInt32(); + component.Reserved2 = data.ReadBytes(28); + component.Reserved3 = data.ReadBytes(majorVersion <= 5 ? 2 : 1); + component.DependsCount = data.ReadUInt16(); + component.DependsOffset = data.ReadUInt32(); component.FileGroupCount = data.ReadUInt16(); - component.FileGroupTableOffset = data.ReadUInt32(); + component.FileGroupNamesOffset = data.ReadUInt32(); + component.X3Count = data.ReadUInt16(); + component.X3Offset = data.ReadUInt32(); + component.SubComponentsCount = data.ReadUInt16(); + component.SubComponentsOffset = data.ReadUInt32(); + component.NextComponentOffset = data.ReadUInt32(); + component.ReservedOffset5 = data.ReadUInt32(); + component.ReservedOffset6 = data.ReadUInt32(); + component.ReservedOffset7 = data.ReadUInt32(); + component.ReservedOffset8 = data.ReadUInt32(); // Cache the current position long currentPosition = data.Position; + // Read the identifier, if possible + if (component.IdentifierOffset != 0) + { + // Seek to the identifier + data.Seek(component.IdentifierOffset + descriptorOffset, SeekOrigin.Begin); + + // Read the string + if (majorVersion >= 17) + component.Identifier = data.ReadString(Encoding.Unicode); + else + component.Identifier = data.ReadString(Encoding.ASCII); + } + + // Read the display name, if possible + if (component.DisplayNameOffset != 0) + { + // Seek to the name + data.Seek(component.DisplayNameOffset + descriptorOffset, SeekOrigin.Begin); + + // Read the string + if (majorVersion >= 17) + component.DisplayName = data.ReadString(Encoding.Unicode); + else + component.DisplayName = data.ReadString(Encoding.ASCII); + } + // Read the name, if possible if (component.NameOffset != 0) { @@ -552,13 +653,23 @@ namespace BurnOutSharp.Builders component.Name = data.ReadString(Encoding.ASCII); } - // Read the file group table, if possible - if (component.FileGroupCount != 0 && component.FileGroupTableOffset != 0) + // Read the CLSID, if possible + if (component.CLSIDOffset != 0) + { + // Seek to the CLSID + data.Seek(component.CLSIDOffset + descriptorOffset, SeekOrigin.Begin); + + // Read the GUID + component.CLSID = data.ReadGuid(); + } + + // Read the file group names, if possible + if (component.FileGroupCount != 0 && component.FileGroupNamesOffset != 0) { // Seek to the file group table offset - data.Seek(component.FileGroupTableOffset + descriptorOffset, SeekOrigin.Begin); + data.Seek(component.FileGroupNamesOffset + descriptorOffset, SeekOrigin.Begin); - // Read the file group table + // Read the file group names table component.FileGroupNames = new string[component.FileGroupCount]; for (int j = 0; j < component.FileGroupCount; j++) { diff --git a/BurnOutSharp.Models/InstallShieldCabinet/CabDescriptor.cs b/BurnOutSharp.Models/InstallShieldCabinet/CabDescriptor.cs deleted file mode 100644 index 27cf068e..00000000 --- a/BurnOutSharp.Models/InstallShieldCabinet/CabDescriptor.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace BurnOutSharp.Models.InstallShieldCabinet -{ - /// - public sealed class CabDescriptor - { - public byte[] Reserved0; - - public uint FileTableOffset; - - public byte[] Reserved1; - - public uint FileTableSize; - - public uint FileTableSize2; - - public uint DirectoryCount; - - public byte[] Reserved2; - - public uint FileCount; - - public uint FileTableOffset2; - - public byte[] Reserved3; - - public uint[] FileGroupOffsets; - - public uint[] ComponentOffsets; - } -} \ No newline at end of file diff --git a/BurnOutSharp.Models/InstallShieldCabinet/Cabinet.cs b/BurnOutSharp.Models/InstallShieldCabinet/Cabinet.cs index 266b29b1..012d73f3 100644 --- a/BurnOutSharp.Models/InstallShieldCabinet/Cabinet.cs +++ b/BurnOutSharp.Models/InstallShieldCabinet/Cabinet.cs @@ -19,9 +19,9 @@ namespace BurnOutSharp.Models.InstallShieldCabinet public VolumeHeader VolumeHeader { get; set; } /// - /// Cabinet descriptor + /// Descriptor /// - public CabDescriptor CabinetDescriptor { get; set; } + public Descriptor Descriptor { get; set; } #endregion diff --git a/BurnOutSharp.Models/InstallShieldCabinet/CommonHeader.cs b/BurnOutSharp.Models/InstallShieldCabinet/CommonHeader.cs index 744fff37..099fba58 100644 --- a/BurnOutSharp.Models/InstallShieldCabinet/CommonHeader.cs +++ b/BurnOutSharp.Models/InstallShieldCabinet/CommonHeader.cs @@ -3,14 +3,29 @@ namespace BurnOutSharp.Models.InstallShieldCabinet /// public sealed class CommonHeader { + /// + /// "ISc(" + /// public string Signature; + /// + /// Encoded version + /// public uint Version; + /// + /// Volume information + /// public uint VolumeInfo; - public uint CabDescriptorOffset; + /// + /// Offset to cabinet descriptor + /// + public uint DescriptorOffset; - public uint CabDescriptorSize; + /// + /// Cabinet descriptor size + /// + public uint DescriptorSize; } } \ No newline at end of file diff --git a/BurnOutSharp.Models/InstallShieldCabinet/Component.cs b/BurnOutSharp.Models/InstallShieldCabinet/Component.cs index e11ce421..61878e5d 100644 --- a/BurnOutSharp.Models/InstallShieldCabinet/Component.cs +++ b/BurnOutSharp.Models/InstallShieldCabinet/Component.cs @@ -1,16 +1,173 @@ +using System; + namespace BurnOutSharp.Models.InstallShieldCabinet { /// public sealed class Component { + /// + /// Offset to the component identifier + /// + public uint IdentifierOffset; + + /// + /// Component identifier + /// + public string Identifier; + + /// + /// Offset to the component descriptor + /// + public uint DescriptorOffset; + + /// + /// Offset to the display name + /// + public uint DisplayNameOffset; + + /// + /// Display name + /// + public string DisplayName; + + /// + /// Reserved + /// + public byte[] Reserved0; + + /// + /// Reserved offset + /// + public uint ReservedOffset0; + + /// + /// Reserved offset + /// + public uint ReservedOffset1; + + /// + /// Component index + /// + public ushort ComponentIndex; + + /// + /// Offset to the component name + /// public uint NameOffset; + /// + /// Component name + /// public string Name; - public ushort FileGroupCount; + /// + /// Reserved offset + /// + public uint ReservedOffset2; - public uint FileGroupTableOffset; + /// + /// Reserved offset + /// + public uint ReservedOffset3; + /// + /// Reserved offset + /// + public uint ReservedOffset4; + + /// + /// Reserved + /// + public byte[] Reserved1; + + /// + /// Offset to the component CLSID + /// + public uint CLSIDOffset; + + /// + /// Component CLSID + /// + public Guid CLSID; + + /// + /// Reserved + /// + public byte[] Reserved2; + + /// + /// Reserved + /// + public byte[] Reserved3; + + /// + /// Number of depends(?) + /// + public ushort DependsCount; + + /// + /// Offset to depends(?) + /// + public uint DependsOffset; + + /// + /// Number of file groups + /// + public uint FileGroupCount; + + /// + /// Offset to the file group names + /// + public uint FileGroupNamesOffset; + + /// + /// File group names + /// public string[] FileGroupNames; + + /// + /// Number of X3(?) + /// + public ushort X3Count; + + /// + /// Offset to X3(?) + /// + public uint X3Offset; + + /// + /// Number of sub-components + /// + public ushort SubComponentsCount; + + /// + /// Offset to the sub-components + /// + public uint SubComponentsOffset; + + /// + /// Offset to the next component + /// + public uint NextComponentOffset; + + /// + /// Reserved offset + /// + public uint ReservedOffset5; + + /// + /// Reserved offset + /// + public uint ReservedOffset6; + + /// + /// Reserved offset + /// + public uint ReservedOffset7; + + /// + /// Reserved offset + /// + public uint ReservedOffset8; } } \ No newline at end of file diff --git a/BurnOutSharp.Models/InstallShieldCabinet/Descriptor.cs b/BurnOutSharp.Models/InstallShieldCabinet/Descriptor.cs new file mode 100644 index 00000000..20b1b620 --- /dev/null +++ b/BurnOutSharp.Models/InstallShieldCabinet/Descriptor.cs @@ -0,0 +1,121 @@ +namespace BurnOutSharp.Models.InstallShieldCabinet +{ + /// + public sealed class Descriptor + { + /// + /// Offset to the descriptor strings + /// + public uint StringsOffset; + + /// + /// Reserved + /// + public byte[] Reserved0; + + /// + /// Offset to the component list + /// + public uint ComponentListOffset; + + /// + /// Offset to the file table + /// + public uint FileTableOffset; + + /// + /// Reserved + /// + public byte[] Reserved1; + + /// + /// Size of the file table + /// + public uint FileTableSize; + + /// + /// Redundant size of the file table + /// + public uint FileTableSize2; + + /// + /// Number of directories + /// + public ushort DirectoryCount; + + /// + /// Reserved + /// + public byte[] Reserved2; + + /// + /// Reserved + /// + public byte[] Reserved3; + + /// + /// Reserved + /// + public byte[] Reserved4; + + /// + /// Number of files + /// + public uint FileCount; + + /// + /// Redundant offset to the file table + /// + public uint FileTableOffset2; + + /// + /// Number of component table infos + /// + public ushort ComponentTableInfoCount; + + /// + /// Offset to the component table + /// + public uint ComponentTableOffset; + + /// + /// Reserved + /// + public byte[] Reserved5; + + /// + /// Reserved + /// + public byte[] Reserved6; + + /// + /// Offsets to the file groups + /// + public uint[] FileGroupOffsets; + + /// + /// Offsets to the components + /// + public uint[] ComponentOffsets; + + /// + /// Offset to the setup types + /// + public uint SetupTypesOffset; + + /// + /// Offset to the setup table + /// + public uint SetupTableOffset; + + /// + /// Reserved + /// + public byte[] Reserved7; + + /// + /// Reserved + /// + public byte[] Reserved8; + } +} \ No newline at end of file diff --git a/BurnOutSharp.Models/InstallShieldCabinet/FileDescriptor.cs b/BurnOutSharp.Models/InstallShieldCabinet/FileDescriptor.cs index 79266a5b..7b1af119 100644 --- a/BurnOutSharp.Models/InstallShieldCabinet/FileDescriptor.cs +++ b/BurnOutSharp.Models/InstallShieldCabinet/FileDescriptor.cs @@ -3,28 +3,64 @@ namespace BurnOutSharp.Models.InstallShieldCabinet /// public sealed class FileDescriptor { + /// + /// Offset to the file descriptor name + /// public uint NameOffset; + /// + /// File descriptor name + /// public string Name; + /// + /// Directory index + /// public uint DirectoryIndex; + /// + /// File flags + /// public FileFlags Flags; + /// + /// Size of the entry when expanded + /// public ulong ExpandedSize; + /// + /// Size of the entry when compressed + /// public ulong CompressedSize; + /// + /// Offset to the entry data + /// public ulong DataOffset; + /// + /// MD5 of the entry data + /// public byte[] MD5; + /// + /// Volume number + /// public ushort Volume; + /// + /// Link previous + /// public uint LinkPrevious; + /// + /// Link next + /// public uint LinkNext; + /// + /// Link flags + /// public LinkFlags LinkFlags; } } \ No newline at end of file diff --git a/BurnOutSharp.Models/InstallShieldCabinet/FileGroup.cs b/BurnOutSharp.Models/InstallShieldCabinet/FileGroup.cs index 8e84f495..9c56f8bd 100644 --- a/BurnOutSharp.Models/InstallShieldCabinet/FileGroup.cs +++ b/BurnOutSharp.Models/InstallShieldCabinet/FileGroup.cs @@ -3,12 +3,124 @@ namespace BurnOutSharp.Models.InstallShieldCabinet /// public sealed class FileGroup { + /// + /// Offset to the file group name + /// public uint NameOffset; + /// + /// File group name + /// public string Name; + /// + /// Size of the expanded data + /// + public uint ExpandedSize; + + /// + /// Reserved + /// + public byte[] Reserved0; + + /// + /// Size of the compressed data + /// + public uint CompressedSize; + + /// + /// Reserved + /// + public byte[] Reserved1; + + /// + /// Reserved + /// + public byte[] Reserved2; + + /// + /// Attribute(?) + /// + public ushort Attribute1; + + /// + /// Attribute(?) + /// + public ushort Attribute2; + + /// + /// Index of the first file + /// public uint FirstFile; + /// + /// Index of the last file + /// public uint LastFile; + + /// + /// Unknown offset(?) + /// + public uint UnknownOffset; + + /// + /// Var 4 offset(?) + /// + public uint Var4Offset; + + /// + /// Var 1 offset(?) + /// + public uint Var1Offset; + + /// + /// Offset to the HTTP location + /// + public uint HTTPLocationOffset; + + /// + /// Offset to the FTP location + /// + public uint FTPLocationOffset; + + /// + /// Misc offset(?) + /// + public uint MiscOffset; + + /// + /// Var 2 offset(?) + /// + public uint Var2Offset; + + /// + /// Offset to the target directory + /// + public uint TargetDirectoryOffset; + + /// + /// Reserved + /// + public byte[] Reserved3; + + /// + /// Reserved + /// + public byte[] Reserved4; + + /// + /// Reserved + /// + public byte[] Reserved5; + + /// + /// Reserved + /// + public byte[] Reserved6; + + /// + /// Reserved + /// + public byte[] Reserved7; } } \ No newline at end of file diff --git a/BurnOutSharp.Wrappers/InstallShieldCabinet.cs b/BurnOutSharp.Wrappers/InstallShieldCabinet.cs index 8c43241e..feaf82dc 100644 --- a/BurnOutSharp.Wrappers/InstallShieldCabinet.cs +++ b/BurnOutSharp.Wrappers/InstallShieldCabinet.cs @@ -20,11 +20,11 @@ namespace BurnOutSharp.Wrappers /// public uint VolumeInfo => _cabinet.CommonHeader.VolumeInfo; - /// - public uint CabDescriptorOffset => _cabinet.CommonHeader.CabDescriptorOffset; + /// + public uint DescriptorOffset => _cabinet.CommonHeader.DescriptorOffset; - /// - public uint CabDescriptorSize => _cabinet.CommonHeader.CabDescriptorSize; + /// + public uint DescriptorSize => _cabinet.CommonHeader.DescriptorSize; #endregion @@ -80,6 +80,79 @@ namespace BurnOutSharp.Wrappers #endregion + #region Descriptor + + /// + public uint StringsOffset => _cabinet.Descriptor.StringsOffset; + + /// + public byte[] Reserved0 => _cabinet.Descriptor.Reserved0; + + /// + public uint ComponentListOffset => _cabinet.Descriptor.ComponentListOffset; + + /// + public uint FileTableOffset => _cabinet.Descriptor.FileTableOffset; + + /// + public byte[] Reserved1 => _cabinet.Descriptor.Reserved1; + + /// + public uint FileTableSize => _cabinet.Descriptor.FileTableSize; + + /// + public uint FileTableSize2 => _cabinet.Descriptor.FileTableSize2; + + /// + public ushort DirectoryCount => _cabinet.Descriptor.DirectoryCount; + + /// + public byte[] Reserved2 => _cabinet.Descriptor.Reserved2; + + /// + public byte[] Reserved3 => _cabinet.Descriptor.Reserved3; + + /// + public byte[] Reserved4 => _cabinet.Descriptor.Reserved4; + + /// + public uint FileCount => _cabinet.Descriptor.FileCount; + + /// + public uint FileTableOffset2 => _cabinet.Descriptor.FileTableOffset2; + + /// + public ushort ComponentTableInfoCount => _cabinet.Descriptor.ComponentTableInfoCount; + + /// + public uint ComponentTableOffset => _cabinet.Descriptor.ComponentTableOffset; + + /// + public byte[] Reserved5 => _cabinet.Descriptor.Reserved5; + + /// + public byte[] Reserved6 => _cabinet.Descriptor.Reserved6; + + /// + public uint[] D_FileGroupOffsets => _cabinet.Descriptor.FileGroupOffsets; + + /// + public uint[] D_ComponentOffsets => _cabinet.Descriptor.ComponentOffsets; + + /// + public uint SetupTypesOffset => _cabinet.Descriptor.SetupTypesOffset; + + /// + public uint SetupTableOffset => _cabinet.Descriptor.SetupTableOffset; + + /// + public byte[] Reserved7 => _cabinet.Descriptor.Reserved7; + + /// + public byte[] Reserved8 => _cabinet.Descriptor.Reserved8; + + #endregion + #region File Descriptor Offsets /// @@ -235,6 +308,7 @@ namespace BurnOutSharp.Wrappers // Headers PrintCommonHeader(builder); PrintVolumeHeader(builder); + PrintDescriptor(builder); // File Descriptors PrintFileDescriptorOffsets(builder); @@ -263,8 +337,8 @@ namespace BurnOutSharp.Wrappers builder.AppendLine($" Signature: {Signature}"); builder.AppendLine($" Version: {Version} (0x{Version:X}) [{MajorVersion}]"); builder.AppendLine($" Volume info: {VolumeInfo} (0x{VolumeInfo:X})"); - builder.AppendLine($" Cabinet descriptor offset: {CabDescriptorOffset} (0x{CabDescriptorOffset:X})"); - builder.AppendLine($" Cabinet descriptor size: {CabDescriptorSize} (0x{CabDescriptorSize:X})"); + builder.AppendLine($" Descriptor offset: {DescriptorOffset} (0x{DescriptorOffset:X})"); + builder.AppendLine($" Descriptor size: {DescriptorSize} (0x{DescriptorSize:X})"); builder.AppendLine(); } @@ -311,6 +385,70 @@ namespace BurnOutSharp.Wrappers builder.AppendLine(); } + /// + /// Print descriptor information + /// + /// StringBuilder to append information to + private void PrintDescriptor(StringBuilder builder) + { + builder.AppendLine(" Descriptor Information:"); + builder.AppendLine(" -------------------------"); + builder.AppendLine($" Strings offset: {StringsOffset} (0x{StringsOffset:X})"); + builder.AppendLine($" Reserved 0: {BitConverter.ToString(Reserved0).Replace('-', ' ')}"); + builder.AppendLine($" Component list offset: {ComponentListOffset} (0x{ComponentListOffset:X})"); + builder.AppendLine($" File table offset: {FileTableOffset} (0x{FileTableOffset:X})"); + builder.AppendLine($" Reserved 1: {BitConverter.ToString(Reserved1).Replace('-', ' ')}"); + builder.AppendLine($" File table size: {FileTableSize} (0x{FileTableSize:X})"); + builder.AppendLine($" File table size 2: {FileTableSize2} (0x{FileTableSize2:X})"); + builder.AppendLine($" Directory count: {DirectoryCount} (0x{DirectoryCount:X})"); + builder.AppendLine($" Reserved 2: {BitConverter.ToString(Reserved2).Replace('-', ' ')}"); + builder.AppendLine($" Reserved 3: {BitConverter.ToString(Reserved3).Replace('-', ' ')}"); + builder.AppendLine($" Reserved 4: {BitConverter.ToString(Reserved4).Replace('-', ' ')}"); + builder.AppendLine($" File count: {FileCount} (0x{FileCount:X})"); + builder.AppendLine($" File table offset 2: {FileTableOffset2} (0x{FileTableOffset2:X})"); + builder.AppendLine($" Component table info count: {ComponentTableInfoCount} (0x{ComponentTableInfoCount:X})"); + builder.AppendLine($" Component table offset: {ComponentTableOffset} (0x{ComponentTableOffset:X})"); + builder.AppendLine($" Reserved 5: {BitConverter.ToString(Reserved5).Replace('-', ' ')}"); + builder.AppendLine($" Reserved 6: {BitConverter.ToString(Reserved6).Replace('-', ' ')}"); + builder.AppendLine(); + + builder.AppendLine($" File group offsets:"); + builder.AppendLine(" -------------------------"); + if (D_FileGroupOffsets == null || D_FileGroupOffsets.Length == 0) + { + builder.AppendLine(" No file group offsets"); + } + else + { + for (int i = 0; i < D_FileGroupOffsets.Length; i++) + { + builder.AppendLine($" File Group Offset {i}: {D_FileGroupOffsets[i]} (0x{D_FileGroupOffsets[i]:X})"); + } + } + builder.AppendLine(); + + builder.AppendLine($" Component offsets:"); + builder.AppendLine(" -------------------------"); + if (D_ComponentOffsets == null || D_ComponentOffsets.Length == 0) + { + builder.AppendLine(" No component offsets"); + } + else + { + for (int i = 0; i < D_ComponentOffsets.Length; i++) + { + builder.AppendLine($" Component Offset {i}: {D_ComponentOffsets[i]} (0x{D_ComponentOffsets[i]:X})"); + } + } + builder.AppendLine(); + + builder.AppendLine($" Setup types offset: {SetupTypesOffset} (0x{SetupTypesOffset:X})"); + builder.AppendLine($" Setup table offset: {SetupTableOffset} (0x{SetupTableOffset:X})"); + builder.AppendLine($" Reserved 7: {BitConverter.ToString(Reserved7).Replace('-', ' ')}"); + builder.AppendLine($" Reserved 8: {BitConverter.ToString(Reserved8).Replace('-', ' ')}"); + builder.AppendLine(); + } + /// /// Print file descriptor offsets information /// @@ -422,10 +560,17 @@ namespace BurnOutSharp.Wrappers long offset = kvp.Key; var offsetList = kvp.Value; builder.AppendLine($" File Group Offset {offset}:"); - builder.AppendLine($" Name offset: {offsetList.NameOffset} (0x{offsetList.NameOffset:X})"); - builder.AppendLine($" Name: {offsetList.Name ?? "[NULL]"}"); - builder.AppendLine($" Descriptor offset: {offsetList.DescriptorOffset} (0x{offsetList.DescriptorOffset:X})"); - builder.AppendLine($" Next offset: {offsetList.NextOffset} (0x{offsetList.NextOffset:X})"); + if (offsetList == null) + { + builder.AppendLine($" Unassigned file group"); + } + else + { + builder.AppendLine($" Name offset: {offsetList.NameOffset} (0x{offsetList.NameOffset:X})"); + builder.AppendLine($" Name: {offsetList.Name ?? "[NULL]"}"); + builder.AppendLine($" Descriptor offset: {offsetList.DescriptorOffset} (0x{offsetList.DescriptorOffset:X})"); + builder.AppendLine($" Next offset: {offsetList.NextOffset} (0x{offsetList.NextOffset:X})"); + } } } builder.AppendLine(); @@ -449,10 +594,37 @@ namespace BurnOutSharp.Wrappers { var fileGroup = FileGroups[i]; builder.AppendLine($" File Group {i}:"); - builder.AppendLine($" Name offset: {fileGroup.NameOffset} (0x{fileGroup.NameOffset:X})"); - builder.AppendLine($" Name: {fileGroup.Name ?? "[NULL]"}"); - builder.AppendLine($" First file: {fileGroup.FirstFile} (0x{fileGroup.FirstFile:X})"); - builder.AppendLine($" Last file: {fileGroup.LastFile} (0x{fileGroup.LastFile:X})"); + if (fileGroup == null) + { + builder.AppendLine($" Unassigned file group"); + } + else + { + builder.AppendLine($" Name offset: {fileGroup.NameOffset} (0x{fileGroup.NameOffset:X})"); + builder.AppendLine($" Name: {fileGroup.Name ?? "[NULL]"}"); + builder.AppendLine($" Expanded size: {fileGroup.ExpandedSize} (0x{fileGroup.ExpandedSize:X})"); + builder.AppendLine($" Reserved 0: {BitConverter.ToString(fileGroup.Reserved0).Replace('-', ' ')}"); + builder.AppendLine($" Compressed size: {fileGroup.CompressedSize} (0x{fileGroup.CompressedSize:X})"); + builder.AppendLine($" Reserved 1: {BitConverter.ToString(fileGroup.Reserved1).Replace('-', ' ')}"); + builder.AppendLine($" Reserved 2: {BitConverter.ToString(fileGroup.Reserved2).Replace('-', ' ')}"); + builder.AppendLine($" Attribute 1: {fileGroup.Attribute1} (0x{fileGroup.Attribute1:X})"); + builder.AppendLine($" Attribute 2: {fileGroup.Attribute2} (0x{fileGroup.Attribute2:X})"); + builder.AppendLine($" First file: {fileGroup.FirstFile} (0x{fileGroup.FirstFile:X})"); + builder.AppendLine($" Last file: {fileGroup.LastFile} (0x{fileGroup.LastFile:X})"); + builder.AppendLine($" Unknown offset: {fileGroup.UnknownOffset} (0x{fileGroup.UnknownOffset:X})"); + builder.AppendLine($" Var 4 offset: {fileGroup.Var4Offset} (0x{fileGroup.Var4Offset:X})"); + builder.AppendLine($" Var 1 offset: {fileGroup.Var1Offset} (0x{fileGroup.Var1Offset:X})"); + builder.AppendLine($" HTTP location offset: {fileGroup.HTTPLocationOffset} (0x{fileGroup.HTTPLocationOffset:X})"); + builder.AppendLine($" FTP location offset: {fileGroup.FTPLocationOffset} (0x{fileGroup.FTPLocationOffset:X})"); + builder.AppendLine($" Misc. offset: {fileGroup.MiscOffset} (0x{fileGroup.MiscOffset:X})"); + builder.AppendLine($" Var 2 offset: {fileGroup.Var2Offset} (0x{fileGroup.Var2Offset:X})"); + builder.AppendLine($" Target directory offset: {fileGroup.TargetDirectoryOffset} (0x{fileGroup.TargetDirectoryOffset:X})"); + builder.AppendLine($" Reserved 3: {BitConverter.ToString(fileGroup.Reserved3).Replace('-', ' ')}"); + builder.AppendLine($" Reserved 4: {BitConverter.ToString(fileGroup.Reserved4).Replace('-', ' ')}"); + builder.AppendLine($" Reserved 5: {BitConverter.ToString(fileGroup.Reserved5).Replace('-', ' ')}"); + builder.AppendLine($" Reserved 6: {BitConverter.ToString(fileGroup.Reserved6).Replace('-', ' ')}"); + builder.AppendLine($" Reserved 7: {BitConverter.ToString(fileGroup.Reserved7).Replace('-', ' ')}"); + } } } builder.AppendLine(); @@ -477,10 +649,17 @@ namespace BurnOutSharp.Wrappers long offset = kvp.Key; var offsetList = kvp.Value; builder.AppendLine($" Component Offset {offset}:"); - builder.AppendLine($" Name offset: {offsetList.NameOffset} (0x{offsetList.NameOffset:X})"); - builder.AppendLine($" Name: {offsetList.Name ?? "[NULL]"}"); - builder.AppendLine($" Descriptor offset: {offsetList.DescriptorOffset} (0x{offsetList.DescriptorOffset:X})"); - builder.AppendLine($" Next offset: {offsetList.NextOffset} (0x{offsetList.NextOffset:X})"); + if (offsetList == null) + { + builder.AppendLine($" Unassigned component"); + } + else + { + builder.AppendLine($" Name offset: {offsetList.NameOffset} (0x{offsetList.NameOffset:X})"); + builder.AppendLine($" Name: {offsetList.Name ?? "[NULL]"}"); + builder.AppendLine($" Descriptor offset: {offsetList.DescriptorOffset} (0x{offsetList.DescriptorOffset:X})"); + builder.AppendLine($" Next offset: {offsetList.NextOffset} (0x{offsetList.NextOffset:X})"); + } } } builder.AppendLine(); @@ -504,22 +683,61 @@ namespace BurnOutSharp.Wrappers { var component = Components[i]; builder.AppendLine($" Component {i}:"); - builder.AppendLine($" Name offset: {component.NameOffset} (0x{component.NameOffset:X})"); - builder.AppendLine($" Name: {component.Name ?? "[NULL]"}"); - builder.AppendLine($" File group count: {component.FileGroupCount} (0x{component.FileGroupCount:X})"); - builder.AppendLine($" File group table offset: {component.FileGroupTableOffset} (0x{component.FileGroupTableOffset:X})"); - builder.AppendLine($" File group names:"); - builder.AppendLine(" -------------------------"); - if (component.FileGroupNames == null || component.FileGroupNames.Length == 0) + if (component == null) { - builder.AppendLine(" No file group names"); + builder.AppendLine($" Unassigned component"); } else { - for (int j = 0; j < component.FileGroupNames.Length; j++) + builder.AppendLine($" Identifier offset: {component.IdentifierOffset} (0x{component.IdentifierOffset:X})"); + builder.AppendLine($" Identifier: {component.Identifier ?? "[NULL]"}"); + builder.AppendLine($" Descriptor offset: {component.DescriptorOffset} (0x{component.DescriptorOffset:X})"); + builder.AppendLine($" Display name offset: {component.DisplayNameOffset} (0x{component.DisplayNameOffset:X})"); + builder.AppendLine($" Display name: {component.DisplayName ?? "[NULL]"}"); + builder.AppendLine($" Reserved 0: {BitConverter.ToString(component.Reserved0).Replace('-', ' ')}"); + builder.AppendLine($" Reserved offset 0: {component.ReservedOffset0} (0x{component.ReservedOffset0:X})"); + builder.AppendLine($" Reserved offset 1: {component.ReservedOffset1} (0x{component.ReservedOffset1:X})"); + builder.AppendLine($" Component index: {component.ComponentIndex} (0x{component.ComponentIndex:X})"); + builder.AppendLine($" Name offset: {component.NameOffset} (0x{component.NameOffset:X})"); + builder.AppendLine($" Name: {component.Name ?? "[NULL]"}"); + builder.AppendLine($" Reserved offset 2: {component.ReservedOffset2} (0x{component.ReservedOffset2:X})"); + builder.AppendLine($" Reserved offset 3: {component.ReservedOffset3} (0x{component.ReservedOffset3:X})"); + builder.AppendLine($" Reserved offset 4: {component.ReservedOffset4} (0x{component.ReservedOffset4:X})"); + builder.AppendLine($" Reserved 1: {BitConverter.ToString(component.Reserved1).Replace('-', ' ')}"); + builder.AppendLine($" CLSID offset: {component.CLSIDOffset} (0x{component.CLSIDOffset:X})"); + builder.AppendLine($" CLSID: {component.CLSID}"); + builder.AppendLine($" Reserved 2: {BitConverter.ToString(component.Reserved2).Replace('-', ' ')}"); + builder.AppendLine($" Reserved 3: {BitConverter.ToString(component.Reserved3).Replace('-', ' ')}"); + builder.AppendLine($" Depends count: {component.DependsCount} (0x{component.DependsCount:X})"); + builder.AppendLine($" Depends offset: {component.DependsOffset} (0x{component.DependsOffset:X})"); + builder.AppendLine($" File group count: {component.FileGroupCount} (0x{component.FileGroupCount:X})"); + builder.AppendLine($" File group names offset: {component.FileGroupNamesOffset} (0x{component.FileGroupNamesOffset:X})"); + builder.AppendLine(); + + builder.AppendLine($" File group names:"); + builder.AppendLine(" -------------------------"); + if (component.FileGroupNames == null || component.FileGroupNames.Length == 0) { - builder.AppendLine($" File Group Name {j}: {component.FileGroupNames[j] ?? "[NULL]"}"); + builder.AppendLine(" No file group names"); } + else + { + for (int j = 0; j < component.FileGroupNames.Length; j++) + { + builder.AppendLine($" File Group Name {j}: {component.FileGroupNames[j] ?? "[NULL]"}"); + } + } + builder.AppendLine(); + + builder.AppendLine($" X3 count: {component.X3Count} (0x{component.X3Count:X})"); + builder.AppendLine($" X3 offset: {component.X3Offset} (0x{component.X3Offset:X})"); + builder.AppendLine($" Sub-components count: {component.SubComponentsCount} (0x{component.SubComponentsCount:X})"); + builder.AppendLine($" Sub-components offset: {component.SubComponentsOffset} (0x{component.SubComponentsOffset:X})"); + builder.AppendLine($" Next component offset: {component.NextComponentOffset} (0x{component.NextComponentOffset:X})"); + builder.AppendLine($" Reserved offset 5: {component.ReservedOffset5} (0x{component.ReservedOffset5:X})"); + builder.AppendLine($" Reserved offset 6: {component.ReservedOffset6} (0x{component.ReservedOffset6:X})"); + builder.AppendLine($" Reserved offset 7: {component.ReservedOffset7} (0x{component.ReservedOffset7:X})"); + builder.AppendLine($" Reserved offset 8: {component.ReservedOffset8} (0x{component.ReservedOffset8:X})"); } } }