Fill in some missing IS-CAB parts

This commit is contained in:
Matt Nadareski
2023-01-14 00:41:13 -08:00
parent fbe09d9082
commit d7639495ac
9 changed files with 900 additions and 160 deletions

View File

@@ -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<long, OffsetList>();
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<FileGroup> fileGroups = new List<FileGroup>();
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<long, OffsetList>();
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<Component> components = new List<Component>();
int componentId = 0;
foreach (KeyValuePair<long, OffsetList> 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
}
/// <summary>
/// Parse a Stream into a cabinet descriptor
/// Parse a Stream into a descriptor
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled cabinet descriptor on success, null on error</returns>
private static CabDescriptor ParseCabinetDescriptor(Stream data)
/// <returns>Filled descriptor on success, null on error</returns>
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;
}
/// <summary>
@@ -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++)
{

View File

@@ -1,30 +0,0 @@
namespace BurnOutSharp.Models.InstallShieldCabinet
{
/// <see href="https://github.com/twogood/unshield/blob/main/lib/cabfile.h"/>
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;
}
}

View File

@@ -19,9 +19,9 @@ namespace BurnOutSharp.Models.InstallShieldCabinet
public VolumeHeader VolumeHeader { get; set; }
/// <summary>
/// Cabinet descriptor
/// Descriptor
/// </summary>
public CabDescriptor CabinetDescriptor { get; set; }
public Descriptor Descriptor { get; set; }
#endregion

View File

@@ -3,14 +3,29 @@ namespace BurnOutSharp.Models.InstallShieldCabinet
/// <see href="https://github.com/twogood/unshield/blob/main/lib/cabfile.h"/>
public sealed class CommonHeader
{
/// <summary>
/// "ISc("
/// </summary>
public string Signature;
/// <summary>
/// Encoded version
/// </summary>
public uint Version;
/// <summary>
/// Volume information
/// </summary>
public uint VolumeInfo;
public uint CabDescriptorOffset;
/// <summary>
/// Offset to cabinet descriptor
/// </summary>
public uint DescriptorOffset;
public uint CabDescriptorSize;
/// <summary>
/// Cabinet descriptor size
/// </summary>
public uint DescriptorSize;
}
}

View File

@@ -1,16 +1,173 @@
using System;
namespace BurnOutSharp.Models.InstallShieldCabinet
{
/// <see href="https://github.com/twogood/unshield/blob/main/lib/libunshield.h"/>
public sealed class Component
{
/// <summary>
/// Offset to the component identifier
/// </summary>
public uint IdentifierOffset;
/// <summary>
/// Component identifier
/// </summary>
public string Identifier;
/// <summary>
/// Offset to the component descriptor
/// </summary>
public uint DescriptorOffset;
/// <summary>
/// Offset to the display name
/// </summary>
public uint DisplayNameOffset;
/// <summary>
/// Display name
/// </summary>
public string DisplayName;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved0;
/// <summary>
/// Reserved offset
/// </summary>
public uint ReservedOffset0;
/// <summary>
/// Reserved offset
/// </summary>
public uint ReservedOffset1;
/// <summary>
/// Component index
/// </summary>
public ushort ComponentIndex;
/// <summary>
/// Offset to the component name
/// </summary>
public uint NameOffset;
/// <summary>
/// Component name
/// </summary>
public string Name;
public ushort FileGroupCount;
/// <summary>
/// Reserved offset
/// </summary>
public uint ReservedOffset2;
public uint FileGroupTableOffset;
/// <summary>
/// Reserved offset
/// </summary>
public uint ReservedOffset3;
/// <summary>
/// Reserved offset
/// </summary>
public uint ReservedOffset4;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved1;
/// <summary>
/// Offset to the component CLSID
/// </summary>
public uint CLSIDOffset;
/// <summary>
/// Component CLSID
/// </summary>
public Guid CLSID;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved2;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved3;
/// <summary>
/// Number of depends(?)
/// </summary>
public ushort DependsCount;
/// <summary>
/// Offset to depends(?)
/// </summary>
public uint DependsOffset;
/// <summary>
/// Number of file groups
/// </summary>
public uint FileGroupCount;
/// <summary>
/// Offset to the file group names
/// </summary>
public uint FileGroupNamesOffset;
/// <summary>
/// File group names
/// </summary>
public string[] FileGroupNames;
/// <summary>
/// Number of X3(?)
/// </summary>
public ushort X3Count;
/// <summary>
/// Offset to X3(?)
/// </summary>
public uint X3Offset;
/// <summary>
/// Number of sub-components
/// </summary>
public ushort SubComponentsCount;
/// <summary>
/// Offset to the sub-components
/// </summary>
public uint SubComponentsOffset;
/// <summary>
/// Offset to the next component
/// </summary>
public uint NextComponentOffset;
/// <summary>
/// Reserved offset
/// </summary>
public uint ReservedOffset5;
/// <summary>
/// Reserved offset
/// </summary>
public uint ReservedOffset6;
/// <summary>
/// Reserved offset
/// </summary>
public uint ReservedOffset7;
/// <summary>
/// Reserved offset
/// </summary>
public uint ReservedOffset8;
}
}

