mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-09-21 22:35:06 +00:00
Add ISAv3 deserializer
This commit is contained in:
140
SabreTools.Serialization/Deserializers/InstallShieldArchiveV3.cs
Normal file
140
SabreTools.Serialization/Deserializers/InstallShieldArchiveV3.cs
Normal 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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user