diff --git a/SabreTools.Serialization/UnshieldSharp/Reader.cs b/SabreTools.Serialization/UnshieldSharp/Reader.cs deleted file mode 100644 index 4f1144af..00000000 --- a/SabreTools.Serialization/UnshieldSharp/Reader.cs +++ /dev/null @@ -1,249 +0,0 @@ -using System; -using System.IO; -using SabreTools.Models.InstallShieldCabinet; -using Header = SabreTools.Serialization.Wrappers.InstallShieldCabinet; - -namespace UnshieldSharpInternal -{ - internal class Reader : IDisposable - { - #region Private Instance Variables - - /// - /// Cabinet file to read from - /// - private readonly Header _cabinet; - - /// - /// Currently selected index - /// - private readonly uint _index; - - /// - /// File descriptor defining the currently selected index - /// - private readonly FileDescriptor _fileDescriptor; - - /// - /// Offset in the data where the file exists - /// - private ulong _dataOffset; - - /// - /// Number of bytes left in the current volume - /// - private ulong _volumeBytesLeft; - - /// - /// Handle to the current volume stream - /// - private Stream? _volumeFile; - - /// - /// Current volume header - /// - private VolumeHeader? _volumeHeader; - - /// - /// Current volume ID - /// - private ushort _volumeId; - - /// - /// Offset for obfuscation seed - /// - private uint _obfuscationOffset; - - #endregion - - #region Constructors - - private Reader(Header cabinet, uint index, FileDescriptor fileDescriptor) - { - _cabinet = cabinet; - _index = index; - _fileDescriptor = fileDescriptor; - } - - #endregion - - /// - /// Create a new from an existing cabinet, index, and file descriptor - /// - public static Reader? Create(Header cabinet, int index, FileDescriptor fileDescriptor) - { - var reader = new Reader(cabinet, (uint)index, fileDescriptor); - for (; ; ) - { - // If the volume is invalid - if (!reader.OpenVolume(fileDescriptor.Volume)) - { - Console.Error.WriteLine($"Failed to open volume {fileDescriptor.Volume}"); - return null; - } - else if (reader._volumeFile == null || reader._volumeHeader == null) - { - Console.Error.WriteLine($"Volume {fileDescriptor.Volume} is invalid"); - return null; - } - - // Start with the correct volume for IS5 cabinets - if (reader._cabinet.MajorVersion <= 5 && index > (int)reader._volumeHeader.LastFileIndex) - { - // Normalize the volume ID for odd cases - if (fileDescriptor.Volume == ushort.MinValue || fileDescriptor.Volume == ushort.MaxValue) - fileDescriptor.Volume = 1; - - fileDescriptor.Volume++; - continue; - } - - break; - } - - return reader; - } - - /// - /// Dispose of the current object - /// - public void Dispose() - { - _volumeFile?.Close(); - } - - #region Reading - - /// - /// Read a certain number of bytes from the current volume - /// - public bool Read(byte[] buffer, int start, long size) - { - long bytesLeft = size; - while (bytesLeft > 0) - { - // Open the next volume, if necessary - if (_volumeBytesLeft == 0) - { - if (!OpenNextVolume(out _)) - return false; - } - - // Get the number of bytes to read from this volume - int bytesToRead = (int)Math.Min(bytesLeft, (long)_volumeBytesLeft); - if (bytesToRead == 0) - break; - - // Read as much as possible from this volume - if (bytesToRead != _volumeFile!.Read(buffer, start, bytesToRead)) - return false; - - // Set the number of bytes left - bytesLeft -= bytesToRead; - _volumeBytesLeft -= (uint)bytesToRead; - } - -#if NET20 || NET35 - if ((_fileDescriptor.Flags & FileFlags.FILE_OBFUSCATED) != 0) -#else - if (_fileDescriptor.Flags.HasFlag(FileFlags.FILE_OBFUSCATED)) -#endif - Header.Deobfuscate(buffer, size, ref _obfuscationOffset); - - return true; - } - - /// - /// Open the next volume based on the current index - /// - private bool OpenNextVolume(out ushort nextVolume) - { - nextVolume = (ushort)(_volumeId + 1); - return OpenVolume(nextVolume); - } - - /// - /// Open the volume at the inputted index - /// - private bool OpenVolume(ushort volume) - { - // Read the volume from the cabinet set - var next = _cabinet.OpenVolume(volume, out var volumeStream); - if (next?.VolumeHeader == null || volumeStream == null) - { - Console.Error.WriteLine($"Failed to open input cabinet file {volume}"); - return false; - } - - // Assign the next items - _volumeFile?.Close(); - _volumeFile = volumeStream; - _volumeHeader = next.VolumeHeader; - - // Enable support for split archives for IS5 - if (_cabinet.MajorVersion == 5) - { - if (_index < (_cabinet.FileCount - 1) - && _index == _volumeHeader.LastFileIndex - && _volumeHeader.LastFileSizeCompressed != _fileDescriptor.CompressedSize) - { - _fileDescriptor.Flags |= FileFlags.FILE_SPLIT; - } - else if (_index > 0 - && _index == _volumeHeader.FirstFileIndex - && _volumeHeader.FirstFileSizeCompressed != _fileDescriptor.CompressedSize) - { - _fileDescriptor.Flags |= FileFlags.FILE_SPLIT; - } - } - - ulong volumeBytesLeftCompressed, volumeBytesLeftExpanded; -#if NET20 || NET35 - if ((_fileDescriptor.Flags & FileFlags.FILE_SPLIT) != 0) -#else - if (_fileDescriptor.Flags.HasFlag(FileFlags.FILE_SPLIT)) -#endif - { - if (_index == _volumeHeader.LastFileIndex && _volumeHeader.LastFileOffset != 0x7FFFFFFF) - { - // can be first file too - _dataOffset = _volumeHeader.LastFileOffset; - volumeBytesLeftExpanded = _volumeHeader.LastFileSizeExpanded; - volumeBytesLeftCompressed = _volumeHeader.LastFileSizeCompressed; - } - else if (_index == _volumeHeader.FirstFileIndex) - { - _dataOffset = _volumeHeader.FirstFileOffset; - volumeBytesLeftExpanded = _volumeHeader.FirstFileSizeExpanded; - volumeBytesLeftCompressed = _volumeHeader.FirstFileSizeCompressed; - } - else - { - return true; - } - } - else - { - _dataOffset = _fileDescriptor.DataOffset; - volumeBytesLeftExpanded = _fileDescriptor.ExpandedSize; - volumeBytesLeftCompressed = _fileDescriptor.CompressedSize; - } - -#if NET20 || NET35 - if ((_fileDescriptor.Flags & FileFlags.FILE_COMPRESSED) != 0) -#else - if (_fileDescriptor.Flags.HasFlag(FileFlags.FILE_COMPRESSED)) -#endif - _volumeBytesLeft = volumeBytesLeftCompressed; - else - _volumeBytesLeft = volumeBytesLeftExpanded; - - _volumeFile.Seek((long)_dataOffset, SeekOrigin.Begin); - _volumeId = volume; - - return true; - } - - #endregion - } -} diff --git a/SabreTools.Serialization/Wrappers/InstallShieldCabinet.cs b/SabreTools.Serialization/Wrappers/InstallShieldCabinet.cs index f3dac980..dad9ea4f 100644 --- a/SabreTools.Serialization/Wrappers/InstallShieldCabinet.cs +++ b/SabreTools.Serialization/Wrappers/InstallShieldCabinet.cs @@ -5,7 +5,6 @@ using SabreTools.Hashing; using SabreTools.IO.Compression.zlib; using SabreTools.Models.InstallShieldCabinet; using SabreTools.Serialization.Interfaces; -using UnshieldSharpInternal; using static SabreTools.Models.InstallShieldCabinet.Constants; namespace SabreTools.Serialization.Wrappers @@ -940,5 +939,254 @@ namespace SabreTools.Serialization.Wrappers private static int ROL8(int x, byte n) => (x << n) | (x >> (8 - n)); #endregion + + #region Helper Classes + + /// + /// Helper to read a single file from a cabinet set + /// + private class Reader : IDisposable + { + #region Private Instance Variables + + /// + /// Cabinet file to read from + /// + private readonly InstallShieldCabinet _cabinet; + + /// + /// Currently selected index + /// + private readonly uint _index; + + /// + /// File descriptor defining the currently selected index + /// + private readonly FileDescriptor _fileDescriptor; + + /// + /// Offset in the data where the file exists + /// + private ulong _dataOffset; + + /// + /// Number of bytes left in the current volume + /// + private ulong _volumeBytesLeft; + + /// + /// Handle to the current volume stream + /// + private Stream? _volumeFile; + + /// + /// Current volume header + /// + private VolumeHeader? _volumeHeader; + + /// + /// Current volume ID + /// + private ushort _volumeId; + + /// + /// Offset for obfuscation seed + /// + private uint _obfuscationOffset; + + #endregion + + #region Constructors + + private Reader(InstallShieldCabinet cabinet, uint index, FileDescriptor fileDescriptor) + { + _cabinet = cabinet; + _index = index; + _fileDescriptor = fileDescriptor; + } + + #endregion + + /// + /// Create a new from an existing cabinet, index, and file descriptor + /// + public static Reader? Create(InstallShieldCabinet cabinet, int index, FileDescriptor fileDescriptor) + { + var reader = new Reader(cabinet, (uint)index, fileDescriptor); + for (; ; ) + { + // If the volume is invalid + if (!reader.OpenVolume(fileDescriptor.Volume)) + { + Console.Error.WriteLine($"Failed to open volume {fileDescriptor.Volume}"); + return null; + } + else if (reader._volumeFile == null || reader._volumeHeader == null) + { + Console.Error.WriteLine($"Volume {fileDescriptor.Volume} is invalid"); + return null; + } + + // Start with the correct volume for IS5 cabinets + if (reader._cabinet.MajorVersion <= 5 && index > (int)reader._volumeHeader.LastFileIndex) + { + // Normalize the volume ID for odd cases + if (fileDescriptor.Volume == ushort.MinValue || fileDescriptor.Volume == ushort.MaxValue) + fileDescriptor.Volume = 1; + + fileDescriptor.Volume++; + continue; + } + + break; + } + + return reader; + } + + /// + /// Dispose of the current object + /// + public void Dispose() + { + _volumeFile?.Close(); + } + + #region Reading + + /// + /// Read a certain number of bytes from the current volume + /// + public bool Read(byte[] buffer, int start, long size) + { + long bytesLeft = size; + while (bytesLeft > 0) + { + // Open the next volume, if necessary + if (_volumeBytesLeft == 0) + { + if (!OpenNextVolume(out _)) + return false; + } + + // Get the number of bytes to read from this volume + int bytesToRead = (int)Math.Min(bytesLeft, (long)_volumeBytesLeft); + if (bytesToRead == 0) + break; + + // Read as much as possible from this volume + if (bytesToRead != _volumeFile!.Read(buffer, start, bytesToRead)) + return false; + + // Set the number of bytes left + bytesLeft -= bytesToRead; + _volumeBytesLeft -= (uint)bytesToRead; + } + +#if NET20 || NET35 + if ((_fileDescriptor.Flags & FileFlags.FILE_OBFUSCATED) != 0) +#else + if (_fileDescriptor.Flags.HasFlag(FileFlags.FILE_OBFUSCATED)) +#endif + Deobfuscate(buffer, size, ref _obfuscationOffset); + + return true; + } + + /// + /// Open the next volume based on the current index + /// + private bool OpenNextVolume(out ushort nextVolume) + { + nextVolume = (ushort)(_volumeId + 1); + return OpenVolume(nextVolume); + } + + /// + /// Open the volume at the inputted index + /// + private bool OpenVolume(ushort volume) + { + // Read the volume from the cabinet set + var next = _cabinet.OpenVolume(volume, out var volumeStream); + if (next?.VolumeHeader == null || volumeStream == null) + { + Console.Error.WriteLine($"Failed to open input cabinet file {volume}"); + return false; + } + + // Assign the next items + _volumeFile?.Close(); + _volumeFile = volumeStream; + _volumeHeader = next.VolumeHeader; + + // Enable support for split archives for IS5 + if (_cabinet.MajorVersion == 5) + { + if (_index < (_cabinet.FileCount - 1) + && _index == _volumeHeader.LastFileIndex + && _volumeHeader.LastFileSizeCompressed != _fileDescriptor.CompressedSize) + { + _fileDescriptor.Flags |= FileFlags.FILE_SPLIT; + } + else if (_index > 0 + && _index == _volumeHeader.FirstFileIndex + && _volumeHeader.FirstFileSizeCompressed != _fileDescriptor.CompressedSize) + { + _fileDescriptor.Flags |= FileFlags.FILE_SPLIT; + } + } + + ulong volumeBytesLeftCompressed, volumeBytesLeftExpanded; +#if NET20 || NET35 + if ((_fileDescriptor.Flags & FileFlags.FILE_SPLIT) != 0) +#else + if (_fileDescriptor.Flags.HasFlag(FileFlags.FILE_SPLIT)) +#endif + { + if (_index == _volumeHeader.LastFileIndex && _volumeHeader.LastFileOffset != 0x7FFFFFFF) + { + // can be first file too + _dataOffset = _volumeHeader.LastFileOffset; + volumeBytesLeftExpanded = _volumeHeader.LastFileSizeExpanded; + volumeBytesLeftCompressed = _volumeHeader.LastFileSizeCompressed; + } + else if (_index == _volumeHeader.FirstFileIndex) + { + _dataOffset = _volumeHeader.FirstFileOffset; + volumeBytesLeftExpanded = _volumeHeader.FirstFileSizeExpanded; + volumeBytesLeftCompressed = _volumeHeader.FirstFileSizeCompressed; + } + else + { + return true; + } + } + else + { + _dataOffset = _fileDescriptor.DataOffset; + volumeBytesLeftExpanded = _fileDescriptor.ExpandedSize; + volumeBytesLeftCompressed = _fileDescriptor.CompressedSize; + } + +#if NET20 || NET35 + if ((_fileDescriptor.Flags & FileFlags.FILE_COMPRESSED) != 0) +#else + if (_fileDescriptor.Flags.HasFlag(FileFlags.FILE_COMPRESSED)) +#endif + _volumeBytesLeft = volumeBytesLeftCompressed; + else + _volumeBytesLeft = volumeBytesLeftExpanded; + + _volumeFile.Seek((long)_dataOffset, SeekOrigin.Begin); + _volumeId = volume; + + return true; + } + + #endregion + } + + #endregion } }