Port MS-ZIP for MS-CAB

This commit is contained in:
Matt Nadareski
2023-01-03 22:11:57 -08:00
parent 42b4c40d87
commit c14300ffbb
11 changed files with 524 additions and 2371 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -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]);
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -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` |