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