rlm@1
|
1 // BZip2Decoder.cpp
|
rlm@1
|
2
|
rlm@1
|
3 #include "StdAfx.h"
|
rlm@1
|
4
|
rlm@1
|
5 extern "C"
|
rlm@1
|
6 {
|
rlm@1
|
7 #include "../../../C/Alloc.h"
|
rlm@1
|
8 }
|
rlm@1
|
9
|
rlm@1
|
10 #include "../../Common/Defs.h"
|
rlm@1
|
11
|
rlm@1
|
12 #include "BZip2Crc.h"
|
rlm@1
|
13 #include "BZip2Decoder.h"
|
rlm@1
|
14 #include "Mtf8.h"
|
rlm@1
|
15
|
rlm@1
|
16 namespace NCompress {
|
rlm@1
|
17 namespace NBZip2 {
|
rlm@1
|
18
|
rlm@1
|
19 #define NO_INLINE MY_FAST_CALL
|
rlm@1
|
20
|
rlm@1
|
21 const UInt32 kNumThreadsMax = 4;
|
rlm@1
|
22
|
rlm@1
|
23 static const UInt32 kBufferSize = (1 << 17);
|
rlm@1
|
24
|
rlm@1
|
25 static Int16 kRandNums[512] = {
|
rlm@1
|
26 619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
|
rlm@1
|
27 985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
|
rlm@1
|
28 733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
|
rlm@1
|
29 419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
|
rlm@1
|
30 878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
|
rlm@1
|
31 862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
|
rlm@1
|
32 150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
|
rlm@1
|
33 170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
|
rlm@1
|
34 73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
|
rlm@1
|
35 909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
|
rlm@1
|
36 641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
|
rlm@1
|
37 161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
|
rlm@1
|
38 382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
|
rlm@1
|
39 98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
|
rlm@1
|
40 227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
|
rlm@1
|
41 469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
|
rlm@1
|
42 184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
|
rlm@1
|
43 715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
|
rlm@1
|
44 951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
|
rlm@1
|
45 652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
|
rlm@1
|
46 645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
|
rlm@1
|
47 609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
|
rlm@1
|
48 653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
|
rlm@1
|
49 411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
|
rlm@1
|
50 170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
|
rlm@1
|
51 857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
|
rlm@1
|
52 669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
|
rlm@1
|
53 944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
|
rlm@1
|
54 344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
|
rlm@1
|
55 897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
|
rlm@1
|
56 433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
|
rlm@1
|
57 686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
|
rlm@1
|
58 946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
|
rlm@1
|
59 978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
|
rlm@1
|
60 680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
|
rlm@1
|
61 707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
|
rlm@1
|
62 297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
|
rlm@1
|
63 134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
|
rlm@1
|
64 343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
|
rlm@1
|
65 140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
|
rlm@1
|
66 170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
|
rlm@1
|
67 369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
|
rlm@1
|
68 804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
|
rlm@1
|
69 896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
|
rlm@1
|
70 661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
|
rlm@1
|
71 768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
|
rlm@1
|
72 61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
|
rlm@1
|
73 372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
|
rlm@1
|
74 780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
|
rlm@1
|
75 920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
|
rlm@1
|
76 645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
|
rlm@1
|
77 936, 638
|
rlm@1
|
78 };
|
rlm@1
|
79
|
rlm@1
|
80 bool CState::Alloc()
|
rlm@1
|
81 {
|
rlm@1
|
82 if (Counters == 0)
|
rlm@1
|
83 Counters = (UInt32 *)BigAlloc((256 + kBlockSizeMax) * sizeof(UInt32));
|
rlm@1
|
84 return (Counters != 0);
|
rlm@1
|
85 }
|
rlm@1
|
86
|
rlm@1
|
87 void CState::Free()
|
rlm@1
|
88 {
|
rlm@1
|
89 ::BigFree(Counters);
|
rlm@1
|
90 Counters = 0;
|
rlm@1
|
91 }
|
rlm@1
|
92
|
rlm@1
|
93 UInt32 CDecoder::ReadBits(int numBits) { return m_InStream.ReadBits(numBits); }
|
rlm@1
|
94 Byte CDecoder::ReadByte() {return (Byte)ReadBits(8); }
|
rlm@1
|
95 bool CDecoder::ReadBit() { return ReadBits(1) != 0; }
|
rlm@1
|
96
|
rlm@1
|
97 UInt32 CDecoder::ReadCrc()
|
rlm@1
|
98 {
|
rlm@1
|
99 UInt32 crc = 0;
|
rlm@1
|
100 for (int i = 0; i < 4; i++)
|
rlm@1
|
101 {
|
rlm@1
|
102 crc <<= 8;
|
rlm@1
|
103 crc |= ReadByte();
|
rlm@1
|
104 }
|
rlm@1
|
105 return crc;
|
rlm@1
|
106 }
|
rlm@1
|
107
|
rlm@1
|
108 UInt32 NO_INLINE ReadBits(NBitm::CDecoder<CInBuffer> *m_InStream, int num)
|
rlm@1
|
109 {
|
rlm@1
|
110 return m_InStream->ReadBits(num);
|
rlm@1
|
111 }
|
rlm@1
|
112
|
rlm@1
|
113 UInt32 NO_INLINE ReadBit(NBitm::CDecoder<CInBuffer> *m_InStream)
|
rlm@1
|
114 {
|
rlm@1
|
115 return m_InStream->ReadBits(1);
|
rlm@1
|
116 }
|
rlm@1
|
117
|
rlm@1
|
118 static HRESULT NO_INLINE ReadBlock(NBitm::CDecoder<CInBuffer> *m_InStream,
|
rlm@1
|
119 UInt32 *CharCounters, UInt32 blockSizeMax, Byte *m_Selectors, CHuffmanDecoder *m_HuffmanDecoders,
|
rlm@1
|
120 UInt32 *blockSizeRes, UInt32 *origPtrRes, bool *randRes)
|
rlm@1
|
121 {
|
rlm@1
|
122 *randRes = ReadBit(m_InStream) ? true : false;
|
rlm@1
|
123 *origPtrRes = ReadBits(m_InStream, kNumOrigBits);
|
rlm@1
|
124
|
rlm@1
|
125 // in original code it compares OrigPtr to (UInt32)(10 + blockSizeMax)) : why ?
|
rlm@1
|
126 if (*origPtrRes >= blockSizeMax)
|
rlm@1
|
127 return S_FALSE;
|
rlm@1
|
128
|
rlm@1
|
129 CMtf8Decoder mtf;
|
rlm@1
|
130 mtf.StartInit();
|
rlm@1
|
131
|
rlm@1
|
132 int numInUse = 0;
|
rlm@1
|
133 {
|
rlm@1
|
134 Byte inUse16[16];
|
rlm@1
|
135 int i;
|
rlm@1
|
136 for (i = 0; i < 16; i++)
|
rlm@1
|
137 inUse16[i] = (Byte)ReadBit(m_InStream);
|
rlm@1
|
138 for (i = 0; i < 256; i++)
|
rlm@1
|
139 if (inUse16[i >> 4])
|
rlm@1
|
140 {
|
rlm@1
|
141 if (ReadBit(m_InStream))
|
rlm@1
|
142 mtf.Add(numInUse++, (Byte)i);
|
rlm@1
|
143 }
|
rlm@1
|
144 if (numInUse == 0)
|
rlm@1
|
145 return S_FALSE;
|
rlm@1
|
146 // mtf.Init(numInUse);
|
rlm@1
|
147 }
|
rlm@1
|
148 int alphaSize = numInUse + 2;
|
rlm@1
|
149
|
rlm@1
|
150 int numTables = ReadBits(m_InStream, kNumTablesBits);
|
rlm@1
|
151 if (numTables < kNumTablesMin || numTables > kNumTablesMax)
|
rlm@1
|
152 return S_FALSE;
|
rlm@1
|
153
|
rlm@1
|
154 UInt32 numSelectors = ReadBits(m_InStream, kNumSelectorsBits);
|
rlm@1
|
155 if (numSelectors < 1 || numSelectors > kNumSelectorsMax)
|
rlm@1
|
156 return S_FALSE;
|
rlm@1
|
157
|
rlm@1
|
158 {
|
rlm@1
|
159 Byte mtfPos[kNumTablesMax];
|
rlm@1
|
160 int t = 0;
|
rlm@1
|
161 do
|
rlm@1
|
162 mtfPos[t] = (Byte)t;
|
rlm@1
|
163 while(++t < numTables);
|
rlm@1
|
164 UInt32 i = 0;
|
rlm@1
|
165 do
|
rlm@1
|
166 {
|
rlm@1
|
167 int j = 0;
|
rlm@1
|
168 while (ReadBit(m_InStream))
|
rlm@1
|
169 if (++j >= numTables)
|
rlm@1
|
170 return S_FALSE;
|
rlm@1
|
171 Byte tmp = mtfPos[j];
|
rlm@1
|
172 for (;j > 0; j--)
|
rlm@1
|
173 mtfPos[j] = mtfPos[j - 1];
|
rlm@1
|
174 m_Selectors[i] = mtfPos[0] = tmp;
|
rlm@1
|
175 }
|
rlm@1
|
176 while(++i < numSelectors);
|
rlm@1
|
177 }
|
rlm@1
|
178
|
rlm@1
|
179 int t = 0;
|
rlm@1
|
180 do
|
rlm@1
|
181 {
|
rlm@1
|
182 Byte lens[kMaxAlphaSize];
|
rlm@1
|
183 int len = (int)ReadBits(m_InStream, kNumLevelsBits);
|
rlm@1
|
184 int i;
|
rlm@1
|
185 for (i = 0; i < alphaSize; i++)
|
rlm@1
|
186 {
|
rlm@1
|
187 for (;;)
|
rlm@1
|
188 {
|
rlm@1
|
189 if (len < 1 || len > kMaxHuffmanLen)
|
rlm@1
|
190 return S_FALSE;
|
rlm@1
|
191 if (!ReadBit(m_InStream))
|
rlm@1
|
192 break;
|
rlm@1
|
193 len += 1 - (int)(ReadBit(m_InStream) << 1);
|
rlm@1
|
194 }
|
rlm@1
|
195 lens[i] = (Byte)len;
|
rlm@1
|
196 }
|
rlm@1
|
197 for (; i < kMaxAlphaSize; i++)
|
rlm@1
|
198 lens[i] = 0;
|
rlm@1
|
199 if(!m_HuffmanDecoders[t].SetCodeLengths(lens))
|
rlm@1
|
200 return S_FALSE;
|
rlm@1
|
201 }
|
rlm@1
|
202 while(++t < numTables);
|
rlm@1
|
203
|
rlm@1
|
204 {
|
rlm@1
|
205 for (int i = 0; i < 256; i++)
|
rlm@1
|
206 CharCounters[i] = 0;
|
rlm@1
|
207 }
|
rlm@1
|
208
|
rlm@1
|
209 UInt32 blockSize = 0;
|
rlm@1
|
210 {
|
rlm@1
|
211 UInt32 groupIndex = 0;
|
rlm@1
|
212 UInt32 groupSize = 0;
|
rlm@1
|
213 CHuffmanDecoder *huffmanDecoder = 0;
|
rlm@1
|
214 int runPower = 0;
|
rlm@1
|
215 UInt32 runCounter = 0;
|
rlm@1
|
216
|
rlm@1
|
217 for (;;)
|
rlm@1
|
218 {
|
rlm@1
|
219 if (groupSize == 0)
|
rlm@1
|
220 {
|
rlm@1
|
221 if (groupIndex >= numSelectors)
|
rlm@1
|
222 return S_FALSE;
|
rlm@1
|
223 groupSize = kGroupSize;
|
rlm@1
|
224 huffmanDecoder = &m_HuffmanDecoders[m_Selectors[groupIndex++]];
|
rlm@1
|
225 }
|
rlm@1
|
226 groupSize--;
|
rlm@1
|
227
|
rlm@1
|
228 UInt32 nextSym = huffmanDecoder->DecodeSymbol(m_InStream);
|
rlm@1
|
229
|
rlm@1
|
230 if (nextSym < 2)
|
rlm@1
|
231 {
|
rlm@1
|
232 runCounter += ((UInt32)(nextSym + 1) << runPower++);
|
rlm@1
|
233 if (blockSizeMax - blockSize < runCounter)
|
rlm@1
|
234 return S_FALSE;
|
rlm@1
|
235 continue;
|
rlm@1
|
236 }
|
rlm@1
|
237 if (runCounter != 0)
|
rlm@1
|
238 {
|
rlm@1
|
239 UInt32 b = (UInt32)mtf.GetHead();
|
rlm@1
|
240 CharCounters[b] += runCounter;
|
rlm@1
|
241 do
|
rlm@1
|
242 CharCounters[256 + blockSize++] = b;
|
rlm@1
|
243 while(--runCounter != 0);
|
rlm@1
|
244 runPower = 0;
|
rlm@1
|
245 }
|
rlm@1
|
246 if (nextSym <= (UInt32)numInUse)
|
rlm@1
|
247 {
|
rlm@1
|
248 UInt32 b = (UInt32)mtf.GetAndMove((int)nextSym - 1);
|
rlm@1
|
249 if (blockSize >= blockSizeMax)
|
rlm@1
|
250 return S_FALSE;
|
rlm@1
|
251 CharCounters[b]++;
|
rlm@1
|
252 CharCounters[256 + blockSize++] = b;
|
rlm@1
|
253 }
|
rlm@1
|
254 else if (nextSym == (UInt32)numInUse + 1)
|
rlm@1
|
255 break;
|
rlm@1
|
256 else
|
rlm@1
|
257 return S_FALSE;
|
rlm@1
|
258 }
|
rlm@1
|
259 }
|
rlm@1
|
260 *blockSizeRes = blockSize;
|
rlm@1
|
261 return (*origPtrRes < blockSize) ? S_OK : S_FALSE;
|
rlm@1
|
262 }
|
rlm@1
|
263
|
rlm@1
|
264 void NO_INLINE DecodeBlock1(UInt32 *charCounters, UInt32 blockSize)
|
rlm@1
|
265 {
|
rlm@1
|
266 {
|
rlm@1
|
267 UInt32 sum = 0;
|
rlm@1
|
268 for (UInt32 i = 0; i < 256; i++)
|
rlm@1
|
269 {
|
rlm@1
|
270 sum += charCounters[i];
|
rlm@1
|
271 charCounters[i] = sum - charCounters[i];
|
rlm@1
|
272 }
|
rlm@1
|
273 }
|
rlm@1
|
274
|
rlm@1
|
275 UInt32 *tt = charCounters + 256;
|
rlm@1
|
276 // Compute the T^(-1) vector
|
rlm@1
|
277 UInt32 i = 0;
|
rlm@1
|
278 do
|
rlm@1
|
279 tt[charCounters[tt[i] & 0xFF]++] |= (i << 8);
|
rlm@1
|
280 while(++i < blockSize);
|
rlm@1
|
281 }
|
rlm@1
|
282
|
rlm@1
|
283 static UInt32 NO_INLINE DecodeBlock2(const UInt32 *tt, UInt32 blockSize, UInt32 OrigPtr, COutBuffer &m_OutStream)
|
rlm@1
|
284 {
|
rlm@1
|
285 CBZip2Crc crc;
|
rlm@1
|
286
|
rlm@1
|
287 // it's for speed optimization: prefetch & prevByte_init;
|
rlm@1
|
288 UInt32 tPos = tt[tt[OrigPtr] >> 8];
|
rlm@1
|
289 unsigned int prevByte = (unsigned int)(tPos & 0xFF);
|
rlm@1
|
290
|
rlm@1
|
291 int numReps = 0;
|
rlm@1
|
292
|
rlm@1
|
293 do
|
rlm@1
|
294 {
|
rlm@1
|
295 unsigned int b = (unsigned int)(tPos & 0xFF);
|
rlm@1
|
296 tPos = tt[tPos >> 8];
|
rlm@1
|
297
|
rlm@1
|
298 if (numReps == kRleModeRepSize)
|
rlm@1
|
299 {
|
rlm@1
|
300 for (; b > 0; b--)
|
rlm@1
|
301 {
|
rlm@1
|
302 crc.UpdateByte(prevByte);
|
rlm@1
|
303 m_OutStream.WriteByte((Byte)prevByte);
|
rlm@1
|
304 }
|
rlm@1
|
305 numReps = 0;
|
rlm@1
|
306 continue;
|
rlm@1
|
307 }
|
rlm@1
|
308 if (b != prevByte)
|
rlm@1
|
309 numReps = 0;
|
rlm@1
|
310 numReps++;
|
rlm@1
|
311 prevByte = b;
|
rlm@1
|
312 crc.UpdateByte(b);
|
rlm@1
|
313 m_OutStream.WriteByte((Byte)b);
|
rlm@1
|
314
|
rlm@1
|
315 /*
|
rlm@1
|
316 prevByte = b;
|
rlm@1
|
317 crc.UpdateByte(b);
|
rlm@1
|
318 m_OutStream.WriteByte((Byte)b);
|
rlm@1
|
319 for (; --blockSize != 0;)
|
rlm@1
|
320 {
|
rlm@1
|
321 b = (unsigned int)(tPos & 0xFF);
|
rlm@1
|
322 tPos = tt[tPos >> 8];
|
rlm@1
|
323 crc.UpdateByte(b);
|
rlm@1
|
324 m_OutStream.WriteByte((Byte)b);
|
rlm@1
|
325 if (b != prevByte)
|
rlm@1
|
326 {
|
rlm@1
|
327 prevByte = b;
|
rlm@1
|
328 continue;
|
rlm@1
|
329 }
|
rlm@1
|
330 if (--blockSize == 0)
|
rlm@1
|
331 break;
|
rlm@1
|
332
|
rlm@1
|
333 b = (unsigned int)(tPos & 0xFF);
|
rlm@1
|
334 tPos = tt[tPos >> 8];
|
rlm@1
|
335 crc.UpdateByte(b);
|
rlm@1
|
336 m_OutStream.WriteByte((Byte)b);
|
rlm@1
|
337 if (b != prevByte)
|
rlm@1
|
338 {
|
rlm@1
|
339 prevByte = b;
|
rlm@1
|
340 continue;
|
rlm@1
|
341 }
|
rlm@1
|
342 if (--blockSize == 0)
|
rlm@1
|
343 break;
|
rlm@1
|
344
|
rlm@1
|
345 b = (unsigned int)(tPos & 0xFF);
|
rlm@1
|
346 tPos = tt[tPos >> 8];
|
rlm@1
|
347 crc.UpdateByte(b);
|
rlm@1
|
348 m_OutStream.WriteByte((Byte)b);
|
rlm@1
|
349 if (b != prevByte)
|
rlm@1
|
350 {
|
rlm@1
|
351 prevByte = b;
|
rlm@1
|
352 continue;
|
rlm@1
|
353 }
|
rlm@1
|
354 --blockSize;
|
rlm@1
|
355 break;
|
rlm@1
|
356 }
|
rlm@1
|
357 if (blockSize == 0)
|
rlm@1
|
358 break;
|
rlm@1
|
359
|
rlm@1
|
360 b = (unsigned int)(tPos & 0xFF);
|
rlm@1
|
361 tPos = tt[tPos >> 8];
|
rlm@1
|
362
|
rlm@1
|
363 for (; b > 0; b--)
|
rlm@1
|
364 {
|
rlm@1
|
365 crc.UpdateByte(prevByte);
|
rlm@1
|
366 m_OutStream.WriteByte((Byte)prevByte);
|
rlm@1
|
367 }
|
rlm@1
|
368 */
|
rlm@1
|
369 }
|
rlm@1
|
370 while(--blockSize != 0);
|
rlm@1
|
371 return crc.GetDigest();
|
rlm@1
|
372 }
|
rlm@1
|
373
|
rlm@1
|
374 static UInt32 NO_INLINE DecodeBlock2Rand(const UInt32 *tt, UInt32 blockSize, UInt32 OrigPtr, COutBuffer &m_OutStream)
|
rlm@1
|
375 {
|
rlm@1
|
376 CBZip2Crc crc;
|
rlm@1
|
377
|
rlm@1
|
378 UInt32 randIndex = 1;
|
rlm@1
|
379 UInt32 randToGo = kRandNums[0] - 2;
|
rlm@1
|
380
|
rlm@1
|
381 int numReps = 0;
|
rlm@1
|
382
|
rlm@1
|
383 // it's for speed optimization: prefetch & prevByte_init;
|
rlm@1
|
384 UInt32 tPos = tt[tt[OrigPtr] >> 8];
|
rlm@1
|
385 unsigned int prevByte = (unsigned int)(tPos & 0xFF);
|
rlm@1
|
386
|
rlm@1
|
387 do
|
rlm@1
|
388 {
|
rlm@1
|
389 unsigned int b = (unsigned int)(tPos & 0xFF);
|
rlm@1
|
390 tPos = tt[tPos >> 8];
|
rlm@1
|
391
|
rlm@1
|
392 {
|
rlm@1
|
393 if (randToGo == 0)
|
rlm@1
|
394 {
|
rlm@1
|
395 b ^= 1;
|
rlm@1
|
396 randToGo = kRandNums[randIndex++];
|
rlm@1
|
397 randIndex &= 0x1FF;
|
rlm@1
|
398 }
|
rlm@1
|
399 randToGo--;
|
rlm@1
|
400 }
|
rlm@1
|
401
|
rlm@1
|
402 if (numReps == kRleModeRepSize)
|
rlm@1
|
403 {
|
rlm@1
|
404 for (; b > 0; b--)
|
rlm@1
|
405 {
|
rlm@1
|
406 crc.UpdateByte(prevByte);
|
rlm@1
|
407 m_OutStream.WriteByte((Byte)prevByte);
|
rlm@1
|
408 }
|
rlm@1
|
409 numReps = 0;
|
rlm@1
|
410 continue;
|
rlm@1
|
411 }
|
rlm@1
|
412 if (b != prevByte)
|
rlm@1
|
413 numReps = 0;
|
rlm@1
|
414 numReps++;
|
rlm@1
|
415 prevByte = b;
|
rlm@1
|
416 crc.UpdateByte(b);
|
rlm@1
|
417 m_OutStream.WriteByte((Byte)b);
|
rlm@1
|
418 }
|
rlm@1
|
419 while(--blockSize != 0);
|
rlm@1
|
420 return crc.GetDigest();
|
rlm@1
|
421 }
|
rlm@1
|
422
|
rlm@1
|
423 #ifdef COMPRESS_BZIP2_MT
|
rlm@1
|
424
|
rlm@1
|
425 CDecoder::CDecoder():
|
rlm@1
|
426 m_States(0)
|
rlm@1
|
427 {
|
rlm@1
|
428 m_NumThreadsPrev = 0;
|
rlm@1
|
429 NumThreads = 1;
|
rlm@1
|
430 }
|
rlm@1
|
431
|
rlm@1
|
432 CDecoder::~CDecoder()
|
rlm@1
|
433 {
|
rlm@1
|
434 Free();
|
rlm@1
|
435 }
|
rlm@1
|
436
|
rlm@1
|
437 #define RINOK_THREAD(x) { WRes __result_ = (x); if(__result_ != 0) return __result_; }
|
rlm@1
|
438
|
rlm@1
|
439 HRESULT CDecoder::Create()
|
rlm@1
|
440 {
|
rlm@1
|
441 RINOK_THREAD(CanProcessEvent.CreateIfNotCreated());
|
rlm@1
|
442 RINOK_THREAD(CanStartWaitingEvent.CreateIfNotCreated());
|
rlm@1
|
443 if (m_States != 0 && m_NumThreadsPrev == NumThreads)
|
rlm@1
|
444 return S_OK;
|
rlm@1
|
445 Free();
|
rlm@1
|
446 MtMode = (NumThreads > 1);
|
rlm@1
|
447 m_NumThreadsPrev = NumThreads;
|
rlm@1
|
448 try
|
rlm@1
|
449 {
|
rlm@1
|
450 m_States = new CState[NumThreads];
|
rlm@1
|
451 if (m_States == 0)
|
rlm@1
|
452 return E_OUTOFMEMORY;
|
rlm@1
|
453 }
|
rlm@1
|
454 catch(...) { return E_OUTOFMEMORY; }
|
rlm@1
|
455 for (UInt32 t = 0; t < NumThreads; t++)
|
rlm@1
|
456 {
|
rlm@1
|
457 CState &ti = m_States[t];
|
rlm@1
|
458 ti.Decoder = this;
|
rlm@1
|
459 if (MtMode)
|
rlm@1
|
460 {
|
rlm@1
|
461 HRESULT res = ti.Create();
|
rlm@1
|
462 if (res != S_OK)
|
rlm@1
|
463 {
|
rlm@1
|
464 NumThreads = t;
|
rlm@1
|
465 Free();
|
rlm@1
|
466 return res;
|
rlm@1
|
467 }
|
rlm@1
|
468 }
|
rlm@1
|
469 }
|
rlm@1
|
470 return S_OK;
|
rlm@1
|
471 }
|
rlm@1
|
472
|
rlm@1
|
473 void CDecoder::Free()
|
rlm@1
|
474 {
|
rlm@1
|
475 if (!m_States)
|
rlm@1
|
476 return;
|
rlm@1
|
477 CloseThreads = true;
|
rlm@1
|
478 CanProcessEvent.Set();
|
rlm@1
|
479 for (UInt32 t = 0; t < NumThreads; t++)
|
rlm@1
|
480 {
|
rlm@1
|
481 CState &s = m_States[t];
|
rlm@1
|
482 if (MtMode)
|
rlm@1
|
483 s.Thread.Wait();
|
rlm@1
|
484 s.Free();
|
rlm@1
|
485 }
|
rlm@1
|
486 delete []m_States;
|
rlm@1
|
487 m_States = 0;
|
rlm@1
|
488 }
|
rlm@1
|
489 #endif
|
rlm@1
|
490
|
rlm@1
|
491 HRESULT CDecoder::ReadSignatures(bool &wasFinished, UInt32 &crc)
|
rlm@1
|
492 {
|
rlm@1
|
493 wasFinished = false;
|
rlm@1
|
494 Byte s[6];
|
rlm@1
|
495 for (int i = 0; i < 6; i++)
|
rlm@1
|
496 s[i] = ReadByte();
|
rlm@1
|
497 crc = ReadCrc();
|
rlm@1
|
498 if (s[0] == kFinSig0)
|
rlm@1
|
499 {
|
rlm@1
|
500 if (s[1] != kFinSig1 ||
|
rlm@1
|
501 s[2] != kFinSig2 ||
|
rlm@1
|
502 s[3] != kFinSig3 ||
|
rlm@1
|
503 s[4] != kFinSig4 ||
|
rlm@1
|
504 s[5] != kFinSig5)
|
rlm@1
|
505 return S_FALSE;
|
rlm@1
|
506
|
rlm@1
|
507 wasFinished = true;
|
rlm@1
|
508 return (crc == CombinedCrc.GetDigest()) ? S_OK : S_FALSE;
|
rlm@1
|
509 }
|
rlm@1
|
510 if (s[0] != kBlockSig0 ||
|
rlm@1
|
511 s[1] != kBlockSig1 ||
|
rlm@1
|
512 s[2] != kBlockSig2 ||
|
rlm@1
|
513 s[3] != kBlockSig3 ||
|
rlm@1
|
514 s[4] != kBlockSig4 ||
|
rlm@1
|
515 s[5] != kBlockSig5)
|
rlm@1
|
516 return S_FALSE;
|
rlm@1
|
517 CombinedCrc.Update(crc);
|
rlm@1
|
518 return S_OK;
|
rlm@1
|
519 }
|
rlm@1
|
520
|
rlm@1
|
521 HRESULT CDecoder::DecodeFile(bool &isBZ, ICompressProgressInfo *progress)
|
rlm@1
|
522 {
|
rlm@1
|
523 #ifdef COMPRESS_BZIP2_MT
|
rlm@1
|
524 Progress = progress;
|
rlm@1
|
525 RINOK(Create());
|
rlm@1
|
526 for (UInt32 t = 0; t < NumThreads; t++)
|
rlm@1
|
527 {
|
rlm@1
|
528 CState &s = m_States[t];
|
rlm@1
|
529 if (!s.Alloc())
|
rlm@1
|
530 return E_OUTOFMEMORY;
|
rlm@1
|
531 if (MtMode)
|
rlm@1
|
532 {
|
rlm@1
|
533 RINOK(s.StreamWasFinishedEvent.Reset());
|
rlm@1
|
534 RINOK(s.WaitingWasStartedEvent.Reset());
|
rlm@1
|
535 RINOK(s.CanWriteEvent.Reset());
|
rlm@1
|
536 }
|
rlm@1
|
537 }
|
rlm@1
|
538 #else
|
rlm@1
|
539 if (!m_States[0].Alloc())
|
rlm@1
|
540 return E_OUTOFMEMORY;
|
rlm@1
|
541 #endif
|
rlm@1
|
542
|
rlm@1
|
543 isBZ = false;
|
rlm@1
|
544 Byte s[6];
|
rlm@1
|
545 int i;
|
rlm@1
|
546 for (i = 0; i < 4; i++)
|
rlm@1
|
547 s[i] = ReadByte();
|
rlm@1
|
548 if (s[0] != kArSig0 ||
|
rlm@1
|
549 s[1] != kArSig1 ||
|
rlm@1
|
550 s[2] != kArSig2 ||
|
rlm@1
|
551 s[3] <= kArSig3 ||
|
rlm@1
|
552 s[3] > kArSig3 + kBlockSizeMultMax)
|
rlm@1
|
553 return S_OK;
|
rlm@1
|
554 isBZ = true;
|
rlm@1
|
555 UInt32 dicSize = (UInt32)(s[3] - kArSig3) * kBlockSizeStep;
|
rlm@1
|
556
|
rlm@1
|
557 CombinedCrc.Init();
|
rlm@1
|
558 #ifdef COMPRESS_BZIP2_MT
|
rlm@1
|
559 if (MtMode)
|
rlm@1
|
560 {
|
rlm@1
|
561 NextBlockIndex = 0;
|
rlm@1
|
562 StreamWasFinished1 = StreamWasFinished2 = false;
|
rlm@1
|
563 CloseThreads = false;
|
rlm@1
|
564 CanStartWaitingEvent.Reset();
|
rlm@1
|
565 m_States[0].CanWriteEvent.Set();
|
rlm@1
|
566 BlockSizeMax = dicSize;
|
rlm@1
|
567 Result1 = Result2 = S_OK;
|
rlm@1
|
568 CanProcessEvent.Set();
|
rlm@1
|
569 UInt32 t;
|
rlm@1
|
570 for (t = 0; t < NumThreads; t++)
|
rlm@1
|
571 m_States[t].StreamWasFinishedEvent.Lock();
|
rlm@1
|
572 CanProcessEvent.Reset();
|
rlm@1
|
573 CanStartWaitingEvent.Set();
|
rlm@1
|
574 for (t = 0; t < NumThreads; t++)
|
rlm@1
|
575 m_States[t].WaitingWasStartedEvent.Lock();
|
rlm@1
|
576 CanStartWaitingEvent.Reset();
|
rlm@1
|
577 RINOK(Result2);
|
rlm@1
|
578 RINOK(Result1);
|
rlm@1
|
579 }
|
rlm@1
|
580 else
|
rlm@1
|
581 #endif
|
rlm@1
|
582 {
|
rlm@1
|
583 CState &state = m_States[0];
|
rlm@1
|
584 for (;;)
|
rlm@1
|
585 {
|
rlm@1
|
586 if (progress)
|
rlm@1
|
587 {
|
rlm@1
|
588 UInt64 packSize = m_InStream.GetProcessedSize();
|
rlm@1
|
589 UInt64 unpackSize = m_OutStream.GetProcessedSize();
|
rlm@1
|
590 RINOK(progress->SetRatioInfo(&packSize, &unpackSize));
|
rlm@1
|
591 }
|
rlm@1
|
592 bool wasFinished;
|
rlm@1
|
593 UInt32 crc;
|
rlm@1
|
594 RINOK(ReadSignatures(wasFinished, crc));
|
rlm@1
|
595 if (wasFinished)
|
rlm@1
|
596 return S_OK;
|
rlm@1
|
597
|
rlm@1
|
598 UInt32 blockSize, origPtr;
|
rlm@1
|
599 bool randMode;
|
rlm@1
|
600 RINOK(ReadBlock(&m_InStream, state.Counters, dicSize,
|
rlm@1
|
601 m_Selectors, m_HuffmanDecoders,
|
rlm@1
|
602 &blockSize, &origPtr, &randMode));
|
rlm@1
|
603 DecodeBlock1(state.Counters, blockSize);
|
rlm@1
|
604 if ((randMode ?
|
rlm@1
|
605 DecodeBlock2Rand(state.Counters + 256, blockSize, origPtr, m_OutStream) :
|
rlm@1
|
606 DecodeBlock2(state.Counters + 256, blockSize, origPtr, m_OutStream)) != crc)
|
rlm@1
|
607 return S_FALSE;
|
rlm@1
|
608 }
|
rlm@1
|
609 }
|
rlm@1
|
610 return S_OK;
|
rlm@1
|
611 }
|
rlm@1
|
612
|
rlm@1
|
613 HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
rlm@1
|
614 const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
|
rlm@1
|
615 {
|
rlm@1
|
616 if (!m_InStream.Create(kBufferSize))
|
rlm@1
|
617 return E_OUTOFMEMORY;
|
rlm@1
|
618 if (!m_OutStream.Create(kBufferSize))
|
rlm@1
|
619 return E_OUTOFMEMORY;
|
rlm@1
|
620
|
rlm@1
|
621 m_InStream.SetStream(inStream);
|
rlm@1
|
622 m_InStream.Init();
|
rlm@1
|
623
|
rlm@1
|
624 m_OutStream.SetStream(outStream);
|
rlm@1
|
625 m_OutStream.Init();
|
rlm@1
|
626
|
rlm@1
|
627 CDecoderFlusher flusher(this);
|
rlm@1
|
628
|
rlm@1
|
629 bool isBZ;
|
rlm@1
|
630 RINOK(DecodeFile(isBZ, progress));
|
rlm@1
|
631 return isBZ ? S_OK: S_FALSE;
|
rlm@1
|
632 }
|
rlm@1
|
633
|
rlm@1
|
634 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
rlm@1
|
635 const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
rlm@1
|
636 {
|
rlm@1
|
637 try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
|
rlm@1
|
638 catch(const CInBufferException &e) { return e.ErrorCode; }
|
rlm@1
|
639 catch(const COutBufferException &e) { return e.ErrorCode; }
|
rlm@1
|
640 catch(...) { return E_FAIL; }
|
rlm@1
|
641 }
|
rlm@1
|
642
|
rlm@1
|
643 STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
|
rlm@1
|
644 {
|
rlm@1
|
645 if (value == NULL)
|
rlm@1
|
646 return E_INVALIDARG;
|
rlm@1
|
647 *value = m_InStream.GetProcessedSize();
|
rlm@1
|
648 return S_OK;
|
rlm@1
|
649 }
|
rlm@1
|
650
|
rlm@1
|
651 #ifdef COMPRESS_BZIP2_MT
|
rlm@1
|
652
|
rlm@1
|
653 static THREAD_FUNC_DECL MFThread(void *p) { ((CState *)p)->ThreadFunc(); return 0; }
|
rlm@1
|
654
|
rlm@1
|
655 HRESULT CState::Create()
|
rlm@1
|
656 {
|
rlm@1
|
657 RINOK_THREAD(StreamWasFinishedEvent.CreateIfNotCreated());
|
rlm@1
|
658 RINOK_THREAD(WaitingWasStartedEvent.CreateIfNotCreated());
|
rlm@1
|
659 RINOK_THREAD(CanWriteEvent.CreateIfNotCreated());
|
rlm@1
|
660 RINOK_THREAD(Thread.Create(MFThread, this));
|
rlm@1
|
661 return S_OK;
|
rlm@1
|
662 }
|
rlm@1
|
663
|
rlm@1
|
664 void CState::FinishStream()
|
rlm@1
|
665 {
|
rlm@1
|
666 Decoder->StreamWasFinished1 = true;
|
rlm@1
|
667 StreamWasFinishedEvent.Set();
|
rlm@1
|
668 Decoder->CS.Leave();
|
rlm@1
|
669 Decoder->CanStartWaitingEvent.Lock();
|
rlm@1
|
670 WaitingWasStartedEvent.Set();
|
rlm@1
|
671 }
|
rlm@1
|
672
|
rlm@1
|
673 void CState::ThreadFunc()
|
rlm@1
|
674 {
|
rlm@1
|
675 for (;;)
|
rlm@1
|
676 {
|
rlm@1
|
677 Decoder->CanProcessEvent.Lock();
|
rlm@1
|
678 Decoder->CS.Enter();
|
rlm@1
|
679 if (Decoder->CloseThreads)
|
rlm@1
|
680 {
|
rlm@1
|
681 Decoder->CS.Leave();
|
rlm@1
|
682 return;
|
rlm@1
|
683 }
|
rlm@1
|
684 if (Decoder->StreamWasFinished1)
|
rlm@1
|
685 {
|
rlm@1
|
686 FinishStream();
|
rlm@1
|
687 continue;
|
rlm@1
|
688 }
|
rlm@1
|
689 HRESULT res = S_OK;
|
rlm@1
|
690
|
rlm@1
|
691 UInt32 blockIndex = Decoder->NextBlockIndex;
|
rlm@1
|
692 UInt32 nextBlockIndex = blockIndex + 1;
|
rlm@1
|
693 if (nextBlockIndex == Decoder->NumThreads)
|
rlm@1
|
694 nextBlockIndex = 0;
|
rlm@1
|
695 Decoder->NextBlockIndex = nextBlockIndex;
|
rlm@1
|
696 UInt32 crc;
|
rlm@1
|
697 UInt64 packSize;
|
rlm@1
|
698 UInt32 blockSize = 0, origPtr = 0;
|
rlm@1
|
699 bool randMode = false;
|
rlm@1
|
700
|
rlm@1
|
701 try
|
rlm@1
|
702 {
|
rlm@1
|
703 bool wasFinished;
|
rlm@1
|
704 res = Decoder->ReadSignatures(wasFinished, crc);
|
rlm@1
|
705 if (res != S_OK)
|
rlm@1
|
706 {
|
rlm@1
|
707 Decoder->Result1 = res;
|
rlm@1
|
708 FinishStream();
|
rlm@1
|
709 continue;
|
rlm@1
|
710 }
|
rlm@1
|
711 if (wasFinished)
|
rlm@1
|
712 {
|
rlm@1
|
713 Decoder->Result1 = res;
|
rlm@1
|
714 FinishStream();
|
rlm@1
|
715 continue;
|
rlm@1
|
716 }
|
rlm@1
|
717
|
rlm@1
|
718 res = ReadBlock(&Decoder->m_InStream, Counters, Decoder->BlockSizeMax,
|
rlm@1
|
719 Decoder->m_Selectors, Decoder->m_HuffmanDecoders,
|
rlm@1
|
720 &blockSize, &origPtr, &randMode);
|
rlm@1
|
721 if (res != S_OK)
|
rlm@1
|
722 {
|
rlm@1
|
723 Decoder->Result1 = res;
|
rlm@1
|
724 FinishStream();
|
rlm@1
|
725 continue;
|
rlm@1
|
726 }
|
rlm@1
|
727 packSize = Decoder->m_InStream.GetProcessedSize();
|
rlm@1
|
728 }
|
rlm@1
|
729 catch(const CInBufferException &e) { res = e.ErrorCode; if (res != S_OK) res = E_FAIL; }
|
rlm@1
|
730 catch(...) { res = E_FAIL; }
|
rlm@1
|
731 if (res != S_OK)
|
rlm@1
|
732 {
|
rlm@1
|
733 Decoder->Result1 = res;
|
rlm@1
|
734 FinishStream();
|
rlm@1
|
735 continue;
|
rlm@1
|
736 }
|
rlm@1
|
737
|
rlm@1
|
738 Decoder->CS.Leave();
|
rlm@1
|
739
|
rlm@1
|
740 DecodeBlock1(Counters, blockSize);
|
rlm@1
|
741
|
rlm@1
|
742 bool needFinish = true;
|
rlm@1
|
743 try
|
rlm@1
|
744 {
|
rlm@1
|
745 Decoder->m_States[blockIndex].CanWriteEvent.Lock();
|
rlm@1
|
746 needFinish = Decoder->StreamWasFinished2;
|
rlm@1
|
747 if (!needFinish)
|
rlm@1
|
748 {
|
rlm@1
|
749 if ((randMode ?
|
rlm@1
|
750 DecodeBlock2Rand(Counters + 256, blockSize, origPtr, Decoder->m_OutStream) :
|
rlm@1
|
751 DecodeBlock2(Counters + 256, blockSize, origPtr, Decoder->m_OutStream)) == crc)
|
rlm@1
|
752 {
|
rlm@1
|
753 if (Decoder->Progress)
|
rlm@1
|
754 {
|
rlm@1
|
755 UInt64 unpackSize = Decoder->m_OutStream.GetProcessedSize();
|
rlm@1
|
756 res = Decoder->Progress->SetRatioInfo(&packSize, &unpackSize);
|
rlm@1
|
757 }
|
rlm@1
|
758 }
|
rlm@1
|
759 else
|
rlm@1
|
760 res = S_FALSE;
|
rlm@1
|
761 }
|
rlm@1
|
762 }
|
rlm@1
|
763 catch(const COutBufferException &e) { res = e.ErrorCode; if (res != S_OK) res = E_FAIL; }
|
rlm@1
|
764 catch(...) { res = E_FAIL; }
|
rlm@1
|
765 if (res != S_OK)
|
rlm@1
|
766 {
|
rlm@1
|
767 Decoder->Result2 = res;
|
rlm@1
|
768 Decoder->StreamWasFinished2 = true;
|
rlm@1
|
769 }
|
rlm@1
|
770 Decoder->m_States[nextBlockIndex].CanWriteEvent.Set();
|
rlm@1
|
771 if (res != S_OK || needFinish)
|
rlm@1
|
772 {
|
rlm@1
|
773 StreamWasFinishedEvent.Set();
|
rlm@1
|
774 Decoder->CanStartWaitingEvent.Lock();
|
rlm@1
|
775 WaitingWasStartedEvent.Set();
|
rlm@1
|
776 }
|
rlm@1
|
777 }
|
rlm@1
|
778 }
|
rlm@1
|
779
|
rlm@1
|
780 STDMETHODIMP CDecoder::SetNumberOfThreads(UInt32 numThreads)
|
rlm@1
|
781 {
|
rlm@1
|
782 NumThreads = numThreads;
|
rlm@1
|
783 if (NumThreads < 1)
|
rlm@1
|
784 NumThreads = 1;
|
rlm@1
|
785 if (NumThreads > kNumThreadsMax)
|
rlm@1
|
786 NumThreads = kNumThreadsMax;
|
rlm@1
|
787 return S_OK;
|
rlm@1
|
788 }
|
rlm@1
|
789 #endif
|
rlm@1
|
790
|
rlm@1
|
791 }}
|