mirror of https://github.com/Cisco-Talos/clamav
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
557 lines
15 KiB
557 lines
15 KiB
/*
|
|
* LZMADecode.c
|
|
*
|
|
* This file is a part of LZMA compression module for NSIS.
|
|
*
|
|
* Original LZMA SDK Copyright (C) 1999-2006 Igor Pavlov
|
|
* Modifications Copyright (C) 2003-2007 Amir Szekely <kichik@netvision.net.il>
|
|
*
|
|
* Licensed under the Common Public License version 1.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
*
|
|
* Licence details can be found in the file COPYING.nsis.
|
|
*
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include "LZMADecode.h"
|
|
|
|
#define LEAVE { goto saveStateAndReturn; }
|
|
#define NEED_BYTE(c) case c: if (!avail_in) { mode = c; LEAVE; }
|
|
#define NEED_BYTE_ if (!avail_in) LEAVE;
|
|
#define NEXT_BYTE (avail_in--, *next_in++)
|
|
#define NEED_OUT(c) case c: if (!avail_out) { mode = c; LEAVE; }
|
|
#define PUT_BYTE_(b) { *next_out = b; next_out++; avail_out--; }
|
|
#define PUT_BYTE(b) { totalOut++; PUT_BYTE_(b) }
|
|
#define DECODE_BIT(c, x) prob = x; last = c; goto _LZMA_C_RDBD; case c:
|
|
#define DECODE_LEN(c, x) probs = x; last2 = c; goto _LZMA_C_LEND; case c:
|
|
#define DECODE_BIT_TREE(c, x, y) probs = x; numLevels = y; last3 = c; goto _LZMA_C_BTD; case c:
|
|
|
|
enum {
|
|
/* 0 */ LZMA_C_INIT = 0,
|
|
/* 1 */ LZMA_C_GETDICT,
|
|
/* 2 */ LZMA_C_BLOCK,
|
|
/* 3 */ LZMA_C_RDI, /* RangeDecoderInit */
|
|
/* 4 */ LZMA_C_RDBD, /* RangeDecoderBitDecode */
|
|
/* 5 */ LZMA_C_RDBD_IN, /* RangeDecoderBitDecode */
|
|
/* 6 */ LZMA_C_TYPE,
|
|
/* 7 */ LZMA_C_ISREP,
|
|
/* 8 */ LZMA_C_ISREPG0,
|
|
/* 9 */ LZMA_C_ISREP0LONG,
|
|
/* 10 */ LZMA_C_ISREPG1,
|
|
/* 11 */ LZMA_C_ISREPG2,
|
|
/* 12 */ LZMA_C_NORM,
|
|
/* 13 */ LZMA_C_LITDM1, /* LzmaLiteralDecodeMatch */
|
|
/* 14 */ LZMA_C_LITDM2, /* LzmaLiteralDecodeMatch */
|
|
/* 15 */ LZMA_C_LITD, /* LzmaLiteralDecode */
|
|
/* 16 */ LZMA_C_RDRBTD, /* RangeDecoderReverseBitTreeDecode */
|
|
/* 17 */ LZMA_C_LEND, /* LzmaLenDecode */
|
|
/* 18 */ LZMA_C_LEND1, /* LzmaLenDecode */
|
|
/* 19 */ LZMA_C_LEND2, /* LzmaLenDecode */
|
|
/* 20 */ LZMA_C_LEND_RES, /* LzmaLenDecode */
|
|
/* 21 */ LZMA_C_LEND_C1,
|
|
/* 22 */ LZMA_C_LEND_C2,
|
|
/* 23 */ LZMA_C_BTD, /* RangeDecoderBitTreeDecode */
|
|
/* 24 */ LZMA_C_BTD_LOOP,
|
|
/* 25 */ LZMA_C_BTD_C1,
|
|
/* 26 */ LZMA_C_OUTPUT_1,
|
|
/* 27 */ LZMA_C_OUTPUT_2,
|
|
/* 28 */ LZMA_C_OUTPUT_3
|
|
};
|
|
|
|
#define kNumTopBits 24
|
|
#define kTopValue ((UInt32)1 << kNumTopBits)
|
|
|
|
#define kNumBitModelTotalBits 11
|
|
#define kBitModelTotal (1 << kNumBitModelTotalBits)
|
|
#define kNumMoveBits 5
|
|
|
|
#define RC_NORMALIZE(c) if (range < kTopValue) { NEED_BYTE(c); range <<= 8; code = (code << 8) | NEXT_BYTE; }
|
|
|
|
#define RC_GET_BIT2(c, prob, mi, A0, A1) { \
|
|
UInt32 bound = (range >> kNumBitModelTotalBits) * *prob; \
|
|
if (code < bound) \
|
|
{ A0; range = bound; *prob += (kBitModelTotal - *prob) >> kNumMoveBits; mi <<= 1; } \
|
|
else \
|
|
{ A1; range -= bound; code -= bound; *prob -= (*prob) >> kNumMoveBits; mi = (mi + mi) + 1; } \
|
|
RC_NORMALIZE(c) \
|
|
}
|
|
|
|
#define RC_GET_BIT(c, prob, mi) RC_GET_BIT2(c, prob, mi, ; , ;)
|
|
|
|
#define kNumPosBitsMax 4
|
|
#define kNumPosStatesMax (1 << kNumPosBitsMax)
|
|
|
|
#define kLenNumLowBits 3
|
|
#define kLenNumLowSymbols (1 << kLenNumLowBits)
|
|
#define kLenNumMidBits 3
|
|
#define kLenNumMidSymbols (1 << kLenNumMidBits)
|
|
#define kLenNumHighBits 8
|
|
#define kLenNumHighSymbols (1 << kLenNumHighBits)
|
|
|
|
#define LenChoice 0
|
|
#define LenChoice2 (LenChoice + 1)
|
|
#define LenLow (LenChoice2 + 1)
|
|
#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
|
|
#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
|
|
#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
|
|
|
|
#define kNumStates 12
|
|
|
|
#define kStartPosModelIndex 4
|
|
#define kEndPosModelIndex 14
|
|
#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
|
|
|
|
#define kNumPosSlotBits 6
|
|
#define kNumLenToPosStates 4
|
|
|
|
#define kNumAlignBits 4
|
|
#define kAlignTableSize (1 << kNumAlignBits)
|
|
|
|
#define kMatchMinLen 2
|
|
|
|
#define IsMatch 0
|
|
#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
|
|
#define IsRepG0 (IsRep + kNumStates)
|
|
#define IsRepG1 (IsRepG0 + kNumStates)
|
|
#define IsRepG2 (IsRepG1 + kNumStates)
|
|
#define IsRep0Long (IsRepG2 + kNumStates)
|
|
#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
|
|
#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
|
|
#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
|
|
#define LenCoder (Align + kAlignTableSize)
|
|
#define RepLenCoder (LenCoder + kNumLenProbs)
|
|
#define Literal (RepLenCoder + kNumLenProbs)
|
|
|
|
#define LZMA_BASE_SIZE 1846
|
|
#define LZMA_LIT_SIZE 768
|
|
|
|
#if Literal != LZMA_BASE_SIZE
|
|
StopCompilingDueBUG
|
|
#endif
|
|
|
|
void lzmaInit(lzma_stream *s)
|
|
{
|
|
/* size of lzma_stream minus the size of the two allocated buffer pointers.
|
|
we don't want to lose to pointer or else we won't be able to free them. */
|
|
size_t i = sizeof(lzma_stream) - (sizeof(unsigned char *) * 2);
|
|
while (i--)
|
|
((lzByte *)s)[i] = 0;
|
|
|
|
s->rep0 = s->rep1 = s->rep2 = s->rep3 = 1;
|
|
s->range = (0xFFFFFFFF);
|
|
}
|
|
|
|
int lzmaDecode(lzma_stream *s)
|
|
{
|
|
/* restore decoder state */
|
|
lzma_stream _s = *s;
|
|
|
|
#define mode _s.mode
|
|
#define last _s.last
|
|
#define last2 _s.last2
|
|
#define last3 _s.last3
|
|
|
|
#define p (*(CProb **) &_s.dynamicData)
|
|
#define dynamicDataSize _s.dynamicDataSize
|
|
|
|
#define state _s.state
|
|
#define isPreviousMatch _s.isPreviousMatch
|
|
#define previousByte _s.previousByte
|
|
#define rep0 _s.rep0
|
|
#define rep1 _s.rep1
|
|
#define rep2 _s.rep2
|
|
#define rep3 _s.rep3
|
|
#define lc _s.lc
|
|
#define len _s.len
|
|
#define totalOut _s.totalOut
|
|
|
|
#define dictionary _s.dictionary
|
|
#define dictionarySize _s.dictionarySize
|
|
#define dictionaryPos _s.dictionaryPos
|
|
|
|
#define posStateMask _s.posStateMask
|
|
#define literalPosMask _s.literalPosMask
|
|
|
|
#define avail_in _s.avail_in
|
|
#define next_in _s.next_in
|
|
#define avail_out _s.avail_out
|
|
#define next_out _s.next_out
|
|
|
|
#define range _s.range
|
|
#define code _s.code
|
|
|
|
#define probs _s.probs
|
|
#define prob _s.prob
|
|
|
|
#define symbol _s.temp2
|
|
#define bit _s.temp3
|
|
#define matchBit _s.temp1
|
|
#define i _s.temp1
|
|
#define result _s.temp2
|
|
#define numLevels _s.temp3
|
|
#define posSlot _s.temp2
|
|
#define newDictionarySize (*(UInt32*) &_s.temp3)
|
|
|
|
#define matchByte _s.matchByte
|
|
#define mi _s.mi
|
|
#define posState _s.posState
|
|
|
|
if (len == -1)
|
|
return LZMA_STREAM_END;
|
|
|
|
for (;;) switch (mode)
|
|
{
|
|
case LZMA_C_INIT:
|
|
{
|
|
lzByte firstByte;
|
|
UInt32 newDynamicDataSize;
|
|
UInt32 numProbs;
|
|
int lp;
|
|
int pb;
|
|
|
|
NEED_BYTE_;
|
|
|
|
firstByte = NEXT_BYTE;
|
|
|
|
if (firstByte > (9*5*5))
|
|
return LZMA_DATA_ERROR;
|
|
|
|
pb = firstByte / (9*5);
|
|
firstByte %= (9*5);
|
|
lp = firstByte / 9;
|
|
firstByte %= 9;
|
|
lc = firstByte;
|
|
|
|
posStateMask = (1 << (pb)) - 1;
|
|
literalPosMask = (1 << (lp)) - 1;
|
|
|
|
numProbs = Literal + (LZMA_LIT_SIZE << (lc + pb));
|
|
newDynamicDataSize = numProbs * sizeof(CProb);
|
|
|
|
if (newDynamicDataSize != dynamicDataSize)
|
|
{
|
|
if (p)
|
|
lzmafree(p);
|
|
p = lzmaalloc(newDynamicDataSize);
|
|
if (!p)
|
|
return LZMA_NOT_ENOUGH_MEM;
|
|
dynamicDataSize = newDynamicDataSize;
|
|
}
|
|
|
|
while (numProbs--)
|
|
p[numProbs] = kBitModelTotal >> 1;
|
|
|
|
for (i = 0, newDictionarySize = 0; i < 4; i++)
|
|
{
|
|
NEED_BYTE(LZMA_C_GETDICT);
|
|
newDictionarySize |= NEXT_BYTE << (i * 8);
|
|
}
|
|
|
|
if (newDictionarySize != dictionarySize)
|
|
{
|
|
dictionarySize = newDictionarySize;
|
|
if (dictionary)
|
|
lzmafree(dictionary);
|
|
dictionary = lzmaalloc(dictionarySize);
|
|
if (!dictionary)
|
|
return LZMA_NOT_ENOUGH_MEM;
|
|
}
|
|
|
|
dictionary[dictionarySize - 1] = 0;
|
|
|
|
i = 5;
|
|
while (i--)
|
|
{
|
|
NEED_BYTE(LZMA_C_RDI);
|
|
code = (code << 8) | NEXT_BYTE;
|
|
}
|
|
}
|
|
case LZMA_C_BLOCK:
|
|
posState = (int)(totalOut & posStateMask);
|
|
DECODE_BIT(LZMA_C_TYPE, p + IsMatch + (state << kNumPosBitsMax) + posState);
|
|
if (bit == 0)
|
|
{
|
|
probs = p + Literal + (LZMA_LIT_SIZE *
|
|
(((totalOut & literalPosMask) << lc) + (previousByte >> (8 - lc))));
|
|
|
|
if (state < 4) state = 0;
|
|
else if (state < 10) state -= 3;
|
|
else state -= 6;
|
|
if (isPreviousMatch)
|
|
{
|
|
UInt32 pos = dictionaryPos - rep0;
|
|
if (pos >= dictionarySize)
|
|
pos += dictionarySize;
|
|
matchByte = dictionary[pos];
|
|
{
|
|
symbol = 1;
|
|
do
|
|
{
|
|
matchBit = (matchByte >> 7) & 1;
|
|
matchByte <<= 1;
|
|
{
|
|
prob = probs + ((1 + matchBit) << 8) + symbol;
|
|
RC_GET_BIT2(LZMA_C_LITDM1, prob, symbol, bit = 0, bit = 1)
|
|
}
|
|
if (matchBit != bit)
|
|
{
|
|
while (symbol < 0x100)
|
|
{
|
|
prob = probs + symbol;
|
|
RC_GET_BIT(LZMA_C_LITDM2, prob, symbol)
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
while (symbol < 0x100);
|
|
previousByte = symbol;
|
|
}
|
|
isPreviousMatch = 0;
|
|
}
|
|
else
|
|
{
|
|
symbol = 1;
|
|
do
|
|
{
|
|
prob = probs + symbol;
|
|
RC_GET_BIT(LZMA_C_LITD, prob, symbol)
|
|
}
|
|
while (symbol < 0x100);
|
|
previousByte = symbol;
|
|
}
|
|
NEED_OUT(LZMA_C_OUTPUT_1);
|
|
PUT_BYTE(previousByte);
|
|
dictionary[dictionaryPos] = previousByte;
|
|
dictionaryPos = (dictionaryPos + 1) % dictionarySize;
|
|
}
|
|
/* bit == 1 */
|
|
else
|
|
{
|
|
isPreviousMatch = 1;
|
|
DECODE_BIT(LZMA_C_ISREP, p + IsRep + state);
|
|
if (bit == 1)
|
|
{
|
|
DECODE_BIT(LZMA_C_ISREPG0, p + IsRepG0 + state);
|
|
if (bit == 0)
|
|
{
|
|
DECODE_BIT(LZMA_C_ISREP0LONG, p + IsRep0Long + (state << kNumPosBitsMax) + posState);
|
|
if (bit == 0)
|
|
{
|
|
UInt32 pos;
|
|
if (totalOut == 0)
|
|
return LZMA_DATA_ERROR;
|
|
state = state < 7 ? 9 : 11;
|
|
NEED_OUT(LZMA_C_OUTPUT_2);
|
|
pos = dictionaryPos - rep0;
|
|
if (pos >= dictionarySize)
|
|
pos += dictionarySize;
|
|
previousByte = dictionary[pos];
|
|
dictionary[dictionaryPos] = previousByte;
|
|
dictionaryPos = (dictionaryPos + 1) % dictionarySize;
|
|
PUT_BYTE(previousByte);
|
|
mode = LZMA_C_BLOCK;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UInt32 distance;
|
|
DECODE_BIT(LZMA_C_ISREPG1, p + IsRepG1 + state);
|
|
if (bit == 0)
|
|
{
|
|
distance = rep1;
|
|
}
|
|
else
|
|
{
|
|
DECODE_BIT(LZMA_C_ISREPG2, p + IsRepG2 + state);
|
|
if (bit == 0)
|
|
distance = rep2;
|
|
else
|
|
{
|
|
distance = rep3;
|
|
rep3 = rep2;
|
|
}
|
|
rep2 = rep1;
|
|
}
|
|
rep1 = rep0;
|
|
rep0 = distance;
|
|
}
|
|
DECODE_LEN(LZMA_C_LEND_C1, p + RepLenCoder);
|
|
state = state < 7 ? 8 : 11;
|
|
}
|
|
else
|
|
{
|
|
rep3 = rep2;
|
|
rep2 = rep1;
|
|
rep1 = rep0;
|
|
state = state < 7 ? 7 : 10;
|
|
DECODE_LEN(LZMA_C_LEND_C2, p + LenCoder);
|
|
DECODE_BIT_TREE(
|
|
LZMA_C_BTD_C1,
|
|
p + PosSlot + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits),
|
|
kNumPosSlotBits
|
|
);
|
|
if (posSlot >= kStartPosModelIndex)
|
|
{
|
|
int numDirectBits = ((posSlot >> 1) - 1);
|
|
rep0 = ((2 | ((UInt32)posSlot & 1)) << numDirectBits);
|
|
if (posSlot < kEndPosModelIndex)
|
|
{
|
|
probs = p + SpecPos + rep0 - posSlot - 1;
|
|
numLevels = numDirectBits;
|
|
}
|
|
else
|
|
{
|
|
int numTotalBits = numDirectBits - kNumAlignBits;
|
|
result = 0;
|
|
for (i = numTotalBits; i > 0; i--)
|
|
{
|
|
/* UInt32 t; */
|
|
range >>= 1;
|
|
|
|
result <<= 1;
|
|
if (code >= range)
|
|
{
|
|
code -= range;
|
|
result |= 1;
|
|
}
|
|
/*
|
|
t = (code - range) >> 31;
|
|
t &= 1;
|
|
code -= range & (t - 1);
|
|
result = (result + result) | (1 - t);
|
|
*/
|
|
RC_NORMALIZE(LZMA_C_NORM)
|
|
}
|
|
rep0 += result << kNumAlignBits;
|
|
probs = p + Align;
|
|
numLevels = kNumAlignBits;
|
|
}
|
|
mi = 1;
|
|
symbol = 0;
|
|
for(i = 0; i < numLevels; i++)
|
|
{
|
|
prob = probs + mi;
|
|
RC_GET_BIT2(LZMA_C_RDRBTD, prob, mi, ; , symbol |= (1 << i));
|
|
}
|
|
rep0 += symbol;
|
|
}
|
|
else
|
|
rep0 = posSlot;
|
|
rep0++;
|
|
}
|
|
if (rep0 == (UInt32)(0))
|
|
{
|
|
len = -1;
|
|
LEAVE;
|
|
}
|
|
if (rep0 > totalOut)
|
|
{
|
|
return LZMA_DATA_ERROR;
|
|
}
|
|
len += kMatchMinLen;
|
|
totalOut += len;
|
|
do
|
|
{
|
|
UInt32 pos;
|
|
NEED_OUT(LZMA_C_OUTPUT_3);
|
|
pos = dictionaryPos - rep0;
|
|
if (pos >= dictionarySize)
|
|
pos += dictionarySize;
|
|
previousByte = dictionary[pos];
|
|
dictionary[dictionaryPos] = previousByte;
|
|
dictionaryPos = (dictionaryPos + 1) % dictionarySize;
|
|
PUT_BYTE_(previousByte);
|
|
len--;
|
|
}
|
|
while(len > 0);
|
|
}
|
|
mode = LZMA_C_BLOCK;
|
|
break;
|
|
case LZMA_C_RDBD:
|
|
_LZMA_C_RDBD:
|
|
{
|
|
UInt32 bound = (range >> kNumBitModelTotalBits) * *prob;
|
|
if (code < bound)
|
|
{
|
|
range = bound;
|
|
*prob += (kBitModelTotal - *prob) >> kNumMoveBits;
|
|
bit = 0;
|
|
}
|
|
else
|
|
{
|
|
range -= bound;
|
|
code -= bound;
|
|
*prob -= (*prob) >> kNumMoveBits;
|
|
bit = 1;
|
|
}
|
|
RC_NORMALIZE(LZMA_C_RDBD_IN);
|
|
}
|
|
mode = last;
|
|
break;
|
|
case LZMA_C_LEND:
|
|
_LZMA_C_LEND:
|
|
DECODE_BIT(LZMA_C_LEND1, probs + LenChoice);
|
|
if (bit == 0)
|
|
{
|
|
len = 0;
|
|
probs += LenLow + (posState << kLenNumLowBits);
|
|
numLevels = kLenNumLowBits;
|
|
}
|
|
else {
|
|
DECODE_BIT(LZMA_C_LEND2, probs + LenChoice2);
|
|
if (bit == 0)
|
|
{
|
|
len = kLenNumLowSymbols;
|
|
probs += + LenMid + (posState << kLenNumMidBits);
|
|
numLevels = kLenNumMidBits;
|
|
}
|
|
else
|
|
{
|
|
len = kLenNumLowSymbols + kLenNumMidSymbols;
|
|
probs += LenHigh;
|
|
numLevels = kLenNumHighBits;
|
|
}
|
|
}
|
|
|
|
last3 = LZMA_C_LEND_RES;
|
|
case LZMA_C_BTD:
|
|
_LZMA_C_BTD:
|
|
mi = 1;
|
|
for(i = numLevels; i > 0; i--)
|
|
{
|
|
prob = probs + mi;
|
|
RC_GET_BIT(LZMA_C_BTD_LOOP, prob, mi)
|
|
}
|
|
result = mi - (1 << numLevels);
|
|
mode = last3;
|
|
break;
|
|
case LZMA_C_LEND_RES:
|
|
len += result;
|
|
mode = last2;
|
|
break;
|
|
default:
|
|
return LZMA_DATA_ERROR;
|
|
}
|
|
|
|
saveStateAndReturn:
|
|
|
|
/* save decoder state */
|
|
*s = _s;
|
|
|
|
return LZMA_OK;
|
|
}
|
|
|
|
|
|
/* aCaB */
|
|
void lzmaShutdown(lzma_stream *s) {
|
|
lzma_stream _s = *s;
|
|
if (p) lzmafree(p);
|
|
if (dictionary) lzmafree(dictionary);
|
|
p = NULL;
|
|
dictionary = NULL;
|
|
*s = _s;
|
|
}
|
|
|