• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Bcj2Coder.cpp
2 
3 #include "StdAfx.h"
4 
5 // #include <stdio.h>
6 
7 #include "../../../C/Alloc.h"
8 
9 #include "../Common/StreamUtils.h"
10 
11 #include "Bcj2Coder.h"
12 
13 namespace NCompress {
14 namespace NBcj2 {
15 
CBaseCoder()16 CBaseCoder::CBaseCoder()
17 {
18   for (unsigned i = 0; i < BCJ2_NUM_STREAMS + 1; i++)
19   {
20     _bufs[i] = NULL;
21     _bufsSizes[i] = 0;
22     _bufsSizes_New[i] = (1 << 18);
23   }
24 }
25 
~CBaseCoder()26 CBaseCoder::~CBaseCoder()
27 {
28   for (unsigned i = 0; i < BCJ2_NUM_STREAMS + 1; i++)
29     ::MidFree(_bufs[i]);
30 }
31 
Alloc(bool allocForOrig)32 HRESULT CBaseCoder::Alloc(bool allocForOrig)
33 {
34   const unsigned num = allocForOrig ? BCJ2_NUM_STREAMS + 1 : BCJ2_NUM_STREAMS;
35   for (unsigned i = 0; i < num; i++)
36   {
37     UInt32 size = _bufsSizes_New[i];
38     /* buffer sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP streams
39        must be aligned for 4 */
40     size &= ~(UInt32)3;
41     const UInt32 kMinBufSize = 4;
42     if (size < kMinBufSize)
43       size = kMinBufSize;
44     // size = 4 * 100; // for debug
45     // if (BCJ2_IS_32BIT_STREAM(i) == 1) size = 4 * 1; // for debug
46     if (!_bufs[i] || size != _bufsSizes[i])
47     {
48       if (_bufs[i])
49       {
50         ::MidFree(_bufs[i]);
51         _bufs[i] = NULL;
52       }
53       _bufsSizes[i] = 0;
54       Byte *buf = (Byte *)::MidAlloc(size);
55       if (!buf)
56         return E_OUTOFMEMORY;
57       _bufs[i] = buf;
58       _bufsSizes[i] = size;
59     }
60   }
61   return S_OK;
62 }
63 
64 
65 
66 #ifndef Z7_EXTRACT_ONLY
67 
CEncoder()68 CEncoder::CEncoder():
69     _relatLim(BCJ2_ENC_RELAT_LIMIT_DEFAULT)
70     // , _excludeRangeBits(BCJ2_RELAT_EXCLUDE_NUM_BITS)
71     {}
~CEncoder()72 CEncoder::~CEncoder() {}
73 
Z7_COM7F_IMF(CEncoder::SetInBufSize (UInt32,UInt32 size))74 Z7_COM7F_IMF(CEncoder::SetInBufSize(UInt32, UInt32 size))
75   { _bufsSizes_New[BCJ2_NUM_STREAMS] = size; return S_OK; }
Z7_COM7F_IMF(CEncoder::SetOutBufSize (UInt32 streamIndex,UInt32 size))76 Z7_COM7F_IMF(CEncoder::SetOutBufSize(UInt32 streamIndex, UInt32 size))
77   { _bufsSizes_New[streamIndex] = size; return S_OK; }
78 
Z7_COM7F_IMF(CEncoder::SetCoderProperties (const PROPID * propIDs,const PROPVARIANT * props,UInt32 numProps))79 Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps))
80 {
81   UInt32 relatLim = BCJ2_ENC_RELAT_LIMIT_DEFAULT;
82   // UInt32 excludeRangeBits = BCJ2_RELAT_EXCLUDE_NUM_BITS;
83   for (UInt32 i = 0; i < numProps; i++)
84   {
85     const PROPVARIANT &prop = props[i];
86     const PROPID propID = propIDs[i];
87     if (propID >= NCoderPropID::kReduceSize
88         // && propID != NCoderPropID::kHashBits
89         )
90       continue;
91     switch (propID)
92     {
93       /*
94       case NCoderPropID::kDefaultProp:
95       {
96         if (prop.vt != VT_UI4)
97           return E_INVALIDARG;
98         UInt32 v = prop.ulVal;
99         if (v > 31)
100           return E_INVALIDARG;
101         relatLim = (UInt32)1 << v;
102         break;
103       }
104       case NCoderPropID::kHashBits:
105       {
106         if (prop.vt != VT_UI4)
107           return E_INVALIDARG;
108         UInt32 v = prop.ulVal;
109         if (v > 31)
110           return E_INVALIDARG;
111         excludeRangeBits = v;
112         break;
113       }
114       */
115       case NCoderPropID::kDictionarySize:
116       {
117         if (prop.vt != VT_UI4)
118           return E_INVALIDARG;
119         relatLim = prop.ulVal;
120         if (relatLim > BCJ2_ENC_RELAT_LIMIT_MAX)
121           return E_INVALIDARG;
122         break;
123       }
124       case NCoderPropID::kNumThreads:
125       case NCoderPropID::kLevel:
126         continue;
127       default: return E_INVALIDARG;
128     }
129   }
130   _relatLim = relatLim;
131   // _excludeRangeBits = excludeRangeBits;
132   return S_OK;
133 }
134 
135 
CodeReal(ISequentialInStream * const * inStreams,const UInt64 * const * inSizes,UInt32 numInStreams,ISequentialOutStream * const * outStreams,const UInt64 * const *,UInt32 numOutStreams,ICompressProgressInfo * progress)136 HRESULT CEncoder::CodeReal(
137     ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
138     ISequentialOutStream * const *outStreams, const UInt64 * const * /* outSizes */, UInt32 numOutStreams,
139     ICompressProgressInfo *progress)
140 {
141   if (numInStreams != 1 || numOutStreams != BCJ2_NUM_STREAMS)
142     return E_INVALIDARG;
143 
144   RINOK(Alloc())
145 
146   CBcj2Enc_ip_unsigned fileSize_minus1 = BCJ2_ENC_FileSizeField_UNLIMITED;
147   if (inSizes && inSizes[0])
148   {
149     const UInt64 inSize = *inSizes[0];
150    #ifdef BCJ2_ENC_FileSize_MAX
151     if (inSize <= BCJ2_ENC_FileSize_MAX)
152    #endif
153       fileSize_minus1 = BCJ2_ENC_GET_FileSizeField_VAL_FROM_FileSize(inSize);
154   }
155 
156   Z7_DECL_CMyComPtr_QI_FROM(ICompressGetSubStreamSize, getSubStreamSize, inStreams[0])
157 
158   CBcj2Enc enc;
159   enc.src = _bufs[BCJ2_NUM_STREAMS];
160   enc.srcLim = enc.src;
161   {
162     for (unsigned i = 0; i < BCJ2_NUM_STREAMS; i++)
163     {
164       enc.bufs[i] = _bufs[i];
165       enc.lims[i] = _bufs[i] + _bufsSizes[i];
166     }
167   }
168   Bcj2Enc_Init(&enc);
169   enc.fileIp64 = 0;
170   enc.fileSize64_minus1 = fileSize_minus1;
171   enc.relatLimit = _relatLim;
172   // enc.relatExcludeBits = _excludeRangeBits;
173   enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
174 
175   // Varibales that correspond processed data in input stream:
176   UInt64 inPos_without_Temp = 0;  // it doesn't include data in enc.temp[]
177   UInt64 inPos_with_Temp = 0;     // it        includes data in enc.temp[]
178 
179   UInt64 prevProgress = 0;
180   UInt64 totalRead = 0;  // size read from input stream
181   UInt64 outSizeRc = 0;
182   UInt64 subStream_Index = 0;
183   UInt64 subStream_StartPos = 0; // global start offset of subStreams[subStream_Index]
184   UInt64 subStream_Size = 0;
185   const Byte *srcLim_Read = _bufs[BCJ2_NUM_STREAMS];
186   bool readWasFinished = false;
187   bool isAccurate = false;
188   bool wasUnknownSize = false;
189 
190   for (;;)
191   {
192     if (readWasFinished && enc.srcLim == srcLim_Read)
193       enc.finishMode = BCJ2_ENC_FINISH_MODE_END_STREAM;
194 
195     // for debug:
196     // for (int y=0;y<100;y++) { CBcj2Enc enc2 = enc; Bcj2Enc_Encode(&enc2); }
197 
198     Bcj2Enc_Encode(&enc);
199 
200     inPos_with_Temp = totalRead - (size_t)(srcLim_Read - enc.src);
201     inPos_without_Temp = inPos_with_Temp - Bcj2Enc_Get_AvailInputSize_in_Temp(&enc);
202 
203     // if (inPos_without_Temp != enc.ip64) return E_FAIL;
204 
205     if (Bcj2Enc_IsFinished(&enc))
206       break;
207 
208     if (enc.state < BCJ2_NUM_STREAMS)
209     {
210       if (enc.bufs[enc.state] != enc.lims[enc.state])
211         return E_FAIL;
212       const size_t curSize = (size_t)(enc.bufs[enc.state] - _bufs[enc.state]);
213       // printf("Write stream = %2d %6d\n", enc.state, curSize);
214       RINOK(WriteStream(outStreams[enc.state], _bufs[enc.state], curSize))
215       if (enc.state == BCJ2_STREAM_RC)
216         outSizeRc += curSize;
217       enc.bufs[enc.state] = _bufs[enc.state];
218       enc.lims[enc.state] = _bufs[enc.state] + _bufsSizes[enc.state];
219     }
220     else
221     {
222       if (enc.state != BCJ2_ENC_STATE_ORIG)
223         return E_FAIL;
224       // (enc.state == BCJ2_ENC_STATE_ORIG)
225       if (enc.src != enc.srcLim)
226         return E_FAIL;
227       if (enc.finishMode != BCJ2_ENC_FINISH_MODE_CONTINUE
228           && Bcj2Enc_Get_AvailInputSize_in_Temp(&enc) != 0)
229         return E_FAIL;
230 
231       if (enc.src == srcLim_Read)
232       {
233         if (readWasFinished)
234           return E_FAIL;
235         UInt32 curSize = _bufsSizes[BCJ2_NUM_STREAMS];
236         RINOK(inStreams[0]->Read(_bufs[BCJ2_NUM_STREAMS], curSize, &curSize))
237         // printf("Read %6u bytes\n", curSize);
238         if (curSize == 0)
239           readWasFinished = true;
240         totalRead += curSize;
241         enc.src     = _bufs[BCJ2_NUM_STREAMS];
242         srcLim_Read = _bufs[BCJ2_NUM_STREAMS] + curSize;
243       }
244       enc.srcLim = srcLim_Read;
245 
246       if (getSubStreamSize)
247       {
248         /* we set base default conversions options that will be used,
249            if subStream related options will be not OK */
250         enc.fileIp64 = 0;
251         enc.fileSize64_minus1 = fileSize_minus1;
252         for (;;)
253         {
254           UInt64 nextPos;
255           if (isAccurate)
256             nextPos = subStream_StartPos + subStream_Size;
257           else
258           {
259             const HRESULT hres = getSubStreamSize->GetSubStreamSize(subStream_Index, &subStream_Size);
260             if (hres != S_OK)
261             {
262               enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
263               /* if sub-stream size is unknown, we use default settings.
264                  We still can recover to normal mode for next sub-stream,
265                  if GetSubStreamSize() will return S_OK, when current
266                  sub-stream will be finished.
267               */
268               if (hres == S_FALSE)
269               {
270                 wasUnknownSize = true;
271                 break;
272               }
273               if (hres == E_NOTIMPL)
274               {
275                 getSubStreamSize.Release();
276                 break;
277               }
278               return hres;
279             }
280             // printf("GetSubStreamSize %6u : %6u \n", (unsigned)subStream_Index, (unsigned)subStream_Size);
281             nextPos = subStream_StartPos + subStream_Size;
282             if ((Int64)subStream_Size == -1)
283             {
284               /* it's not expected, but (-1) can mean unknown size. */
285               enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
286               wasUnknownSize = true;
287               break;
288             }
289             if (nextPos < subStream_StartPos)
290               return E_FAIL;
291             isAccurate =
292                  (nextPos <  totalRead
293               || (nextPos <= totalRead && readWasFinished));
294           }
295 
296           /* (nextPos) is estimated end position of current sub_stream.
297              But only (totalRead) and (readWasFinished) values
298              can confirm that this estimated end position is accurate.
299              That end position is accurate, if it can't be changed in
300              further calls of GetSubStreamSize() */
301 
302           /* (nextPos < inPos_with_Temp) is unexpected case here, that we
303                can get if from some incorrect ICompressGetSubStreamSize object,
304                where new GetSubStreamSize() call returns smaller size than
305                confirmed by Read() size from previous GetSubStreamSize() call.
306           */
307           if (nextPos < inPos_with_Temp)
308           {
309             if (wasUnknownSize)
310             {
311               /* that case can be complicated for recovering.
312                  so we disable sub-streams requesting. */
313               enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
314               getSubStreamSize.Release();
315               break;
316             }
317             return E_FAIL; // to stop after failure
318           }
319 
320           if (nextPos <= inPos_with_Temp)
321           {
322             // (nextPos == inPos_with_Temp)
323             /* CBcj2Enc encoder requires to finish each [non-empty] block (sub-stream)
324                   with BCJ2_ENC_FINISH_MODE_END_BLOCK
325                or with BCJ2_ENC_FINISH_MODE_END_STREAM for last block:
326                And we send data of new block to CBcj2Enc, only if previous block was finished.
327                So we switch to next sub-stream if after Bcj2Enc_Encode() call we have
328                  && (enc.finishMode != BCJ2_ENC_FINISH_MODE_CONTINUE)
329                  && (nextPos == inPos_with_Temp)
330                  && (enc.state == BCJ2_ENC_STATE_ORIG)
331             */
332             if (enc.finishMode != BCJ2_ENC_FINISH_MODE_CONTINUE)
333             {
334               /* subStream_StartPos is increased only here.
335                    (subStream_StartPos == inPos_with_Temp) : at start
336                    (subStream_StartPos <= inPos_with_Temp) : will be later
337               */
338               subStream_StartPos = nextPos;
339               subStream_Size = 0;
340               wasUnknownSize = false;
341               subStream_Index++;
342               isAccurate = false;
343               // we don't change finishMode here
344               continue;
345             }
346           }
347 
348           enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
349           /* for (!isAccurate) case:
350              (totalRead <= real_end_of_subStream)
351              so we can use BCJ2_ENC_FINISH_MODE_CONTINUE up to (totalRead)
352              // we don't change settings at the end of substream, if settings were unknown,
353           */
354 
355           /* if (wasUnknownSize) then we can't trust size of that sub-stream.
356              so we use default settings instead */
357           if (!wasUnknownSize)
358          #ifdef BCJ2_ENC_FileSize_MAX
359           if (subStream_Size <= BCJ2_ENC_FileSize_MAX)
360          #endif
361           {
362             enc.fileIp64 =
363                 (CBcj2Enc_ip_unsigned)(
364                 (CBcj2Enc_ip_signed)enc.ip64 +
365                 (CBcj2Enc_ip_signed)(subStream_StartPos - inPos_without_Temp));
366             Bcj2Enc_SET_FileSize(&enc, subStream_Size)
367           }
368 
369           if (isAccurate)
370           {
371             /* (real_end_of_subStream == nextPos <= totalRead)
372                So we can use BCJ2_ENC_FINISH_MODE_END_BLOCK up to (nextPos). */
373             const size_t rem = (size_t)(totalRead - nextPos);
374             if ((size_t)(enc.srcLim - enc.src) < rem)
375               return E_FAIL;
376             enc.srcLim -= rem;
377             enc.finishMode = BCJ2_ENC_FINISH_MODE_END_BLOCK;
378           }
379 
380           break;
381         } // for() loop
382       } // getSubStreamSize
383     }
384 
385     if (progress && inPos_without_Temp - prevProgress >= (1 << 22))
386     {
387       prevProgress = inPos_without_Temp;
388       const UInt64 outSize2 = inPos_without_Temp + outSizeRc +
389           (size_t)(enc.bufs[BCJ2_STREAM_RC] - _bufs[BCJ2_STREAM_RC]);
390       // printf("progress %8u, %8u\n", (unsigned)inSize2, (unsigned)outSize2);
391       RINOK(progress->SetRatioInfo(&inPos_without_Temp, &outSize2))
392     }
393   }
394 
395   for (unsigned i = 0; i < BCJ2_NUM_STREAMS; i++)
396   {
397     RINOK(WriteStream(outStreams[i], _bufs[i], (size_t)(enc.bufs[i] - _bufs[i])))
398   }
399   // if (inPos_without_Temp != subStream_StartPos + subStream_Size) return E_FAIL;
400   return S_OK;
401 }
402 
403 
Z7_COM7F_IMF(CEncoder::Code (ISequentialInStream * const * inStreams,const UInt64 * const * inSizes,UInt32 numInStreams,ISequentialOutStream * const * outStreams,const UInt64 * const * outSizes,UInt32 numOutStreams,ICompressProgressInfo * progress))404 Z7_COM7F_IMF(CEncoder::Code(
405     ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
406     ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
407     ICompressProgressInfo *progress))
408 {
409   try
410   {
411     return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress);
412   }
413   catch(...) { return E_FAIL; }
414 }
415 
416 #endif
417 
418 
419 
420 
421 
422 
CDecoder()423 CDecoder::CDecoder():
424     _finishMode(false)
425 #ifndef Z7_NO_READ_FROM_CODER
426     , _outSizeDefined(false)
427     , _outSize(0)
428     , _outSize_Processed(0)
429 #endif
430 {}
431 
Z7_COM7F_IMF(CDecoder::SetInBufSize (UInt32 streamIndex,UInt32 size))432 Z7_COM7F_IMF(CDecoder::SetInBufSize(UInt32 streamIndex, UInt32 size))
433   { _bufsSizes_New[streamIndex] = size; return S_OK; }
Z7_COM7F_IMF(CDecoder::SetOutBufSize (UInt32,UInt32 size))434 Z7_COM7F_IMF(CDecoder::SetOutBufSize(UInt32, UInt32 size))
435   { _bufsSizes_New[BCJ2_NUM_STREAMS] = size; return S_OK; }
436 
Z7_COM7F_IMF(CDecoder::SetFinishMode (UInt32 finishMode))437 Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode))
438 {
439   _finishMode = (finishMode != 0);
440   return S_OK;
441 }
442 
InitCommon()443 void CBaseDecoder::InitCommon()
444 {
445   for (unsigned i = 0; i < BCJ2_NUM_STREAMS; i++)
446   {
447     dec.lims[i] = dec.bufs[i] = _bufs[i];
448     _readRes[i] = S_OK;
449     _extraSizes[i] = 0;
450     _readSizes[i] = 0;
451   }
452   Bcj2Dec_Init(&dec);
453 }
454 
455 
456 /* call ReadInStream() only after Bcj2Dec_Decode().
457    input requirement:
458       (dec.state < BCJ2_NUM_STREAMS)
459 */
ReadInStream(ISequentialInStream * inStream)460 void CBaseDecoder::ReadInStream(ISequentialInStream *inStream)
461 {
462   const unsigned state = dec.state;
463   UInt32 total;
464   {
465     Byte *buf = _bufs[state];
466     const Byte *cur = dec.bufs[state];
467     // if (cur != dec.lims[state]) throw 1; // unexpected case
468     dec.lims[state] =
469     dec.bufs[state] = buf;
470     total = (UInt32)_extraSizes[state];
471     for (UInt32 i = 0; i < total; i++)
472       buf[i] = cur[i];
473   }
474 
475   if (_readRes[state] != S_OK)
476     return;
477 
478   do
479   {
480     UInt32 curSize = _bufsSizes[state] - total;
481     // if (state == 0) curSize = 0; // for debug
482     // curSize = 7; // for debug
483     /* even if we have reached provided inSizes[state] limit,
484        we call Read() with (curSize != 0), because
485        we want the called handler of stream->Read() could
486        execute required Init/Flushing code even for empty stream.
487        In another way we could call Read() with (curSize == 0) for
488        finished streams, but some Read() handlers can ignore Read(size=0) calls.
489     */
490     const HRESULT hres = inStream->Read(_bufs[state] + total, curSize, &curSize);
491     _readRes[state] = hres;
492     if (curSize == 0)
493       break;
494     _readSizes[state] += curSize;
495     total += curSize;
496     if (hres != S_OK)
497       break;
498   }
499   while (total < 4 && BCJ2_IS_32BIT_STREAM(state));
500 
501   /* we exit from decoding loop here, if we can't
502      provide new data for input stream.
503      Usually it's normal exit after full stream decoding. */
504   if (total == 0)
505     return;
506 
507   if (BCJ2_IS_32BIT_STREAM(state))
508   {
509     const unsigned extra = ((unsigned)total & 3);
510     _extraSizes[state] = extra;
511     if (total < 4)
512     {
513       if (_readRes[state] == S_OK)
514         _readRes[state] = S_FALSE; // actually it's stream error. So maybe we need another error code.
515       return;
516     }
517     total -= extra;
518   }
519 
520   dec.lims[state] += total; // = _bufs[state] + total;
521 }
522 
523 
Z7_COM7F_IMF(CDecoder::Code (ISequentialInStream * const * inStreams,const UInt64 * const * inSizes,UInt32 numInStreams,ISequentialOutStream * const * outStreams,const UInt64 * const * outSizes,UInt32 numOutStreams,ICompressProgressInfo * progress))524 Z7_COM7F_IMF(CDecoder::Code(
525     ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
526     ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
527     ICompressProgressInfo *progress))
528 {
529   if (numInStreams != BCJ2_NUM_STREAMS || numOutStreams != 1)
530     return E_INVALIDARG;
531 
532   RINOK(Alloc())
533   InitCommon();
534 
535   dec.destLim = dec.dest = _bufs[BCJ2_NUM_STREAMS];
536 
537   UInt64 outSizeWritten = 0;
538   UInt64 prevProgress = 0;
539 
540   HRESULT hres_Crit = S_OK;  // critical hres status (mostly from input stream reading)
541   HRESULT hres_Weak = S_OK;  // first non-critical error code from input stream reading
542 
543   for (;;)
544   {
545     if (Bcj2Dec_Decode(&dec) != SZ_OK)
546     {
547       /* it's possible only at start (first 5 bytes in RC stream) */
548       hres_Crit = S_FALSE;
549       break;
550     }
551     if (dec.state < BCJ2_NUM_STREAMS)
552     {
553       ReadInStream(inStreams[dec.state]);
554       const unsigned state = dec.state;
555       const HRESULT hres = _readRes[state];
556       if (dec.lims[state] == _bufs[state])
557       {
558         // we break decoding, if there are no new data in input stream
559         hres_Crit = hres;
560         break;
561       }
562       if (hres != S_OK && hres_Weak == S_OK)
563         hres_Weak = hres;
564     }
565     else  // (BCJ2_DEC_STATE_ORIG_0 <= state <= BCJ2_STATE_ORIG)
566     {
567       {
568         const size_t curSize = (size_t)(dec.dest - _bufs[BCJ2_NUM_STREAMS]);
569         if (curSize != 0)
570         {
571           outSizeWritten += curSize;
572           RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize))
573         }
574       }
575       {
576         UInt32 rem = _bufsSizes[BCJ2_NUM_STREAMS];
577         if (outSizes && outSizes[0])
578         {
579           const UInt64 outSize = *outSizes[0] - outSizeWritten;
580           if (rem > outSize)
581             rem = (UInt32)outSize;
582         }
583         dec.dest = _bufs[BCJ2_NUM_STREAMS];
584         dec.destLim = dec.dest + rem;
585         /* we exit from decoding loop here,
586            if (outSizes[0]) limit for output stream was reached */
587         if (rem == 0)
588           break;
589       }
590     }
591 
592     if (progress)
593     {
594       // here we don't count additional data in dec.temp (up to 4 bytes for output stream)
595       const UInt64 processed = outSizeWritten + (size_t)(dec.dest - _bufs[BCJ2_NUM_STREAMS]);
596       if (processed - prevProgress >= (1 << 24))
597       {
598         prevProgress = processed;
599         const UInt64 inSize = processed +
600             _readSizes[BCJ2_STREAM_RC] - (size_t)(
601               dec.lims[BCJ2_STREAM_RC] -
602               dec.bufs[BCJ2_STREAM_RC]);
603         RINOK(progress->SetRatioInfo(&inSize, &prevProgress))
604       }
605     }
606   }
607 
608   {
609     const size_t curSize = (size_t)(dec.dest - _bufs[BCJ2_NUM_STREAMS]);
610     if (curSize != 0)
611     {
612       outSizeWritten += curSize;
613       RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize))
614     }
615   }
616 
617   if (hres_Crit == S_OK) hres_Crit = hres_Weak;
618   if (hres_Crit != S_OK) return hres_Crit;
619 
620   if (_finishMode)
621   {
622     if (!Bcj2Dec_IsMaybeFinished_code(&dec))
623       return S_FALSE;
624 
625     /* here we support two correct ways to finish full stream decoding
626        with one of the following conditions:
627           - the end of input  stream MAIN was reached
628           - the end of output stream ORIG was reached
629        Currently 7-Zip/7z code ends with (state == BCJ2_STREAM_MAIN),
630        because the sizes of MAIN and ORIG streams are known and these
631        sizes are stored in 7z archive headers.
632        And Bcj2Dec_Decode() exits with (state == BCJ2_STREAM_MAIN),
633        if both MAIN and ORIG streams have reached buffers limits.
634        But if the size of MAIN stream is not known or if the
635        size of MAIN stream includes some padding after payload data,
636        then we still can correctly finish decoding with
637        (state == BCJ2_DEC_STATE_ORIG), if we know the exact size
638        of output ORIG stream.
639     */
640     if (dec.state != BCJ2_STREAM_MAIN)
641     if (dec.state != BCJ2_DEC_STATE_ORIG)
642       return S_FALSE;
643 
644     /* the caller also will know written size.
645        So the following check is optional: */
646     if (outSizes && outSizes[0] && *outSizes[0] != outSizeWritten)
647       return S_FALSE;
648 
649     if (inSizes)
650     {
651       for (unsigned i = 0; i < BCJ2_NUM_STREAMS; i++)
652       {
653         /* if (inSizes[i]) is defined, we do full check for processed stream size. */
654         if (inSizes[i] && *inSizes[i] != GetProcessedSize_ForInStream(i))
655           return S_FALSE;
656       }
657     }
658   }
659 
660   return S_OK;
661 }
662 
663 
Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize2 (UInt32 streamIndex,UInt64 * value))664 Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize2(UInt32 streamIndex, UInt64 *value))
665 {
666   *value = GetProcessedSize_ForInStream(streamIndex);
667   return S_OK;
668 }
669 
670 
671 #ifndef Z7_NO_READ_FROM_CODER
672 
Z7_COM7F_IMF(CDecoder::SetInStream2 (UInt32 streamIndex,ISequentialInStream * inStream))673 Z7_COM7F_IMF(CDecoder::SetInStream2(UInt32 streamIndex, ISequentialInStream *inStream))
674 {
675   _inStreams[streamIndex] = inStream;
676   return S_OK;
677 }
678 
Z7_COM7F_IMF(CDecoder::ReleaseInStream2 (UInt32 streamIndex))679 Z7_COM7F_IMF(CDecoder::ReleaseInStream2(UInt32 streamIndex))
680 {
681   _inStreams[streamIndex].Release();
682   return S_OK;
683 }
684 
Z7_COM7F_IMF(CDecoder::SetOutStreamSize (const UInt64 * outSize))685 Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize))
686 {
687   _outSizeDefined = (outSize != NULL);
688   _outSize = 0;
689   if (_outSizeDefined)
690     _outSize = *outSize;
691   _outSize_Processed = 0;
692 
693   const HRESULT res = Alloc(false); // allocForOrig
694   InitCommon();
695   dec.destLim = dec.dest = NULL;
696   return res;
697 }
698 
699 
Z7_COM7F_IMF(CDecoder::Read (void * data,UInt32 size,UInt32 * processedSize))700 Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize))
701 {
702   if (processedSize)
703     *processedSize = 0;
704 
705   /* Note the case:
706      The output (ORIG) stream can be empty.
707      But BCJ2_STREAM_RC stream always is not empty.
708      And we want to support full data processing for all streams.
709      We disable check (size == 0) here.
710      So if the caller calls this CDecoder::Read() with (size == 0),
711      we execute required Init/Flushing code in this CDecoder object.
712      Also this CDecoder::Read() function will call Read() for input streams.
713      So the handlers of input streams objects also can do Init/Flushing.
714   */
715   // if (size == 0) return S_OK;  // disabled to allow (size == 0) processing
716 
717   UInt32 totalProcessed = 0;
718 
719   if (_outSizeDefined)
720   {
721     const UInt64 rem = _outSize - _outSize_Processed;
722     if (size > rem)
723       size = (UInt32)rem;
724   }
725   dec.dest = (Byte *)data;
726   dec.destLim = (const Byte *)data + size;
727 
728   HRESULT res = S_OK;
729 
730   for (;;)
731   {
732     if (Bcj2Dec_Decode(&dec) != SZ_OK)
733       return S_FALSE;  // this error can be only at start of stream
734     {
735       const UInt32 curSize = (UInt32)(size_t)(dec.dest - (Byte *)data);
736       if (curSize != 0)
737       {
738         data = (void *)((Byte *)data + curSize);
739         size -= curSize;
740         _outSize_Processed += curSize;
741         totalProcessed += curSize;
742         if (processedSize)
743           *processedSize = totalProcessed;
744       }
745     }
746     if (dec.state >= BCJ2_NUM_STREAMS)
747       break;
748     ReadInStream(_inStreams[dec.state]);
749     if (dec.lims[dec.state] == _bufs[dec.state])
750     {
751       /* we break decoding, if there are no new data in input stream.
752          and we ignore error code, if some data were written to output buffer. */
753       if (totalProcessed == 0)
754         res = _readRes[dec.state];
755       break;
756     }
757   }
758 
759   if (res == S_OK)
760   if (_finishMode && _outSizeDefined && _outSize == _outSize_Processed)
761   {
762     if (!Bcj2Dec_IsMaybeFinished_code(&dec))
763       return S_FALSE;
764     if (dec.state != BCJ2_STREAM_MAIN)
765     if (dec.state != BCJ2_DEC_STATE_ORIG)
766       return S_FALSE;
767   }
768 
769   return res;
770 }
771 
772 #endif
773 
774 }}
775 
776 
777 /*
778 extern "C"
779 {
780 extern UInt32 bcj2_stats[256 + 2][2];
781 }
782 
783 static class CBcj2Stat
784 {
785 public:
786   ~CBcj2Stat()
787   {
788     printf("\nBCJ2 stat:");
789     unsigned sums[2] = { 0, 0 };
790     int i;
791     for (i = 2; i < 256 + 2; i++)
792     {
793       sums[0] += bcj2_stats[i][0];
794       sums[1] += bcj2_stats[i][1];
795     }
796     const unsigned sums2 = sums[0] + sums[1];
797     for (int vi = 0; vi < 256 + 3; vi++)
798     {
799       printf("\n");
800       UInt32 n0, n1;
801       if (vi < 4)
802         printf("\n");
803 
804       if (vi < 2)
805         i = vi;
806       else if (vi == 2)
807         i = -1;
808       else
809         i = vi - 1;
810 
811       if (i < 0)
812       {
813         n0 = sums[0];
814         n1 = sums[1];
815         printf("calls   :");
816       }
817       else
818       {
819         if (i == 0)
820           printf("jcc     :");
821         else if (i == 1)
822           printf("jump    :");
823         else
824           printf("call %02x :", i - 2);
825         n0 = bcj2_stats[i][0];
826         n1 = bcj2_stats[i][1];
827       }
828 
829       const UInt32 sum = n0 + n1;
830       printf(" %10u", sum);
831 
832     #define PRINT_PERC(val, sum) \
833         { UInt32 _sum  = sum; if (_sum == 0) _sum = 1; \
834         printf(" %7.3f %%", (double)((double)val * (double)100 / (double)_sum )); }
835 
836       if (i >= 2 || i < 0)
837       {
838         PRINT_PERC(sum, sums2);
839       }
840       else
841         printf("%10s", "");
842 
843       printf(" :%10u", n0);
844       PRINT_PERC(n0, sum);
845 
846       printf(" :%10u", n1);
847       PRINT_PERC(n1, sum);
848     }
849     printf("\n\n");
850     fflush(stdout);
851   }
852 } g_CBcjStat;
853 */
854