Files
InnoPatcher/InnoSetup.cs

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
}
}