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(¤tInPos, &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