• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Bcj2Coder.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../C/Alloc.h"
6 
7 #include "../Common/StreamUtils.h"
8 
9 #include "Bcj2Coder.h"
10 
11 namespace NCompress {
12 namespace NBcj2 {
13 
CBaseCoder()14 CBaseCoder::CBaseCoder()
15 {
16   for (int i = 0; i < BCJ2_NUM_STREAMS + 1; i++)
17   {
18     _bufs[i] = NULL;
19     _bufsCurSizes[i] = 0;
20     _bufsNewSizes[i] = (1 << 18);
21   }
22 }
23 
~CBaseCoder()24 CBaseCoder::~CBaseCoder()
25 {
26   for (int i = 0; i < BCJ2_NUM_STREAMS + 1; i++)
27     ::MidFree(_bufs[i]);
28 }
29 
Alloc(bool allocForOrig)30 HRESULT CBaseCoder::Alloc(bool allocForOrig)
31 {
32   unsigned num = allocForOrig ? BCJ2_NUM_STREAMS + 1 : BCJ2_NUM_STREAMS;
33   for (unsigned i = 0; i < num; i++)
34   {
35     UInt32 newSize = _bufsNewSizes[i];
36     const UInt32 kMinBufSize = 1;
37     if (newSize < kMinBufSize)
38       newSize = kMinBufSize;
39     if (!_bufs[i] || newSize != _bufsCurSizes[i])
40     {
41       if (_bufs[i])
42       {
43         ::MidFree(_bufs[i]);
44         _bufs[i] = 0;
45       }
46       _bufsCurSizes[i] = 0;
47       Byte *buf = (Byte *)::MidAlloc(newSize);
48       _bufs[i] = buf;
49       if (!buf)
50         return E_OUTOFMEMORY;
51       _bufsCurSizes[i] = newSize;
52     }
53   }
54   return S_OK;
55 }
56 
57 
58 
59 #ifndef EXTRACT_ONLY
60 
CEncoder()61 CEncoder::CEncoder(): _relatLim(BCJ2_RELAT_LIMIT) {}
~CEncoder()62 CEncoder::~CEncoder() {}
63 
SetInBufSize(UInt32,UInt32 size)64 STDMETHODIMP CEncoder::SetInBufSize(UInt32, UInt32 size) { _bufsNewSizes[BCJ2_NUM_STREAMS] = size; return S_OK; }
SetOutBufSize(UInt32 streamIndex,UInt32 size)65 STDMETHODIMP CEncoder::SetOutBufSize(UInt32 streamIndex, UInt32 size) { _bufsNewSizes[streamIndex] = size; return S_OK; }
66 
SetCoderProperties(const PROPID * propIDs,const PROPVARIANT * props,UInt32 numProps)67 STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
68 {
69   UInt32 relatLim = BCJ2_RELAT_LIMIT;
70 
71   for (UInt32 i = 0; i < numProps; i++)
72   {
73     const PROPVARIANT &prop = props[i];
74     PROPID propID = propIDs[i];
75     if (propID >= NCoderPropID::kReduceSize)
76       continue;
77     switch (propID)
78     {
79       /*
80       case NCoderPropID::kDefaultProp:
81       {
82         if (prop.vt != VT_UI4)
83           return E_INVALIDARG;
84         UInt32 v = prop.ulVal;
85         if (v > 31)
86           return E_INVALIDARG;
87         relatLim = (UInt32)1 << v;
88         break;
89       }
90       */
91       case NCoderPropID::kDictionarySize:
92       {
93         if (prop.vt != VT_UI4)
94           return E_INVALIDARG;
95         relatLim = prop.ulVal;
96         if (relatLim > ((UInt32)1 << 31))
97           return E_INVALIDARG;
98         break;
99       }
100 
101       case NCoderPropID::kNumThreads:
102         continue;
103       case NCoderPropID::kLevel:
104         continue;
105 
106       default: return E_INVALIDARG;
107     }
108   }
109 
110   _relatLim = relatLim;
111 
112   return S_OK;
113 }
114 
115 
CodeReal(ISequentialInStream * const * inStreams,const UInt64 * const * inSizes,UInt32 numInStreams,ISequentialOutStream * const * outStreams,const UInt64 * const *,UInt32 numOutStreams,ICompressProgressInfo * progress)116 HRESULT CEncoder::CodeReal(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
117     ISequentialOutStream * const *outStreams, const UInt64 * const * /* outSizes */, UInt32 numOutStreams,
118     ICompressProgressInfo *progress)
119 {
120   if (numInStreams != 1 || numOutStreams != BCJ2_NUM_STREAMS)
121     return E_INVALIDARG;
122 
123   RINOK(Alloc());
124 
125   UInt32 fileSize_for_Conv = 0;
126   if (inSizes && inSizes[0])
127   {
128     UInt64 inSize = *inSizes[0];
129     if (inSize <= BCJ2_FileSize_MAX)
130       fileSize_for_Conv = (UInt32)inSize;
131   }
132 
133   CMyComPtr<ICompressGetSubStreamSize> getSubStreamSize;
134   inStreams[0]->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStreamSize);
135 
136   CBcj2Enc enc;
137 
138   enc.src = _bufs[BCJ2_NUM_STREAMS];
139   enc.srcLim = enc.src;
140 
141   {
142     for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
143     {
144       enc.bufs[i] = _bufs[i];
145       enc.lims[i] = _bufs[i] + _bufsCurSizes[i];
146     }
147   }
148 
149   size_t numBytes_in_ReadBuf = 0;
150   UInt64 prevProgress = 0;
151   UInt64 totalStreamRead = 0; // size read from InputStream
152   UInt64 currentInPos = 0; // data that was processed, it doesn't include data in input buffer and data in enc.temp
153   UInt64 outSizeRc = 0;
154 
155   Bcj2Enc_Init(&enc);
156 
157   enc.fileIp = 0;
158   enc.fileSize = fileSize_for_Conv;
159 
160   enc.relatLimit = _relatLim;
161 
162   enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
163 
164   bool needSubSize = false;
165   UInt64 subStreamIndex = 0;
166   UInt64 subStreamStartPos = 0;
167   bool readWasFinished = false;
168 
169   for (;;)
170   {
171     if (needSubSize && getSubStreamSize)
172     {
173       enc.fileIp = 0;
174       enc.fileSize = fileSize_for_Conv;
175       enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
176 
177       for (;;)
178       {
179         UInt64 subStreamSize = 0;
180         HRESULT result = getSubStreamSize->GetSubStreamSize(subStreamIndex, &subStreamSize);
181         needSubSize = false;
182 
183         if (result == S_OK)
184         {
185           UInt64 newEndPos = subStreamStartPos + subStreamSize;
186 
187           bool isAccurateEnd = (newEndPos < totalStreamRead ||
188             (newEndPos <= totalStreamRead && readWasFinished));
189 
190           if (newEndPos <= currentInPos && isAccurateEnd)
191           {
192             subStreamStartPos = newEndPos;
193             subStreamIndex++;
194             continue;
195           }
196 
197           enc.srcLim = _bufs[BCJ2_NUM_STREAMS] + numBytes_in_ReadBuf;
198 
199           if (isAccurateEnd)
200           {
201             // data in enc.temp is possible here
202             size_t rem = (size_t)(totalStreamRead - newEndPos);
203 
204             /* Pos_of(enc.src) <= old newEndPos <= newEndPos
205                in another case, it's fail in some code */
206             if ((size_t)(enc.srcLim - enc.src) < rem)
207               return E_FAIL;
208 
209             enc.srcLim -= rem;
210             enc.finishMode = BCJ2_ENC_FINISH_MODE_END_BLOCK;
211           }
212 
213           if (subStreamSize <= BCJ2_FileSize_MAX)
214           {
215             enc.fileIp = enc.ip + (UInt32)(subStreamStartPos - currentInPos);
216             enc.fileSize = (UInt32)subStreamSize;
217           }
218           break;
219         }
220 
221         if (result == S_FALSE)
222           break;
223         if (result == E_NOTIMPL)
224         {
225           getSubStreamSize.Release();
226           break;
227         }
228         return result;
229       }
230     }
231 
232     if (readWasFinished && totalStreamRead - currentInPos == Bcj2Enc_Get_InputData_Size(&enc))
233       enc.finishMode = BCJ2_ENC_FINISH_MODE_END_STREAM;
234 
235     Bcj2Enc_Encode(&enc);
236 
237     currentInPos = totalStreamRead - numBytes_in_ReadBuf + (enc.src - _bufs[BCJ2_NUM_STREAMS]) - enc.tempPos;
238 
239     if (Bcj2Enc_IsFinished(&enc))
240       break;
241 
242     if (enc.state < BCJ2_NUM_STREAMS)
243     {
244       size_t curSize = enc.bufs[enc.state] - _bufs[enc.state];
245       // printf("Write stream = %2d %6d\n", enc.state, curSize);
246       RINOK(WriteStream(outStreams[enc.state], _bufs[enc.state], curSize));
247       if (enc.state == BCJ2_STREAM_RC)
248         outSizeRc += curSize;
249 
250       enc.bufs[enc.state] = _bufs[enc.state];
251       enc.lims[enc.state] = _bufs[enc.state] + _bufsCurSizes[enc.state];
252     }
253     else if (enc.state != BCJ2_ENC_STATE_ORIG)
254       return E_FAIL;
255     else
256     {
257       needSubSize = true;
258 
259       if (numBytes_in_ReadBuf != (size_t)(enc.src - _bufs[BCJ2_NUM_STREAMS]))
260       {
261         enc.srcLim = _bufs[BCJ2_NUM_STREAMS] + numBytes_in_ReadBuf;
262         continue;
263       }
264 
265       if (readWasFinished)
266         continue;
267 
268       numBytes_in_ReadBuf = 0;
269       enc.src    = _bufs[BCJ2_NUM_STREAMS];
270       enc.srcLim = _bufs[BCJ2_NUM_STREAMS];
271 
272       UInt32 curSize = _bufsCurSizes[BCJ2_NUM_STREAMS];
273       RINOK(inStreams[0]->Read(_bufs[BCJ2_NUM_STREAMS], curSize, &curSize));
274 
275       // printf("Read %6d bytes\n", curSize);
276       if (curSize == 0)
277       {
278         readWasFinished = true;
279         continue;
280       }
281 
282       numBytes_in_ReadBuf = curSize;
283       totalStreamRead += numBytes_in_ReadBuf;
284       enc.srcLim = _bufs[BCJ2_NUM_STREAMS] + numBytes_in_ReadBuf;
285     }
286 
287     if (progress && currentInPos - prevProgress >= (1 << 20))
288     {
289       UInt64 outSize2 = currentInPos + outSizeRc + enc.bufs[BCJ2_STREAM_RC] - enc.bufs[BCJ2_STREAM_RC];
290       prevProgress = currentInPos;
291       // printf("progress %8d, %8d\n", (int)inSize2, (int)outSize2);
292       RINOK(progress->SetRatioInfo(&currentInPos, &outSize2));
293     }
294   }
295 
296   for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
297   {
298     RINOK(WriteStream(outStreams[i], _bufs[i], enc.bufs[i] - _bufs[i]));
299   }
300 
301   // if (currentInPos != subStreamStartPos + subStreamSize) return E_FAIL;
302 
303   return S_OK;
304 }
305 
Code(ISequentialInStream * const * inStreams,const UInt64 * const * inSizes,UInt32 numInStreams,ISequentialOutStream * const * outStreams,const UInt64 * const * outSizes,UInt32 numOutStreams,ICompressProgressInfo * progress)306 STDMETHODIMP CEncoder::Code(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
307     ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
308     ICompressProgressInfo *progress)
309 {
310   try
311   {
312     return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress);
313   }
314   catch(...) { return E_FAIL; }
315 }
316 
317 #endif
318 
319 
320 
321 
322 
323 
SetInBufSize(UInt32 streamIndex,UInt32 size)324 STDMETHODIMP CDecoder::SetInBufSize(UInt32 streamIndex, UInt32 size) { _bufsNewSizes[streamIndex] = size; return S_OK; }
SetOutBufSize(UInt32,UInt32 size)325 STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _bufsNewSizes[BCJ2_NUM_STREAMS] = size; return S_OK; }
326 
CDecoder()327 CDecoder::CDecoder(): _finishMode(false), _outSizeDefined(false), _outSize(0)
328 {}
329 
SetFinishMode(UInt32 finishMode)330 STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)
331 {
332   _finishMode = (finishMode != 0);
333   return S_OK;
334 }
335 
InitCommon()336 void CDecoder::InitCommon()
337 {
338   {
339     for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
340       dec.lims[i] = dec.bufs[i] = _bufs[i];
341   }
342 
343   {
344     for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
345     {
346       _extraReadSizes[i] = 0;
347       _inStreamsProcessed[i] = 0;
348       _readRes[i] = S_OK;
349     }
350   }
351 
352   Bcj2Dec_Init(&dec);
353 }
354 
Code(ISequentialInStream * const * inStreams,const UInt64 * const * inSizes,UInt32 numInStreams,ISequentialOutStream * const * outStreams,const UInt64 * const * outSizes,UInt32 numOutStreams,ICompressProgressInfo * progress)355 HRESULT CDecoder::Code(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
356     ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
357     ICompressProgressInfo *progress)
358 {
359   if (numInStreams != BCJ2_NUM_STREAMS || numOutStreams != 1)
360     return E_INVALIDARG;
361 
362   RINOK(Alloc());
363 
364   InitCommon();
365 
366   dec.destLim = dec.dest = _bufs[BCJ2_NUM_STREAMS];
367 
368   UInt64 outSizeProcessed = 0;
369   UInt64 prevProgress = 0;
370 
371   HRESULT res = S_OK;
372 
373   for (;;)
374   {
375     if (Bcj2Dec_Decode(&dec) != SZ_OK)
376       return S_FALSE;
377 
378     if (dec.state < BCJ2_NUM_STREAMS)
379     {
380       size_t totalRead = _extraReadSizes[dec.state];
381       {
382         Byte *buf = _bufs[dec.state];
383         for (size_t i = 0; i < totalRead; i++)
384           buf[i] = dec.bufs[dec.state][i];
385         dec.lims[dec.state] =
386         dec.bufs[dec.state] = buf;
387       }
388 
389       if (_readRes[dec.state] != S_OK)
390       {
391         res = _readRes[dec.state];
392         break;
393       }
394 
395       do
396       {
397         UInt32 curSize = _bufsCurSizes[dec.state] - (UInt32)totalRead;
398         /*
399         we want to call Read even even if size is 0
400         if (inSizes && inSizes[dec.state])
401         {
402           UInt64 rem = *inSizes[dec.state] - _inStreamsProcessed[dec.state];
403           if (curSize > rem)
404             curSize = (UInt32)rem;
405         }
406         */
407 
408         HRESULT res2 = inStreams[dec.state]->Read(_bufs[dec.state] + totalRead, curSize, &curSize);
409         _readRes[dec.state] = res2;
410         if (curSize == 0)
411           break;
412         _inStreamsProcessed[dec.state] += curSize;
413         totalRead += curSize;
414         if (res2 != S_OK)
415           break;
416       }
417       while (totalRead < 4 && BCJ2_IS_32BIT_STREAM(dec.state));
418 
419       if (_readRes[dec.state] != S_OK)
420         res = _readRes[dec.state];
421 
422       if (totalRead == 0)
423         break;
424 
425       // res == S_OK;
426 
427       if (BCJ2_IS_32BIT_STREAM(dec.state))
428       {
429         unsigned extraSize = ((unsigned)totalRead & 3);
430         _extraReadSizes[dec.state] = extraSize;
431         if (totalRead < 4)
432         {
433           res = (_readRes[dec.state] != S_OK) ? _readRes[dec.state] : S_FALSE;
434           break;
435         }
436         totalRead -= extraSize;
437       }
438 
439       dec.lims[dec.state] = _bufs[dec.state] + totalRead;
440     }
441     else // if (dec.state <= BCJ2_STATE_ORIG)
442     {
443       size_t curSize = dec.dest - _bufs[BCJ2_NUM_STREAMS];
444       if (curSize != 0)
445       {
446         outSizeProcessed += curSize;
447         RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize));
448       }
449       dec.dest = _bufs[BCJ2_NUM_STREAMS];
450       {
451         size_t rem = _bufsCurSizes[BCJ2_NUM_STREAMS];
452         if (outSizes && outSizes[0])
453         {
454           UInt64 outSize = *outSizes[0] - outSizeProcessed;
455           if (rem > outSize)
456             rem = (size_t)outSize;
457         }
458         dec.destLim = dec.dest + rem;
459         if (rem == 0)
460           break;
461       }
462     }
463 
464     if (progress)
465     {
466       const UInt64 outSize2 = outSizeProcessed + (dec.dest - _bufs[BCJ2_NUM_STREAMS]);
467       if (outSize2 - prevProgress >= (1 << 22))
468       {
469         const UInt64 inSize2 = outSize2 + _inStreamsProcessed[BCJ2_STREAM_RC] - (dec.lims[BCJ2_STREAM_RC] - dec.bufs[BCJ2_STREAM_RC]);
470         RINOK(progress->SetRatioInfo(&inSize2, &outSize2));
471         prevProgress = outSize2;
472       }
473     }
474   }
475 
476   size_t curSize = dec.dest - _bufs[BCJ2_NUM_STREAMS];
477   if (curSize != 0)
478   {
479     outSizeProcessed += curSize;
480     RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize));
481   }
482 
483   if (res != S_OK)
484     return res;
485 
486   if (_finishMode)
487   {
488     if (!Bcj2Dec_IsFinished(&dec))
489       return S_FALSE;
490 
491     // we still allow the cases when input streams are larger than required for decoding.
492     // so the case (dec.state == BCJ2_STATE_ORIG) is also allowed, if MAIN stream is larger than required.
493     if (dec.state != BCJ2_STREAM_MAIN &&
494         dec.state != BCJ2_DEC_STATE_ORIG)
495       return S_FALSE;
496 
497     if (inSizes)
498     {
499       for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
500       {
501         size_t rem = dec.lims[i] - dec.bufs[i] + _extraReadSizes[i];
502         /*
503         if (rem != 0)
504           return S_FALSE;
505         */
506         if (inSizes[i] && *inSizes[i] != _inStreamsProcessed[i] - rem)
507           return S_FALSE;
508       }
509     }
510   }
511 
512   return S_OK;
513 }
514 
SetInStream2(UInt32 streamIndex,ISequentialInStream * inStream)515 STDMETHODIMP CDecoder::SetInStream2(UInt32 streamIndex, ISequentialInStream *inStream)
516 {
517   _inStreams[streamIndex] = inStream;
518   return S_OK;
519 }
520 
ReleaseInStream2(UInt32 streamIndex)521 STDMETHODIMP CDecoder::ReleaseInStream2(UInt32 streamIndex)
522 {
523   _inStreams[streamIndex].Release();
524   return S_OK;
525 }
526 
SetOutStreamSize(const UInt64 * outSize)527 STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
528 {
529   _outSizeDefined = (outSize != NULL);
530   _outSize = 0;
531   if (_outSizeDefined)
532     _outSize = *outSize;
533 
534   _outSize_Processed = 0;
535 
536   HRESULT res = Alloc(false);
537 
538   InitCommon();
539   dec.destLim = dec.dest = NULL;
540 
541   return res;
542 }
543 
544 
Read(void * data,UInt32 size,UInt32 * processedSize)545 STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
546 {
547   if (processedSize)
548     *processedSize = 0;
549 
550   if (size == 0)
551     return S_OK;
552 
553   UInt32 totalProcessed = 0;
554 
555   if (_outSizeDefined)
556   {
557     UInt64 rem = _outSize - _outSize_Processed;
558     if (size > rem)
559       size = (UInt32)rem;
560   }
561   dec.dest = (Byte *)data;
562   dec.destLim = (const Byte *)data + size;
563 
564   HRESULT res = S_OK;
565 
566   for (;;)
567   {
568     SRes sres = Bcj2Dec_Decode(&dec);
569     if (sres != SZ_OK)
570       return S_FALSE;
571 
572     {
573       UInt32 curSize = (UInt32)(dec.dest - (Byte *)data);
574       if (curSize != 0)
575       {
576         totalProcessed += curSize;
577         if (processedSize)
578           *processedSize = totalProcessed;
579         data = (void *)((Byte *)data + curSize);
580         size -= curSize;
581         _outSize_Processed += curSize;
582       }
583     }
584 
585     if (dec.state >= BCJ2_NUM_STREAMS)
586       break;
587 
588     {
589       size_t totalRead = _extraReadSizes[dec.state];
590       {
591         Byte *buf = _bufs[dec.state];
592         for (size_t i = 0; i < totalRead; i++)
593           buf[i] = dec.bufs[dec.state][i];
594         dec.lims[dec.state] =
595         dec.bufs[dec.state] = buf;
596       }
597 
598       if (_readRes[dec.state] != S_OK)
599         return _readRes[dec.state];
600 
601       do
602       {
603         UInt32 curSize = _bufsCurSizes[dec.state] - (UInt32)totalRead;
604         HRESULT res2 = _inStreams[dec.state]->Read(_bufs[dec.state] + totalRead, curSize, &curSize);
605         _readRes[dec.state] = res2;
606         if (curSize == 0)
607           break;
608         _inStreamsProcessed[dec.state] += curSize;
609         totalRead += curSize;
610         if (res2 != S_OK)
611           break;
612       }
613       while (totalRead < 4 && BCJ2_IS_32BIT_STREAM(dec.state));
614 
615       if (totalRead == 0)
616       {
617         if (totalProcessed == 0)
618           res = _readRes[dec.state];
619         break;
620       }
621 
622       if (BCJ2_IS_32BIT_STREAM(dec.state))
623       {
624         unsigned extraSize = ((unsigned)totalRead & 3);
625         _extraReadSizes[dec.state] = extraSize;
626         if (totalRead < 4)
627         {
628           if (totalProcessed != 0)
629             return S_OK;
630           return (_readRes[dec.state] != S_OK) ? _readRes[dec.state] : S_FALSE;
631         }
632         totalRead -= extraSize;
633       }
634 
635       dec.lims[dec.state] = _bufs[dec.state] + totalRead;
636     }
637   }
638 
639   if (_finishMode && _outSizeDefined && _outSize == _outSize_Processed)
640   {
641     if (!Bcj2Dec_IsFinished(&dec))
642       return S_FALSE;
643 
644     if (dec.state != BCJ2_STREAM_MAIN &&
645         dec.state != BCJ2_DEC_STATE_ORIG)
646       return S_FALSE;
647 
648     /*
649     for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
650       if (dec.bufs[i] != dec.lims[i] || _extraReadSizes[i] != 0)
651         return S_FALSE;
652     */
653   }
654 
655   return res;
656 }
657 
658 
GetInStreamProcessedSize2(UInt32 streamIndex,UInt64 * value)659 STDMETHODIMP CDecoder::GetInStreamProcessedSize2(UInt32 streamIndex, UInt64 *value)
660 {
661   const size_t rem = dec.lims[streamIndex] - dec.bufs[streamIndex] + _extraReadSizes[streamIndex];
662   *value = _inStreamsProcessed[streamIndex] - rem;
663   return S_OK;
664 }
665 
666 }}
667