mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-04-24 15:13:23 +00:00
Port MS-ZIP for MS-CAB
This commit is contained in:
@@ -1,35 +0,0 @@
|
||||
using System;
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression;
|
||||
|
||||
namespace BurnOutSharp.Compression
|
||||
{
|
||||
public class MSZIP_zlib
|
||||
{
|
||||
#region Instance Variables
|
||||
|
||||
/// <summary>
|
||||
/// Inflater to be shared between blocks
|
||||
/// </summary>
|
||||
private readonly Inflater _inflater = new Inflater(noHeader: true);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Decompressiom
|
||||
|
||||
/// <summary>
|
||||
/// Decompress MSZIP data block
|
||||
/// </summary>
|
||||
public byte[] DecompressMSZIPData(byte[] data, bool previousBlock = false)
|
||||
{
|
||||
if (previousBlock)
|
||||
_inflater.Reset();
|
||||
|
||||
_inflater.SetInput(buffer: data, 2, data.Length - 2);
|
||||
byte[] outputData = new byte[128 * 1024];
|
||||
int read = _inflater.Inflate(outputData);
|
||||
return outputData.AsSpan(0, read).ToArray();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,63 +1,69 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using BurnOutSharp.Models.Compression.MSZIP;
|
||||
using static BurnOutSharp.Models.Compression.MSZIP.Constants;
|
||||
|
||||
namespace BurnOutSharp.Compression.MSZIP
|
||||
{
|
||||
/// <see href="https://github.com/wine-mirror/wine/blob/master/dlls/cabinet/fdi.c"/>
|
||||
public class Decompressor
|
||||
public unsafe class Decompressor
|
||||
{
|
||||
/// <summary>
|
||||
/// Decompress a byte array using a given State
|
||||
/// </summary>
|
||||
public static bool Decompress(State state, int inlen, byte[] inbuf, int outlen, byte[] outbuf)
|
||||
{
|
||||
state.InputPosition = 0; // inbuf[0];
|
||||
state.BitBuffer = state.BitCount = state.WindowPosition = 0;
|
||||
if (outlen > ZIPWSIZE)
|
||||
return false;
|
||||
|
||||
// CK = Chris Kirmse, official Microsoft purloiner
|
||||
if (inbuf[state.InputPosition + 0] != 0x43 || inbuf[state.InputPosition + 1] != 0x48)
|
||||
return false;
|
||||
|
||||
state.InputPosition += 2;
|
||||
|
||||
int lastBlockFlag = 0;
|
||||
do
|
||||
fixed (byte* inpos = inbuf)
|
||||
{
|
||||
if (InflateBlock(ref lastBlockFlag, state, inbuf, outbuf) != 0)
|
||||
state.inpos = inpos;
|
||||
state.bb = state.bk = state.window_posn = 0;
|
||||
if (outlen > ZIPWSIZE)
|
||||
return false;
|
||||
} while (lastBlockFlag == 0);
|
||||
|
||||
// Return success
|
||||
return true;
|
||||
// CK = Chris Kirmse, official Microsoft purloiner
|
||||
if (state.inpos[0] != 0x43 || state.inpos[1] != 0x48)
|
||||
return false;
|
||||
|
||||
state.inpos += 2;
|
||||
|
||||
int lastBlockFlag = 0;
|
||||
do
|
||||
{
|
||||
if (InflateBlock(&lastBlockFlag, state, inbuf, outbuf) != 0)
|
||||
return false;
|
||||
} while (lastBlockFlag == 0);
|
||||
|
||||
// Return success
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decompress a deflated block
|
||||
/// </summary>
|
||||
private static uint InflateBlock(ref int e, State state, byte[] inbuf, byte[] outbuf)
|
||||
private static uint InflateBlock(int* e, State state, byte[] inbuf, byte[] outbuf)
|
||||
{
|
||||
// Make local bit buffer
|
||||
uint bitBuffer = state.BitBuffer;
|
||||
uint bitCount = state.BitCount;
|
||||
uint b = state.bb;
|
||||
uint k = state.bk;
|
||||
|
||||
// Read the deflate block header
|
||||
var header = new DeflateBlockHeader();
|
||||
|
||||
// Read in last block bit
|
||||
ZIPNEEDBITS(1, state, inbuf, ref bitBuffer, ref bitCount);
|
||||
header.BFINAL = (e = (int)(bitBuffer & 1)) != 0;
|
||||
ZIPDUMPBITS(1, ref bitBuffer, ref bitCount);
|
||||
ZIPNEEDBITS(1, state, ref b, ref k);
|
||||
header.BFINAL = (*e = (int)b & 1) != 0;
|
||||
ZIPDUMPBITS(1, ref b, ref k);
|
||||
|
||||
// Read in block type
|
||||
ZIPNEEDBITS(2, state, inbuf, ref bitBuffer, ref bitCount);
|
||||
header.BTYPE = (CompressionType)(bitBuffer & 3);
|
||||
ZIPDUMPBITS(2, ref bitBuffer, ref bitCount);
|
||||
ZIPNEEDBITS(2, state, ref b, ref k);
|
||||
header.BTYPE = (CompressionType)(b & 3);
|
||||
ZIPDUMPBITS(2, ref b, ref k);
|
||||
|
||||
// Restore the global bit buffer
|
||||
state.BitBuffer = bitBuffer;
|
||||
state.BitCount = bitCount;
|
||||
state.bb = b;
|
||||
state.bk = k;
|
||||
|
||||
// Inflate that block type
|
||||
switch (header.BTYPE)
|
||||
@@ -82,42 +88,42 @@ namespace BurnOutSharp.Compression.MSZIP
|
||||
private static int DecompressStored(State state, byte[] inbuf, byte[] outbuf)
|
||||
{
|
||||
// Make local copies of globals
|
||||
uint bitBuffer = state.BitBuffer;
|
||||
uint bitCount = state.BitCount;
|
||||
uint windowPosition = state.WindowPosition;
|
||||
uint b = state.bb;
|
||||
uint k = state.bk;
|
||||
uint w = state.window_posn;
|
||||
|
||||
// Go to byte boundary
|
||||
int n = (int)(bitCount & 7);
|
||||
ZIPDUMPBITS(n, ref bitBuffer, ref bitCount);
|
||||
int n = (int)(k & 7);
|
||||
ZIPDUMPBITS(n, ref b, ref k);
|
||||
|
||||
// Read the stored block header
|
||||
var header = new NonCompressedBlockHeader();
|
||||
|
||||
// Get the length and its compliment
|
||||
ZIPNEEDBITS(16, state, inbuf, ref bitBuffer, ref bitCount);
|
||||
header.LEN = (ushort)(bitBuffer & 0xffff);
|
||||
ZIPDUMPBITS(16, ref bitBuffer, ref bitCount);
|
||||
ZIPNEEDBITS(16, state, ref b, ref k);
|
||||
header.LEN = (ushort)(b & 0xffff);
|
||||
ZIPDUMPBITS(16, ref b, ref k);
|
||||
|
||||
ZIPNEEDBITS(16, state, inbuf, ref bitBuffer, ref bitCount);
|
||||
header.NLEN = (ushort)(bitBuffer & 0xffff);
|
||||
ZIPNEEDBITS(16, state, ref b, ref k);
|
||||
header.NLEN = (ushort)(b & 0xffff);
|
||||
|
||||
if (header.LEN != (~header.NLEN & 0xffff))
|
||||
return 1; // Error in compressed data
|
||||
|
||||
ZIPDUMPBITS(16, ref bitBuffer, ref bitCount);
|
||||
ZIPDUMPBITS(16, ref b, ref k);
|
||||
|
||||
// Read and output the compressed data
|
||||
while (n-- > 0)
|
||||
{
|
||||
ZIPNEEDBITS(8, state, inbuf, ref bitBuffer, ref bitCount);
|
||||
outbuf[windowPosition++] = (byte)bitBuffer;
|
||||
ZIPDUMPBITS(8, ref bitBuffer, ref bitCount);
|
||||
ZIPNEEDBITS(8, state, ref b, ref k);
|
||||
outbuf[w++] = (byte)b;
|
||||
ZIPDUMPBITS(8, ref b, ref k);
|
||||
}
|
||||
|
||||
// Restore the globals from the locals
|
||||
state.WindowPosition = windowPosition;
|
||||
state.BitBuffer = bitBuffer;
|
||||
state.BitCount = bitCount;
|
||||
state.window_posn = w;
|
||||
state.bb = b;
|
||||
state.bk = k;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -128,78 +134,492 @@ namespace BurnOutSharp.Compression.MSZIP
|
||||
private static int DecompressFixed(State state, byte[] inbuf, byte[] outbuf)
|
||||
{
|
||||
// Create the block header
|
||||
var header = new FixedHuffmanCompressedBlockHeader();
|
||||
FixedHuffmanCompressedBlockHeader header = new FixedHuffmanCompressedBlockHeader();
|
||||
|
||||
// Assign the literal lengths
|
||||
state.Lengths = header.LiteralLengths;
|
||||
var literalLengthTable = new HuffmanNode[30];
|
||||
int literalLengthBitCount = 7;
|
||||
fixed (uint* l = state.ll)
|
||||
fixed (ushort* Zipcplens = CopyLengths)
|
||||
fixed (ushort* Zipcplext = LiteralExtraBits)
|
||||
fixed (ushort* Zipcpdist = CopyOffsets)
|
||||
fixed (ushort* Zipcpdext = DistanceExtraBits)
|
||||
{
|
||||
// Assign the literal lengths
|
||||
state.ll = header.LiteralLengths;
|
||||
HuffmanNode* fixed_tl;
|
||||
int fixed_bl = 7;
|
||||
|
||||
// Build the literal length tree
|
||||
int i = BuildHuffmanTree(state.Lengths, 0, 30, 0, CopyOffsets, LiteralExtraBits, ref literalLengthTable, ref literalLengthBitCount, state);
|
||||
if (i != 0)
|
||||
return i;
|
||||
// Build the literal length tree
|
||||
int i = BuildHuffmanTree(l, 288, 257, Zipcplens, Zipcplext, &fixed_tl, &fixed_bl, state);
|
||||
if (i != 0)
|
||||
return i;
|
||||
|
||||
// Assign the distance codes
|
||||
state.Lengths = header.DistanceCodes;
|
||||
var distanceCodeTable = new HuffmanNode[30];
|
||||
int distanceCodeBitCount = 5;
|
||||
// Assign the distance codes
|
||||
state.ll = header.DistanceCodes;
|
||||
HuffmanNode* fixed_td;
|
||||
int fixed_bd = 5;
|
||||
|
||||
// Build the distance code tree
|
||||
i = BuildHuffmanTree(state.Lengths, 0, 30, 0, CopyOffsets, DistanceExtraBits, ref distanceCodeTable, ref distanceCodeBitCount, state);
|
||||
if (i != 0)
|
||||
return i;
|
||||
// Build the distance code tree
|
||||
i = BuildHuffmanTree(l, 30, 0, Zipcpdist, Zipcpdext, &fixed_td, &fixed_bd, state);
|
||||
if (i != 0)
|
||||
return i;
|
||||
|
||||
// Decompress until an end-of-block code
|
||||
return InflateCodes(literalLengthTable, distanceCodeTable, literalLengthBitCount, distanceCodeBitCount, state, inbuf, outbuf);
|
||||
// Decompress until an end-of-block code
|
||||
return InflateCodes(fixed_tl, fixed_td, fixed_bl, fixed_bd, state, inbuf, outbuf);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decompress a block originally compressed with dynamic Huffman codes
|
||||
/// </summary>
|
||||
/// INCORRECT IMPLEMENTATION TO SATISFY COMPILER FOR NOW
|
||||
private static int DecompressDynamic(State state, byte[] inbuf, byte[] outbuf)
|
||||
{
|
||||
int i; /* temporary variables */
|
||||
uint j;
|
||||
uint l; /* last length */
|
||||
uint m; /* mask for bit lengths table */
|
||||
uint n; /* number of lengths to get */
|
||||
HuffmanNode* tl; /* literal/length code table */
|
||||
HuffmanNode* td; /* distance code table */
|
||||
int bl; /* lookup bits for tl */
|
||||
int bd; /* lookup bits for td */
|
||||
uint nb; /* number of bit length codes */
|
||||
uint nl; /* number of literal/length codes */
|
||||
uint nd; /* number of distance codes */
|
||||
uint b; /* bit buffer */
|
||||
uint k; /* number of bits in bit buffer */
|
||||
|
||||
// TODO: Finish implementation
|
||||
return 0;
|
||||
/* make local bit buffer */
|
||||
b = state.bb;
|
||||
k = state.bk;
|
||||
|
||||
fixed (uint* ll = state.ll)
|
||||
{
|
||||
/* read in table lengths */
|
||||
ZIPNEEDBITS(5, state, ref b, ref k);
|
||||
nl = 257 + (b & 0x1f); /* number of literal/length codes */
|
||||
ZIPDUMPBITS(5, ref b, ref k);
|
||||
|
||||
ZIPNEEDBITS(5, state, ref b, ref k);
|
||||
nd = 1 + (b & 0x1f); /* number of distance codes */
|
||||
ZIPDUMPBITS(5, ref b, ref k);
|
||||
|
||||
ZIPNEEDBITS(4, state, ref b, ref k);
|
||||
nb = 4 + (b & 0xf); /* number of bit length codes */
|
||||
ZIPDUMPBITS(4, ref b, ref k);
|
||||
if (nl > 288 || nd > 32)
|
||||
return 1; /* bad lengths */
|
||||
|
||||
/* read in bit-length-code lengths */
|
||||
for (j = 0; j < nb; j++)
|
||||
{
|
||||
ZIPNEEDBITS(3, state, ref b, ref k);
|
||||
state.ll[BitLengthOrder[j]] = b & 7;
|
||||
ZIPDUMPBITS(3, ref b, ref k);
|
||||
}
|
||||
for (; j < 19; j++)
|
||||
state.ll[BitLengthOrder[j]] = 0;
|
||||
|
||||
/* build decoding table for trees--single level, 7 bit lookup */
|
||||
bl = 7;
|
||||
if ((i = BuildHuffmanTree(ll, 19, 19, null, null, &tl, &bl, state)) != 0)
|
||||
return i; /* incomplete code set */
|
||||
|
||||
/* read in literal and distance code lengths */
|
||||
n = nl + nd;
|
||||
m = BitMasks[bl];
|
||||
i = (int)(l = 0);
|
||||
while ((uint)i < n)
|
||||
{
|
||||
ZIPNEEDBITS(bl, state, ref b, ref k);
|
||||
j = (td = tl + (b & m))->b;
|
||||
ZIPDUMPBITS((int)j, ref b, ref k);
|
||||
j = td->n;
|
||||
if (j < 16) /* length of code in bits (0..15) */
|
||||
{
|
||||
state.ll[i++] = l = j; /* save last length in l */
|
||||
}
|
||||
else if (j == 16) /* repeat last length 3 to 6 times */
|
||||
{
|
||||
ZIPNEEDBITS(2, state, ref b, ref k);
|
||||
j = 3 + (b & 3);
|
||||
ZIPDUMPBITS(2, ref b, ref k);
|
||||
if ((uint)i + j > n)
|
||||
return 1;
|
||||
while (j-- > 0)
|
||||
{
|
||||
state.ll[i++] = l;
|
||||
}
|
||||
}
|
||||
else if (j == 17) /* 3 to 10 zero length codes */
|
||||
{
|
||||
ZIPNEEDBITS(3, state, ref b, ref k);
|
||||
j = 3 + (b & 7);
|
||||
ZIPDUMPBITS(3, ref b, ref k);
|
||||
if ((uint)i + j > n)
|
||||
return 1;
|
||||
while (j-- > 0)
|
||||
state.ll[i++] = 0;
|
||||
l = 0;
|
||||
}
|
||||
else /* j == 18: 11 to 138 zero length codes */
|
||||
{
|
||||
ZIPNEEDBITS(7, state, ref b, ref k);
|
||||
j = 11 + (b & 0x7f);
|
||||
ZIPDUMPBITS(7, ref b, ref k);
|
||||
if ((uint)i + j > n)
|
||||
return 1;
|
||||
while (j-- > 0)
|
||||
state.ll[i++] = 0;
|
||||
l = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* restore the global bit buffer */
|
||||
state.bb = b;
|
||||
state.bk = k;
|
||||
|
||||
fixed (ushort* Zipcplens = CopyLengths)
|
||||
fixed (ushort* Zipcplext = LiteralExtraBits)
|
||||
fixed (ushort* Zipcpdist = CopyOffsets)
|
||||
fixed (ushort* Zipcpdext = DistanceExtraBits)
|
||||
{
|
||||
/* build the decoding tables for literal/length and distance codes */
|
||||
bl = ZIPLBITS;
|
||||
if ((i = BuildHuffmanTree(ll, nl, 257, Zipcplens, Zipcplext, &tl, &bl, state)) != 0)
|
||||
{
|
||||
return i; /* incomplete code set */
|
||||
}
|
||||
bd = ZIPDBITS;
|
||||
BuildHuffmanTree(ll + nl, nd, 0, Zipcpdist, Zipcpdext, &td, &bd, state);
|
||||
|
||||
/* decompress until an end-of-block code */
|
||||
if (InflateCodes(tl, td, bl, bd, state, inbuf, outbuf) != 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build a Huffman tree from a set of lengths
|
||||
/// </summary>
|
||||
/// INCORRECT IMPLEMENTATION TO SATISFY COMPILER FOR NOW
|
||||
private static int BuildHuffmanTree(uint[] b, int bi, uint n, uint s, ushort[] d, ushort[] e, ref HuffmanNode[] t, ref int m, State state)
|
||||
private static int BuildHuffmanTree(uint* b, uint n, uint s, ushort* d, ushort* e, HuffmanNode** t, int* m, State state)
|
||||
{
|
||||
|
||||
// TODO: Finish implementation
|
||||
return 0;
|
||||
uint a; /* counter for codes of length k */
|
||||
uint el; /* length of EOB code (value 256) */
|
||||
uint f; /* i repeats in table every f entries */
|
||||
int g; /* maximum code length */
|
||||
int h; /* table level */
|
||||
uint i; /* counter, current code */
|
||||
uint j; /* counter */
|
||||
int k; /* number of bits in current code */
|
||||
int* l; /* stack of bits per table */
|
||||
uint* p; /* pointer into state.c[],state.b[],state.v[] */
|
||||
HuffmanNode* q; /* points to current table */
|
||||
HuffmanNode r = new HuffmanNode(); /* table entry for structure assignment */
|
||||
int w; /* bits before this table == (l * h) */
|
||||
uint* xp; /* pointer into x */
|
||||
int y; /* number of dummy codes added */
|
||||
uint z; /* number of entries in current table */
|
||||
|
||||
fixed (int* state_lx_ptr = state.lx)
|
||||
{
|
||||
l = state_lx_ptr + 1;
|
||||
|
||||
/* Generate counts for each bit length */
|
||||
el = n > 256 ? b[256] : ZIPBMAX; /* set length of EOB code, if any */
|
||||
|
||||
for (i = 0; i < ZIPBMAX + 1; ++i)
|
||||
state.c[i] = 0;
|
||||
p = b; i = n;
|
||||
do
|
||||
{
|
||||
state.c[*p]++; p++; /* assume all entries <= ZIPBMAX */
|
||||
} while (--i > 0);
|
||||
|
||||
if (state.c[0] == n) /* null input--all zero length codes */
|
||||
{
|
||||
*t = null;
|
||||
*m = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find minimum and maximum length, bound *m by those */
|
||||
for (j = 1; j <= ZIPBMAX; j++)
|
||||
{
|
||||
if (state.c[j] > 0)
|
||||
break;
|
||||
}
|
||||
|
||||
k = (int)j; /* minimum code length */
|
||||
if ((uint)*m < j)
|
||||
*m = (int)j;
|
||||
|
||||
for (i = ZIPBMAX; i > 0; i--)
|
||||
{
|
||||
if (state.c[i] > 0)
|
||||
break;
|
||||
}
|
||||
|
||||
g = (int)i; /* maximum code length */
|
||||
if ((uint)*m > i)
|
||||
*m = (int)i;
|
||||
|
||||
/* Adjust last length count to fill out codes, if needed */
|
||||
for (y = 1 << (int)j; j < i; j++, y <<= 1)
|
||||
{
|
||||
if ((y -= (int)state.c[j]) < 0)
|
||||
return 2; /* bad input: more codes than bits */
|
||||
}
|
||||
|
||||
if ((y -= (int)state.c[i]) < 0)
|
||||
return 2;
|
||||
|
||||
state.c[i] += (uint)y;
|
||||
|
||||
/* Generate starting offsets LONGo the value table for each length */
|
||||
state.x[1] = j = 0;
|
||||
|
||||
fixed (uint* state_c_ptr = state.c)
|
||||
fixed (uint* state_x_ptr = state.x)
|
||||
{
|
||||
p = state_c_ptr + 1;
|
||||
xp = state_x_ptr + 2;
|
||||
while (--i > 0)
|
||||
{
|
||||
/* note that i == g from above */
|
||||
*xp++ = (j += *p++);
|
||||
}
|
||||
}
|
||||
|
||||
/* Make a table of values in order of bit lengths */
|
||||
p = b; i = 0;
|
||||
do
|
||||
{
|
||||
if ((j = *p++) != 0)
|
||||
state.v[state.x[j]++] = i;
|
||||
} while (++i < n);
|
||||
|
||||
/* Generate the Huffman codes and for each, make the table entries */
|
||||
state.x[0] = i = 0; /* first Huffman code is zero */
|
||||
|
||||
fixed (uint* state_v_ptr = state.v)
|
||||
{
|
||||
p = state_v_ptr; /* grab values in bit order */
|
||||
h = -1; /* no tables yet--level -1 */
|
||||
w = l[-1] = 0; /* no bits decoded yet */
|
||||
state.u[0] = default; /* just to keep compilers happy */
|
||||
q = null; /* ditto */
|
||||
z = 0; /* ditto */
|
||||
|
||||
/* go through the bit lengths (k already is bits in shortest code) */
|
||||
for (; k <= g; k++)
|
||||
{
|
||||
a = state.c[k];
|
||||
while (a-- > 0)
|
||||
{
|
||||
/* here i is the Huffman code of length k bits for value *p */
|
||||
/* make tables up to required level */
|
||||
while (k > w + l[h])
|
||||
{
|
||||
w += l[h++]; /* add bits already decoded */
|
||||
|
||||
/* compute minimum size table less than or equal to *m bits */
|
||||
if ((z = (uint)(g - w)) > (uint)*m) /* upper limit */
|
||||
z = (uint)*m;
|
||||
|
||||
if ((f = (uint)(1 << (int)(j = (uint)(k - w)))) > a + 1) /* try a k-w bit table */
|
||||
{ /* too few codes for k-w bit table */
|
||||
f -= a + 1; /* deduct codes from patterns left */
|
||||
fixed (uint* state_c_ptr = state.c)
|
||||
{
|
||||
xp = state_c_ptr + k;
|
||||
while (++j < z) /* try smaller tables up to z bits */
|
||||
{
|
||||
if ((f <<= 1) <= *++xp)
|
||||
break; /* enough codes to use up j bits */
|
||||
f -= *xp; /* else deduct codes from patterns */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((uint)w + j > el && (uint)w < el)
|
||||
j = (uint)(el - w); /* make EOB code end at table */
|
||||
|
||||
z = (uint)(1 << (int)j); /* table entries for j-bit table */
|
||||
l[h] = (int)j; /* set table size in stack */
|
||||
|
||||
/* allocate and link in new table */
|
||||
q = (HuffmanNode*)Marshal.AllocHGlobal((int)((z + 1) * sizeof(HuffmanNode)));
|
||||
*t = q + 1; /* link to list for HuffmanNode_free() */
|
||||
*(t = &(*q).t) = null;
|
||||
state.u[h] = ++q; /* table starts after link */
|
||||
|
||||
/* connect to last table, if there is one */
|
||||
if (h > 0)
|
||||
{
|
||||
state.x[h] = i; /* save pattern for backing up */
|
||||
r.b = (byte)l[h - 1]; /* bits to dump before this table */
|
||||
r.e = (byte)(16 + j); /* bits in this table */
|
||||
r.t = q; /* pointer to this table */
|
||||
j = (uint)((i & ((1 << w) - 1)) >> (w - l[h - 1]));
|
||||
state.u[h - 1][j] = r; /* connect to last table */
|
||||
}
|
||||
}
|
||||
|
||||
/* set up table entry in r */
|
||||
r.b = (byte)(k - w);
|
||||
|
||||
fixed (uint* state_v_ptr_comp = state.v)
|
||||
{
|
||||
if (p >= state_v_ptr_comp + n)
|
||||
{
|
||||
r.e = 99; /* out of values--invalid code */
|
||||
}
|
||||
else if (*p < s)
|
||||
{
|
||||
r.e = (byte)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */
|
||||
r.n = (ushort)*p++; /* simple code is just the value */
|
||||
}
|
||||
else
|
||||
{
|
||||
r.e = (byte)e[*p - s]; /* non-simple--look up in lists */
|
||||
r.n = d[*p++ - s];
|
||||
}
|
||||
}
|
||||
|
||||
/* fill code-like entries with r */
|
||||
f = (uint)(1 << (k - w));
|
||||
for (j = i >> w; j < z; j += f)
|
||||
{
|
||||
q[j] = r;
|
||||
}
|
||||
|
||||
/* backwards increment the k-bit code i */
|
||||
for (j = (uint)(1 << (k - 1)); (i & j) != 0; j >>= 1)
|
||||
{
|
||||
i ^= j;
|
||||
}
|
||||
|
||||
i ^= j;
|
||||
|
||||
/* backup over finished tables */
|
||||
while ((i & ((1 << w) - 1)) != state.x[h])
|
||||
w -= l[--h]; /* don't need to update q */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* return actual size of base table */
|
||||
*m = l[0];
|
||||
}
|
||||
|
||||
/* Return true (1) if we were given an incomplete table */
|
||||
return y != 0 && g != 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inflate codes into Huffman trees
|
||||
/// </summary>
|
||||
/// INCORRECT IMPLEMENTATION TO SATISFY COMPILER FOR NOW
|
||||
private static int InflateCodes(HuffmanNode[] tl, HuffmanNode[] td, int bl, int bd, State state, byte[] inbuf, byte[] outbuf)
|
||||
private static int InflateCodes(HuffmanNode* tl, HuffmanNode* td, int bl, int bd, State state, byte[] inbuf, byte[] outbuf)
|
||||
{
|
||||
uint e; /* table entry flag/number of extra bits */
|
||||
uint n, d; /* length and index for copy */
|
||||
uint w; /* current window position */
|
||||
HuffmanNode* t; /* pointer to table entry */
|
||||
uint ml, md; /* masks for bl and bd bits */
|
||||
uint b; /* bit buffer */
|
||||
uint k; /* number of bits in bit buffer */
|
||||
|
||||
// TODO: Finish implementation
|
||||
/* make local copies of globals */
|
||||
b = state.bb; /* initialize bit buffer */
|
||||
k = state.bk;
|
||||
w = state.window_posn; /* initialize window position */
|
||||
|
||||
/* inflate the coded data */
|
||||
ml = BitMasks[bl]; /* precompute masks for speed */
|
||||
md = BitMasks[bd];
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
ZIPNEEDBITS(bl, state, ref b, ref k);
|
||||
if ((e = (t = tl + (b & ml))->e) > 16)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (e == 99)
|
||||
return 1;
|
||||
ZIPDUMPBITS(t->b, ref b, ref k);
|
||||
e -= 16;
|
||||
ZIPNEEDBITS((int)e, state, ref b, ref k);
|
||||
} while ((e = (*(t = t->t + (b & BitMasks[e]))).e) > 16);
|
||||
}
|
||||
|
||||
ZIPDUMPBITS(t->b, ref b, ref k);
|
||||
if (e == 16) /* then it's a literal */
|
||||
{
|
||||
outbuf[w++] = (byte)t->n;
|
||||
}
|
||||
else /* it's an EOB or a length */
|
||||
{
|
||||
/* exit if end of block */
|
||||
if (e == 15)
|
||||
break;
|
||||
|
||||
/* get length of block to copy */
|
||||
ZIPNEEDBITS((int)e, state, ref b, ref k);
|
||||
n = t->n + (b & BitMasks[e]);
|
||||
ZIPDUMPBITS((int)e, ref b, ref k);
|
||||
|
||||
/* decode distance of block to copy */
|
||||
ZIPNEEDBITS(bd, state, ref b, ref k);
|
||||
|
||||
if ((e = (*(t = td + (b & md))).e) > 16)
|
||||
do
|
||||
{
|
||||
if (e == 99)
|
||||
return 1;
|
||||
ZIPDUMPBITS(t->b, ref b, ref k);
|
||||
e -= 16;
|
||||
ZIPNEEDBITS((int)e, state, ref b, ref k);
|
||||
} while ((e = (*(t = t->t + (b & BitMasks[e]))).e) > 16);
|
||||
|
||||
ZIPDUMPBITS(t->b, ref b, ref k);
|
||||
|
||||
ZIPNEEDBITS((int)e, state, ref b, ref k);
|
||||
d = w - t->n - (b & BitMasks[e]);
|
||||
ZIPDUMPBITS((int)e, ref b, ref k);
|
||||
|
||||
do
|
||||
{
|
||||
d &= ZIPWSIZE - 1;
|
||||
e = ZIPWSIZE - Math.Max(d, w);
|
||||
e = Math.Min(e, n);
|
||||
n -= e;
|
||||
do
|
||||
{
|
||||
outbuf[w++] = outbuf[d++];
|
||||
} while (--e > 0);
|
||||
} while (n > 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* restore the globals from the locals */
|
||||
state.window_posn = w; /* restore global window pointer */
|
||||
state.bb = b; /* restore global bit buffer */
|
||||
state.bk = k;
|
||||
|
||||
/* done */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Free a single huffman node
|
||||
/// </summary>
|
||||
/// <remarks>No-op because of garbage collection</remarks>
|
||||
private static void Free(HuffmanNode node) { }
|
||||
|
||||
#region Macros
|
||||
|
||||
private static void ZIPNEEDBITS(int n, State state, byte[] inbuf, ref uint bitBuffer, ref uint bitCount)
|
||||
private static void ZIPNEEDBITS(int n, State state, ref uint bitBuffer, ref uint bitCount)
|
||||
{
|
||||
while (bitCount < n)
|
||||
{
|
||||
int c = inbuf[state.InputPosition++];
|
||||
int c = *state.inpos++;
|
||||
bitBuffer |= (uint)(c << (int)bitCount);
|
||||
bitCount += 8;
|
||||
}
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
namespace BurnOutSharp.Compression.MSZIP
|
||||
{
|
||||
public class HuffmanNode
|
||||
public unsafe struct HuffmanNode
|
||||
{
|
||||
/// <summary>
|
||||
/// Number of extra bits or operation
|
||||
/// </summary>
|
||||
public byte ExtraBits;
|
||||
public byte e;
|
||||
|
||||
/// <summary>
|
||||
/// Number of bits in this code or subcode
|
||||
/// </summary>
|
||||
public byte BitLength;
|
||||
public byte b;
|
||||
|
||||
#region v
|
||||
|
||||
/// <summary>
|
||||
/// Literal, length base, or distance base
|
||||
/// </summary>
|
||||
public ushort Base;
|
||||
public ushort n;
|
||||
|
||||
/// <summary>
|
||||
/// Pointer to next level of table
|
||||
/// </summary>
|
||||
public HuffmanNode[] NextLevel;
|
||||
public HuffmanNode* t;
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -3,54 +3,54 @@ using static BurnOutSharp.Models.Compression.MSZIP.Constants;
|
||||
namespace BurnOutSharp.Compression.MSZIP
|
||||
{
|
||||
/// <see href="https://github.com/wine-mirror/wine/blob/master/dlls/cabinet/cabinet.h"/>
|
||||
public class State
|
||||
public unsafe class State
|
||||
{
|
||||
/// <summary>
|
||||
/// Current offset within the window
|
||||
/// </summary>
|
||||
public uint WindowPosition;
|
||||
public uint window_posn;
|
||||
|
||||
/// <summary>
|
||||
/// Bit buffer
|
||||
/// </summary>
|
||||
public uint BitBuffer;
|
||||
public uint bb;
|
||||
|
||||
/// <summary>
|
||||
/// Bits in bit buffer
|
||||
/// </summary>
|
||||
public uint BitCount;
|
||||
public uint bk;
|
||||
|
||||
/// <summary>
|
||||
/// Literal/length and distance code lengths
|
||||
/// </summary>
|
||||
public uint[] Lengths = new uint[288 + 32];
|
||||
public uint[] ll = new uint[288 + 32];
|
||||
|
||||
/// <summary>
|
||||
/// Bit length count table
|
||||
/// </summary>
|
||||
public uint[] Counts = new uint[ZIPBMAX + 1];
|
||||
public uint[] c = new uint[ZIPBMAX + 1];
|
||||
|
||||
/// <summary>
|
||||
/// Memory for l[-1..ZIPBMAX-1]
|
||||
/// </summary>
|
||||
public int[] LengthMemory = new int[ZIPBMAX + 1];
|
||||
public int[] lx = new int[ZIPBMAX + 1];
|
||||
|
||||
/// <summary>
|
||||
/// Table stack
|
||||
/// </summary>
|
||||
public HuffmanNode[] TableStack = new HuffmanNode[ZIPBMAX];
|
||||
public HuffmanNode*[] u = new HuffmanNode*[ZIPBMAX];
|
||||
|
||||
/// <summary>
|
||||
/// Values in order of bit length
|
||||
/// </summary>
|
||||
public uint[] Values = new uint[ZIPN_MAX];
|
||||
public uint[] v = new uint[ZIPN_MAX];
|
||||
|
||||
/// <summary>
|
||||
/// Bit offsets, then code stack
|
||||
/// </summary>
|
||||
public uint[] BitOffsets = new uint[ZIPBMAX + 1];
|
||||
public uint[] x = new uint[ZIPBMAX + 1];
|
||||
|
||||
/// <remarks>byte*</remarks>
|
||||
public int InputPosition;
|
||||
public byte* inpos;
|
||||
}
|
||||
}
|
||||
@@ -218,11 +218,9 @@ namespace BurnOutSharp.Wrappers
|
||||
// Setup LZX decompression
|
||||
var lzx = new Compression.LZX.State();
|
||||
Compression.LZX.Decompressor.Init(((ushort)folder.CompressionType >> 8) & 0x1f, lzx);
|
||||
// TODO: Use this area for LZX
|
||||
|
||||
// Setup MS-ZIP decompression
|
||||
Compression.MSZIP_zlib mszip = new Compression.MSZIP_zlib();
|
||||
bool hasLastBlock = false;
|
||||
Compression.MSZIP.State mszip = new Compression.MSZIP.State();
|
||||
|
||||
// Setup Quantum decompression
|
||||
var qtm = new Compression.Quantum.State();
|
||||
@@ -238,7 +236,7 @@ namespace BurnOutSharp.Wrappers
|
||||
decompressed = dataBlock.CompressedData;
|
||||
break;
|
||||
case Models.MicrosoftCabinet.CompressionType.TYPE_MSZIP:
|
||||
decompressed = mszip.DecompressMSZIPData(dataBlock.CompressedData, hasLastBlock);
|
||||
Compression.MSZIP.Decompressor.Decompress(mszip, dataBlock.CompressedSize, dataBlock.CompressedData, dataBlock.UncompressedSize, decompressed);
|
||||
break;
|
||||
case Models.MicrosoftCabinet.CompressionType.TYPE_QUANTUM:
|
||||
Compression.Quantum.Decompressor.Decompress(qtm, dataBlock.CompressedSize, dataBlock.CompressedData, dataBlock.UncompressedSize, decompressed);
|
||||
@@ -250,7 +248,6 @@ namespace BurnOutSharp.Wrappers
|
||||
return null;
|
||||
}
|
||||
|
||||
hasLastBlock = true;
|
||||
data.AddRange(decompressed ?? new byte[0]);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,444 +0,0 @@
|
||||
// using static BurnOutSharp.Wrappers.CabinetConstants;
|
||||
// using static BurnOutSharp.Wrappers.FDIcConstants;
|
||||
// using static BurnOutSharp.Wrappers.FDIConstants;
|
||||
// using static BurnOutSharp.Models.Compression.MSZIP.Constants;
|
||||
// using cab_LONG = System.Int32;
|
||||
// using cab_off_t = System.UInt32;
|
||||
// using cab_UBYTE = System.Byte;
|
||||
// using uint = System.UInt32;
|
||||
// using cab_UWORD = System.UInt16;
|
||||
|
||||
// namespace BurnOutSharp.Wrappers
|
||||
// {
|
||||
// internal unsafe class MSZIPfdi
|
||||
// {
|
||||
// /// <summary>
|
||||
// /// BuildHuffmanTree (internal)
|
||||
// /// </summary>
|
||||
// static cab_LONG BuildHuffmanTree(uint* b, uint n, uint s, cab_UWORD* d, cab_UWORD* e, ref Ziphuft[] t, cab_LONG* m, fdi_decomp_state decomp_state)
|
||||
// {
|
||||
// uint a; /* counter for codes of length k */
|
||||
// uint el; /* length of EOB code (value 256) */
|
||||
// uint f; /* i repeats in table every f entries */
|
||||
// cab_LONG g; /* maximum code length */
|
||||
// cab_LONG h; /* table level */
|
||||
// uint i; /* counter, current code */
|
||||
// uint j; /* counter */
|
||||
// cab_LONG k; /* number of bits in current code */
|
||||
// cab_LONG* l; /* stack of bits per table */
|
||||
// uint* p; /* pointer into decomp_state.zip.c[],decomp_state.zip.b[],decomp_state.zip.v[] */
|
||||
// Ziphuft* q; /* points to current table */
|
||||
// Ziphuft r; /* table entry for structure assignment */
|
||||
// cab_LONG w; /* bits before this table == (l * h) */
|
||||
// uint* xp; /* pointer into x */
|
||||
// cab_LONG y; /* number of dummy codes added */
|
||||
// uint z; /* number of entries in current table */
|
||||
|
||||
// l = decomp_state.zip.lx + 1;
|
||||
|
||||
// // Generate counts for each bit length
|
||||
// // set length of EOB code, if any
|
||||
// el = n > 256 ? b[256] : ZIPBMAX;
|
||||
|
||||
// for (i = 0; i < ZIPBMAX + 1; ++i)
|
||||
// {
|
||||
// decomp_state.zip.c[i] = 0;
|
||||
// }
|
||||
|
||||
// p = b; i = n;
|
||||
|
||||
// // assume all entries <= ZIPBMAX
|
||||
// do
|
||||
// {
|
||||
// decomp_state.zip.c[*p]++; p++;
|
||||
// } while (--i != 0);
|
||||
|
||||
// // null input--all zero length codes
|
||||
// if (decomp_state.zip.c[0] == n)
|
||||
// {
|
||||
// t = null;
|
||||
// *m = 0;
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// // Find minimum and maximum length, bound *m by those
|
||||
// for (j = 1; j <= ZIPBMAX; j++)
|
||||
// {
|
||||
// if (decomp_state.zip.c[j] != 0)
|
||||
// break;
|
||||
// }
|
||||
|
||||
// // minimum code length
|
||||
// k = (int)j;
|
||||
// if (*m < j)
|
||||
// *m = (int)j;
|
||||
|
||||
// for (i = ZIPBMAX; i != 0; i--)
|
||||
// {
|
||||
// if (decomp_state.zip.c[i] != 0)
|
||||
// break;
|
||||
// }
|
||||
|
||||
// // maximum code length
|
||||
// g = (int)i;
|
||||
// if (*m > i)
|
||||
// *m = (int)i;
|
||||
|
||||
// // Adjust last length count to fill out codes, if needed */
|
||||
// for (y = 1 << (int)j; j < i; j++, y <<= 1)
|
||||
// {
|
||||
// // bad input: more codes than bits
|
||||
// if ((y -= (int)decomp_state.zip.c[j]) < 0)
|
||||
// return 2;
|
||||
// }
|
||||
|
||||
// if ((y -= (int)decomp_state.zip.c[i]) < 0)
|
||||
// return 2;
|
||||
|
||||
// decomp_state.zip.c[i] += (uint)y;
|
||||
|
||||
// // Generate starting offsets LONGo the value table for each length
|
||||
// decomp_state.zip.x[1] = j = 0;
|
||||
// p = decomp_state.zip.c + 1; xp = decomp_state.zip.x + 2;
|
||||
// while (--i != 0)
|
||||
// {
|
||||
// // note that i == g from above
|
||||
// *xp++ = (j += *p++);
|
||||
// }
|
||||
|
||||
// /* Make a table of values in order of bit lengths */
|
||||
// p = b; i = 0;
|
||||
// do
|
||||
// {
|
||||
// if ((j = *p++) != 0)
|
||||
// decomp_state.zip.v[decomp_state.zip.x[j]++] = i;
|
||||
// } while (++i < n);
|
||||
|
||||
// // Generate the Huffman codes and for each, make the table entries
|
||||
// decomp_state.zip.x[0] = i = 0; /* first Huffman code is zero */
|
||||
// p = decomp_state.zip.v; /* grab values in bit order */
|
||||
// h = -1; /* no tables yet--level -1 */
|
||||
// w = l[-1] = 0; /* no bits decoded yet */
|
||||
// decomp_state.zip.u[0] = null; /* just to keep compilers happy */
|
||||
// q = null; /* ditto */
|
||||
// z = 0; /* ditto */
|
||||
|
||||
// /* go through the bit lengths (k already is bits in shortest code) */
|
||||
// for (; k <= g; k++)
|
||||
// {
|
||||
// a = decomp_state.zip.c[k];
|
||||
// while (a-- != 0)
|
||||
// {
|
||||
// // here i is the Huffman code of length k bits for value *p
|
||||
// // make tables up to required level
|
||||
// while (k > w + l[h])
|
||||
// {
|
||||
// // add bits already decoded
|
||||
// w += l[h++];
|
||||
|
||||
// // compute minimum size table less than or equal to *m bits
|
||||
// if ((z = (uint)(g - w)) > *m) /* upper limit */
|
||||
// z = (uint)*m;
|
||||
|
||||
// // try a k-w bit table
|
||||
// if ((f = (uint)(1 << (int)(j = (uint)(k - w)))) > a + 1)
|
||||
// { /* too few codes for k-w bit table */
|
||||
// f -= a + 1; /* deduct codes from patterns left */
|
||||
// xp = decomp_state.zip.c + k;
|
||||
// while (++j < z) /* try smaller tables up to z bits */
|
||||
// {
|
||||
// if ((f <<= 1) <= *++xp)
|
||||
// break; /* enough codes to use up j bits */
|
||||
// f -= *xp; /* else deduct codes from patterns */
|
||||
// }
|
||||
// }
|
||||
|
||||
// if ((uint)w + j > el && (uint)w < el)
|
||||
// j = el - w; /* make EOB code end at table */
|
||||
|
||||
// z = 1 << j; /* table entries for j-bit table */
|
||||
// l[h] = j; /* set table size in stack */
|
||||
|
||||
// /* allocate and link in new table */
|
||||
// if (!(q = decomp_state.fdi.alloc((z + 1) * sizeof(Ziphuft))))
|
||||
// {
|
||||
// if (h)
|
||||
// Free(decomp_state.fdi, decomp_state.zip.u[0]);
|
||||
// return 3; /* not enough memory */
|
||||
// }
|
||||
|
||||
// *t = q + 1; /* link to list for Ziphuft_free() */
|
||||
// *(t = &(q.v.t)) = null;
|
||||
// decomp_state.zip.u[h] = ++q; /* table starts after link */
|
||||
|
||||
// // connect to last table, if there is one
|
||||
// if (h != 0)
|
||||
// {
|
||||
// decomp_state.zip.x[h] = i; /* save pattern for backing up */
|
||||
// r.b = (cab_UBYTE)l[h - 1]; /* bits to dump before this table */
|
||||
// r.e = (cab_UBYTE)(16 + j); /* bits in this table */
|
||||
// r.t = q; /* pointer to this table */
|
||||
// j = (i & ((1 << w) - 1)) >> (w - l[h - 1]);
|
||||
// decomp_state.zip.u[h - 1][j] = r; /* connect to last table */
|
||||
// }
|
||||
// }
|
||||
|
||||
// /* set up table entry in r */
|
||||
// r.b = (cab_UBYTE)(k - w);
|
||||
// if (p >= decomp_state.zip.v + n)
|
||||
// {
|
||||
// r.e = 99; /* out of values--invalid code */
|
||||
// }
|
||||
// else if (*p < s)
|
||||
// {
|
||||
// r.e = (cab_UBYTE)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */
|
||||
// r.n = *p++; /* simple code is just the value */
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// r.e = (cab_UBYTE)e[*p - s]; /* non-simple--look up in lists */
|
||||
// r.n = d[*p++ - s];
|
||||
// }
|
||||
|
||||
// /* fill code-like entries with r */
|
||||
// f = 1 << (k - w);
|
||||
// for (j = i >> w; j < z; j += f)
|
||||
// q[j] = r;
|
||||
|
||||
// /* backwards increment the k-bit code i */
|
||||
// for (j = 1 << (k - 1); i & j; j >>= 1)
|
||||
// i ^= j;
|
||||
// i ^= j;
|
||||
|
||||
// /* backup over finished tables */
|
||||
// while ((i & ((1 << w) - 1)) != decomp_state.zip.x[h])
|
||||
// w -= l[--h]; /* don't need to update q */
|
||||
// }
|
||||
// }
|
||||
|
||||
// /* return actual size of base table */
|
||||
// *m = l[0];
|
||||
|
||||
// /* Return true (1) if we were given an incomplete table */
|
||||
// return y != 0 && g != 1;
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// fdi_Zipinflate_codes (internal)
|
||||
// /// </summary>
|
||||
// static cab_LONG fdi_Zipinflate_codes(in Ziphuft tl, in Ziphuft td, cab_LONG bl, cab_LONG bd, fdi_decomp_state decomp_state)
|
||||
// {
|
||||
// uint e; /* table entry flag/number of extra bits */
|
||||
// uint n, d; /* length and index for copy */
|
||||
// uint w; /* current window position */
|
||||
// Ziphuft t; /* pointer to table entry */
|
||||
// uint ml, md; /* masks for bl and bd bits */
|
||||
// uint b; /* bit buffer */
|
||||
// uint k; /* number of bits in bit buffer */
|
||||
|
||||
// /* make local copies of globals */
|
||||
// b = decomp_state.zip.bb; /* initialize bit buffer */
|
||||
// k = decomp_state.zip.bk;
|
||||
// w = decomp_state.zip.window_posn; /* initialize window position */
|
||||
|
||||
// /* inflate the coded data */
|
||||
// ml = BitMasks[bl]; /* precompute masks for speed */
|
||||
// md = BitMasks[bd];
|
||||
|
||||
// for (; ; )
|
||||
// {
|
||||
// ZIPNEEDBITS((uint)bl)
|
||||
// if ((e = (t = tl + (b & ml)).e) > 16)
|
||||
// do
|
||||
// {
|
||||
// if (e == 99)
|
||||
// return 1;
|
||||
// ZIPDUMPBITS(t.b)
|
||||
// e -= 16;
|
||||
// ZIPNEEDBITS(e)
|
||||
// } while ((e = (t = t.v.t + (b & BitMasks[e])).e) > 16);
|
||||
// ZIPDUMPBITS(t.b)
|
||||
// if (e == 16) /* then it's a literal */
|
||||
// decomp_state.outbuf[w++] = (cab_UBYTE)t.v.n;
|
||||
// else /* it's an EOB or a length */
|
||||
// {
|
||||
// /* exit if end of block */
|
||||
// if (e == 15)
|
||||
// break;
|
||||
|
||||
// /* get length of block to copy */
|
||||
// ZIPNEEDBITS(e)
|
||||
// n = t.v.n + (b & BitMasks[e]);
|
||||
// ZIPDUMPBITS(e);
|
||||
|
||||
// /* decode distance of block to copy */
|
||||
// ZIPNEEDBITS((uint)bd)
|
||||
// if ((e = (t = td + (b & md)).e) > 16)
|
||||
// do
|
||||
// {
|
||||
// if (e == 99)
|
||||
// return 1;
|
||||
// ZIPDUMPBITS(t.b)
|
||||
// e -= 16;
|
||||
// ZIPNEEDBITS(e)
|
||||
// } while ((e = (t = t.v.t + (b & BitMasks[e])).e) > 16);
|
||||
// ZIPDUMPBITS(t.b)
|
||||
// ZIPNEEDBITS(e)
|
||||
// d = w - t.v.n - (b & BitMasks[e]);
|
||||
// ZIPDUMPBITS(e)
|
||||
// do
|
||||
// {
|
||||
// d &= ZIPWSIZE - 1;
|
||||
// e = ZIPWSIZE - max(d, w);
|
||||
// e = min(e, n);
|
||||
// n -= e;
|
||||
// do
|
||||
// {
|
||||
// decomp_state.outbuf[w++] = decomp_state.outbuf[d++];
|
||||
// } while (--e);
|
||||
// } while (n);
|
||||
// }
|
||||
// }
|
||||
|
||||
// /* restore the globals from the locals */
|
||||
// decomp_state.zip.window_posn = w; /* restore global window pointer */
|
||||
// decomp_state.zip.bb = b; /* restore global bit buffer */
|
||||
// decomp_state.zip.bk = k;
|
||||
|
||||
// /* done */
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// fdi_Zipinflate_dynamic (internal)
|
||||
// ///
|
||||
// /// decompress an inflated type 2 (dynamic Huffman codes) block.
|
||||
// /// </summary>
|
||||
// static cab_LONG fdi_Zipinflate_dynamic(fdi_decomp_state decomp_state)
|
||||
// {
|
||||
// cab_LONG i; /* temporary variables */
|
||||
// uint j;
|
||||
// uint l; /* last length */
|
||||
// uint m; /* mask for bit lengths table */
|
||||
// uint n; /* number of lengths to get */
|
||||
// Ziphuft tl; /* literal/length code table */
|
||||
// Ziphuft td; /* distance code table */
|
||||
// cab_LONG bl; /* lookup bits for tl */
|
||||
// cab_LONG bd; /* lookup bits for td */
|
||||
// uint nb; /* number of bit length codes */
|
||||
// uint nl; /* number of literal/length codes */
|
||||
// uint nd; /* number of distance codes */
|
||||
// uint bitBuffer; /* bit buffer */
|
||||
// uint bitCount; /* number of bits in bit buffer */
|
||||
|
||||
// /* make local bit buffer */
|
||||
// bitBuffer = decomp_state.zip.bb;
|
||||
// bitCount = decomp_state.zip.bk;
|
||||
|
||||
// /* read in table lengths */
|
||||
// ZIPNEEDBITS(5)
|
||||
// nl = 257 + (bitBuffer & 0x1f); /* number of literal/length codes */
|
||||
// ZIPDUMPBITS(5)
|
||||
// ZIPNEEDBITS(5)
|
||||
// nd = 1 + (bitBuffer & 0x1f); /* number of distance codes */
|
||||
// ZIPDUMPBITS(5)
|
||||
// ZIPNEEDBITS(4)
|
||||
// nb = 4 + (bitBuffer & 0xf); /* number of bit length codes */
|
||||
// ZIPDUMPBITS(4)
|
||||
// if (nl > 288 || nd > 32)
|
||||
// return 1; /* bad lengths */
|
||||
|
||||
// /* read in bit-length-code lengths */
|
||||
// for (j = 0; j < nb; j++)
|
||||
// {
|
||||
// ZIPNEEDBITS(3)
|
||||
// state.Lengths[BitLengthOrder[j]] = bitBuffer & 7;
|
||||
// ZIPDUMPBITS(3)
|
||||
// }
|
||||
// for (; j < 19; j++)
|
||||
// state.Lengths[BitLengthOrder[j]] = 0;
|
||||
|
||||
// /* build decoding table for trees--single level, 7 bit lookup */
|
||||
// bl = 7;
|
||||
// if ((i = BuildHuffmanTree(state.Lengths, 19, 19, null, null, &tl, &bl, decomp_state)) != 0)
|
||||
// {
|
||||
// if (i == 1)
|
||||
// Free(decomp_state.fdi, tl);
|
||||
// return i; /* incomplete code set */
|
||||
// }
|
||||
|
||||
// /* read in literal and distance code lengths */
|
||||
// n = nl + nd;
|
||||
// m = BitMasks[bl];
|
||||
// i = l = 0;
|
||||
// while ((uint)i < n)
|
||||
// {
|
||||
// ZIPNEEDBITS((uint)bl)
|
||||
// j = (td = tl + (bitBuffer & m)).b;
|
||||
// ZIPDUMPBITS(j)
|
||||
// j = td.v.n;
|
||||
// if (j < 16) /* length of code in bits (0..15) */
|
||||
// state.Lengths[i++] = l = j; /* save last length in l */
|
||||
// else if (j == 16) /* repeat last length 3 to 6 times */
|
||||
// {
|
||||
// ZIPNEEDBITS(2)
|
||||
// j = 3 + (bitBuffer & 3);
|
||||
// ZIPDUMPBITS(2)
|
||||
// if ((uint)i + j > n)
|
||||
// return 1;
|
||||
// while (j--)
|
||||
// state.Lengths[i++] = l;
|
||||
// }
|
||||
// else if (j == 17) /* 3 to 10 zero length codes */
|
||||
// {
|
||||
// ZIPNEEDBITS(3)
|
||||
// j = 3 + (bitBuffer & 7);
|
||||
// ZIPDUMPBITS(3)
|
||||
// if ((uint)i + j > n)
|
||||
// return 1;
|
||||
// while (j--)
|
||||
// state.Lengths[i++] = 0;
|
||||
// l = 0;
|
||||
// }
|
||||
// else /* j == 18: 11 to 138 zero length codes */
|
||||
// {
|
||||
// ZIPNEEDBITS(7)
|
||||
// j = 11 + (bitBuffer & 0x7f);
|
||||
// ZIPDUMPBITS(7)
|
||||
// if ((uint)i + j > n)
|
||||
// return 1;
|
||||
// while (j--)
|
||||
// state.Lengths[i++] = 0;
|
||||
// l = 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
// /* free decoding table for trees */
|
||||
// Free(decomp_state.fdi, tl);
|
||||
|
||||
// /* restore the global bit buffer */
|
||||
// decomp_state.zip.bb = bitBuffer;
|
||||
// decomp_state.zip.bk = bitCount;
|
||||
|
||||
// /* build the decoding tables for literal/length and distance codes */
|
||||
// bl = ZIPLBITS;
|
||||
// if ((i = BuildHuffmanTree(state.Lengths, nl, 257, CopyLengths, LiteralExtraBits, &tl, &bl, decomp_state)) != 0)
|
||||
// {
|
||||
// if (i == 1)
|
||||
// Free(decomp_state.fdi, tl);
|
||||
// return i; /* incomplete code set */
|
||||
// }
|
||||
// bd = ZIPDBITS;
|
||||
// BuildHuffmanTree(state.Lengths + nl, nd, 0, CopyOffsets, DistanceExtraBits, &td, &bd, decomp_state);
|
||||
|
||||
// /* decompress until an end-of-block code */
|
||||
// if (fdi_Zipinflate_codes(tl, td, bl, bd, decomp_state))
|
||||
// return 1;
|
||||
|
||||
// /* free the decoding tables, return */
|
||||
// Free(decomp_state.fdi, tl);
|
||||
// Free(decomp_state.fdi, td);
|
||||
// return 0;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,32 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <see href="https://learn.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-patch/cc78752a-b4af-4eee-88cb-01f4d8a4c2bf"/>
|
||||
/// <see href="https://interoperability.blob.core.windows.net/files/MS-PATCH/%5bMS-PATCH%5d.pdf"/>
|
||||
/// <see href="https://github.com/kyz/libmspack/blob/master/libmspack/mspack/lzx.h"/>
|
||||
/// <see href="https://github.com/kyz/libmspack/blob/master/libmspack/mspack/lzxc.c"/>
|
||||
/// <see href="https://github.com/kyz/libmspack/blob/master/libmspack/mspack/lzxd.c"/>
|
||||
/// <see href="https://wimlib.net/"/>
|
||||
/// <see href="http://xavprods.free.fr/lzx/"/>
|
||||
/// <see href="https://github.com/jhermsmeier/node-lzx"/>
|
||||
/// <see href="https://github.com/jhermsmeier/node-cabarc"/>
|
||||
namespace BurnOutSharp.FileType
|
||||
{
|
||||
public class MSCABLZX
|
||||
{
|
||||
/// <summary>
|
||||
/// The window size determines the number of window subdivisions, or position slots
|
||||
/// </summary>
|
||||
public static readonly Dictionary<int, int> PositionSlots = new Dictionary<int, int>()
|
||||
{
|
||||
[128 * 1024] = 34, // 128 KB
|
||||
[256 * 1024] = 36, // 256 KB
|
||||
[512 * 1024] = 38, // 512 KB
|
||||
[1024 * 1024] = 42, // 1 MB
|
||||
[2 * 1024 * 1024] = 50, // 2 MB
|
||||
[4 * 1024 * 1024] = 66, // 4 MB
|
||||
[8 * 1024 * 1024] = 98, // 8 MB
|
||||
[16 * 1024 * 1024] = 162, // 16 MB
|
||||
[32 * 1024 * 1024] = 290, // 32 MB
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
using BurnOutSharp.Models.Compression.Quantum;
|
||||
|
||||
/// <see href="http://www.russotto.net/quantumcomp.html"/>
|
||||
/// <see href="https://handwiki.org/wiki/Software:Quantum_compression"/>
|
||||
/// <see href="https://archive.org/details/datacompressionc00salo_251/page/n206/mode/2up"/>
|
||||
/// <see href="https://github.com/kyz/libmspack/blob/master/libmspack/mspack/qtm.h"/>
|
||||
/// <see href="https://github.com/kyz/libmspack/blob/master/libmspack/mspack/qtmc.c"/>
|
||||
/// <see href="https://github.com/kyz/libmspack/blob/master/libmspack/mspack/qtmd.c"/>
|
||||
namespace BurnOutSharp.FileType
|
||||
{
|
||||
#region LZ Compression Tables
|
||||
|
||||
public static class QuantumConstants
|
||||
{
|
||||
/// <summary>
|
||||
/// Base position for each position slot (0..41)
|
||||
/// Used by selectors 4, 5, and 6
|
||||
/// </summary>
|
||||
public static readonly uint[] PositionBaseTable = new uint[]
|
||||
{
|
||||
0x000000, 0x000001, 0x000002, 0x000003, 0x000004, 0x000006, 0x000008, 0x00000c,
|
||||
0x000010, 0x000018, 0x000020, 0x000030, 0x000040, 0x000060, 0x000080, 0x0000c0,
|
||||
0x000100, 0x000180, 0x000200, 0x000300, 0x000400, 0x000600, 0x000800, 0x000c00,
|
||||
0x001000, 0x001800, 0x002000, 0x003000, 0x004000, 0x006000, 0x008000, 0x00c000,
|
||||
0x010000, 0x018000, 0x020000, 0x030000, 0x040000, 0x060000, 0x080000, 0x0c0000,
|
||||
0x100000, 0x180000,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Extra bits for each position slot (0..41)
|
||||
/// Used by selectors 4, 5, and 6
|
||||
/// </summary>
|
||||
public static readonly int[] PositionExtraBitsTable = new int[]
|
||||
{
|
||||
0, 0, 0, 0, 1, 1, 2, 2,
|
||||
3, 3, 4, 4, 5, 5, 6, 6,
|
||||
7, 7, 8, 8, 9, 9, 10, 10,
|
||||
11, 11, 12, 12, 13, 13, 14, 14,
|
||||
15, 15, 16, 16, 17, 17, 18, 18,
|
||||
19, 19,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Base length for each length slot (0..26)
|
||||
/// Used by selector 6
|
||||
/// </summary>
|
||||
public static readonly byte[] LengthBaseTable = new byte[]
|
||||
{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08,
|
||||
0x0a, 0x0c, 0x0e, 0x12, 0x16, 0x1a, 0x1e, 0x26,
|
||||
0x2e, 0x36, 0x3e, 0x4e, 0x5e, 0x6e, 0x7e, 0x9e,
|
||||
0xbe, 0xde, 0xfe
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Extra bits for each length slot (0..26)
|
||||
/// Used by selector 6
|
||||
/// </summary>
|
||||
public static readonly int[] LengthExtraBitsTable = new int[]
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 1, 1,
|
||||
1, 1, 2, 2, 2, 2, 3, 3,
|
||||
3, 3, 4, 4, 4, 4, 5, 5,
|
||||
5, 5, 0,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Number of position slots for (tsize - 10)
|
||||
/// </summary>
|
||||
public static readonly int[] NumberOfPositionSlots = new int[]
|
||||
{
|
||||
20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42,
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public static class QuantumCompressor
|
||||
{
|
||||
// TODO: Determine how these values are set
|
||||
private static uint CS_C = 0;
|
||||
private static uint CS_H = 0;
|
||||
private static uint CS_L = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Get frequency from code
|
||||
/// </summary>
|
||||
public static ushort GetFrequency(ushort totfreq)
|
||||
{
|
||||
uint range = ((CS_H - CS_L) & 0xFFFF) + 1;
|
||||
uint freq = ((CS_C - CS_L + 1) * totfreq - 1) / range;
|
||||
return (ushort)(freq & 0xFFFF);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The decoder renormalization loop
|
||||
/// </summary>
|
||||
public static int GetCode(int cumfreqm1, int cumfreq, int totfreq)
|
||||
{
|
||||
uint range = (CS_H - CS_L) + 1;
|
||||
CS_H = CS_L + (uint)((cumfreqm1 * range) / totfreq) - 1;
|
||||
CS_L = CS_L + (uint)((cumfreq * range) / totfreq);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if ((CS_L & 0x8000) != (CS_H & 0x8000))
|
||||
{
|
||||
if ((CS_L & 0x4000) != 0 && (CS_H & 0x4000) == 0)
|
||||
{
|
||||
// Underflow case
|
||||
CS_C ^= 0x4000;
|
||||
CS_L &= 0x3FFF;
|
||||
CS_H |= 0x4000;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CS_L <<= 1;
|
||||
CS_H = (CS_H << 1) | 1;
|
||||
CS_C = (CS_C << 1) | 0; // TODO: Figure out what `getbit()` is and replace the placeholder `0`
|
||||
}
|
||||
|
||||
// TODO: Figure out what is supposed to return here
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int GetSymbol(Model model)
|
||||
{
|
||||
int freq = GetFrequency(model.Symbols[0].CumulativeFrequency);
|
||||
|
||||
int i = 1;
|
||||
for (; i < model.Entries; i++)
|
||||
{
|
||||
if (model.Symbols[i].CumulativeFrequency <= freq)
|
||||
break;
|
||||
}
|
||||
|
||||
int sym = model.Symbols[i - 1].Symbol;
|
||||
|
||||
GetCode(model.Symbols[i - 1].CumulativeFrequency, model.Symbols[i].CumulativeFrequency, model.Symbols[0].CumulativeFrequency);
|
||||
|
||||
// TODO: Figure out what `update_model` does
|
||||
//update_model(model, i);
|
||||
|
||||
return sym;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,7 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Interfaces;
|
||||
#if NET48
|
||||
using WixToolset.Dtf.Compression;
|
||||
using WixToolset.Dtf.Compression.Cab;
|
||||
#elif NET6_0_OR_GREATER
|
||||
using BurnOutSharp.Wrappers;
|
||||
#endif
|
||||
using static BurnOutSharp.Utilities.Dictionary;
|
||||
|
||||
namespace BurnOutSharp.FileType
|
||||
@@ -17,7 +12,7 @@ namespace BurnOutSharp.FileType
|
||||
/// </summary>
|
||||
/// <remarks>Specification available at <see href="http://download.microsoft.com/download/5/0/1/501ED102-E53F-4CE0-AA6B-B0F93629DDC6/Exchange/%5BMS-CAB%5D.pdf"/></remarks>
|
||||
/// <see href="https://github.com/wine-mirror/wine/tree/master/dlls/cabinet"/>
|
||||
public partial class MicrosoftCAB : IScannable
|
||||
public class MicrosoftCAB : IScannable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
@@ -34,7 +29,6 @@ namespace BurnOutSharp.FileType
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
{
|
||||
#if NET6_0_OR_GREATER
|
||||
// If the cab file itself fails
|
||||
try
|
||||
{
|
||||
@@ -87,41 +81,6 @@ namespace BurnOutSharp.FileType
|
||||
}
|
||||
|
||||
return null;
|
||||
#else
|
||||
// If the cab file itself fails
|
||||
try
|
||||
{
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
CabInfo cabInfo = new CabInfo(file);
|
||||
cabInfo.Unpack(tempPath);
|
||||
|
||||
// Collect and format all found protections
|
||||
var protections = scanner.GetProtections(tempPath);
|
||||
|
||||
// If temp directory cleanup fails
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
// Remove temporary path references
|
||||
StripFromKeys(protections, tempPath);
|
||||
|
||||
return protections;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ Below is a list of container formats that are supported in some way:
|
||||
| InstallShield Archive V3 (Z) | No | Yes | Yes | Via `UnshieldSharp` |
|
||||
| InstallShield CAB | No | Yes | Yes | Via `UnshieldSharp` |
|
||||
| Linear Executable | No | No | No | Skeleton only |
|
||||
| Microsoft cabinet file | Yes | Yes | Yes | Via `WixToolset.Dtf` / `SharpZipLib` |
|
||||
| Microsoft cabinet file | Yes | Yes | Yes | |
|
||||
| Microsoft LZ-compressed files | No | Yes | Yes | |
|
||||
| MoPaQ game data archive (MPQ) | No | Yes | Yes | Via `StormLibSharp` |
|
||||
| Microsoft installation package (MSI) | No | Yes | Yes | Via `OpenMcdf` |
|
||||
|
||||
Reference in New Issue
Block a user