View File

@@ -0,0 +1,121 @@
namespace BurnOutSharp.Models.InstallShieldCabinet
{
/// <see href="https://github.com/twogood/unshield/blob/main/lib/cabfile.h"/>
public sealed class Descriptor
{
/// <summary>
/// Offset to the descriptor strings
/// </summary>
public uint StringsOffset;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved0;
/// <summary>
/// Offset to the component list
/// </summary>
public uint ComponentListOffset;
/// <summary>
/// Offset to the file table
/// </summary>
public uint FileTableOffset;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved1;
/// <summary>
/// Size of the file table
/// </summary>
public uint FileTableSize;
/// <summary>
/// Redundant size of the file table
/// </summary>
public uint FileTableSize2;
/// <summary>
/// Number of directories
/// </summary>
public ushort DirectoryCount;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved2;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved3;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved4;
/// <summary>
/// Number of files
/// </summary>
public uint FileCount;
/// <summary>
/// Redundant offset to the file table
/// </summary>
public uint FileTableOffset2;
/// <summary>
/// Number of component table infos
/// </summary>
public ushort ComponentTableInfoCount;
/// <summary>
/// Offset to the component table
/// </summary>
public uint ComponentTableOffset;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved5;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved6;
/// <summary>
/// Offsets to the file groups
/// </summary>
public uint[] FileGroupOffsets;
/// <summary>
/// Offsets to the components
/// </summary>
public uint[] ComponentOffsets;
/// <summary>
/// Offset to the setup types
/// </summary>
public uint SetupTypesOffset;
/// <summary>
/// Offset to the setup table
/// </summary>
public uint SetupTableOffset;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved7;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved8;
}
}

View File

@@ -3,28 +3,64 @@ namespace BurnOutSharp.Models.InstallShieldCabinet
/// <see href="https://github.com/twogood/unshield/blob/main/lib/cabfile.h"/>
public sealed class FileDescriptor
{
/// <summary>
/// Offset to the file descriptor name
/// </summary>
public uint NameOffset;
/// <summary>
/// File descriptor name
/// </summary>
public string Name;
/// <summary>
/// Directory index
/// </summary>
public uint DirectoryIndex;
/// <summary>
/// File flags
/// </summary>
public FileFlags Flags;
/// <summary>
/// Size of the entry when expanded
/// </summary>
public ulong ExpandedSize;
/// <summary>
/// Size of the entry when compressed
/// </summary>
public ulong CompressedSize;
/// <summary>
/// Offset to the entry data
/// </summary>
public ulong DataOffset;
/// <summary>
/// MD5 of the entry data
/// </summary>
public byte[] MD5;
/// <summary>
/// Volume number
/// </summary>
public ushort Volume;
/// <summary>
/// Link previous
/// </summary>
public uint LinkPrevious;
/// <summary>
/// Link next
/// </summary>
public uint LinkNext;
/// <summary>
/// Link flags
/// </summary>
public LinkFlags LinkFlags;
}
}

View File

@@ -3,12 +3,124 @@ namespace BurnOutSharp.Models.InstallShieldCabinet
/// <see href="https://github.com/twogood/unshield/blob/main/lib/libunshield.h"/>
public sealed class FileGroup
{
/// <summary>
/// Offset to the file group name
/// </summary>
public uint NameOffset;
/// <summary>
/// File group name
/// </summary>
public string Name;
/// <summary>
/// Size of the expanded data
/// </summary>
public uint ExpandedSize;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved0;
/// <summary>
/// Size of the compressed data
/// </summary>
public uint CompressedSize;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved1;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved2;
/// <summary>
/// Attribute(?)
/// </summary>
public ushort Attribute1;
/// <summary>
/// Attribute(?)
/// </summary>
public ushort Attribute2;
/// <summary>
/// Index of the first file
/// </summary>
public uint FirstFile;
/// <summary>
/// Index of the last file
/// </summary>
public uint LastFile;
/// <summary>
/// Unknown offset(?)
/// </summary>
public uint UnknownOffset;
/// <summary>
/// Var 4 offset(?)
/// </summary>
public uint Var4Offset;
/// <summary>
/// Var 1 offset(?)
/// </summary>
public uint Var1Offset;
/// <summary>
/// Offset to the HTTP location
/// </summary>
public uint HTTPLocationOffset;
/// <summary>
/// Offset to the FTP location
/// </summary>
public uint FTPLocationOffset;
/// <summary>
/// Misc offset(?)
/// </summary>
public uint MiscOffset;
/// <summary>
/// Var 2 offset(?)
/// </summary>
public uint Var2Offset;
/// <summary>
/// Offset to the target directory
/// </summary>
public uint TargetDirectoryOffset;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved3;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved4;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved5;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved6;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved7;
}
}

