From ba97381b99dc344a10accc05ffd8ff8375ec4005 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Wed, 11 Dec 2024 13:56:01 -0500 Subject: [PATCH] Add more ISAv3 stuff --- .../Wrappers/InstallShieldArchiveV3Tests.cs | 61 ++++++++++ SabreTools.Serialization/Printer.cs | 12 ++ .../Printers/InstallShieldArchiveV3.cs | 114 ++++++++++++++++++ .../Wrappers/InstallShieldArchiveV3.cs | 79 ++++++++++++ .../Wrappers/WrapperFactory.cs | 2 +- .../Wrappers/WrapperType.cs | 1 - 6 files changed, 267 insertions(+), 2 deletions(-) create mode 100644 SabreTools.Serialization.Test/Wrappers/InstallShieldArchiveV3Tests.cs create mode 100644 SabreTools.Serialization/Printers/InstallShieldArchiveV3.cs create mode 100644 SabreTools.Serialization/Wrappers/InstallShieldArchiveV3.cs diff --git a/SabreTools.Serialization.Test/Wrappers/InstallShieldArchiveV3Tests.cs b/SabreTools.Serialization.Test/Wrappers/InstallShieldArchiveV3Tests.cs new file mode 100644 index 00000000..22b3b440 --- /dev/null +++ b/SabreTools.Serialization.Test/Wrappers/InstallShieldArchiveV3Tests.cs @@ -0,0 +1,61 @@ +using System.IO; +using System.Linq; +using SabreTools.Serialization.Wrappers; +using Xunit; + +namespace SabreTools.Serialization.Test.Wrappers +{ + public class InstallShieldArchiveV3Tests + { + [Fact] + public void NullArray_Null() + { + byte[]? data = null; + int offset = 0; + var actual = InstallShieldArchiveV3.Create(data, offset); + Assert.Null(actual); + } + + [Fact] + public void EmptyArray_Null() + { + byte[]? data = []; + int offset = 0; + var actual = InstallShieldArchiveV3.Create(data, offset); + Assert.Null(actual); + } + + [Fact] + public void InvalidArray_Null() + { + byte[]? data = [.. Enumerable.Repeat(0xFF, 1024)]; + int offset = 0; + var actual = InstallShieldArchiveV3.Create(data, offset); + Assert.Null(actual); + } + + [Fact] + public void NullStream_Null() + { + Stream? data = null; + var actual = InstallShieldArchiveV3.Create(data); + Assert.Null(actual); + } + + [Fact] + public void EmptyStream_Null() + { + Stream? data = new MemoryStream([]); + var actual = InstallShieldArchiveV3.Create(data); + Assert.Null(actual); + } + + [Fact] + public void InvalidStream_Null() + { + Stream? data = new MemoryStream([.. Enumerable.Repeat(0xFF, 1024)]); + var actual = InstallShieldArchiveV3.Create(data); + Assert.Null(actual); + } + } +} \ No newline at end of file diff --git a/SabreTools.Serialization/Printer.cs b/SabreTools.Serialization/Printer.cs index 9f608545..0f750754 100644 --- a/SabreTools.Serialization/Printer.cs +++ b/SabreTools.Serialization/Printer.cs @@ -42,6 +42,7 @@ namespace SabreTools.Serialization Wrapper.CHD item => item.PrettyPrint(), Wrapper.CIA item => item.PrettyPrint(), Wrapper.GCF item => item.PrettyPrint(), + Wrapper.InstallShieldArchiveV3 item => item.PrettyPrint(), Wrapper.InstallShieldCabinet item => item.PrettyPrint(), Wrapper.IRD item => item.PrettyPrint(), Wrapper.LinearExecutable item => item.PrettyPrint(), @@ -90,6 +91,7 @@ namespace SabreTools.Serialization Wrapper.CHD item => item.ExportJSON(), Wrapper.CIA item => item.ExportJSON(), Wrapper.GCF item => item.ExportJSON(), + Wrapper.InstallShieldArchiveV3 item => item.ExportJSON(), Wrapper.InstallShieldCabinet item => item.ExportJSON(), Wrapper.IRD item => item.ExportJSON(), Wrapper.LinearExecutable item => item.ExportJSON(), @@ -205,6 +207,16 @@ namespace SabreTools.Serialization return builder; } + /// + /// Export the item information as pretty-printed text + /// + private static StringBuilder PrettyPrint(this Wrapper.InstallShieldArchiveV3 item) + { + var builder = new StringBuilder(); + InstallShieldArchiveV3.Print(builder, item.Model); + return builder; + } + /// /// Export the item information as pretty-printed text /// diff --git a/SabreTools.Serialization/Printers/InstallShieldArchiveV3.cs b/SabreTools.Serialization/Printers/InstallShieldArchiveV3.cs new file mode 100644 index 00000000..1db10794 --- /dev/null +++ b/SabreTools.Serialization/Printers/InstallShieldArchiveV3.cs @@ -0,0 +1,114 @@ +using System.Text; +using SabreTools.Models.InstallShieldArchiveV3; +using SabreTools.Serialization.Interfaces; + +namespace SabreTools.Serialization.Printers +{ + public class InstallShieldArchiveV3 : IPrinter + { + /// + public void PrintInformation(StringBuilder builder, Archive model) + => Print(builder, model); + + public static void Print(StringBuilder builder, Archive archive) + { + builder.AppendLine("InstallShield Archive V3 Information:"); + builder.AppendLine("-------------------------"); + builder.AppendLine(); + + Print(builder, archive.Header); + Print(builder, archive.Directories); + Print(builder, archive.Files); + } + + private static void Print(StringBuilder builder, Header? header) + { + builder.AppendLine(" Header Information:"); + builder.AppendLine(" -------------------------"); + if (header == null) + { + builder.AppendLine(" No header"); + builder.AppendLine(); + return; + } + + builder.AppendLine(header.Signature1, " Signature 1"); + builder.AppendLine(header.Signature2, " Signature 2"); + builder.AppendLine(header.Reserved0, " Reserved 0"); + builder.AppendLine(header.IsMultivolume, " Is multivolume"); + builder.AppendLine(header.FileCount, " File count"); + builder.AppendLine(header.DateTime, " Datetime"); + builder.AppendLine(header.CompressedSize, " Compressed size"); + builder.AppendLine(header.UncompressedSize, " Uncompressed size"); + builder.AppendLine(header.Reserved1, " Reserved 1"); + builder.AppendLine(header.VolumeTotal, " Volume total"); + builder.AppendLine(header.VolumeNumber, " Volume number"); + builder.AppendLine(header.Reserved2, " Reserved 2"); + builder.AppendLine(header.SplitBeginAddress, " Split begin address"); + builder.AppendLine(header.SplitEndAddress, " Split end address"); + builder.AppendLine(header.TocAddress, " TOC address"); + builder.AppendLine(header.Reserved3, " Reserved 3"); + builder.AppendLine(header.DirCount, " Dir count"); + builder.AppendLine(header.Reserved4, " Reserved 4"); + builder.AppendLine(header.Reserved5, " Reserved 5"); + builder.AppendLine(); + } + + private static void Print(StringBuilder builder, Directory[]? entries) + { + builder.AppendLine(" Directories:"); + builder.AppendLine(" -------------------------"); + if (entries == null || entries.Length == 0) + { + builder.AppendLine(" No directories"); + builder.AppendLine(); + return; + } + + for (int i = 0; i < entries.Length; i++) + { + var entry = entries[i]; + builder.AppendLine($" Directory {i}"); + builder.AppendLine(entry.FileCount, " File count"); + builder.AppendLine(entry.ChunkSize, " Chunk size"); + builder.AppendLine(entry.NameLength, " Name length"); + builder.AppendLine(entry.Name, " Name"); + } + + builder.AppendLine(); + } + + private static void Print(StringBuilder builder, File[]? entries) + { + builder.AppendLine(" Files:"); + builder.AppendLine(" -------------------------"); + if (entries == null || entries.Length == 0) + { + builder.AppendLine(" No files"); + builder.AppendLine(); + return; + } + + for (int i = 0; i < entries.Length; i++) + { + var entry = entries[i]; + builder.AppendLine($" File {i}"); + builder.AppendLine(entry.VolumeEnd, " Volume end"); + builder.AppendLine(entry.Index, " Index"); + builder.AppendLine(entry.UncompressedSize, " Uncompressed size"); + builder.AppendLine(entry.CompressedSize, " Compressed size"); + builder.AppendLine(entry.Offset, " Offset"); + builder.AppendLine(entry.DateTime, " Datetime"); + builder.AppendLine(entry.Reserved0, " Reserved 0"); + builder.AppendLine(entry.ChunkSize, " Chunk size"); + builder.AppendLine($" Attrib: {entry.Attrib} (0x{entry.Attrib:X})"); + builder.AppendLine(entry.IsSplit, " Is split"); + builder.AppendLine(entry.Reserved1, " Reserved 1"); + builder.AppendLine(entry.VolumeStart, " Volume start"); + builder.AppendLine(entry.Name, " Name"); + } + + builder.AppendLine(); + } + } +} \ No newline at end of file diff --git a/SabreTools.Serialization/Wrappers/InstallShieldArchiveV3.cs b/SabreTools.Serialization/Wrappers/InstallShieldArchiveV3.cs new file mode 100644 index 00000000..37534625 --- /dev/null +++ b/SabreTools.Serialization/Wrappers/InstallShieldArchiveV3.cs @@ -0,0 +1,79 @@ +using System.IO; +using SabreTools.Models.InstallShieldArchiveV3; + +namespace SabreTools.Serialization.Wrappers +{ + public partial class InstallShieldArchiveV3 : WrapperBase + { + #region Descriptive Properties + + /// + public override string DescriptionString => "InstallShield Archive V3"; + + #endregion + + #region Constructors + + /// + public InstallShieldArchiveV3(Archive? model, byte[]? data, int offset) + : base(model, data, offset) + { + // All logic is handled by the base class + } + + /// + public InstallShieldArchiveV3(Archive? model, Stream? data) + : base(model, data) + { + // All logic is handled by the base class + } + + /// + /// Create an InstallShield Archive V3 from a byte array and offset + /// + /// Byte array representing the archive + /// Offset within the array to parse + /// A archive wrapper on success, null on failure + public static InstallShieldArchiveV3? Create(byte[]? data, int offset) + { + // If the data is invalid + if (data == null || data.Length == 0) + return null; + + // If the offset is out of bounds + if (offset < 0 || offset >= data.Length) + return null; + + // Create a memory stream and use that + var dataStream = new MemoryStream(data, offset, data.Length - offset); + return Create(dataStream); + } + + /// + /// Create a InstallShield Archive V3 from a Stream + /// + /// Stream representing the archive + /// A archive wrapper on success, null on failure + public static InstallShieldArchiveV3? Create(Stream? data) + { + // If the data is invalid + if (data == null || !data.CanRead) + return null; + + try + { + var archive = Deserializers.InstallShieldArchiveV3.DeserializeStream(data); + if (archive == null) + return null; + + return new InstallShieldArchiveV3(archive, data); + } + catch + { + return null; + } + } + + #endregion + } +} diff --git a/SabreTools.Serialization/Wrappers/WrapperFactory.cs b/SabreTools.Serialization/Wrappers/WrapperFactory.cs index c2490aa0..0d457b43 100644 --- a/SabreTools.Serialization/Wrappers/WrapperFactory.cs +++ b/SabreTools.Serialization/Wrappers/WrapperFactory.cs @@ -28,7 +28,7 @@ namespace SabreTools.Serialization.Wrappers WrapperType.GCF => GCF.Create(data), WrapperType.GZIP => null,// TODO: Implement wrapper WrapperType.IniFile => null,// TODO: Implement wrapper - WrapperType.InstallShieldArchiveV3 => null,// TODO: Implement wrapper + WrapperType.InstallShieldArchiveV3 => InstallShieldArchiveV3.Create(data), WrapperType.InstallShieldCAB => InstallShieldCabinet.Create(data), WrapperType.LDSCRYPT => null,// TODO: Implement wrapper WrapperType.LZKWAJ => LZKWAJ.Create(data), diff --git a/SabreTools.Serialization/Wrappers/WrapperType.cs b/SabreTools.Serialization/Wrappers/WrapperType.cs index 3bb31f99..9129c905 100644 --- a/SabreTools.Serialization/Wrappers/WrapperType.cs +++ b/SabreTools.Serialization/Wrappers/WrapperType.cs @@ -77,7 +77,6 @@ namespace SabreTools.Serialization.Wrappers /// /// InstallShield archive v3 /// - /// Currently has no IWrapper implementation InstallShieldArchiveV3, ///