blob: a4d453355a03a202aa104abb85bb922b64193a17 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
// XpressDecoder.cpp
#include "StdAfx.h"
// #include <stdio.h>
#include "../../../C/CpuArch.h"
#include "HuffmanDecoder.h"
namespace NCompress {
namespace NXpress {
struct CBitStream
{
UInt32 Value;
unsigned BitPos;
UInt32 GetValue(unsigned numBits) const
{
return (Value >> (BitPos - numBits)) & ((1 << numBits) - 1);
}
void MovePos(unsigned numBits)
{
BitPos -= numBits;
}
};
#define BIT_STREAM_NORMALIZE \
if (bs.BitPos < 16) { \
if (in >= lim) return S_FALSE; \
bs.Value = (bs.Value << 16) | GetUi16(in); \
in += 2; bs.BitPos += 16; }
const unsigned kNumHuffBits = 15;
const unsigned kNumLenSlots = 16;
const unsigned kNumPosSlots = 16;
const unsigned kNumSyms = 256 + kNumPosSlots * kNumLenSlots;
HRESULT Decode(const Byte *in, size_t inSize, Byte *out, size_t outSize)
{
NCompress::NHuffman::CDecoder<kNumHuffBits, kNumSyms> huff;
if (inSize < kNumSyms / 2 + 4)
return S_FALSE;
{
Byte levels[kNumSyms];
for (unsigned i = 0; i < kNumSyms / 2; i++)
{
Byte b = in[i];
levels[i * 2] = (Byte)(b & 0xF);
levels[i * 2 + 1] = (Byte)(b >> 4);
}
if (!huff.BuildFull(levels))
return S_FALSE;
}
CBitStream bs;
const Byte *lim = in + inSize - 1;
in += kNumSyms / 2;
bs.Value = (GetUi16(in) << 16) | GetUi16(in + 2);
in += 4;
bs.BitPos = 32;
size_t pos = 0;
for (;;)
{
// printf("\n%d", pos);
UInt32 sym = huff.DecodeFull(&bs);
// printf(" sym = %d", sym);
BIT_STREAM_NORMALIZE
if (pos >= outSize)
return (sym == 256 && in == lim + 1) ? S_OK : S_FALSE;
if (sym < 256)
out[pos++] = (Byte)sym;
else
{
sym -= 256;
UInt32 dist = sym / kNumLenSlots;
UInt32 len = sym & (kNumLenSlots - 1);
if (len == kNumLenSlots - 1)
{
if (in > lim)
return S_FALSE;
len = *in++;
if (len == 0xFF)
{
if (in >= lim)
return S_FALSE;
len = GetUi16(in);
in += 2;
}
else
len += kNumLenSlots - 1;
}
bs.BitPos -= dist;
dist = (UInt32)1 << dist;
dist += ((bs.Value >> bs.BitPos) & (dist - 1));
BIT_STREAM_NORMALIZE
if (len > outSize - pos)
return S_FALSE;
if (dist > pos)
return S_FALSE;
Byte *dest = out + pos;
const Byte *src = dest - dist;
pos += len + 3;
len += 1;
*dest++ = *src++;
*dest++ = *src++;
do
*dest++ = *src++;
while (--len);
}
}
}
}}
|