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
11namespace NCompress {
12namespace NBcj2 {
13
14CBaseCoder::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
24CBaseCoder::~CBaseCoder()
25{
26  for (int i = 0; i < BCJ2_NUM_STREAMS + 1; i++)
27    ::MidFree(_bufs[i]);
28}
29
30HRESULT 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
61CEncoder::CEncoder(): _relatLim(BCJ2_RELAT_LIMIT) {}
62CEncoder::~CEncoder() {}
63
64STDMETHODIMP CEncoder::SetInBufSize(UInt32, UInt32 size) { _bufsNewSizes[BCJ2_NUM_STREAMS] = size; return S_OK; }
65STDMETHODIMP CEncoder::SetOutBufSize(UInt32 streamIndex, UInt32 size) { _bufsNewSizes[streamIndex] = size; return S_OK; }
66
67STDMETHODIMP 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
116HRESULT 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
306STDMETHODIMP 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
324STDMETHODIMP CDecoder::SetInBufSize(UInt32 streamIndex, UInt32 size) { _bufsNewSizes[streamIndex] = size; return S_OK; }
325STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _bufsNewSizes[BCJ2_NUM_STREAMS] = size; return S_OK; }
326
327CDecoder::CDecoder(): _finishMode(false), _outSizeDefined(false), _outSize(0)
328{}
329
330STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)
331{
332  _finishMode = (finishMode != 0);
333  return S_OK;
334}
335
336void 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
355HRESULT 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      UInt64 outSize2 = outSizeProcessed + (dec.dest - _bufs[BCJ2_NUM_STREAMS]);
467      if (outSize2 - prevProgress >= (1 << 22))
468      {
469        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
515STDMETHODIMP CDecoder::SetInStream2(UInt32 streamIndex, ISequentialInStream *inStream)
516{
517  _inStreams[streamIndex] = inStream;
518  return S_OK;
519}
520
521STDMETHODIMP CDecoder::ReleaseInStream2(UInt32 streamIndex)
522{
523  _inStreams[streamIndex].Release();
524  return S_OK;
525}
526
527STDMETHODIMP 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
545STDMETHODIMP 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}}
659