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