mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-04-21 21:59:47 +00:00
Let's see how UnshieldSharp goes
This commit is contained in:
@@ -67,7 +67,6 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SabreTools.IO" Version="1.7.0" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.8" Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))" />
|
||||
<PackageReference Include="UnshieldSharp" Version="1.9.4" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -286,7 +286,7 @@ namespace ExtractionTool
|
||||
if (!File.Exists(file))
|
||||
return false;
|
||||
|
||||
var cabfile = UnshieldSharp.InstallShieldCabinet.Open(file);
|
||||
var cabfile = UnshieldSharpInternal.InstallShieldCabinet.Open(file);
|
||||
if (cabfile?.HeaderList == null)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<InternalsVisibleTo Include="ExtractionTool" />
|
||||
<InternalsVisibleTo Include="SabreTools.Serialization.Test" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
274
SabreTools.Serialization/UnshieldSharp/InstallShieldCabinet.cs
Normal file
274
SabreTools.Serialization/UnshieldSharp/InstallShieldCabinet.cs
Normal file
@@ -0,0 +1,274 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SabreTools.Hashing;
|
||||
using SabreTools.IO.Compression.zlib;
|
||||
using SabreTools.Models.InstallShieldCabinet;
|
||||
using Header = SabreTools.Serialization.Wrappers.InstallShieldCabinet;
|
||||
|
||||
namespace UnshieldSharpInternal
|
||||
{
|
||||
// TODO: Figure out if individual parts of a split cab can be extracted separately
|
||||
internal class InstallShieldCabinet
|
||||
{
|
||||
/// <summary>
|
||||
/// Linked CAB headers
|
||||
/// </summary>
|
||||
public Header? HeaderList { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Base filename path for related CAB files
|
||||
/// </summary>
|
||||
public string? FilenamePattern { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default buffer size
|
||||
/// </summary>
|
||||
private const int BUFFER_SIZE = 64 * 1024;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum size of the window in bits
|
||||
/// </summary>
|
||||
/// TODO: Remove when Serialization is updated
|
||||
private const int MAX_WBITS = 15;
|
||||
|
||||
#region Open Cabinet
|
||||
|
||||
/// <summary>
|
||||
/// Open a file as an InstallShield CAB
|
||||
/// </summary>
|
||||
public static InstallShieldCabinet? Open(string filename)
|
||||
{
|
||||
var cabinet = new InstallShieldCabinet();
|
||||
|
||||
cabinet.FilenamePattern = Header.CreateFilenamePattern(filename);
|
||||
if (cabinet.FilenamePattern == null)
|
||||
{
|
||||
Console.Error.WriteLine("Failed to create filename pattern");
|
||||
return null;
|
||||
}
|
||||
|
||||
cabinet.HeaderList = Header.OpenSet(cabinet.FilenamePattern);
|
||||
if (cabinet.HeaderList == null)
|
||||
{
|
||||
Console.Error.WriteLine("Failed to read header files");
|
||||
return null;
|
||||
}
|
||||
|
||||
return cabinet;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region File
|
||||
|
||||
/// <summary>
|
||||
/// Save the file at the given index to the filename specified
|
||||
/// </summary>
|
||||
public bool FileSave(int index, string filename, bool useOld = false)
|
||||
{
|
||||
if (HeaderList == null)
|
||||
{
|
||||
Console.Error.WriteLine("Header list is not built");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the file descriptor
|
||||
if (!HeaderList.TryGetFileDescriptor(index, out var fileDescriptor) || fileDescriptor == null)
|
||||
return false;
|
||||
|
||||
// If the file is split
|
||||
if (fileDescriptor.LinkFlags == LinkFlags.LINK_PREV)
|
||||
return FileSave((int)fileDescriptor.LinkPrevious, filename, useOld);
|
||||
|
||||
// Get the reader at the index
|
||||
var reader = Reader.Create(this, index, fileDescriptor);
|
||||
if (reader == null)
|
||||
return false;
|
||||
|
||||
// Create the output file and hasher
|
||||
FileStream output = File.OpenWrite(filename);
|
||||
var md5 = new HashWrapper(HashType.MD5);
|
||||
|
||||
ulong bytesLeft = Header.GetReadableBytes(fileDescriptor);
|
||||
byte[] inputBuffer;
|
||||
byte[] outputBuffer = new byte[BUFFER_SIZE];
|
||||
ulong totalWritten = 0;
|
||||
|
||||
// Read while there are bytes remaining
|
||||
while (bytesLeft > 0)
|
||||
{
|
||||
ulong bytesToWrite = BUFFER_SIZE;
|
||||
int result;
|
||||
|
||||
// Handle compressed files
|
||||
#if NET20 || NET35
|
||||
if ((fileDescriptor.Flags & FileFlags.FILE_COMPRESSED) != 0)
|
||||
#else
|
||||
if (fileDescriptor.Flags.HasFlag(FileFlags.FILE_COMPRESSED))
|
||||
#endif
|
||||
{
|
||||
// Attempt to read the length value
|
||||
byte[] lengthArr = new byte[sizeof(ushort)];
|
||||
if (!reader.Read(lengthArr, 0, lengthArr.Length))
|
||||
{
|
||||
Console.Error.WriteLine($"Failed to read {lengthArr.Length} bytes of file {index} ({HeaderList.GetFileName(index)}) from input cabinet file {fileDescriptor.Volume}");
|
||||
reader.Dispose();
|
||||
output?.Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate the number of bytes to read
|
||||
ushort bytesToRead = BitConverter.ToUInt16(lengthArr, 0);
|
||||
if (bytesToRead == 0)
|
||||
{
|
||||
Console.Error.WriteLine("bytesToRead can't be zero");
|
||||
reader.Dispose();
|
||||
output?.Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attempt to read the specified number of bytes
|
||||
inputBuffer = new byte[BUFFER_SIZE + 1];
|
||||
if (!reader.Read(inputBuffer, 0, bytesToRead))
|
||||
{
|
||||
Console.Error.WriteLine($"Failed to read {lengthArr.Length} bytes of file {index} ({HeaderList.GetFileName(index)}) from input cabinet file {fileDescriptor.Volume}");
|
||||
reader.Dispose();
|
||||
output?.Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add a null byte to make inflate happy
|
||||
inputBuffer[bytesToRead] = 0;
|
||||
ulong readBytes = (ulong)(bytesToRead + 1);
|
||||
|
||||
// Uncompress into a buffer
|
||||
if (useOld)
|
||||
result = Header.UncompressOld(outputBuffer, ref bytesToWrite, inputBuffer, ref readBytes);
|
||||
else
|
||||
result = Header.Uncompress(outputBuffer, ref bytesToWrite, inputBuffer, ref readBytes);
|
||||
|
||||
// If we didn't get a positive result that's not a data error (false positives)
|
||||
if (result != zlibConst.Z_OK && result != zlibConst.Z_DATA_ERROR)
|
||||
{
|
||||
Console.Error.WriteLine($"Decompression failed with code {result.ToZlibConstName()}. bytes_to_read={bytesToRead}, volume={fileDescriptor.Volume}, read_bytes={readBytes}");
|
||||
reader.Dispose();
|
||||
output?.Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set remaining bytes
|
||||
bytesLeft -= 2;
|
||||
bytesLeft -= bytesToRead;
|
||||
}
|
||||
|
||||
// Handle uncompressed files
|
||||
else
|
||||
{
|
||||
bytesToWrite = Math.Min(bytesLeft, BUFFER_SIZE);
|
||||
if (!reader.Read(outputBuffer, 0, (int)bytesToWrite))
|
||||
{
|
||||
Console.Error.WriteLine($"Failed to write {bytesToWrite} bytes from input cabinet file {fileDescriptor.Volume}");
|
||||
reader.Dispose();
|
||||
output?.Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set remaining bytes
|
||||
bytesLeft -= (uint)bytesToWrite;
|
||||
}
|
||||
|
||||
// Hash and write the next block
|
||||
md5.Process(outputBuffer, 0, (int)bytesToWrite);
|
||||
output?.Write(outputBuffer, 0, (int)bytesToWrite);
|
||||
totalWritten += bytesToWrite;
|
||||
}
|
||||
|
||||
// Validate the number of bytes written
|
||||
if (fileDescriptor.ExpandedSize != totalWritten)
|
||||
{
|
||||
Console.Error.WriteLine($"Expanded size expected to be {fileDescriptor.ExpandedSize}, but was {totalWritten}");
|
||||
reader.Dispose();
|
||||
output?.Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Finalize output values
|
||||
md5.Terminate();
|
||||
reader?.Dispose();
|
||||
output?.Close();
|
||||
|
||||
// Failing the file has been disabled because for a subset of CABs the values don't seem to match
|
||||
// TODO: Investigate what is causing this to fail and what data needs to be hashed
|
||||
|
||||
// // Validate the data written, if required
|
||||
// if (HeaderList!.MajorVersion >= 6)
|
||||
// {
|
||||
// string? md5result = md5.CurrentHashString;
|
||||
// if (md5result == null || md5result != BitConverter.ToString(fileDescriptor.MD5!))
|
||||
// {
|
||||
// Console.Error.WriteLine($"MD5 checksum failure for file {index} ({HeaderList.GetFileName(index)})");
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save the file at the given index to the filename specified as raw
|
||||
/// </summary>
|
||||
public bool FileSaveRaw(int index, string filename)
|
||||
{
|
||||
if (HeaderList == null)
|
||||
{
|
||||
Console.Error.WriteLine("Header list is not built");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the file descriptor
|
||||
if (!HeaderList.TryGetFileDescriptor(index, out var fileDescriptor) || fileDescriptor == null)
|
||||
return false;
|
||||
|
||||
// If the file is split
|
||||
if (fileDescriptor.LinkFlags == LinkFlags.LINK_PREV)
|
||||
return FileSaveRaw((int)fileDescriptor.LinkPrevious, filename);
|
||||
|
||||
// Get the reader at the index
|
||||
var reader = Reader.Create(this, index, fileDescriptor);
|
||||
if (reader == null)
|
||||
return false;
|
||||
|
||||
// Create the output file
|
||||
FileStream output = File.OpenWrite(filename);
|
||||
|
||||
ulong bytesLeft = Header.GetReadableBytes(fileDescriptor);
|
||||
byte[] outputBuffer = new byte[BUFFER_SIZE];
|
||||
|
||||
// Read while there are bytes remaining
|
||||
while (bytesLeft > 0)
|
||||
{
|
||||
ulong bytesToWrite = Math.Min(bytesLeft, BUFFER_SIZE);
|
||||
if (!reader.Read(outputBuffer, 0, (int)bytesToWrite))
|
||||
{
|
||||
Console.Error.WriteLine($"Failed to read {bytesToWrite} bytes from input cabinet file {fileDescriptor.Volume}");
|
||||
reader.Dispose();
|
||||
output?.Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set remaining bytes
|
||||
bytesLeft -= (uint)bytesToWrite;
|
||||
|
||||
// Write the next block
|
||||
output.Write(outputBuffer, 0, (int)bytesToWrite);
|
||||
}
|
||||
|
||||
// Finalize output values
|
||||
reader.Dispose();
|
||||
output?.Close();
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
254
SabreTools.Serialization/UnshieldSharp/Reader.cs
Normal file
254
SabreTools.Serialization/UnshieldSharp/Reader.cs
Normal file
@@ -0,0 +1,254 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.Models.InstallShieldCabinet;
|
||||
using static SabreTools.Models.InstallShieldCabinet.Constants;
|
||||
|
||||
namespace UnshieldSharpInternal
|
||||
{
|
||||
internal class Reader : IDisposable
|
||||
{
|
||||
#region Private Instance Variables
|
||||
|
||||
/// <summary>
|
||||
/// Cabinet file to read from
|
||||
/// </summary>
|
||||
private InstallShieldCabinet? _cabinet;
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected index
|
||||
/// </summary>
|
||||
private uint _index;
|
||||
|
||||
/// <summary>
|
||||
/// File descriptor defining the currently selected index
|
||||
/// </summary>
|
||||
private FileDescriptor? _fileDescriptor;
|
||||
|
||||
/// <summary>
|
||||
/// Number of bytes left in the current volume
|
||||
/// </summary>
|
||||
private ulong _volumeBytesLeft;
|
||||
|
||||
/// <summary>
|
||||
/// Handle to the current volume stream
|
||||
/// </summary>
|
||||
private Stream? _volumeFile;
|
||||
|
||||
/// <summary>
|
||||
/// Current volume header
|
||||
/// </summary>
|
||||
private VolumeHeader? _volumeHeader;
|
||||
|
||||
/// <summary>
|
||||
/// Current volume ID
|
||||
/// </summary>
|
||||
private ushort _volumeId;
|
||||
|
||||
/// <summary>
|
||||
/// Offset for obfuscation seed
|
||||
/// </summary>
|
||||
private uint _obfuscationOffset;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Reader"> from an existing cabinet, index, and file descriptor
|
||||
/// </summary>
|
||||
public static Reader? Create(InstallShieldCabinet cabinet, int index, FileDescriptor fileDescriptor)
|
||||
{
|
||||
var reader = new Reader
|
||||
{
|
||||
_cabinet = cabinet,
|
||||
_index = (uint)index,
|
||||
_fileDescriptor = fileDescriptor,
|
||||
};
|
||||
|
||||
// If the cabinet header list is invalid
|
||||
if (reader._cabinet.HeaderList == null)
|
||||
{
|
||||
Console.Error.WriteLine($"Header list is invalid");
|
||||
return null;
|
||||
}
|
||||
|
||||
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.HeaderList.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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of the current object
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
_volumeFile?.Close();
|
||||
}
|
||||
|
||||
#region Reading
|
||||
|
||||
/// <summary>
|
||||
/// Open the next volume based on the current index
|
||||
/// </summary>
|
||||
public bool OpenNextVolume(out ushort nextVolume)
|
||||
{
|
||||
nextVolume = (ushort)(_volumeId + 1);
|
||||
return OpenVolume(nextVolume);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a certain number of bytes from the current volume
|
||||
/// </summary>
|
||||
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
|
||||
SabreTools.Serialization.Wrappers.InstallShieldCabinet.Deobfuscate(buffer, size, ref _obfuscationOffset);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open the volume at the inputted index
|
||||
/// </summary>
|
||||
private bool OpenVolume(ushort volume)
|
||||
{
|
||||
// Normalize the volume ID for odd cases
|
||||
if (volume == ushort.MinValue || volume == ushort.MaxValue)
|
||||
volume = 1;
|
||||
|
||||
_volumeFile?.Close();
|
||||
_volumeFile = SabreTools.Serialization.Wrappers.InstallShieldCabinet.OpenFileForReading(_cabinet!.FilenamePattern, volume, CABINET_SUFFIX);
|
||||
if (_volumeFile == null)
|
||||
{
|
||||
Console.Error.WriteLine($"Failed to open input cabinet file {volume}");
|
||||
return false;
|
||||
}
|
||||
|
||||
var commonHeader = _volumeFile.ReadType<CommonHeader>();
|
||||
if (commonHeader == default)
|
||||
return false;
|
||||
|
||||
_volumeHeader = SabreTools.Serialization.Deserializers.InstallShieldCabinet.ParseVolumeHeader(_volumeFile, _cabinet.HeaderList!.MajorVersion);
|
||||
if (_volumeHeader == null)
|
||||
return false;
|
||||
|
||||
// Enable support for split archives for IS5
|
||||
if (_cabinet.HeaderList.MajorVersion == 5)
|
||||
{
|
||||
if (_index < (_cabinet.HeaderList.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 dataOffset, 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
|
||||
}
|
||||
}
|
||||
@@ -277,7 +277,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// <param name="index">Cabinet part index to be opened</param>
|
||||
/// <param name="suffix">Cabinet files suffix (e.g. `.cab`)</param>
|
||||
/// <returns>A Stream representing the cabinet part, null on error</returns>
|
||||
private static Stream? OpenFileForReading(string? pattern, int index, string suffix)
|
||||
public static Stream? OpenFileForReading(string? pattern, int index, string suffix)
|
||||
{
|
||||
// An invalid pattern means no cabinet files
|
||||
if (string.IsNullOrEmpty(pattern))
|
||||
@@ -351,6 +351,84 @@ namespace SabreTools.Serialization.Wrappers
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extraction
|
||||
|
||||
/// <summary>
|
||||
/// Uncompress a source byte array to a destination
|
||||
/// </summary>
|
||||
public unsafe static int Uncompress(byte[] dest, ref ulong destLen, byte[] source, ref ulong sourceLen)
|
||||
{
|
||||
fixed (byte* sourcePtr = source)
|
||||
fixed (byte* destPtr = dest)
|
||||
{
|
||||
var stream = new ZLib.z_stream_s
|
||||
{
|
||||
next_in = sourcePtr,
|
||||
avail_in = (uint)sourceLen,
|
||||
next_out = destPtr,
|
||||
avail_out = (uint)destLen,
|
||||
};
|
||||
|
||||
// make second parameter negative to disable checksum verification
|
||||
int err = ZLib.inflateInit2_(stream, -MAX_WBITS, ZLib.zlibVersion(), source.Length);
|
||||
if (err != zlibConst.Z_OK)
|
||||
return err;
|
||||
|
||||
err = ZLib.inflate(stream, 1);
|
||||
if (err != zlibConst.Z_STREAM_END)
|
||||
{
|
||||
ZLib.inflateEnd(stream);
|
||||
return err;
|
||||
}
|
||||
|
||||
destLen = stream.total_out;
|
||||
sourceLen = stream.total_in;
|
||||
return ZLib.inflateEnd(stream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uncompress a source byte array to a destination (old version)
|
||||
/// </summary>
|
||||
public unsafe static int UncompressOld(byte[] dest, ref ulong destLen, byte[] source, ref ulong sourceLen)
|
||||
{
|
||||
fixed (byte* sourcePtr = source)
|
||||
fixed (byte* destPtr = dest)
|
||||
{
|
||||
var stream = new ZLib.z_stream_s
|
||||
{
|
||||
next_in = sourcePtr,
|
||||
avail_in = (uint)sourceLen,
|
||||
next_out = destPtr,
|
||||
avail_out = (uint)destLen,
|
||||
};
|
||||
|
||||
destLen = 0;
|
||||
sourceLen = 0;
|
||||
|
||||
// make second parameter negative to disable checksum verification
|
||||
int err = ZLib.inflateInit2_(stream, -MAX_WBITS, ZLib.zlibVersion(), source.Length);
|
||||
if (err != zlibConst.Z_OK)
|
||||
return err;
|
||||
|
||||
while (stream.avail_in > 1)
|
||||
{
|
||||
err = ZLib.inflate(stream, 1);
|
||||
if (err != zlibConst.Z_OK)
|
||||
{
|
||||
ZLib.inflateEnd(stream);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
destLen = stream.total_out;
|
||||
sourceLen = stream.total_in;
|
||||
return ZLib.inflateEnd(stream);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region File
|
||||
|
||||
/// <summary>
|
||||
@@ -519,90 +597,12 @@ namespace SabreTools.Serialization.Wrappers
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extraction
|
||||
|
||||
/// <summary>
|
||||
/// Uncompress a source byte array to a destination
|
||||
/// </summary>
|
||||
public unsafe static int Uncompress(byte[] dest, ref ulong destLen, byte[] source, ref ulong sourceLen)
|
||||
{
|
||||
fixed (byte* sourcePtr = source)
|
||||
fixed (byte* destPtr = dest)
|
||||
{
|
||||
var stream = new ZLib.z_stream_s
|
||||
{
|
||||
next_in = sourcePtr,
|
||||
avail_in = (uint)sourceLen,
|
||||
next_out = destPtr,
|
||||
avail_out = (uint)destLen,
|
||||
};
|
||||
|
||||
// make second parameter negative to disable checksum verification
|
||||
int err = ZLib.inflateInit2_(stream, -MAX_WBITS, ZLib.zlibVersion(), source.Length);
|
||||
if (err != zlibConst.Z_OK)
|
||||
return err;
|
||||
|
||||
err = ZLib.inflate(stream, 1);
|
||||
if (err != zlibConst.Z_STREAM_END)
|
||||
{
|
||||
ZLib.inflateEnd(stream);
|
||||
return err;
|
||||
}
|
||||
|
||||
destLen = stream.total_out;
|
||||
sourceLen = stream.total_in;
|
||||
return ZLib.inflateEnd(stream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uncompress a source byte array to a destination (old version)
|
||||
/// </summary>
|
||||
public unsafe static int UncompressOld(byte[] dest, ref ulong destLen, byte[] source, ref ulong sourceLen)
|
||||
{
|
||||
fixed (byte* sourcePtr = source)
|
||||
fixed (byte* destPtr = dest)
|
||||
{
|
||||
var stream = new ZLib.z_stream_s
|
||||
{
|
||||
next_in = sourcePtr,
|
||||
avail_in = (uint)sourceLen,
|
||||
next_out = destPtr,
|
||||
avail_out = (uint)destLen,
|
||||
};
|
||||
|
||||
destLen = 0;
|
||||
sourceLen = 0;
|
||||
|
||||
// make second parameter negative to disable checksum verification
|
||||
int err = ZLib.inflateInit2_(stream, -MAX_WBITS, ZLib.zlibVersion(), source.Length);
|
||||
if (err != zlibConst.Z_OK)
|
||||
return err;
|
||||
|
||||
while (stream.avail_in > 1)
|
||||
{
|
||||
err = ZLib.inflate(stream, 1);
|
||||
if (err != zlibConst.Z_OK)
|
||||
{
|
||||
ZLib.inflateEnd(stream);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
destLen = stream.total_out;
|
||||
sourceLen = stream.total_in;
|
||||
return ZLib.inflateEnd(stream);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Obfuscation
|
||||
|
||||
/// <summary>
|
||||
/// Deobfuscate a buffer
|
||||
/// </summary>
|
||||
private void Deobfuscate(byte[] buffer, long size, ref uint offset)
|
||||
public static void Deobfuscate(byte[] buffer, long size, ref uint offset)
|
||||
{
|
||||
offset = Deobfuscate(buffer, size, offset);
|
||||
}
|
||||
@@ -611,7 +611,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// Deobfuscate a buffer with a seed value
|
||||
/// </summary>
|
||||
/// <remarks>Seed is 0 at file start</remarks>
|
||||
private static uint Deobfuscate(byte[] buffer, long size, uint seed)
|
||||
public static uint Deobfuscate(byte[] buffer, long size, uint seed)
|
||||
{
|
||||
for (int i = 0; size > 0; size--, i++, seed++)
|
||||
{
|
||||
@@ -624,7 +624,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// <summary>
|
||||
/// Obfuscate a buffer
|
||||
/// </summary>
|
||||
private void Obfuscate(byte[] buffer, long size, ref uint offset)
|
||||
public static void Obfuscate(byte[] buffer, long size, ref uint offset)
|
||||
{
|
||||
offset = Obfuscate(buffer, size, offset);
|
||||
}
|
||||
@@ -633,7 +633,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// Obfuscate a buffer with a seed value
|
||||
/// </summary>
|
||||
/// <remarks>Seed is 0 at file start</remarks>
|
||||
private static uint Obfuscate(byte[] buffer, long size, uint seed)
|
||||
public static uint Obfuscate(byte[] buffer, long size, uint seed)
|
||||
{
|
||||
for (int i = 0; size > 0; size--, i++, seed++)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user