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