View File

@@ -20,11 +20,11 @@ namespace BurnOutSharp.Wrappers
/// <inheritdoc cref="Models.InstallShieldCabinet.CommonHeader.VolumeInfo"/>
public uint VolumeInfo => _cabinet.CommonHeader.VolumeInfo;
/// <inheritdoc cref="Models.InstallShieldCabinet.CommonHeader.CabDescriptorOffset"/>
public uint CabDescriptorOffset => _cabinet.CommonHeader.CabDescriptorOffset;
/// <inheritdoc cref="Models.InstallShieldCabinet.CommonHeader.DescriptorOffset"/>
public uint DescriptorOffset => _cabinet.CommonHeader.DescriptorOffset;
/// <inheritdoc cref="Models.InstallShieldCabinet.CommonHeader.CabDescriptorSize"/>
public uint CabDescriptorSize => _cabinet.CommonHeader.CabDescriptorSize;
/// <inheritdoc cref="Models.InstallShieldCabinet.CommonHeader.DescriptorSize"/>
public uint DescriptorSize => _cabinet.CommonHeader.DescriptorSize;
#endregion
@@ -80,6 +80,79 @@ namespace BurnOutSharp.Wrappers
#endregion
#region Descriptor
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.StringsOffset"/>
public uint StringsOffset => _cabinet.Descriptor.StringsOffset;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.Reserved0"/>
public byte[] Reserved0 => _cabinet.Descriptor.Reserved0;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.ComponentListOffset"/>
public uint ComponentListOffset => _cabinet.Descriptor.ComponentListOffset;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.FileTableOffset"/>
public uint FileTableOffset => _cabinet.Descriptor.FileTableOffset;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.Reserved1"/>
public byte[] Reserved1 => _cabinet.Descriptor.Reserved1;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.FileTableSize"/>
public uint FileTableSize => _cabinet.Descriptor.FileTableSize;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.FileTableSize2"/>
public uint FileTableSize2 => _cabinet.Descriptor.FileTableSize2;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.DirectoryCount"/>
public ushort DirectoryCount => _cabinet.Descriptor.DirectoryCount;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.Reserved2"/>
public byte[] Reserved2 => _cabinet.Descriptor.Reserved2;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.Reserved3"/>
public byte[] Reserved3 => _cabinet.Descriptor.Reserved3;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.Reserved4"/>
public byte[] Reserved4 => _cabinet.Descriptor.Reserved4;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.FileCount"/>
public uint FileCount => _cabinet.Descriptor.FileCount;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.FileTableOffset2"/>
public uint FileTableOffset2 => _cabinet.Descriptor.FileTableOffset2;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.ComponentTableInfoCount"/>
public ushort ComponentTableInfoCount => _cabinet.Descriptor.ComponentTableInfoCount;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.ComponentTableOffset"/>
public uint ComponentTableOffset => _cabinet.Descriptor.ComponentTableOffset;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.Reserved5"/>
public byte[] Reserved5 => _cabinet.Descriptor.Reserved5;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.Reserved6"/>
public byte[] Reserved6 => _cabinet.Descriptor.Reserved6;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.FileGroupOffsets"/>
public uint[] D_FileGroupOffsets => _cabinet.Descriptor.FileGroupOffsets;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.ComponentOffsets"/>
public uint[] D_ComponentOffsets => _cabinet.Descriptor.ComponentOffsets;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.SetupTypesOffset"/>
public uint SetupTypesOffset => _cabinet.Descriptor.SetupTypesOffset;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.SetupTableOffset"/>
public uint SetupTableOffset => _cabinet.Descriptor.SetupTableOffset;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.Reserved7"/>
public byte[] Reserved7 => _cabinet.Descriptor.Reserved7;
/// <inheritdoc cref="Models.InstallShieldCabinet.Descriptor.Reserved8"/>
public byte[] Reserved8 => _cabinet.Descriptor.Reserved8;
#endregion
#region File Descriptor Offsets
/// <inheritdoc cref="Models.InstallShieldCabinet.Cabinet.FileDescriptorOffsets"/>
@@ -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();
}
/// <summary>
/// Print descriptor information
/// </summary>
/// <param name="builder">StringBuilder to append information to</param>
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();
}
/// <summary>
/// Print file descriptor offsets information
/// </summary>
@@ -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})");
}
}
}