mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-24 04:51:19 +00:00
- Added input buffering to the Implode and Shrink routines for a marked
speedup. - Replaced the Shanno-Fano/Huffman reading routines from FZipExploder with ones of my own devising, based solely on the specs in the APPNOTE. SVN r1590 (trunk)
This commit is contained in:
parent
c0d2f78b2a
commit
2e87ebff22
7 changed files with 348 additions and 305 deletions
|
@ -1,9 +1,16 @@
|
||||||
May 15, 2009
|
May 16, 2009
|
||||||
|
- Added input buffering to the Implode and Shrink routines for a marked
|
||||||
|
speedup.
|
||||||
|
- Replaced the Shanno-Fano/Huffman reading routines from FZipExploder with
|
||||||
|
ones of my own devising, based solely on the specs in the APPNOTE.
|
||||||
|
|
||||||
|
May 15, 2009
|
||||||
- Found a copy of PKZIP 1.1 and verified that Implode support works with
|
- Found a copy of PKZIP 1.1 and verified that Implode support works with
|
||||||
files that use a literal table and 8k dictionary, and that the just-added
|
files that use a literal table and 8k dictionary, and that the just-added
|
||||||
Shrink support works at all.
|
Shrink support works at all.
|
||||||
- Replaced the bit-at-a-time Shannon-Fano decoder from GunZip.c64 with the
|
- Replaced the bit-at-a-time Shannon-Fano decoder from GunZip.c64 with the
|
||||||
word-at-a-time one from 7-Zip.
|
word-at-a-time one from 7-Zip for a slight speedup when working with
|
||||||
|
Imploded files.
|
||||||
|
|
||||||
May 15, 2009 (Changes by Graf Zahl)
|
May 15, 2009 (Changes by Graf Zahl)
|
||||||
- Fixed: Monsters should not check the inventory for damage absorbtion when
|
- Fixed: Monsters should not check the inventory for damage absorbtion when
|
||||||
|
|
|
@ -656,7 +656,7 @@ add_executable( zdoom WIN32
|
||||||
oplsynth/music_opldumper_mididevice.cpp
|
oplsynth/music_opldumper_mididevice.cpp
|
||||||
oplsynth/music_opl_mididevice.cpp
|
oplsynth/music_opl_mididevice.cpp
|
||||||
oplsynth/opl_mus_player.cpp
|
oplsynth/opl_mus_player.cpp
|
||||||
resourcefiles/explode.cpp
|
resourcefiles/ancientzip.cpp
|
||||||
resourcefiles/file_7z.cpp
|
resourcefiles/file_7z.cpp
|
||||||
resourcefiles/file_grp.cpp
|
resourcefiles/file_grp.cpp
|
||||||
resourcefiles/file_lump.cpp
|
resourcefiles/file_lump.cpp
|
||||||
|
|
|
@ -1,272 +1,303 @@
|
||||||
/*
|
/*
|
||||||
gunzip.c by Pasi Ojala, a1bert@iki.fi
|
gunzip.c by Pasi Ojala, a1bert@iki.fi
|
||||||
http://www.iki.fi/a1bert/
|
http://www.iki.fi/a1bert/
|
||||||
|
|
||||||
A hopefully easier to understand guide to GZip
|
A hopefully easier to understand guide to GZip
|
||||||
(deflate) decompression routine than the GZip
|
(deflate) decompression routine than the GZip
|
||||||
source code.
|
source code.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "explode.h"
|
#include "ancientzip.h"
|
||||||
|
|
||||||
static const unsigned char BitReverse[] = {
|
/****************************************************************
|
||||||
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
|
Bit-I/O variables and routines/macros
|
||||||
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
|
|
||||||
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
|
These routines work in the bit level because the target
|
||||||
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
|
environment does not have a barrel shifter. Trying to
|
||||||
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
|
handle several bits at once would've only made the code
|
||||||
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
|
slower.
|
||||||
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
|
|
||||||
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
|
If the environment supports multi-bit shifts, you should
|
||||||
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
|
write these routines again (see e.g. the GZIP sources).
|
||||||
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
|
|
||||||
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
|
[RH] Since the target environment is not a C64, I did as
|
||||||
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
|
suggested and rewrote these using zlib as a reference.
|
||||||
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
|
|
||||||
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
|
****************************************************************/
|
||||||
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
|
|
||||||
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
|
#define READBYTE(c) \
|
||||||
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
|
do { \
|
||||||
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
|
c = 0; \
|
||||||
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
|
if (InLeft) { \
|
||||||
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
|
InLeft--; \
|
||||||
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
|
if (bs < be) \
|
||||||
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
|
c = ReadBuf[bs++]; \
|
||||||
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
|
else { \
|
||||||
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
|
be = In->Read(&ReadBuf, sizeof(ReadBuf)); \
|
||||||
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
|
c = ReadBuf[0]; \
|
||||||
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
|
bs = 1; \
|
||||||
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
|
} \
|
||||||
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
|
} \
|
||||||
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
|
} while (0)
|
||||||
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
|
|
||||||
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
|
/* Get a byte of input into the bit accumulator. */
|
||||||
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
|
#define PULLBYTE() \
|
||||||
};
|
do { \
|
||||||
|
unsigned char next; \
|
||||||
|
READBYTE(next); \
|
||||||
|
Hold += (unsigned int)(next) << Bits; \
|
||||||
|
Bits += 8; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/* Assure that there are at least n bits in the bit accumulator. */
|
||||||
|
#define NEEDBITS(n) \
|
||||||
|
do { \
|
||||||
|
while (Bits < (unsigned)(n)) \
|
||||||
|
PULLBYTE(); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/* Return the low n bits of the bit accumulator (n < 16) */
|
||||||
|
#define BITS(n) \
|
||||||
|
((unsigned)Hold & ((1U << (n)) - 1))
|
||||||
|
|
||||||
|
/* Remove n bits from the bit accumulator */
|
||||||
|
#define DROPBITS(n) \
|
||||||
|
do { \
|
||||||
|
Hold >>= (n); \
|
||||||
|
Bits -= (unsigned)(n); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define READBITS(c, a) \
|
||||||
|
do { \
|
||||||
|
NEEDBITS(a); \
|
||||||
|
c = BITS(a); \
|
||||||
|
DROPBITS(a); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/****************************************************************
|
/****************************************************************
|
||||||
Bit-I/O variables and routines/macros
|
Shannon-Fano tree routines
|
||||||
|
|
||||||
These routines work in the bit level because the target
|
|
||||||
environment does not have a barrel shifter. Trying to
|
|
||||||
handle several bits at once would've only made the code
|
|
||||||
slower.
|
|
||||||
|
|
||||||
If the environment supports multi-bit shifts, you should
|
|
||||||
write these routines again (see e.g. the GZIP sources).
|
|
||||||
|
|
||||||
[RH] Since the target environment is not a C64, I did as
|
|
||||||
suggested and rewrote these using zlib as a reference.
|
|
||||||
|
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
|
||||||
#define READBYTE(c) \
|
|
||||||
do { \
|
|
||||||
c = 0; \
|
|
||||||
if (InLeft) { \
|
|
||||||
InLeft--; \
|
|
||||||
In->Read(&c, 1); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/* Get a byte of input into the bit accumulator. */
|
|
||||||
#define PULLBYTE() \
|
|
||||||
do { \
|
|
||||||
unsigned char next; \
|
|
||||||
READBYTE(next); \
|
|
||||||
Hold += (unsigned int)(next) << Bits; \
|
|
||||||
Bits += 8; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/* Assure that there are at least n bits in the bit accumulator. */
|
|
||||||
#define NEEDBITS(n) \
|
|
||||||
do { \
|
|
||||||
while (Bits < (unsigned)(n)) \
|
|
||||||
PULLBYTE(); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/* Return the low n bits of the bit accumulator (n < 16) */
|
|
||||||
#define BITS(n) \
|
|
||||||
((unsigned)Hold & ((1U << (n)) - 1))
|
|
||||||
|
|
||||||
/* Remove n bits from the bit accumulator */
|
|
||||||
#define DROPBITS(n) \
|
|
||||||
do { \
|
|
||||||
Hold >>= (n); \
|
|
||||||
Bits -= (unsigned)(n); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define READBITS(c, a) \
|
|
||||||
do { \
|
|
||||||
NEEDBITS(a); \
|
|
||||||
c = BITS(a); \
|
|
||||||
DROPBITS(a); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
|
|
||||||
/* SetCodeLengths() and DecodeSFValue() are from 7-Zip, which is LGPL. */
|
|
||||||
|
|
||||||
bool FZipExploder::DecoderBase::SetCodeLengths(const Byte *codeLengths, const int kNumSymbols)
|
|
||||||
{
|
|
||||||
int lenCounts[kNumBitsInLongestCode + 2], tmpPositions[kNumBitsInLongestCode + 1];
|
|
||||||
int i;
|
|
||||||
for(i = 0; i <= kNumBitsInLongestCode; i++)
|
|
||||||
lenCounts[i] = 0;
|
|
||||||
int symbolIndex;
|
|
||||||
for (symbolIndex = 0; symbolIndex < kNumSymbols; symbolIndex++)
|
|
||||||
lenCounts[codeLengths[symbolIndex]]++;
|
|
||||||
|
|
||||||
Limits[kNumBitsInLongestCode + 1] = 0;
|
|
||||||
Positions[kNumBitsInLongestCode + 1] = 0;
|
|
||||||
lenCounts[kNumBitsInLongestCode + 1] = 0;
|
|
||||||
|
|
||||||
int startPos = 0;
|
static const unsigned char BitReverse4[] = {
|
||||||
static const UInt32 kMaxValue = (1 << kNumBitsInLongestCode);
|
0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e,
|
||||||
|
0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f
|
||||||
|
};
|
||||||
|
|
||||||
for (i = kNumBitsInLongestCode; i > 0; i--)
|
#define FIRST_BIT_LEN 8
|
||||||
{
|
#define REST_BIT_LEN 4
|
||||||
startPos += lenCounts[i] << (kNumBitsInLongestCode - i);
|
|
||||||
if (startPos > kMaxValue)
|
|
||||||
return false;
|
|
||||||
Limits[i] = startPos;
|
|
||||||
Positions[i] = Positions[i + 1] + lenCounts[i + 1];
|
|
||||||
tmpPositions[i] = Positions[i] + lenCounts[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (startPos != kMaxValue)
|
void FZipExploder::InsertCode(TArray<HuffNode> &decoder, unsigned int pos, int bits, unsigned short code, int len, unsigned char value)
|
||||||
return false;
|
{
|
||||||
|
assert(len > 0);
|
||||||
|
unsigned int node = pos + (code & ((1 << bits) - 1));
|
||||||
|
|
||||||
for (symbolIndex = 0; symbolIndex < kNumSymbols; symbolIndex++)
|
if (len > bits)
|
||||||
if (codeLengths[symbolIndex] != 0)
|
{ // This code uses more bits than this level has room for. Store the bottom bits
|
||||||
Symbols[--tmpPositions[codeLengths[symbolIndex]]] = symbolIndex;
|
// in this table, then proceed to the next one.
|
||||||
return true;
|
unsigned int child = decoder[node].ChildTable;
|
||||||
}
|
if (child == 0)
|
||||||
|
{ // Need to create child table.
|
||||||
int FZipExploder::DecodeSFValue(const DecoderBase &decoder, const unsigned int kNumSymbols)
|
child = InitTable(decoder, 1 << REST_BIT_LEN);
|
||||||
{
|
decoder[node].ChildTable = child;
|
||||||
unsigned int numBits = 0;
|
decoder[node].Length = bits;
|
||||||
unsigned int value;
|
decoder[node].Value = 0;
|
||||||
int i;
|
}
|
||||||
NEEDBITS(kNumBitsInLongestCode);
|
else
|
||||||
// value = BITS(kNumBitsInLongestCode);
|
|
||||||
// TODO: Rewrite this so it doesn't need the BitReverse table.
|
|
||||||
// (It should be possible, right?)
|
|
||||||
value = (BitReverse[Hold & 0xFF] << 8) | BitReverse[(Hold >> 8) & 0xFF];
|
|
||||||
for(i = kNumBitsInLongestCode; i > 0; i--)
|
|
||||||
{
|
|
||||||
if (value < decoder.Limits[i])
|
|
||||||
{
|
{
|
||||||
numBits = i;
|
assert(decoder[node].Length == bits);
|
||||||
break;
|
assert(decoder[node].Value == 0);
|
||||||
|
}
|
||||||
|
InsertCode(decoder, child, REST_BIT_LEN, code >> bits, len - bits, value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // If this code uses fewer bits than this level of the table, it is
|
||||||
|
// inserted repeatedly for each value that matches it at its lower
|
||||||
|
// bits.
|
||||||
|
for (int i = 1 << (bits - len); --i >= 0; node += 1 << len)
|
||||||
|
{
|
||||||
|
decoder[node].Length = len;
|
||||||
|
decoder[node].Value = value;
|
||||||
|
assert(decoder[node].ChildTable == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i == 0)
|
}
|
||||||
return -1;
|
|
||||||
DROPBITS(numBits);
|
unsigned int FZipExploder::InitTable(TArray<HuffNode> &decoder, int numspots)
|
||||||
unsigned int index = decoder.Positions[numBits] +
|
{
|
||||||
((value - decoder.Limits[numBits + 1]) >> (kNumBitsInLongestCode - numBits));
|
unsigned int start = decoder.Size();
|
||||||
if (index >= kNumSymbols)
|
decoder.Reserve(numspots);
|
||||||
return -1;
|
memset(&decoder[start], 0, sizeof(HuffNode)*numspots);
|
||||||
return decoder.Symbols[index];
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int STACK_ARGS FZipExploder::buildercmp(const void *a, const void *b)
|
||||||
int FZipExploder::DecodeSF(unsigned char *table)
|
{
|
||||||
|
const TableBuilder *v1 = (const TableBuilder *)a;
|
||||||
|
const TableBuilder *v2 = (const TableBuilder *)b;
|
||||||
|
int d = v1->Length - v2->Length;
|
||||||
|
if (d == 0) {
|
||||||
|
d = v1->Value - v2->Value;
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FZipExploder::BuildDecoder(TArray<HuffNode> &decoder, TableBuilder *values, int numvals)
|
||||||
{
|
{
|
||||||
unsigned char a, c;
|
int i;
|
||||||
int i, n, v = 0;
|
|
||||||
|
|
||||||
READBYTE(c);
|
qsort(values, numvals, sizeof(*values), buildercmp);
|
||||||
n = c + 1;
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
int nv, bl;
|
|
||||||
READBYTE(a);
|
|
||||||
nv = ((a >> 4) & 15) + 1;
|
|
||||||
bl = (a & 15) + 1;
|
|
||||||
while (nv--) {
|
|
||||||
table[v++] = bl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return v; /* entries used */
|
|
||||||
}
|
|
||||||
|
|
||||||
int FZipExploder::Explode(unsigned char *out, unsigned int outsize,
|
// Generate the Shannon-Fano tree:
|
||||||
FileReader *in, unsigned int insize,
|
unsigned short code = 0;
|
||||||
int flags)
|
unsigned short code_increment = 0;
|
||||||
{
|
unsigned short last_bit_length = 0;
|
||||||
int c, i, minMatchLen = 3, len, dist;
|
for (i = numvals - 1; i >= 0; --i)
|
||||||
int lowDistanceBits;
|
|
||||||
unsigned char ll[256];
|
|
||||||
unsigned int bIdx = 0;
|
|
||||||
|
|
||||||
Hold = 0;
|
|
||||||
Bits = 0;
|
|
||||||
In = in;
|
|
||||||
InLeft = insize;
|
|
||||||
|
|
||||||
if ((flags & 4)) {
|
|
||||||
/* 3 trees: literals, lengths, distance top 6 */
|
|
||||||
minMatchLen = 3;
|
|
||||||
if (!LiteralDecoder.SetCodeLengths(ll, DecodeSF(ll)))
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
/* 2 trees: lengths, distance top 6 */
|
|
||||||
minMatchLen = 2;
|
|
||||||
}
|
|
||||||
if (!LengthDecoder.SetCodeLengths(ll, DecodeSF(ll)))
|
|
||||||
return 1;
|
|
||||||
if (!DistanceDecoder.SetCodeLengths(ll, DecodeSF(ll)))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
lowDistanceBits = (flags & 2) ? /* 8k dictionary */ 7 : /* 4k dictionary */ 6;
|
|
||||||
while (bIdx < outsize)
|
|
||||||
{
|
{
|
||||||
READBITS(c, 1);
|
code += code_increment;
|
||||||
if (c) {
|
if (values[i].Length != last_bit_length)
|
||||||
/* literal data */
|
{
|
||||||
if ((flags & 4)) {
|
last_bit_length = values[i].Length;
|
||||||
c = DecodeSFValue(LiteralDecoder, 256);
|
code_increment = 1 << (16 - last_bit_length);
|
||||||
} else {
|
|
||||||
READBITS(c, 8);
|
|
||||||
}
|
|
||||||
out[bIdx++] = c;
|
|
||||||
} else {
|
|
||||||
READBITS(dist, lowDistanceBits);
|
|
||||||
c = DecodeSFValue(DistanceDecoder, 64);
|
|
||||||
dist |= (c << lowDistanceBits);
|
|
||||||
len = DecodeSFValue(LengthDecoder, 64);
|
|
||||||
if (len == 63) {
|
|
||||||
READBITS(c, 8);
|
|
||||||
len += c;
|
|
||||||
}
|
|
||||||
len += minMatchLen;
|
|
||||||
dist++;
|
|
||||||
if (bIdx + len > outsize) {
|
|
||||||
throw CExplosionError("Not enough output space");
|
|
||||||
}
|
|
||||||
if ((unsigned int)dist > bIdx) {
|
|
||||||
/* Anything before the first input byte is zero. */
|
|
||||||
int zeros = dist - bIdx;
|
|
||||||
if (len < zeros)
|
|
||||||
zeros = len;
|
|
||||||
for(i = zeros; i; i--)
|
|
||||||
out[bIdx++] = 0;
|
|
||||||
len -= zeros;
|
|
||||||
}
|
|
||||||
for(i = len; i; i--, bIdx++) {
|
|
||||||
out[bIdx] = out[bIdx - dist];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// Reverse the order of the bits in the code before storing it.
|
||||||
|
values[i].Code = BitReverse4[code >> 12] |
|
||||||
|
(BitReverse4[(code >> 8) & 0xf] << 4) |
|
||||||
|
(BitReverse4[(code >> 4) & 0xf] << 8) |
|
||||||
|
(BitReverse4[code & 0xf] << 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert each code into the hierarchical table. The top level is FIRST_BIT_LEN bits,
|
||||||
|
// and the other levels are REST_BIT_LEN bits. If a code does not completely fill
|
||||||
|
// a level, every permutation for the remaining bits is filled in to
|
||||||
|
// match this one.
|
||||||
|
InitTable(decoder, 1 << FIRST_BIT_LEN); // Set up the top level.
|
||||||
|
for (i = 0; i < numvals; ++i)
|
||||||
|
{
|
||||||
|
InsertCode(decoder, 0, FIRST_BIT_LEN, values[i].Code, values[i].Length, values[i].Value);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int FZipExploder::DecodeSFValue(const TArray<HuffNode> &decoder)
|
||||||
|
{
|
||||||
|
unsigned int bits = FIRST_BIT_LEN, table = 0, code;
|
||||||
|
const HuffNode *pos;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
NEEDBITS(bits);
|
||||||
|
code = BITS(bits);
|
||||||
|
bits = REST_BIT_LEN;
|
||||||
|
pos = &decoder[table + code];
|
||||||
|
DROPBITS(pos->Length);
|
||||||
|
table = pos->ChildTable;
|
||||||
|
}
|
||||||
|
while (table != 0);
|
||||||
|
return pos->Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int FZipExploder::DecodeSF(TArray<HuffNode> &decoder, int numvals)
|
||||||
|
{
|
||||||
|
TableBuilder builder[256];
|
||||||
|
unsigned char a, c;
|
||||||
|
int i, n, v = 0;
|
||||||
|
|
||||||
|
READBYTE(c);
|
||||||
|
n = c + 1;
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
int nv, bl;
|
||||||
|
READBYTE(a);
|
||||||
|
nv = ((a >> 4) & 15) + 1;
|
||||||
|
bl = (a & 15) + 1;
|
||||||
|
while (nv--) {
|
||||||
|
builder[v].Length = bl;
|
||||||
|
builder[v].Value = v;
|
||||||
|
v++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (v != numvals)
|
||||||
|
return 1; /* bad table */
|
||||||
|
return BuildDecoder(decoder, builder, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
int FZipExploder::Explode(unsigned char *out, unsigned int outsize,
|
||||||
|
FileReader *in, unsigned int insize,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
int c, i, minMatchLen = 3, len, dist;
|
||||||
|
int lowDistanceBits;
|
||||||
|
unsigned int bIdx = 0;
|
||||||
|
|
||||||
|
Hold = 0;
|
||||||
|
Bits = 0;
|
||||||
|
In = in;
|
||||||
|
InLeft = insize;
|
||||||
|
bs = be = 0;
|
||||||
|
|
||||||
|
if ((flags & 4)) {
|
||||||
|
/* 3 trees: literals, lengths, distance top 6 */
|
||||||
|
minMatchLen = 3;
|
||||||
|
if (DecodeSF(LiteralDecoder, 256))
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
/* 2 trees: lengths, distance top 6 */
|
||||||
|
minMatchLen = 2;
|
||||||
|
}
|
||||||
|
if (DecodeSF(LengthDecoder, 64))
|
||||||
|
return 1;
|
||||||
|
if (DecodeSF(DistanceDecoder, 64))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
lowDistanceBits = (flags & 2) ? /* 8k dictionary */ 7 : /* 4k dictionary */ 6;
|
||||||
|
while (bIdx < outsize)
|
||||||
|
{
|
||||||
|
READBITS(c, 1);
|
||||||
|
if (c) {
|
||||||
|
/* literal data */
|
||||||
|
if ((flags & 4)) {
|
||||||
|
c = DecodeSFValue(LiteralDecoder);
|
||||||
|
} else {
|
||||||
|
READBITS(c, 8);
|
||||||
|
}
|
||||||
|
out[bIdx++] = c;
|
||||||
|
} else {
|
||||||
|
READBITS(dist, lowDistanceBits);
|
||||||
|
c = DecodeSFValue(DistanceDecoder);
|
||||||
|
dist |= (c << lowDistanceBits);
|
||||||
|
len = DecodeSFValue(LengthDecoder);
|
||||||
|
if (len == 63) {
|
||||||
|
READBITS(c, 8);
|
||||||
|
len += c;
|
||||||
|
}
|
||||||
|
len += minMatchLen;
|
||||||
|
dist++;
|
||||||
|
if (bIdx + len > outsize) {
|
||||||
|
throw CExplosionError("Not enough output space");
|
||||||
|
}
|
||||||
|
if ((unsigned int)dist > bIdx) {
|
||||||
|
/* Anything before the first input byte is zero. */
|
||||||
|
int zeros = dist - bIdx;
|
||||||
|
if (len < zeros)
|
||||||
|
zeros = len;
|
||||||
|
for(i = zeros; i; i--)
|
||||||
|
out[bIdx++] = 0;
|
||||||
|
len -= zeros;
|
||||||
|
}
|
||||||
|
for(i = len; i; i--, bIdx++) {
|
||||||
|
out[bIdx] = out[bIdx - dist];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* HSIZE is defined as 2^13 (8192) in unzip.h */
|
/* HSIZE is defined as 2^13 (8192) in unzip.h */
|
||||||
#define HSIZE 8192
|
#define HSIZE 8192
|
||||||
#define BOGUSCODE 256
|
#define BOGUSCODE 256
|
||||||
|
@ -277,6 +308,7 @@ int FZipExploder::Explode(unsigned char *out, unsigned int outsize,
|
||||||
int ShrinkLoop(unsigned char *out, unsigned int outsize,
|
int ShrinkLoop(unsigned char *out, unsigned int outsize,
|
||||||
FileReader *In, unsigned int InLeft)
|
FileReader *In, unsigned int InLeft)
|
||||||
{
|
{
|
||||||
|
unsigned char ReadBuf[256];
|
||||||
unsigned short Parent[HSIZE];
|
unsigned short Parent[HSIZE];
|
||||||
unsigned char Value[HSIZE], Stack[HSIZE];
|
unsigned char Value[HSIZE], Stack[HSIZE];
|
||||||
unsigned char *newstr;
|
unsigned char *newstr;
|
||||||
|
@ -285,6 +317,7 @@ int ShrinkLoop(unsigned char *out, unsigned int outsize,
|
||||||
int code, oldcode, freecode, curcode;
|
int code, oldcode, freecode, curcode;
|
||||||
unsigned int Bits = 0, Hold = 0;
|
unsigned int Bits = 0, Hold = 0;
|
||||||
unsigned int size = 0;
|
unsigned int size = 0;
|
||||||
|
unsigned int bs = 0, be = 0;
|
||||||
|
|
||||||
freecode = BOGUSCODE;
|
freecode = BOGUSCODE;
|
||||||
for (code = 0; code < BOGUSCODE; code++)
|
for (code = 0; code < BOGUSCODE; code++)
|
50
src/resourcefiles/ancientzip.h
Normal file
50
src/resourcefiles/ancientzip.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#include "files.h"
|
||||||
|
#include "doomerrors.h"
|
||||||
|
|
||||||
|
class FZipExploder
|
||||||
|
{
|
||||||
|
unsigned int Hold, Bits;
|
||||||
|
FileReader *In;
|
||||||
|
unsigned int InLeft;
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
Shannon-Fano tree structures, variables and related routines
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
|
struct HuffNode
|
||||||
|
{
|
||||||
|
unsigned char Value;
|
||||||
|
unsigned char Length;
|
||||||
|
unsigned short ChildTable;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TableBuilder
|
||||||
|
{
|
||||||
|
unsigned char Value;
|
||||||
|
unsigned char Length;
|
||||||
|
unsigned short Code;
|
||||||
|
};
|
||||||
|
|
||||||
|
TArray<HuffNode> LiteralDecoder;
|
||||||
|
TArray<HuffNode> DistanceDecoder;
|
||||||
|
TArray<HuffNode> LengthDecoder;
|
||||||
|
unsigned char ReadBuf[256];
|
||||||
|
unsigned int bs, be;
|
||||||
|
|
||||||
|
static int STACK_ARGS buildercmp(const void *a, const void *b);
|
||||||
|
void InsertCode(TArray<HuffNode> &decoder, unsigned int pos, int bits, unsigned short code, int len, unsigned char value);
|
||||||
|
unsigned int InitTable(TArray<HuffNode> &decoder, int numspots);
|
||||||
|
int BuildDecoder(TArray<HuffNode> &decoder, TableBuilder *values, int numvals);
|
||||||
|
int DecodeSFValue(const TArray<HuffNode> ¤tTree);
|
||||||
|
int DecodeSF(TArray<HuffNode> &decoder, int numvals);
|
||||||
|
public:
|
||||||
|
int Explode(unsigned char *out, unsigned int outsize, FileReader *in, unsigned int insize, int flags);
|
||||||
|
};
|
||||||
|
|
||||||
|
class CExplosionError : CRecoverableError
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CExplosionError(const char *message) : CRecoverableError(message) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
int ShrinkLoop(unsigned char *out, unsigned int outsize, FileReader *in, unsigned int insize);
|
|
@ -1,47 +0,0 @@
|
||||||
#include "files.h"
|
|
||||||
#include "doomerrors.h"
|
|
||||||
|
|
||||||
class FZipExploder
|
|
||||||
{
|
|
||||||
unsigned int Hold, Bits;
|
|
||||||
FileReader *In;
|
|
||||||
unsigned int InLeft;
|
|
||||||
|
|
||||||
/****************************************************************
|
|
||||||
Shannon-Fano tree structures, variables and related routines
|
|
||||||
****************************************************************/
|
|
||||||
|
|
||||||
enum { kNumBitsInLongestCode = 16 };
|
|
||||||
|
|
||||||
struct DecoderBase
|
|
||||||
{
|
|
||||||
unsigned int Limits[kNumBitsInLongestCode + 2]; // Limits[i] = value limit for symbols with length = i
|
|
||||||
unsigned char Positions[kNumBitsInLongestCode + 2]; // Positions[i] = index in Symbols[] of first symbol with length = i
|
|
||||||
unsigned char Symbols[1];
|
|
||||||
|
|
||||||
bool SetCodeLengths(const unsigned char *codeLengths, const int kNumSymbols);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<int kNumSymbols>
|
|
||||||
struct Decoder : DecoderBase
|
|
||||||
{
|
|
||||||
unsigned char RestOfSymbols[kNumSymbols];
|
|
||||||
};
|
|
||||||
|
|
||||||
Decoder<256> LiteralDecoder;
|
|
||||||
Decoder<64> DistanceDecoder;
|
|
||||||
Decoder<64> LengthDecoder;
|
|
||||||
|
|
||||||
int DecodeSFValue(const DecoderBase ¤tTree, const unsigned int kNumSymbols);
|
|
||||||
int DecodeSF(unsigned char *table);
|
|
||||||
public:
|
|
||||||
int Explode(unsigned char *out, unsigned int outsize, FileReader *in, unsigned int insize, int flags);
|
|
||||||
};
|
|
||||||
|
|
||||||
class CExplosionError : CRecoverableError
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CExplosionError(const char *message) : CRecoverableError(message) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
int ShrinkLoop(unsigned char *out, unsigned int outsize, FileReader *in, unsigned int insize);
|
|
|
@ -40,7 +40,7 @@
|
||||||
#include "w_wad.h"
|
#include "w_wad.h"
|
||||||
#include "w_zip.h"
|
#include "w_zip.h"
|
||||||
#include "i_system.h"
|
#include "i_system.h"
|
||||||
#include "explode.h"
|
#include "ancientzip.h"
|
||||||
|
|
||||||
#define BUFREADCOMMENT (0x400)
|
#define BUFREADCOMMENT (0x400)
|
||||||
|
|
||||||
|
|
|
@ -6366,11 +6366,11 @@
|
||||||
Name="Resource Files"
|
Name="Resource Files"
|
||||||
>
|
>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\src\resourcefiles\explode.cpp"
|
RelativePath=".\src\resourcefiles\ancientzip.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\src\resourcefiles\explode.h"
|
RelativePath=".\src\resourcefiles\ancientzip.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
|
|
Loading…
Reference in a new issue