Files
nsis-plugin-ns7zip/versions/26.00/CPP/7zip/Compress/LzxDecoder.cpp
T
Simone d074cc7c07 chore: initial commit (extracted from Launchers monorepo)
Plugin: ns7zip v2.0.0
Architectures: x86-ansi, x86-unicode, amd64-unicode
License: LGPL-2.1-or-later
2026-04-29 14:07:51 +02:00

1518 lines
43 KiB
C++

// LzxDecoder.cpp
#include "StdAfx.h"
#include <string.h>
// #include <stdio.h>
// #define SHOW_DEBUG_INFO
#ifdef SHOW_DEBUG_INFO
#include <stdio.h>
#define PRF(x) x
#else
#define PRF(x)
#endif
#include "../../../C/Alloc.h"
#include "../../../C/RotateDefs.h"
#include "../../../C/CpuArch.h"
#include "LzxDecoder.h"
#ifdef MY_CPU_X86_OR_AMD64
#if defined(MY_CPU_AMD64) \
|| defined(__SSE2__) \
|| defined(_M_IX86_FP) && (_M_IX86_FP >= 2) \
|| 0 && defined(_MSC_VER) && (_MSC_VER >= 1400) // set (1 &&) for debug
#if defined(__clang__) && (__clang_major__ >= 2) \
|| defined(__GNUC__) && (__GNUC__ >= 4) \
|| defined(_MSC_VER) && (_MSC_VER >= 1400)
#define Z7_LZX_X86_FILTER_USE_SSE2
#endif
#endif
#endif
#ifdef Z7_LZX_X86_FILTER_USE_SSE2
// #ifdef MY_CPU_X86_OR_AMD64
#include <emmintrin.h> // SSE2
// #endif
#if defined(__clang__) || defined(__GNUC__)
typedef int ctz_type;
#define MY_CTZ(dest, mask) dest = __builtin_ctz((UInt32)(mask))
#else // #if defined(_MSC_VER)
#if (_MSC_VER >= 1600)
// #include <intrin.h>
#endif
typedef unsigned long ctz_type;
#define MY_CTZ(dest, mask) _BitScanForward(&dest, (mask));
#endif // _MSC_VER
#endif
// when window buffer is filled, we must wrap position to zero,
// and we want to wrap at same points where original-lzx must wrap.
// But the wrapping is possible in point where chunk is finished.
// Usually (chunk_size == 32KB), but (chunk_size != 32KB) also is allowed.
// So we don't use additional buffer space over required (winSize).
// And we can't use large overwrite after (len) in CopyLzMatch().
// But we are allowed to write 3 bytes after (len), because
// (delta <= _winSize - 3).
// #define k_Lz_OverwriteSize 0 // for debug : to disable overwrite
#define k_Lz_OverwriteSize 3 // = kNumReps
#if k_Lz_OverwriteSize > 0
// (k_Lz_OutBufSize_Add >= k_Lz_OverwriteSize) is required
// we use value 4 to simplify memset() code.
#define k_Lz_OutBufSize_Add (k_Lz_OverwriteSize + 1) // == 4
#else
#define k_Lz_OutBufSize_Add 0
#endif
// (len != 0)
// (0 < delta <= _winSize - 3)
Z7_FORCE_INLINE
void CopyLzMatch(Byte *dest, const Byte *src, UInt32 len, UInt32 delta)
{
if (delta >= 4)
{
#if k_Lz_OverwriteSize >= 3
// optimized code with overwrite to reduce the number of branches
#ifdef MY_CPU_LE_UNALIGN
*(UInt32 *)(void *)(dest) = *(const UInt32 *)(const void *)(src);
#else
dest[0] = src[0];
dest[1] = src[1];
dest[2] = src[2];
dest[3] = src[3];
#endif
len--;
src++;
dest++;
{
#else
// no overwrite in out buffer
dest[0] = src[0];
{
const unsigned m = (unsigned)len & 1;
src += m;
dest += m;
}
if (len &= ~(unsigned)1)
{
dest[0] = src[0];
dest[1] = src[1];
#endif
// len == 0 is allowed here
{
const unsigned m = (unsigned)len & 3;
src += m;
dest += m;
}
if (len &= ~(unsigned)3)
{
#ifdef MY_CPU_LE_UNALIGN
#if 1
*(UInt32 *)(void *)(dest) = *(const UInt32 *)(const void *)(src);
{
const unsigned m = (unsigned)len & 7;
dest += m;
src += m;
}
if (len &= ~(unsigned)7)
do
{
*(UInt32 *)(void *)(dest ) = *(const UInt32 *)(const void *)(src);
*(UInt32 *)(void *)(dest + 4) = *(const UInt32 *)(const void *)(src + 4);
src += 8;
dest += 8;
}
while (len -= 8);
#else
// gcc-11 -O3 for x64 generates incorrect code here
do
{
*(UInt32 *)(void *)(dest) = *(const UInt32 *)(const void *)(src);
src += 4;
dest += 4;
}
while (len -= 4);
#endif
#else
do
{
const Byte b0 = src[0];
const Byte b1 = src[1];
dest[0] = b0;
dest[1] = b1;
const Byte b2 = src[2];
const Byte b3 = src[3];
dest[2] = b2;
dest[3] = b3;
src += 4;
dest += 4;
}
while (len -= 4);
#endif
}
}
}
else // (delta < 4)
{
const unsigned b0 = *src;
*dest = (Byte)b0;
if (len >= 2)
{
if (delta < 2)
{
dest += (unsigned)len & 1;
dest[0] = (Byte)b0;
dest[1] = (Byte)b0;
dest += (unsigned)len & 2;
if (len &= ~(unsigned)3)
{
#ifdef MY_CPU_LE_UNALIGN
#ifdef MY_CPU_64BIT
const UInt64 a = (UInt64)b0 * 0x101010101010101;
*(UInt32 *)(void *)dest = (UInt32)a;
dest += (unsigned)len & 7;
if (len &= ~(unsigned)7)
{
// *(UInt64 *)(void *)dest = a;
// dest += 8;
// len -= 8;
// if (len)
{
// const ptrdiff_t delta = (ptrdiff_t)dest & 7;
// dest -= delta;
do
{
*(UInt64 *)(void *)dest = a;
dest += 8;
}
while (len -= 8);
// dest += delta - 8;
// *(UInt64 *)(void *)dest = a;
}
}
#else
const UInt32 a = (UInt32)b0 * 0x1010101;
do
{
*(UInt32 *)(void *)dest = a;
dest += 4;
}
while (len -= 4);
#endif
#else
do
{
dest[0] = (Byte)b0;
dest[1] = (Byte)b0;
dest[2] = (Byte)b0;
dest[3] = (Byte)b0;
dest += 4;
}
while (len -= 4);
#endif
}
}
else if (delta == 2)
{
const unsigned m = (unsigned)len & 1;
len &= ~(unsigned)1;
src += m;
dest += m;
{
const Byte a0 = src[0];
const Byte a1 = src[1];
do
{
dest[0] = a0;
dest[1] = a1;
dest += 2;
}
while (len -= 2);
}
}
else /* if (delta == 3) */
{
const unsigned b1 = src[1];
dest[1] = (Byte)b1;
if (len -= 2)
{
const unsigned b2 = src[2];
dest += 2;
do
{
dest[0] = (Byte)b2; if (--len == 0) break;
dest[1] = (Byte)b0; if (--len == 0) break;
dest[2] = (Byte)b1;
dest += 3;
}
while (--len);
}
}
}
}
}
// #define Z7_LZX_SHOW_STAT
#ifdef Z7_LZX_SHOW_STAT
#include <stdio.h>
#endif
namespace NCompress {
namespace NLzx {
// #define Z7_LZX_SHOW_STAT
#ifdef Z7_LZX_SHOW_STAT
static UInt32 g_stats_Num_x86[3];
static UInt32 g_stats_NumTables;
static UInt32 g_stats_NumLits;
static UInt32 g_stats_NumAlign;
static UInt32 g_stats_main[kMainTableSize];
static UInt32 g_stats_len[kNumLenSymbols];
static UInt32 g_stats_main_levels[kNumHuffmanBits + 1];
static UInt32 g_stats_len_levels[kNumHuffmanBits + 1];
#define UPDATE_STAT(a) a
static void PrintVal(UInt32 v)
{
printf("\n : %9u", v);
}
static void PrintStat(const char *name, const UInt32 *a, size_t num)
{
printf("\n\n==== %s:", name);
UInt32 sum = 0;
size_t i;
for (i = 0; i < num; i++)
sum += a[i];
PrintVal(sum);
if (sum != 0)
{
for (i = 0; i < num; i++)
{
if (i % 8 == 0)
printf("\n");
printf("\n%3x : %9u : %5.2f", (unsigned)i, (unsigned)a[i], (double)a[i] * 100 / sum);
}
}
printf("\n");
}
static struct CStat
{
~CStat()
{
PrintStat("x86_filter", g_stats_Num_x86, Z7_ARRAY_SIZE(g_stats_Num_x86));
printf("\nTables:"); PrintVal(g_stats_NumTables);
printf("\nLits:"); PrintVal(g_stats_NumLits);
printf("\nAlign:"); PrintVal(g_stats_NumAlign);
PrintStat("Main", g_stats_main, Z7_ARRAY_SIZE(g_stats_main));
PrintStat("Len", g_stats_len, Z7_ARRAY_SIZE(g_stats_len));
PrintStat("Main Levels", g_stats_main_levels, Z7_ARRAY_SIZE(g_stats_main_levels));
PrintStat("Len Levels", g_stats_len_levels, Z7_ARRAY_SIZE(g_stats_len_levels));
}
} g_stat;
#else
#define UPDATE_STAT(a)
#endif
/*
3 p015 : ivb- : or r32,r32 / add r32,r32
4 p0156 : hsw+
5 p0156b: adl+
2 p0_5 : ivb- : shl r32,i8
2 p0__6 : hsw+
1 p5 : ivb- : jb
2 p0__6 : hsw+
2 p0_5 : wsm- : SSE2 : pcmpeqb : _mm_cmpeq_epi8
2 p_15 : snb-bdw
2 p01 : skl+
1 p0 : SSE2 : pmovmskb : _mm_movemask_epi8
*/
/*
v24.00: the code was fixed for more compatibility with original-ms-cab-decoder.
for ((Int32)translationSize >= 0) : LZX specification shows the code with signed Int32.
for ((Int32)translationSize < 0) : no specification for that case, but we support that case.
We suppose our code now is compatible with original-ms-cab-decoder.
Starting byte of data stream (real_pos == 0) is special corner case,
where we don't need any conversion (as in original-ms-cab-decoder).
Our optimization: we use unsigned (UInt32 pos) (pos = -1 - real_pos).
So (pos) is always negative: ((Int32)pos < 0).
It allows us to use simple comparison (v > pos) instead of more complex comparisons.
*/
// (p) will point 5 bytes after 0xe8 byte:
// pos == -1 - (p - 5 - data_start) == 4 + data_start - p
// (FILTER_PROCESSED_SIZE_DELTA == 4) is optimized value for better speed in some compilers:
#define FILTER_PROCESSED_SIZE_DELTA 4
#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_OR_ARM64)
// optimized branch:
// size_t must be at least 32-bit for this branch.
#if 1 // use 1 for simpler code
// use integer (low 32 bits of pointer) instead of pointer
#define X86_FILTER_PREPARE processedSize4 = (UInt32)(size_t)(ptrdiff_t)data + \
(UInt32)(4 - FILTER_PROCESSED_SIZE_DELTA) - processedSize4;
#define X86_FILTER_CALC_pos(p) const UInt32 pos = processedSize4 - (UInt32)(size_t)(ptrdiff_t)p;
#else
// note: (dataStart) pointer can point out of array ranges:
#define X86_FILTER_PREPARE const Byte *dataStart = data + \
(4 - FILTER_PROCESSED_SIZE_DELTA) - processedSize4;
#define X86_FILTER_CALC_pos(p) const UInt32 pos = (UInt32)(size_t)(dataStart - p);
#endif
#else
// non-optimized branch for unusual platforms (16-bit size_t or unusual size_t):
#define X86_FILTER_PREPARE processedSize4 = \
(UInt32)(4 - FILTER_PROCESSED_SIZE_DELTA) - processedSize4;
#define X86_FILTER_CALC_pos(p) const UInt32 pos = processedSize4 - (UInt32)(size_t)(p - data);
#endif
#define X86_TRANSLATE_PRE(p) \
UInt32 v = GetUi32((p) - 4);
#define X86_TRANSLATE_POST(p) \
{ \
X86_FILTER_CALC_pos(p) \
if (v < translationSize) { \
UPDATE_STAT(g_stats_Num_x86[0]++;) \
v += pos + 1; \
SetUi32((p) - 4, v) \
} \
else if (v > pos) { \
UPDATE_STAT(g_stats_Num_x86[1]++;) \
v += translationSize; \
SetUi32((p) - 4, v) \
} else { UPDATE_STAT(g_stats_Num_x86[2]++;) } \
}
/*
if ( defined(Z7_LZX_X86_FILTER_USE_SSE2)
&& defined(Z7_LZX_X86_FILTER_USE_SSE2_ALIGNED))
the function can read up to aligned_for_32_up_from(size) bytes in (data).
*/
// processedSize < (1 << 30)
Z7_NO_INLINE
static void x86_Filter4(Byte *data, size_t size, UInt32 processedSize4, UInt32 translationSize)
{
const size_t kResidue = 10;
if (size <= kResidue)
return;
Byte * const lim = data + size - kResidue + 4;
const Byte save = lim[0];
lim[0] = 0xe8;
X86_FILTER_PREPARE
Byte *p = data;
#define FILTER_RETURN_IF_LIM(_p_) if (_p_ > lim) { lim[0] = save; return; }
#ifdef Z7_LZX_X86_FILTER_USE_SSE2
// sse2-aligned/sse2-unaligned provide same speed on real data.
// but the code is smaller for sse2-unaligned version.
// for debug : define it to get alternative version with aligned 128-bit reads:
// #define Z7_LZX_X86_FILTER_USE_SSE2_ALIGNED
#define FILTER_MASK_INT UInt32
#define FILTER_NUM_VECTORS_IN_CHUNK 2
#define FILTER_CHUNK_BYTES_OFFSET (16 * FILTER_NUM_VECTORS_IN_CHUNK - 5)
#ifdef Z7_LZX_X86_FILTER_USE_SSE2_ALIGNED
// aligned version doesn't uses additional space if buf size is aligned for 32
#define k_Filter_OutBufSize_Add 0
#define k_Filter_OutBufSize_AlignMask (16 * FILTER_NUM_VECTORS_IN_CHUNK - 1)
#define FILTER_LOAD_128(p) _mm_load_si128 ((const __m128i *)(const void *)(p))
#else
#define k_Filter_OutBufSize_Add (16 * FILTER_NUM_VECTORS_IN_CHUNK)
#define k_Filter_OutBufSize_AlignMask 0
#define FILTER_LOAD_128(p) _mm_loadu_si128((const __m128i *)(const void *)(p))
#endif
#define GET_E8_MASK(dest, dest1, p) \
{ \
__m128i v0 = FILTER_LOAD_128(p); \
__m128i v1 = FILTER_LOAD_128(p + 16); \
p += 16 * FILTER_NUM_VECTORS_IN_CHUNK; \
v0 = _mm_cmpeq_epi8(v0, k_e8_Vector); \
v1 = _mm_cmpeq_epi8(v1, k_e8_Vector); \
dest = (unsigned)_mm_movemask_epi8(v0); \
dest1 = (unsigned)_mm_movemask_epi8(v1); \
}
const __m128i k_e8_Vector = _mm_set1_epi32((Int32)(UInt32)0xe8e8e8e8);
for (;;)
{
// for debug: define it for smaller code:
// #define Z7_LZX_X86_FILTER_CALC_IN_LOOP
// without Z7_LZX_X86_FILTER_CALC_IN_LOOP, we can get faster and simpler loop
FILTER_MASK_INT mask;
{
FILTER_MASK_INT mask1;
do
{
GET_E8_MASK(mask, mask1, p)
#ifndef Z7_LZX_X86_FILTER_CALC_IN_LOOP
mask += mask1;
#else
mask |= mask1 << 16;
#endif
}
while (!mask);
#ifndef Z7_LZX_X86_FILTER_CALC_IN_LOOP
mask -= mask1;
mask |= mask1 << 16;
#endif
}
#ifdef Z7_LZX_X86_FILTER_USE_SSE2_ALIGNED
for (;;)
{
ctz_type index;
typedef
#ifdef MY_CPU_64BIT
UInt64
#else
UInt32
#endif
SUPER_MASK_INT;
SUPER_MASK_INT superMask;
{
MY_CTZ(index, mask);
Byte *p2 = p - FILTER_CHUNK_BYTES_OFFSET + (unsigned)index;
X86_TRANSLATE_PRE(p2)
superMask = ~(SUPER_MASK_INT)0x1f << index;
FILTER_RETURN_IF_LIM(p2)
X86_TRANSLATE_POST(p2)
mask &= (UInt32)superMask;
}
if (mask)
continue;
if (index <= FILTER_CHUNK_BYTES_OFFSET)
break;
{
FILTER_MASK_INT mask1;
GET_E8_MASK(mask, mask1, p)
mask &=
#ifdef MY_CPU_64BIT
(UInt32)(superMask >> 32);
#else
((FILTER_MASK_INT)0 - 1) << ((int)index - FILTER_CHUNK_BYTES_OFFSET);
#endif
mask |= mask1 << 16;
}
if (!mask)
break;
}
#else // ! Z7_LZX_X86_FILTER_USE_SSE2_ALIGNED
{
// we use simplest version without loop:
// for (;;)
{
ctz_type index;
MY_CTZ(index, mask);
/*
printf("\np=%p, mask=%8x, index = %2d, p + index = %x\n",
(p - 16 * FILTER_NUM_VECTORS_IN_CHUNK), (unsigned)mask,
(unsigned)index, (unsigned)((unsigned)(ptrdiff_t)(p - 16 * FILTER_NUM_VECTORS_IN_CHUNK) + index));
*/
p += (size_t)(unsigned)index - FILTER_CHUNK_BYTES_OFFSET;
FILTER_RETURN_IF_LIM(p)
// mask &= ~(FILTER_MASK_INT)0x1f << index; mask >>= index;
X86_TRANSLATE_PRE(p)
X86_TRANSLATE_POST(p)
// if (!mask) break; // p += 16 * FILTER_NUM_VECTORS_IN_CHUNK;
}
}
#endif // ! Z7_LZX_X86_FILTER_USE_SSE2_ALIGNED
}
#else // ! Z7_LZX_X86_FILTER_USE_SSE2
#define k_Filter_OutBufSize_Add 0
#define k_Filter_OutBufSize_AlignMask 0
for (;;)
{
for (;;)
{
if (p[0] == 0xe8) { p += 5; break; }
if (p[1] == 0xe8) { p += 6; break; }
if (p[2] == 0xe8) { p += 7; break; }
p += 4;
if (p[-1] == 0xe8) { p += 4; break; }
}
FILTER_RETURN_IF_LIM(p)
X86_TRANSLATE_PRE(p)
X86_TRANSLATE_POST(p)
}
#endif // ! Z7_LZX_X86_FILTER_USE_SSE2
}
CDecoder::CDecoder() throw():
_win(NULL),
_isUncompressedBlock(false),
_skipByte(false),
_keepHistory(false),
_keepHistoryForNext(true),
_needAlloc(true),
_wimMode(false),
_numDictBits(15),
_unpackBlockSize(0),
_x86_translationSize(0),
_x86_buf(NULL),
_unpackedData(NULL)
{
{
// it's better to get empty virtual entries, if mispredicted value can be used:
memset(_reps, 0, kPosSlotOffset * sizeof(_reps[0]));
memset(_extra, 0, kPosSlotOffset);
#define SET_NUM_BITS(i) i // #define NUM_BITS_DELTA 31
_extra[kPosSlotOffset + 0] = SET_NUM_BITS(0);
_extra[kPosSlotOffset + 1] = SET_NUM_BITS(0);
// reps[0] = 0 - (kNumReps - 1);
// reps[1] = 1 - (kNumReps - 1);
UInt32 a = 2 - (kNumReps - 1);
UInt32 delta = 1;
unsigned i;
for (i = 0; i < kNumLinearPosSlotBits; i++)
{
_extra[(size_t)i * 2 + 2 + kPosSlotOffset] = (Byte)(SET_NUM_BITS(i));
_extra[(size_t)i * 2 + 3 + kPosSlotOffset] = (Byte)(SET_NUM_BITS(i));
_reps [(size_t)i * 2 + 2 + kPosSlotOffset] = a; a += delta;
_reps [(size_t)i * 2 + 3 + kPosSlotOffset] = a; a += delta;
delta += delta;
}
for (i = kNumLinearPosSlotBits * 2 + 2; i < kNumPosSlots; i++)
{
_extra[(size_t)i + kPosSlotOffset] = SET_NUM_BITS(kNumLinearPosSlotBits);
_reps [(size_t)i + kPosSlotOffset] = a;
a += (UInt32)1 << kNumLinearPosSlotBits;
}
}
}
CDecoder::~CDecoder() throw()
{
if (_needAlloc)
// BigFree
z7_AlignedFree
(_win);
z7_AlignedFree(_x86_buf);
}
HRESULT CDecoder::Flush() throw()
{
// UInt32 t = _x86_processedSize; for (int y = 0; y < 50; y++) { _x86_processedSize = t; // benchmark: (branch predicted)
if (_x86_translationSize != 0)
{
Byte *destData = _win + _writePos;
const UInt32 curSize = _pos - _writePos;
if (_keepHistoryForNext)
{
const size_t kChunkSize = (size_t)1 << 15;
if (curSize > kChunkSize)
return E_NOTIMPL;
if (!_x86_buf)
{
// (kChunkSize % 32 == 0) is required in some cases, because
// the filter can read data by 32-bytes chunks in some cases.
// if (chunk_size > (1 << 15)) is possible, then we must the code:
const size_t kAllocSize = kChunkSize + k_Filter_OutBufSize_Add;
_x86_buf = (Byte *)z7_AlignedAlloc(kAllocSize);
if (!_x86_buf)
return E_OUTOFMEMORY;
#if 0 != k_Filter_OutBufSize_Add || \
0 != k_Filter_OutBufSize_AlignMask
// x86_Filter4() can read after curSize.
// So we set all data to zero to prevent reading of uninitialized data:
memset(_x86_buf, 0, kAllocSize); // optional
#endif
}
// for (int yy = 0; yy < 1; yy++) // for debug
memcpy(_x86_buf, destData, curSize);
_unpackedData = _x86_buf;
destData = _x86_buf;
}
else
{
// x86_Filter4() can overread after (curSize),
// so we can do memset() after (curSize):
// k_Filter_OutBufSize_AlignMask also can be used
// if (!_overDict) memset(destData + curSize, 0, k_Filter_OutBufSize_Add);
}
x86_Filter4(destData, curSize, _x86_processedSize - FILTER_PROCESSED_SIZE_DELTA, _x86_translationSize);
_x86_processedSize += (UInt32)curSize;
if (_x86_processedSize >= ((UInt32)1 << 30))
_x86_translationSize = 0;
}
// }
return S_OK;
}
// (NUM_DELTA_BYTES == 2) reduces the code in main loop.
#if 1
#define NUM_DELTA_BYTES 2
#else
#define NUM_DELTA_BYTES 0
#endif
#define NUM_DELTA_BIT_OFFSET_BITS (NUM_DELTA_BYTES * 8)
#if NUM_DELTA_BIT_OFFSET_BITS > 0
#define DECODE_ERROR_CODE 0
#define IS_OVERFLOW_bitOffset(bo) ((bo) >= 0)
// ( >= 0) comparison after bitOffset change gives simpler commands than ( > 0) comparison
#else
#define DECODE_ERROR_CODE 1
#define IS_OVERFLOW_bitOffset(bo) ((bo) > 0)
#endif
// (numBits != 0)
#define GET_VAL_BASE(numBits) (_value >> (32 - (numBits)))
#define Z7_LZX_HUFF_DECODE( sym, huff, kNumTableBits, move_pos_op, check_op, error_op) \
Z7_HUFF_DECODE_VAL_IN_HIGH32(sym, huff, kNumHuffmanBits, kNumTableBits, \
_value, check_op, error_op, move_pos_op, NORMALIZE, bs)
#define Z7_LZX_HUFF_DECODE_CHECK_YES(sym, huff, kNumTableBits, move_pos_op) \
Z7_LZX_HUFF_DECODE( sym, huff, kNumTableBits, move_pos_op, \
Z7_HUFF_DECODE_ERROR_SYM_CHECK_YES, { return DECODE_ERROR_CODE; })
#define Z7_LZX_HUFF_DECODE_CHECK_NO( sym, huff, kNumTableBits, move_pos_op) \
Z7_LZX_HUFF_DECODE( sym, huff, kNumTableBits, move_pos_op, \
Z7_HUFF_DECODE_ERROR_SYM_CHECK_NO, {})
#define NORMALIZE \
{ \
const Byte *ptr = _buf + (_bitOffset >> 4) * 2; \
/* _value = (((UInt32)GetUi16(ptr) << 16) | GetUi16(ptr + 2)) << (_bitOffset & 15); */ \
const UInt32 v = GetUi32(ptr); \
_value = rotlFixed (v, ((int)_bitOffset & 15) + 16); \
}
#define MOVE_POS(bs, numBits) \
{ \
_bitOffset += numBits; \
}
#define MOVE_POS_STAT(bs, numBits) \
{ \
UPDATE_STAT(g_stats_len_levels[numBits]++;) \
MOVE_POS(bs, numBits); \
}
#define MOVE_POS_CHECK(bs, numBits) \
{ \
if (IS_OVERFLOW_bitOffset(_bitOffset += numBits)) return DECODE_ERROR_CODE; \
}
#define MOVE_POS_CHECK_STAT(bs, numBits) \
{ \
UPDATE_STAT(g_stats_main_levels[numBits]++;) \
MOVE_POS_CHECK(bs, numBits) \
}
// (numBits == 0) is supported
#ifdef Z7_HUFF_USE_64BIT_LIMIT
#define MACRO_ReadBitsBig_pre(numBits) \
{ \
_bitOffset += (numBits); \
_value >>= 32 - (numBits); \
}
#else
#define MACRO_ReadBitsBig_pre(numBits) \
{ \
_bitOffset += (numBits); \
_value = (UInt32)((UInt32)_value >> 1 >> (31 ^ (numBits))); \
}
#endif
#define MACRO_ReadBitsBig_add(dest) \
{ dest += (UInt32)_value; }
#define MACRO_ReadBitsBig_add3(dest) \
{ dest += (UInt32)(_value) << 3; }
// (numBits != 0)
#define MACRO_ReadBits_NonZero(val, numBits) \
{ \
val = (UInt32)(_value >> (32 - (numBits))); \
MOVE_POS(bs, numBits); \
NORMALIZE \
}
struct CBitDecoder
{
ptrdiff_t _bitOffset;
const Byte *_buf;
Z7_FORCE_INLINE
UInt32 GetVal() const
{
const Byte *ptr = _buf + (_bitOffset >> 4) * 2;
const UInt32 v = GetUi32(ptr);
return rotlFixed (v, ((int)_bitOffset & 15) + 16);
}
Z7_FORCE_INLINE
bool IsOverRead() const
{
return _bitOffset > (int)(0 - NUM_DELTA_BIT_OFFSET_BITS);
}
Z7_FORCE_INLINE
bool WasBitStreamFinishedOK() const
{
// we check that all 0-15 unused bits are zeros:
if (_bitOffset == 0 - NUM_DELTA_BIT_OFFSET_BITS)
return true;
if ((_bitOffset + NUM_DELTA_BIT_OFFSET_BITS + 15) & ~(ptrdiff_t)15)
return false;
const Byte *ptr = _buf - NUM_DELTA_BYTES - 2;
if ((UInt16)(GetUi16(ptr) << (_bitOffset & 15)))
return false;
return true;
}
// (numBits != 0)
Z7_FORCE_INLINE
UInt32 ReadBits_NonZero(unsigned numBits) throw()
{
const UInt32 val = GetVal() >> (32 - numBits);
_bitOffset += numBits;
return val;
}
};
class CBitByteDecoder: public CBitDecoder
{
size_t _size;
public:
Z7_FORCE_INLINE
void Init_ByteMode(const Byte *data, size_t size)
{
_buf = data;
_size = size;
}
Z7_FORCE_INLINE
void Init_BitMode(const Byte *data, size_t size)
{
_size = size & 1;
size &= ~(size_t)1;
_buf = data + size + NUM_DELTA_BYTES;
_bitOffset = 0 - (ptrdiff_t)(size * 8) - NUM_DELTA_BIT_OFFSET_BITS;
}
Z7_FORCE_INLINE
void Switch_To_BitMode()
{
Init_BitMode(_buf, _size);
}
Z7_FORCE_INLINE
bool Switch_To_ByteMode()
{
/* here we check that unused bits in high 16-bits word are zeros.
If high word is full (all 16-bits are unused),
we check that all 16-bits are zeros.
So we check and skip (1-16 bits) unused bits */
if ((GetVal() >> (16 + (_bitOffset & 15))) != 0)
return false;
_bitOffset += 16;
_bitOffset &= ~(ptrdiff_t)15;
if (_bitOffset > 0 - NUM_DELTA_BIT_OFFSET_BITS)
return false;
const ptrdiff_t delta = _bitOffset >> 3;
_size = (size_t)((ptrdiff_t)(_size) - delta - NUM_DELTA_BYTES);
_buf += delta;
// _bitOffset = 0; // optional
return true;
}
Z7_FORCE_INLINE
size_t GetRem() const { return _size; }
Z7_FORCE_INLINE
UInt32 ReadUInt32()
{
const Byte *ptr = _buf;
const UInt32 v = GetUi32(ptr);
_buf += 4;
_size -= 4;
return v;
}
Z7_FORCE_INLINE
void CopyTo(Byte *dest, size_t size)
{
memcpy(dest, _buf, size);
_buf += size;
_size -= size;
}
Z7_FORCE_INLINE
bool IsOneDirectByteLeft() const
{
return GetRem() == 1;
}
Z7_FORCE_INLINE
Byte DirectReadByte()
{
_size--;
return *_buf++;
}
};
// numBits != 0
// Z7_FORCE_INLINE
Z7_NO_INLINE
static
UInt32 ReadBits(CBitDecoder &_bitStream, unsigned numBits)
{
return _bitStream.ReadBits_NonZero(numBits);
}
#define RIF(x) { if (!(x)) return false; }
/*
MSVC compiler adds extra move operation,
if we access array with 32-bit index
array[calc_index_32_bit(32-bit_var)]
where calc_index_32_bit operations are: ((unsigned)a>>cnt), &, ^, |
clang is also affected for ((unsigned)a>>cnt) in byte array.
*/
// it can overread input buffer for 7-17 bytes.
// (levels != levelsEnd)
Z7_NO_INLINE
static ptrdiff_t ReadTable(ptrdiff_t _bitOffset, const Byte *_buf, Byte *levels, const Byte *levelsEnd)
{
const unsigned kNumTableBits_Level = 7;
NHuffman::CDecoder256<kNumHuffmanBits, kLevelTableSize, kNumTableBits_Level> _levelDecoder;
NHuffman::CValueInt _value;
// optional check to reduce size of overread zone:
if (_bitOffset > (int)0 - (int)NUM_DELTA_BIT_OFFSET_BITS - (int)(kLevelTableSize * kNumLevelBits))
return DECODE_ERROR_CODE;
NORMALIZE
{
Byte levels2[kLevelTableSize / 4 * 4];
for (size_t i = 0; i < kLevelTableSize / 4 * 4; i += 4)
{
UInt32 val;
MACRO_ReadBits_NonZero(val, kNumLevelBits * 4)
levels2[i + 0] = (Byte)((val >> (3 * kNumLevelBits)));
levels2[i + 1] = (Byte)((val >> (2 * kNumLevelBits)) & ((1u << kNumLevelBits) - 1));
levels2[i + 2] = (Byte)((Byte)val >> (1 * kNumLevelBits));
levels2[i + 3] = (Byte)((val) & ((1u << kNumLevelBits) - 1));
}
RIF(_levelDecoder.Build(levels2, NHuffman::k_BuildMode_Full))
}
do
{
unsigned sym;
Z7_LZX_HUFF_DECODE_CHECK_NO(sym, &_levelDecoder, kNumTableBits_Level, MOVE_POS_CHECK)
// Z7_HUFF_DECODE_CHECK(sym, &_levelDecoder, kNumHuffmanBits, kNumTableBits_Level, &bitStream, return false)
// sym = _levelDecoder.Decode(&bitStream);
// if (!_levelDecoder.Decode_SymCheck_MovePosCheck(&bitStream, sym)) return false;
if (sym <= kNumHuffmanBits)
{
int delta = (int)*levels - (int)sym;
delta += delta < 0 ? kNumHuffmanBits + 1 : 0;
*levels++ = (Byte)delta;
continue;
}
unsigned num;
int symbol;
if (sym < kLevelSym_Same)
{
// sym -= kLevelSym_Zero1;
MACRO_ReadBits_NonZero(num, kLevelSym_Zero1_NumBits + (sym - kLevelSym_Zero1))
num += (sym << kLevelSym_Zero1_NumBits) - (kLevelSym_Zero1 << kLevelSym_Zero1_NumBits) + kLevelSym_Zero1_Start;
symbol = 0;
}
// else if (sym != kLevelSym_Same) return DECODE_ERROR_CODE;
else // (sym == kLevelSym_Same)
{
MACRO_ReadBits_NonZero(num, kLevelSym_Same_NumBits)
num += kLevelSym_Same_Start;
// + (unsigned)bitStream.ReadBitsSmall(kLevelSym_Same_NumBits);
// Z7_HUFF_DECODE_CHECK(sym, &_levelDecoder, kNumHuffmanBits, kNumTableBits_Level, &bitStream, return DECODE_ERROR_CODE)
// if (!_levelDecoder.Decode2(&bitStream, sym)) return DECODE_ERROR_CODE;
// sym = _levelDecoder.Decode(&bitStream);
Z7_LZX_HUFF_DECODE_CHECK_NO(sym, &_levelDecoder, kNumTableBits_Level, MOVE_POS)
if (sym > kNumHuffmanBits) return DECODE_ERROR_CODE;
symbol = *levels - (int)sym;
symbol += symbol < 0 ? kNumHuffmanBits + 1 : 0;
}
if (num > (size_t)(levelsEnd - levels))
return false;
const Byte *limit = levels + num;
do
*levels++ = (Byte)symbol;
while (levels != limit);
}
while (levels != levelsEnd);
return _bitOffset;
}
static const unsigned kPosSlotDelta = 256 / kNumLenSlots - kPosSlotOffset;
#define READ_TABLE(_bitStream, levels, levelsEnd) \
{ \
_bitStream._bitOffset = ReadTable(_bitStream._bitOffset, _bitStream._buf, levels, levelsEnd); \
if (_bitStream.IsOverRead()) return false; \
}
// can over-read input buffer for less than 32 bytes
bool CDecoder::ReadTables(CBitByteDecoder &_bitStream) throw()
{
UPDATE_STAT(g_stats_NumTables++;)
{
const unsigned blockType = (unsigned)ReadBits(_bitStream, kBlockType_NumBits);
// if (blockType > kBlockType_Uncompressed || blockType == 0)
if ((unsigned)(blockType - 1) > kBlockType_Uncompressed - 1)
return false;
_unpackBlockSize = 1u << 15;
if (!_wimMode || ReadBits(_bitStream, 1) == 0)
{
_unpackBlockSize = ReadBits(_bitStream, 16);
// wimlib supports chunks larger than 32KB (unsupported my MS wim).
if (!_wimMode || _numDictBits >= 16)
{
_unpackBlockSize <<= 8;
_unpackBlockSize |= ReadBits(_bitStream, 8);
}
}
PRF(printf("\nBlockSize = %6d %s ", _unpackBlockSize, (_pos & 1) ? "@@@" : " "));
_isUncompressedBlock = (blockType == kBlockType_Uncompressed);
_skipByte = false;
if (_isUncompressedBlock)
{
_skipByte = ((_unpackBlockSize & 1) != 0);
// printf("\n UncompressedBlock %d", _unpackBlockSize);
PRF(printf(" UncompressedBlock ");)
// if (_unpackBlockSize & 1) { PRF(printf(" ######### ")); }
if (!_bitStream.Switch_To_ByteMode())
return false;
if (_bitStream.GetRem() < kNumReps * 4)
return false;
for (unsigned i = 0; i < kNumReps; i++)
{
const UInt32 rep = _bitStream.ReadUInt32();
// here we allow only such values for (rep) that can be set also by LZ code:
if (rep == 0 || rep > _winSize - kNumReps)
return false;
_reps[(size_t)i + kPosSlotOffset] = rep;
}
// printf("\n");
return true;
}
// _numAlignBits = 64;
// const UInt32 k_numAlignBits_PosSlots_MAX = 64 + kPosSlotDelta;
// _numAlignBits_PosSlots = k_numAlignBits_PosSlots_MAX;
const UInt32 k_numAlignBits_Dist_MAX = (UInt32)(Int32)-1;
_numAlignBits_Dist = k_numAlignBits_Dist_MAX;
if (blockType == kBlockType_Aligned)
{
Byte levels[kAlignTableSize];
// unsigned not0 = 0;
unsigned not3 = 0;
for (unsigned i = 0; i < kAlignTableSize; i++)
{
const unsigned val = ReadBits(_bitStream, kNumAlignLevelBits);
levels[i] = (Byte)val;
// not0 |= val;
not3 |= (val ^ 3);
}
// static unsigned number = 0, all = 0; all++;
// if (!not0) return false; // Build(true) will test this case
if (not3)
{
// _numAlignBits_PosSlots = (kNumAlignBits + 1) * 2 + kPosSlotDelta;
// _numAlignBits = kNumAlignBits;
_numAlignBits_Dist = (1u << (kNumAlignBits + 1)) - (kNumReps - 1);
RIF(_alignDecoder.Build(levels, true)) // full
}
// else { number++; if (number % 4 == 0) printf("\nnumber= %u : %u%%", number, number * 100 / all); }
}
// if (_numAlignBits_PosSlots == k_numAlignBits_PosSlots_MAX)
if (_numAlignBits_Dist == k_numAlignBits_Dist_MAX)
{
size_t i;
for (i = 3; i < kNumLinearPosSlotBits; i++)
{
_extra[i * 2 + 2 + kPosSlotOffset] = (Byte)(SET_NUM_BITS(i));
_extra[i * 2 + 3 + kPosSlotOffset] = (Byte)(SET_NUM_BITS(i));
}
for (i = kNumLinearPosSlotBits * 2 + 2; i < kNumPosSlots; i++)
_extra[i + kPosSlotOffset] = (Byte)SET_NUM_BITS(kNumLinearPosSlotBits);
}
else
{
size_t i;
for (i = 3; i < kNumLinearPosSlotBits; i++)
{
_extra[i * 2 + 2 + kPosSlotOffset] = (Byte)(SET_NUM_BITS(i) - 3);
_extra[i * 2 + 3 + kPosSlotOffset] = (Byte)(SET_NUM_BITS(i) - 3);
}
for (i = kNumLinearPosSlotBits * 2 + 2; i < kNumPosSlots; i++)
_extra[i + kPosSlotOffset] = (Byte)(SET_NUM_BITS(kNumLinearPosSlotBits) - 3);
}
}
READ_TABLE(_bitStream, _mainLevels, _mainLevels + 256)
READ_TABLE(_bitStream, _mainLevels + 256, _mainLevels + 256 + _numPosLenSlots)
const unsigned end = 256 + _numPosLenSlots;
memset(_mainLevels + end, 0, kMainTableSize - end);
// #define NUM_CYC 1
// unsigned j; for (j = 0; j < NUM_CYC; j++)
RIF(_mainDecoder.Build(_mainLevels, NHuffman::k_BuildMode_Full))
// if (kNumLenSymols_Big_Start)
memset(_lenLevels, 0, kNumLenSymols_Big_Start);
READ_TABLE(_bitStream,
_lenLevels + kNumLenSymols_Big_Start,
_lenLevels + kNumLenSymols_Big_Start + kNumLenSymbols)
// for (j = 0; j < NUM_CYC; j++)
RIF(_lenDecoder.Build(_lenLevels, NHuffman::k_BuildMode_Full_or_Empty))
return true;
}
static ptrdiff_t CodeLz(CDecoder *dec, size_t next, ptrdiff_t _bitOffset, const Byte *_buf) throw()
{
{
Byte *const win = dec->_win;
const UInt32 winSize = dec->_winSize;
Byte *pos = win + dec->_pos;
const Byte * const posEnd = pos + next;
NHuffman::CValueInt _value;
NORMALIZE
#if 1
#define HUFF_DEC_PREFIX dec->
#else
const NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize, kNumTableBits_Main> _mainDecoder = dec->_mainDecoder;
const NHuffman::CDecoder256<kNumHuffmanBits, kNumLenSymbols, kNumTableBits_Len> _lenDecoder = dec->_lenDecoder;
const NHuffman::CDecoder7b<kAlignTableSize> _alignDecoder = dec->_alignDecoder;
#define HUFF_DEC_PREFIX
#endif
do
{
unsigned sym;
// printf("\npos = %6u", pos - win);
{
const NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize, kNumTableBits_Main>
*mainDecoder = & HUFF_DEC_PREFIX _mainDecoder;
Z7_LZX_HUFF_DECODE_CHECK_NO(sym, mainDecoder, kNumTableBits_Main, MOVE_POS_CHECK_STAT)
}
// if (!_mainDecoder.Decode_SymCheck_MovePosCheck(&bitStream, sym)) return DECODE_ERROR_CODE;
// sym = _mainDecoder.Decode(&bitStream);
// if (bitStream.WasExtraReadError_Fast()) return DECODE_ERROR_CODE;
// printf(" sym = %3x", sym);
UPDATE_STAT(g_stats_main[sym]++;)
if (sym < 256)
{
UPDATE_STAT(g_stats_NumLits++;)
*pos++ = (Byte)sym;
}
else
{
// sym -= 256;
// if (sym >= _numPosLenSlots) return DECODE_ERROR_CODE;
const unsigned posSlot = sym / kNumLenSlots;
unsigned len = sym % kNumLenSlots + kMatchMinLen;
if (len == kNumLenSlots - 1 + kMatchMinLen)
{
const NHuffman::CDecoder256<kNumHuffmanBits, kNumLenSymbols, kNumTableBits_Len>
*lenDecoder = & HUFF_DEC_PREFIX _lenDecoder;
Z7_LZX_HUFF_DECODE_CHECK_YES(len, lenDecoder, kNumTableBits_Len, MOVE_POS_STAT)
// if (!_lenDecoder.Decode2(&bitStream, len)) return DECODE_ERROR_CODE;
// len = _lenDecoder.Decode(&bitStream);
// if (len >= kNumLenSymbols) return DECODE_ERROR_CODE;
UPDATE_STAT(g_stats_len[len - kNumLenSymols_Big_Start]++;)
len += kNumLenSlots - 1 + kMatchMinLen - kNumLenSymols_Big_Start;
}
/*
if ((next -= len) < 0)
return DECODE_ERROR_CODE;
*/
UInt32 dist;
dist = dec->_reps[(size_t)posSlot - kPosSlotDelta];
if (posSlot < kNumReps + 256 / kNumLenSlots)
{
// if (posSlot != kNumReps + kPosSlotDelta)
// if (posSlot - (kNumReps + kPosSlotDelta + 1) < 2)
dec->_reps[(size_t)posSlot - kPosSlotDelta] = dec->_reps[kPosSlotOffset];
/*
if (posSlot != kPosSlotDelta)
{
UInt32 temp = dist;
if (posSlot == kPosSlotDelta + 1)
{
dist = reps[1];
reps[1] = temp;
}
else
{
dist = reps[2];
reps[2] = temp;
}
// dist = reps[(size_t)(posSlot) - kPosSlotDelta];
// reps[(size_t)(posSlot) - kPosSlotDelta] = reps[0];
// reps[(size_t)(posSlot) - kPosSlotDelta] = temp;
}
*/
}
else // if (posSlot != kNumReps + kPosSlotDelta)
{
unsigned numDirectBits;
#if 0
if (posSlot < kNumPowerPosSlots + kPosSlotDelta)
{
numDirectBits = (posSlot - 2 - kPosSlotDelta) >> 1;
dist = (UInt32)(2 | (posSlot & 1)) << numDirectBits;
}
else
{
numDirectBits = kNumLinearPosSlotBits;
dist = (UInt32)(posSlot - 0x22 - kPosSlotDelta) << kNumLinearPosSlotBits;
}
dist -= kNumReps - 1;
#else
numDirectBits = dec->_extra[(size_t)posSlot - kPosSlotDelta];
// dist = reps[(size_t)(posSlot) - kPosSlotDelta];
#endif
dec->_reps[kPosSlotOffset + 2] =
dec->_reps[kPosSlotOffset + 1];
dec->_reps[kPosSlotOffset + 1] =
dec->_reps[kPosSlotOffset + 0];
// dist += val; dist += bitStream.ReadBitsBig(numDirectBits);
// if (posSlot >= _numAlignBits_PosSlots)
// if (numDirectBits >= _numAlignBits)
// if (val >= _numAlignBits_Dist)
// UInt32 val; MACRO_ReadBitsBig(val , numDirectBits)
// dist += val;
// dist += (UInt32)((UInt32)_value >> 1 >> (/* 31 ^ */ (numDirectBits)));
// MOVE_POS((numDirectBits ^ 31))
MACRO_ReadBitsBig_pre(numDirectBits)
// dist += (UInt32)_value;
if (dist >= dec->_numAlignBits_Dist)
{
// if (numDirectBits != _numAlignBits)
{
// UInt32 val;
// dist -= (UInt32)_value;
MACRO_ReadBitsBig_add3(dist)
NORMALIZE
// dist += (val << kNumAlignBits);
// dist += bitStream.ReadBitsSmall(numDirectBits - kNumAlignBits) << kNumAlignBits;
}
{
// const unsigned alignTemp = _alignDecoder.Decode(&bitStream);
const NHuffman::CDecoder7b<kAlignTableSize> *alignDecoder = & HUFF_DEC_PREFIX _alignDecoder;
unsigned alignTemp;
UPDATE_STAT(g_stats_NumAlign++;)
Z7_HUFF_DECODER_7B_DECODE(alignTemp, alignDecoder, GET_VAL_BASE, MOVE_POS, bs)
// NORMALIZE
// if (alignTemp >= kAlignTableSize) return DECODE_ERROR_CODE;
dist += alignTemp;
}
}
else
{
{
MACRO_ReadBitsBig_add(dist)
// dist += bitStream.ReadBitsSmall(numDirectBits - kNumAlignBits) << kNumAlignBits;
}
}
NORMALIZE
/*
else
{
UInt32 val;
MACRO_ReadBitsBig(val, numDirectBits)
dist += val;
// dist += bitStream.ReadBitsBig(numDirectBits);
}
*/
}
dec->_reps[kPosSlotOffset + 0] = dist;
Byte *dest = pos;
if (len > (size_t)(posEnd - pos))
return DECODE_ERROR_CODE;
Int32 srcPos = (Int32)(pos - win);
pos += len;
srcPos -= (Int32)dist;
if (srcPos < 0) // fast version
{
if (!dec->_overDict)
return DECODE_ERROR_CODE;
srcPos &= winSize - 1;
UInt32 rem = winSize - (UInt32)srcPos;
if (len > rem)
{
len -= rem;
const Byte *src = win + (UInt32)srcPos;
do
*dest++ = *src++;
while (--rem);
srcPos = 0;
}
}
CopyLzMatch(dest, win + (UInt32)srcPos, len, dist);
}
}
while (pos != posEnd);
return _bitOffset;
}
}
// inSize != 0
// outSize != 0 ???
HRESULT CDecoder::CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize) throw()
{
// ((inSize & 1) != 0) case is possible, if current call will be finished with Uncompressed Block.
CBitByteDecoder _bitStream;
if (_keepHistory && _isUncompressedBlock)
_bitStream.Init_ByteMode(inData, inSize);
else
_bitStream.Init_BitMode(inData, inSize);
if (!_keepHistory)
{
_isUncompressedBlock = false;
_skipByte = false;
_unpackBlockSize = 0;
memset(_mainLevels, 0, sizeof(_mainLevels));
memset(_lenLevels, 0, sizeof(_lenLevels));
{
_x86_translationSize = 12000000;
if (!_wimMode)
{
_x86_translationSize = 0;
if (ReadBits(_bitStream, 1) != 0)
{
UInt32 v = ReadBits(_bitStream, 16) << 16;
v |= ReadBits(_bitStream, 16);
_x86_translationSize = v;
}
}
_x86_processedSize = 0;
}
_reps[0 + kPosSlotOffset] = 1;
_reps[1 + kPosSlotOffset] = 1;
_reps[2 + kPosSlotOffset] = 1;
}
while (outSize)
{
/*
// check it for bit mode only:
if (_bitStream.WasExtraReadError_Fast())
return S_FALSE;
*/
if (_unpackBlockSize == 0)
{
if (_skipByte)
{
if (_bitStream.GetRem() < 1)
return S_FALSE;
if (_bitStream.DirectReadByte() != 0)
return S_FALSE;
}
if (_isUncompressedBlock)
_bitStream.Switch_To_BitMode();
if (!ReadTables(_bitStream))
return S_FALSE;
continue;
}
// _unpackBlockSize != 0
UInt32 next = _unpackBlockSize;
if (next > outSize)
next = outSize;
// next != 0
// PRF(printf("\nnext = %d", (unsigned)next);)
if (_isUncompressedBlock)
{
if (_bitStream.GetRem() < next)
return S_FALSE;
_bitStream.CopyTo(_win + _pos, next);
_pos += next;
_unpackBlockSize -= next;
}
else
{
_unpackBlockSize -= next;
_bitStream._bitOffset = CodeLz(this, next, _bitStream._bitOffset, _bitStream._buf);
if (_bitStream.IsOverRead())
return S_FALSE;
_pos += next;
}
outSize -= next;
}
// outSize == 0
if (_isUncompressedBlock)
{
/* we don't know where skipByte can be placed, if it's end of chunk:
1) in current chunk - there are such cab archives, if chunk is last
2) in next chunk - are there such archives ? */
if (_unpackBlockSize == 0
&& _skipByte
// && outSize == 0
&& _bitStream.IsOneDirectByteLeft())
{
_skipByte = false;
if (_bitStream.DirectReadByte() != 0)
return S_FALSE;
}
}
if (_bitStream.GetRem() != 0)
return S_FALSE;
if (!_isUncompressedBlock)
if (!_bitStream.WasBitStreamFinishedOK())
return S_FALSE;
return S_OK;
}
#if k_Filter_OutBufSize_Add > k_Lz_OutBufSize_Add
#define k_OutBufSize_Add k_Filter_OutBufSize_Add
#else
#define k_OutBufSize_Add k_Lz_OutBufSize_Add
#endif
HRESULT CDecoder::Code_WithExceedReadWrite(const Byte *inData, size_t inSize, UInt32 outSize) throw()
{
if (!_keepHistory)
{
_pos = 0;
_overDict = false;
}
else if (_pos == _winSize)
{
_pos = 0;
_overDict = true;
#if k_OutBufSize_Add > 0
// data after (_winSize) can be used, because we can use overwrite.
// memset(_win + _winSize, 0, k_OutBufSize_Add);
#endif
}
_writePos = _pos;
_unpackedData = _win + _pos;
if (outSize > _winSize - _pos)
return S_FALSE;
PRF(printf("\ninSize = %d", (unsigned)inSize);)
PRF(if ((inSize & 1) != 0) printf("---------");)
if (inSize == 0)
return S_FALSE;
const HRESULT res = CodeSpec(inData, inSize, outSize);
const HRESULT res2 = Flush();
return (res == S_OK ? res2 : res);
}
HRESULT CDecoder::SetParams2(unsigned numDictBits) throw()
{
if (numDictBits < kNumDictBits_Min ||
numDictBits > kNumDictBits_Max)
return E_INVALIDARG;
_numDictBits = (Byte)numDictBits;
const unsigned numPosSlots2 = (numDictBits < 20) ?
numDictBits : 17 + (1u << (numDictBits - 18));
_numPosLenSlots = numPosSlots2 * (kNumLenSlots * 2);
return S_OK;
}
HRESULT CDecoder::Set_DictBits_and_Alloc(unsigned numDictBits) throw()
{
RINOK(SetParams2(numDictBits))
const UInt32 newWinSize = (UInt32)1 << numDictBits;
if (_needAlloc)
{
if (!_win || newWinSize != _winSize)
{
// BigFree
z7_AlignedFree
(_win);
_winSize = 0;
const size_t alloc_size = newWinSize + k_OutBufSize_Add;
_win = (Byte *)
// BigAlloc
z7_AlignedAlloc
(alloc_size);
if (!_win)
return E_OUTOFMEMORY;
// optional:
memset(_win, 0, alloc_size);
}
}
_winSize = newWinSize;
return S_OK;
}
}}