xref: /aosp_15_r20/external/lzma/CPP/7zip/Compress/Bcj2Coder.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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