76 lines
2.4 KiB
C#
76 lines
2.4 KiB
C#
using System;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Runtime.InteropServices;
|
|
using SevenZip.Compression.LZMA;
|
|
|
|
namespace InnoPatcher;
|
|
|
|
sealed class InnoSetup {
|
|
private const int BlockSize = 4096 + 4;
|
|
private const int CompressionPropertiesLength = 5;
|
|
|
|
internal static bool TryParse(Stream file, int innoVersion, [NotNullWhen(true)] out InnoSetup? result) {
|
|
result = null;
|
|
|
|
byte[] headerB = new byte[Marshal.SizeOf<Header>()];
|
|
int read, offset = 0;
|
|
while ((read = file.Read(headerB, offset, headerB.Length - offset)) != 0)
|
|
offset += read;
|
|
if (offset < headerB.Length)
|
|
return false;
|
|
|
|
// Read header
|
|
Header header = MemoryMarshal.Cast<byte, Header>(headerB)[0];
|
|
ReadOnlySpan<byte> headerB2 = headerB;
|
|
if (!InnoLoader.VerifyCRC(headerB2.Slice(4), header.CRC))
|
|
return false;
|
|
|
|
if (header.Compressed != 0 && innoVersion < 4105)
|
|
throw new NotImplementedException("Zlib decompression not implemented.");
|
|
|
|
// Decode
|
|
Decoder decoder = new Decoder();
|
|
MemoryStream a = new MemoryStream();
|
|
byte[] blockB = new byte[BlockSize];
|
|
bool decoderInitialized = false;
|
|
for (uint toRead = header.StoredSize; toRead > 0;) {
|
|
int blockSize = toRead > BlockSize ? BlockSize : (int)toRead;
|
|
offset = 0;
|
|
while ((read = file.Read(blockB, offset, blockSize - offset)) != 0)
|
|
offset += read;
|
|
if (offset < blockSize)
|
|
return false;
|
|
|
|
ReadOnlySpan<byte> blockData = blockB;
|
|
uint blockCRC = MemoryMarshal.Cast<byte, uint>(blockData.Slice(0, 4))[0];
|
|
blockData = blockData.Slice(4);
|
|
|
|
if (!InnoLoader.VerifyCRC(blockData, blockCRC))
|
|
return false;
|
|
|
|
if (header.Compressed != 0) {
|
|
if (!decoderInitialized) {
|
|
decoder.SetDecoderProperties(blockData.Slice(0, CompressionPropertiesLength).ToArray());
|
|
blockData = blockData.Slice(CompressionPropertiesLength);
|
|
decoderInitialized = true;
|
|
}
|
|
|
|
decoder.Code(new MemoryStream(blockB, blockSize - blockData.Length, blockData.Length), a, blockData.Length, 84158, null);
|
|
} else
|
|
a.Write(blockData);
|
|
|
|
toRead -= (uint)blockSize;
|
|
}
|
|
|
|
result = null;
|
|
return false;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
struct Header {
|
|
internal uint CRC;
|
|
internal uint StoredSize; // Total bytes written, including the CRCs
|
|
internal byte Compressed; // True if data is compressed, False if not
|
|
}
|
|
}
|