Add ISAv3 deserializer

This commit is contained in:
Matt Nadareski
2024-04-23 15:12:42 -04:00
parent 1e83fc4b9a
commit 351f749e20
2 changed files with 151 additions and 11 deletions

View File

@@ -0,0 +1,140 @@
using System.Collections.Generic;
using System.IO;
using SabreTools.IO.Extensions;
using SabreTools.Models.InstallShieldArchiveV3;
namespace SabreTools.Serialization.Deserializers
{
public class InstallShieldArchiveV3 : BaseBinaryDeserializer<Archive>
{
public override Archive? Deserialize(Stream? data)
{
// If the data is invalid
if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead)
return null;
// If the offset is out of bounds
if (data.Position < 0 || data.Position >= data.Length)
return null;
// Cache the current offset
int initialOffset = (int)data.Position;
// Create a new archive to fill
var archive = new Archive();
#region Header
// Try to parse the header
var header = ParseHeader(data);
if (header == null)
return null;
// Set the archive header
archive.Header = header;
#endregion
#region Directories
// Get the directories offset
uint directoriesOffset = header.TocAddress;
if (directoriesOffset < 0 || directoriesOffset >= data.Length)
return null;
// Seek to the directories
data.Seek(directoriesOffset, SeekOrigin.Begin);
// Try to parse the directories
var directories = new List<Models.InstallShieldArchiveV3.Directory>();
for (int i = 0; i < header.DirCount; i++)
{
var directory = ParseDirectory(data, out uint chunkSize);
if (directory?.Name == null)
return null;
directories.Add(directory);
data.Seek(chunkSize - directory.Name.Length - 6, SeekOrigin.Current);
}
// Set the directories
archive.Directories = [.. directories];
#endregion
#region Files
// Try to parse the files
var files = new List<Models.InstallShieldArchiveV3.File>();
for (int i = 0; i < archive.Directories.Length; i++)
{
var directory = archive.Directories[i];
for (int j = 0; j < directory.FileCount; j++)
{
var file = ParseFile(data);
if (file?.Name == null)
return null;
files.Add(file);
data.Seek(file.ChunkSize - file.Name.Length - 30, SeekOrigin.Current);
}
}
// Set the files
archive.Files = [.. files];
#endregion
return archive;
}
/// <summary>
/// Parse a Stream into a header
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled header on success, null on error</returns>
public static Header? ParseHeader(Stream data)
{
var header = data.ReadType<Header>();
if (header == null)
return null;
// Invalid signature
if (header.Signature1 != 0x8C655D13) // TODO: Move constant to Models
return null;
// Invalid TOC address
if (header.TocAddress >= data.Length)
return null;
return header;
}
/// <summary>
/// Parse a Stream into a directory
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled directory on success, null on error</returns>
public static Models.InstallShieldArchiveV3.Directory? ParseDirectory(Stream data, out uint chunkSize)
{
// TODO: Use ReadType when model is fixed
var directory = new Models.InstallShieldArchiveV3.Directory();
directory.FileCount = data.ReadUInt16();
chunkSize = data.ReadUInt16(); // TODO: Add to model and remove from output params
directory.Name = data.ReadPrefixedAnsiString();
return directory;
}
/// <summary>
/// Parse a Stream into a file
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled file on success, null on error</returns>
public static Models.InstallShieldArchiveV3.File? ParseFile(Stream data)
{
return data.ReadType<Models.InstallShieldArchiveV3.File>();
}
}
}

View File

@@ -411,22 +411,22 @@ namespace SabreTools.Serialization.Deserializers
Descriptor descriptor = new Descriptor();
descriptor.StringsOffset = data.ReadUInt32();
descriptor.Reserved0 = data.ReadBytes(4);
descriptor.Reserved0 = data.ReadUInt32();
descriptor.ComponentListOffset = data.ReadUInt32();
descriptor.FileTableOffset = data.ReadUInt32();
descriptor.Reserved1 = data.ReadBytes(4);
descriptor.Reserved1 = data.ReadUInt32();
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.Reserved2 = data.ReadUInt32();
descriptor.Reserved3 = data.ReadUInt16();
descriptor.Reserved4 = data.ReadUInt32();
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);
descriptor.Reserved5 = data.ReadUInt32();
descriptor.Reserved6 = data.ReadUInt32();
descriptor.FileGroupOffsets = new uint[MAX_FILE_GROUP_COUNT];
for (int i = 0; i < descriptor.FileGroupOffsets.Length; i++)
@@ -442,8 +442,8 @@ namespace SabreTools.Serialization.Deserializers
descriptor.SetupTypesOffset = data.ReadUInt32();
descriptor.SetupTableOffset = data.ReadUInt32();
descriptor.Reserved7 = data.ReadBytes(4);
descriptor.Reserved8 = data.ReadBytes(4);
descriptor.Reserved7 = data.ReadUInt32();
descriptor.Reserved8 = data.ReadUInt32();
return descriptor;
}
@@ -471,9 +471,9 @@ namespace SabreTools.Serialization.Deserializers
// Read the string
if (majorVersion >= 17)
offsetList.Name = data.ReadString(Encoding.Unicode);
offsetList.Name = data.ReadNullTerminatedUnicodeString();
else
offsetList.Name = data.ReadString(Encoding.ASCII);
offsetList.Name = data.ReadNullTerminatedAnsiString();
// Seek back to the correct offset
data.Seek(currentOffset, SeekOrigin.Begin);