xref: /aosp_15_r20/external/lzma/CPP/7zip/Compress/Rar5Decoder.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // Rar5Decoder.cpp
2*f6dc9357SAndroid Build Coastguard Worker // According to unRAR license, this code may not be used to develop
3*f6dc9357SAndroid Build Coastguard Worker // a program that creates RAR archives
4*f6dc9357SAndroid Build Coastguard Worker 
5*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
6*f6dc9357SAndroid Build Coastguard Worker 
7*f6dc9357SAndroid Build Coastguard Worker #define DICT_SIZE_MAX ((UInt64)1 << DICT_SIZE_BITS_MAX)
8*f6dc9357SAndroid Build Coastguard Worker 
9*f6dc9357SAndroid Build Coastguard Worker // #include <emmintrin.h> // SSE2
10*f6dc9357SAndroid Build Coastguard Worker // #endif
11*f6dc9357SAndroid Build Coastguard Worker 
12*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/CpuArch.h"
13*f6dc9357SAndroid Build Coastguard Worker #if 0
14*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/Bra.h"
15*f6dc9357SAndroid Build Coastguard Worker #endif
16*f6dc9357SAndroid Build Coastguard Worker 
17*f6dc9357SAndroid Build Coastguard Worker #if defined(MY_CPU_ARM64)
18*f6dc9357SAndroid Build Coastguard Worker #include <arm_neon.h>
19*f6dc9357SAndroid Build Coastguard Worker #endif
20*f6dc9357SAndroid Build Coastguard Worker 
21*f6dc9357SAndroid Build Coastguard Worker // #define Z7_RAR5_SHOW_STAT
22*f6dc9357SAndroid Build Coastguard Worker // #include <stdio.h>
23*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_RAR5_SHOW_STAT
24*f6dc9357SAndroid Build Coastguard Worker #include <stdio.h>
25*f6dc9357SAndroid Build Coastguard Worker #endif
26*f6dc9357SAndroid Build Coastguard Worker 
27*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
28*f6dc9357SAndroid Build Coastguard Worker 
29*f6dc9357SAndroid Build Coastguard Worker #include "Rar5Decoder.h"
30*f6dc9357SAndroid Build Coastguard Worker 
31*f6dc9357SAndroid Build Coastguard Worker /*
32*f6dc9357SAndroid Build Coastguard Worker Note: original-unrar claims that encoder has limitation for Distance:
33*f6dc9357SAndroid Build Coastguard Worker   (Distance <= MaxWinSize - MAX_INC_LZ_MATCH)
34*f6dc9357SAndroid Build Coastguard Worker   MAX_INC_LZ_MATCH = 0x1001 + 3;
35*f6dc9357SAndroid Build Coastguard Worker */
36*f6dc9357SAndroid Build Coastguard Worker 
37*f6dc9357SAndroid Build Coastguard Worker #define LZ_ERROR_TYPE_NO      0
38*f6dc9357SAndroid Build Coastguard Worker #define LZ_ERROR_TYPE_HEADER  1
39*f6dc9357SAndroid Build Coastguard Worker // #define LZ_ERROR_TYPE_SYM     1
40*f6dc9357SAndroid Build Coastguard Worker #define LZ_ERROR_TYPE_DIST    2
41*f6dc9357SAndroid Build Coastguard Worker 
42*f6dc9357SAndroid Build Coastguard Worker static
My_ZeroMemory(void * p,size_t size)43*f6dc9357SAndroid Build Coastguard Worker void My_ZeroMemory(void *p, size_t size)
44*f6dc9357SAndroid Build Coastguard Worker {
45*f6dc9357SAndroid Build Coastguard Worker   #if defined(MY_CPU_AMD64) && !defined(_M_ARM64EC) \
46*f6dc9357SAndroid Build Coastguard Worker     && defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL <= 1400)
47*f6dc9357SAndroid Build Coastguard Worker       // __stosq((UInt64 *)(void *)win, 0, size / 8);
48*f6dc9357SAndroid Build Coastguard Worker       /*
49*f6dc9357SAndroid Build Coastguard Worker       printf("\n__stosb \n");
50*f6dc9357SAndroid Build Coastguard Worker       #define STEP_BIG (1 << 28)
51*f6dc9357SAndroid Build Coastguard Worker       for (size_t i = 0; i < ((UInt64)1 << 50); i += STEP_BIG)
52*f6dc9357SAndroid Build Coastguard Worker       {
53*f6dc9357SAndroid Build Coastguard Worker         printf("\n__stosb end %p\n", (void *)i);
54*f6dc9357SAndroid Build Coastguard Worker         __stosb((Byte *)p + i, 0, STEP_BIG);
55*f6dc9357SAndroid Build Coastguard Worker       }
56*f6dc9357SAndroid Build Coastguard Worker       */
57*f6dc9357SAndroid Build Coastguard Worker       // __stosb((Byte *)p, 0, 0);
58*f6dc9357SAndroid Build Coastguard Worker       __stosb((Byte *)p, 0, size);
59*f6dc9357SAndroid Build Coastguard Worker   #else
60*f6dc9357SAndroid Build Coastguard Worker     // SecureZeroMemory (win, STEP);
61*f6dc9357SAndroid Build Coastguard Worker     // ZeroMemory(win, STEP);
62*f6dc9357SAndroid Build Coastguard Worker     // memset(win, 0, STEP);
63*f6dc9357SAndroid Build Coastguard Worker     memset(p, 0, size);
64*f6dc9357SAndroid Build Coastguard Worker   #endif
65*f6dc9357SAndroid Build Coastguard Worker }
66*f6dc9357SAndroid Build Coastguard Worker 
67*f6dc9357SAndroid Build Coastguard Worker 
68*f6dc9357SAndroid Build Coastguard Worker 
69*f6dc9357SAndroid Build Coastguard Worker #ifdef MY_CPU_LE_UNALIGN
70*f6dc9357SAndroid Build Coastguard Worker   #define Z7_RAR5_DEC_USE_UNALIGNED_COPY
71*f6dc9357SAndroid Build Coastguard Worker #endif
72*f6dc9357SAndroid Build Coastguard Worker 
73*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_RAR5_DEC_USE_UNALIGNED_COPY
74*f6dc9357SAndroid Build Coastguard Worker 
75*f6dc9357SAndroid Build Coastguard Worker   #define COPY_CHUNK_SIZE 16
76*f6dc9357SAndroid Build Coastguard Worker 
77*f6dc9357SAndroid Build Coastguard Worker     #define COPY_CHUNK_4_2(dest, src) \
78*f6dc9357SAndroid Build Coastguard Worker     { \
79*f6dc9357SAndroid Build Coastguard Worker       ((UInt32 *)(void *)dest)[0] = ((const UInt32 *)(const void *)src)[0]; \
80*f6dc9357SAndroid Build Coastguard Worker       ((UInt32 *)(void *)dest)[1] = ((const UInt32 *)(const void *)src)[1]; \
81*f6dc9357SAndroid Build Coastguard Worker       src  += 4 * 2; \
82*f6dc9357SAndroid Build Coastguard Worker       dest += 4 * 2; \
83*f6dc9357SAndroid Build Coastguard Worker     }
84*f6dc9357SAndroid Build Coastguard Worker 
85*f6dc9357SAndroid Build Coastguard Worker   /* sse2 doesn't help here in GCC and CLANG.
86*f6dc9357SAndroid Build Coastguard Worker      so we disabled sse2 here */
87*f6dc9357SAndroid Build Coastguard Worker #if 0
88*f6dc9357SAndroid Build Coastguard Worker   #if defined(MY_CPU_AMD64)
89*f6dc9357SAndroid Build Coastguard Worker     #define Z7_RAR5_DEC_USE_SSE2
90*f6dc9357SAndroid Build Coastguard Worker   #elif defined(MY_CPU_X86)
91*f6dc9357SAndroid Build Coastguard Worker     #if defined(_MSC_VER) && _MSC_VER >= 1300 && defined(_M_IX86_FP) && (_M_IX86_FP >= 2) \
92*f6dc9357SAndroid Build Coastguard Worker       || defined(__SSE2__) \
93*f6dc9357SAndroid Build Coastguard Worker       // || 1 == 1  // for debug only
94*f6dc9357SAndroid Build Coastguard Worker       #define Z7_RAR5_DEC_USE_SSE2
95*f6dc9357SAndroid Build Coastguard Worker     #endif
96*f6dc9357SAndroid Build Coastguard Worker   #endif
97*f6dc9357SAndroid Build Coastguard Worker #endif
98*f6dc9357SAndroid Build Coastguard Worker 
99*f6dc9357SAndroid Build Coastguard Worker   #if defined(MY_CPU_ARM64)
100*f6dc9357SAndroid Build Coastguard Worker 
101*f6dc9357SAndroid Build Coastguard Worker     #define COPY_OFFSET_MIN  16
102*f6dc9357SAndroid Build Coastguard Worker     #define COPY_CHUNK1(dest, src) \
103*f6dc9357SAndroid Build Coastguard Worker     { \
104*f6dc9357SAndroid Build Coastguard Worker       vst1q_u8((uint8_t *)(void *)dest, \
105*f6dc9357SAndroid Build Coastguard Worker       vld1q_u8((const uint8_t *)(const void *)src)); \
106*f6dc9357SAndroid Build Coastguard Worker       src += 16; \
107*f6dc9357SAndroid Build Coastguard Worker       dest += 16; \
108*f6dc9357SAndroid Build Coastguard Worker     }
109*f6dc9357SAndroid Build Coastguard Worker 
110*f6dc9357SAndroid Build Coastguard Worker     #define COPY_CHUNK(dest, src) \
111*f6dc9357SAndroid Build Coastguard Worker     { \
112*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNK1(dest, src) \
113*f6dc9357SAndroid Build Coastguard Worker       if (dest >= lim) break; \
114*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNK1(dest, src) \
115*f6dc9357SAndroid Build Coastguard Worker     }
116*f6dc9357SAndroid Build Coastguard Worker 
117*f6dc9357SAndroid Build Coastguard Worker   #elif defined(Z7_RAR5_DEC_USE_SSE2)
118*f6dc9357SAndroid Build Coastguard Worker     #include <emmintrin.h> // sse2
119*f6dc9357SAndroid Build Coastguard Worker     #define COPY_OFFSET_MIN  16
120*f6dc9357SAndroid Build Coastguard Worker 
121*f6dc9357SAndroid Build Coastguard Worker     #define COPY_CHUNK1(dest, src) \
122*f6dc9357SAndroid Build Coastguard Worker     { \
123*f6dc9357SAndroid Build Coastguard Worker       _mm_storeu_si128((__m128i *)(void *)dest, \
124*f6dc9357SAndroid Build Coastguard Worker       _mm_loadu_si128((const __m128i *)(const void *)src)); \
125*f6dc9357SAndroid Build Coastguard Worker       src += 16; \
126*f6dc9357SAndroid Build Coastguard Worker       dest += 16; \
127*f6dc9357SAndroid Build Coastguard Worker     }
128*f6dc9357SAndroid Build Coastguard Worker 
129*f6dc9357SAndroid Build Coastguard Worker     #define COPY_CHUNK(dest, src) \
130*f6dc9357SAndroid Build Coastguard Worker     { \
131*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNK1(dest, src) \
132*f6dc9357SAndroid Build Coastguard Worker       if (dest >= lim) break; \
133*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNK1(dest, src) \
134*f6dc9357SAndroid Build Coastguard Worker     }
135*f6dc9357SAndroid Build Coastguard Worker 
136*f6dc9357SAndroid Build Coastguard Worker   #elif defined(MY_CPU_64BIT)
137*f6dc9357SAndroid Build Coastguard Worker     #define COPY_OFFSET_MIN  8
138*f6dc9357SAndroid Build Coastguard Worker 
139*f6dc9357SAndroid Build Coastguard Worker     #define COPY_CHUNK(dest, src) \
140*f6dc9357SAndroid Build Coastguard Worker     { \
141*f6dc9357SAndroid Build Coastguard Worker       ((UInt64 *)(void *)dest)[0] = ((const UInt64 *)(const void *)src)[0]; \
142*f6dc9357SAndroid Build Coastguard Worker       src  += 8 * 1; dest += 8 * 1; \
143*f6dc9357SAndroid Build Coastguard Worker       ((UInt64 *)(void *)dest)[0] = ((const UInt64 *)(const void *)src)[0]; \
144*f6dc9357SAndroid Build Coastguard Worker       src  += 8 * 1; dest += 8 * 1; \
145*f6dc9357SAndroid Build Coastguard Worker     }
146*f6dc9357SAndroid Build Coastguard Worker 
147*f6dc9357SAndroid Build Coastguard Worker   #else
148*f6dc9357SAndroid Build Coastguard Worker     #define COPY_OFFSET_MIN  4
149*f6dc9357SAndroid Build Coastguard Worker 
150*f6dc9357SAndroid Build Coastguard Worker     #define COPY_CHUNK(dest, src) \
151*f6dc9357SAndroid Build Coastguard Worker     { \
152*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNK_4_2(dest, src); \
153*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNK_4_2(dest, src); \
154*f6dc9357SAndroid Build Coastguard Worker     }
155*f6dc9357SAndroid Build Coastguard Worker 
156*f6dc9357SAndroid Build Coastguard Worker   #endif
157*f6dc9357SAndroid Build Coastguard Worker #endif
158*f6dc9357SAndroid Build Coastguard Worker 
159*f6dc9357SAndroid Build Coastguard Worker 
160*f6dc9357SAndroid Build Coastguard Worker #ifndef COPY_CHUNK_SIZE
161*f6dc9357SAndroid Build Coastguard Worker     #define COPY_OFFSET_MIN  4
162*f6dc9357SAndroid Build Coastguard Worker     #define COPY_CHUNK_SIZE  8
163*f6dc9357SAndroid Build Coastguard Worker     #define COPY_CHUNK_2(dest, src) \
164*f6dc9357SAndroid Build Coastguard Worker     { \
165*f6dc9357SAndroid Build Coastguard Worker       const Byte a0 = src[0]; \
166*f6dc9357SAndroid Build Coastguard Worker       const Byte a1 = src[1]; \
167*f6dc9357SAndroid Build Coastguard Worker       dest[0] = a0; \
168*f6dc9357SAndroid Build Coastguard Worker       dest[1] = a1; \
169*f6dc9357SAndroid Build Coastguard Worker       src += 2; \
170*f6dc9357SAndroid Build Coastguard Worker       dest += 2; \
171*f6dc9357SAndroid Build Coastguard Worker     }
172*f6dc9357SAndroid Build Coastguard Worker     #define COPY_CHUNK(dest, src) \
173*f6dc9357SAndroid Build Coastguard Worker     { \
174*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNK_2(dest, src) \
175*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNK_2(dest, src) \
176*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNK_2(dest, src) \
177*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNK_2(dest, src) \
178*f6dc9357SAndroid Build Coastguard Worker     }
179*f6dc9357SAndroid Build Coastguard Worker #endif
180*f6dc9357SAndroid Build Coastguard Worker 
181*f6dc9357SAndroid Build Coastguard Worker 
182*f6dc9357SAndroid Build Coastguard Worker #define COPY_CHUNKS \
183*f6dc9357SAndroid Build Coastguard Worker { \
184*f6dc9357SAndroid Build Coastguard Worker   Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \
185*f6dc9357SAndroid Build Coastguard Worker   do { COPY_CHUNK(dest, src) } \
186*f6dc9357SAndroid Build Coastguard Worker   while (dest < lim); \
187*f6dc9357SAndroid Build Coastguard Worker }
188*f6dc9357SAndroid Build Coastguard Worker 
189*f6dc9357SAndroid Build Coastguard Worker namespace NCompress {
190*f6dc9357SAndroid Build Coastguard Worker namespace NRar5 {
191*f6dc9357SAndroid Build Coastguard Worker 
192*f6dc9357SAndroid Build Coastguard Worker typedef
193*f6dc9357SAndroid Build Coastguard Worker #if 1
194*f6dc9357SAndroid Build Coastguard Worker   unsigned
195*f6dc9357SAndroid Build Coastguard Worker #else
196*f6dc9357SAndroid Build Coastguard Worker   size_t
197*f6dc9357SAndroid Build Coastguard Worker #endif
198*f6dc9357SAndroid Build Coastguard Worker   CLenType;
199*f6dc9357SAndroid Build Coastguard Worker 
200*f6dc9357SAndroid Build Coastguard Worker // (len != 0)
201*f6dc9357SAndroid Build Coastguard Worker static
202*f6dc9357SAndroid Build Coastguard Worker Z7_FORCE_INLINE
203*f6dc9357SAndroid Build Coastguard Worker // Z7_ATTRIB_NO_VECTOR
CopyMatch(size_t offset,Byte * dest,const Byte * src,const Byte * lim)204*f6dc9357SAndroid Build Coastguard Worker void CopyMatch(size_t offset, Byte *dest, const Byte *src, const Byte *lim)
205*f6dc9357SAndroid Build Coastguard Worker {
206*f6dc9357SAndroid Build Coastguard Worker   {
207*f6dc9357SAndroid Build Coastguard Worker     // (COPY_OFFSET_MIN >= 4)
208*f6dc9357SAndroid Build Coastguard Worker     if (offset >= COPY_OFFSET_MIN)
209*f6dc9357SAndroid Build Coastguard Worker     {
210*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNKS
211*f6dc9357SAndroid Build Coastguard Worker       // return;
212*f6dc9357SAndroid Build Coastguard Worker     }
213*f6dc9357SAndroid Build Coastguard Worker     else
214*f6dc9357SAndroid Build Coastguard Worker   #if (COPY_OFFSET_MIN > 4)
215*f6dc9357SAndroid Build Coastguard Worker     #if COPY_CHUNK_SIZE < 8
216*f6dc9357SAndroid Build Coastguard Worker       #error Stop_Compiling_Bad_COPY_CHUNK_SIZE
217*f6dc9357SAndroid Build Coastguard Worker     #endif
218*f6dc9357SAndroid Build Coastguard Worker     if (offset >= 4)
219*f6dc9357SAndroid Build Coastguard Worker     {
220*f6dc9357SAndroid Build Coastguard Worker       Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
221*f6dc9357SAndroid Build Coastguard Worker       do
222*f6dc9357SAndroid Build Coastguard Worker       {
223*f6dc9357SAndroid Build Coastguard Worker         COPY_CHUNK_4_2(dest, src)
224*f6dc9357SAndroid Build Coastguard Worker         #if COPY_CHUNK_SIZE < 16
225*f6dc9357SAndroid Build Coastguard Worker           if (dest >= lim) break;
226*f6dc9357SAndroid Build Coastguard Worker         #endif
227*f6dc9357SAndroid Build Coastguard Worker         COPY_CHUNK_4_2(dest, src)
228*f6dc9357SAndroid Build Coastguard Worker       }
229*f6dc9357SAndroid Build Coastguard Worker       while (dest < lim);
230*f6dc9357SAndroid Build Coastguard Worker       // return;
231*f6dc9357SAndroid Build Coastguard Worker     }
232*f6dc9357SAndroid Build Coastguard Worker     else
233*f6dc9357SAndroid Build Coastguard Worker   #endif
234*f6dc9357SAndroid Build Coastguard Worker     {
235*f6dc9357SAndroid Build Coastguard Worker       // (offset < 4)
236*f6dc9357SAndroid Build Coastguard Worker       const unsigned b0 = src[0];
237*f6dc9357SAndroid Build Coastguard Worker       if (offset < 2)
238*f6dc9357SAndroid Build Coastguard Worker       {
239*f6dc9357SAndroid Build Coastguard Worker       #if defined(Z7_RAR5_DEC_USE_UNALIGNED_COPY) && (COPY_CHUNK_SIZE == 16)
240*f6dc9357SAndroid Build Coastguard Worker         #if defined(MY_CPU_64BIT)
241*f6dc9357SAndroid Build Coastguard Worker         {
242*f6dc9357SAndroid Build Coastguard Worker           const UInt64 v64 = (UInt64)b0 * 0x0101010101010101;
243*f6dc9357SAndroid Build Coastguard Worker           Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
244*f6dc9357SAndroid Build Coastguard Worker           do
245*f6dc9357SAndroid Build Coastguard Worker           {
246*f6dc9357SAndroid Build Coastguard Worker             ((UInt64 *)(void *)dest)[0] = v64;
247*f6dc9357SAndroid Build Coastguard Worker             ((UInt64 *)(void *)dest)[1] = v64;
248*f6dc9357SAndroid Build Coastguard Worker             dest += 16;
249*f6dc9357SAndroid Build Coastguard Worker           }
250*f6dc9357SAndroid Build Coastguard Worker           while (dest < lim);
251*f6dc9357SAndroid Build Coastguard Worker         }
252*f6dc9357SAndroid Build Coastguard Worker         #else
253*f6dc9357SAndroid Build Coastguard Worker         {
254*f6dc9357SAndroid Build Coastguard Worker           UInt32 v = b0;
255*f6dc9357SAndroid Build Coastguard Worker           v |= v << 8;
256*f6dc9357SAndroid Build Coastguard Worker           v |= v << 16;
257*f6dc9357SAndroid Build Coastguard Worker           do
258*f6dc9357SAndroid Build Coastguard Worker           {
259*f6dc9357SAndroid Build Coastguard Worker             ((UInt32 *)(void *)dest)[0] = v;
260*f6dc9357SAndroid Build Coastguard Worker             ((UInt32 *)(void *)dest)[1] = v;
261*f6dc9357SAndroid Build Coastguard Worker             dest += 8;
262*f6dc9357SAndroid Build Coastguard Worker             ((UInt32 *)(void *)dest)[0] = v;
263*f6dc9357SAndroid Build Coastguard Worker             ((UInt32 *)(void *)dest)[1] = v;
264*f6dc9357SAndroid Build Coastguard Worker             dest += 8;
265*f6dc9357SAndroid Build Coastguard Worker           }
266*f6dc9357SAndroid Build Coastguard Worker           while (dest < lim);
267*f6dc9357SAndroid Build Coastguard Worker         }
268*f6dc9357SAndroid Build Coastguard Worker         #endif
269*f6dc9357SAndroid Build Coastguard Worker       #else
270*f6dc9357SAndroid Build Coastguard Worker         do
271*f6dc9357SAndroid Build Coastguard Worker         {
272*f6dc9357SAndroid Build Coastguard Worker           dest[0] = (Byte)b0;
273*f6dc9357SAndroid Build Coastguard Worker           dest[1] = (Byte)b0;
274*f6dc9357SAndroid Build Coastguard Worker           dest += 2;
275*f6dc9357SAndroid Build Coastguard Worker           dest[0] = (Byte)b0;
276*f6dc9357SAndroid Build Coastguard Worker           dest[1] = (Byte)b0;
277*f6dc9357SAndroid Build Coastguard Worker           dest += 2;
278*f6dc9357SAndroid Build Coastguard Worker         }
279*f6dc9357SAndroid Build Coastguard Worker         while (dest < lim);
280*f6dc9357SAndroid Build Coastguard Worker       #endif
281*f6dc9357SAndroid Build Coastguard Worker       }
282*f6dc9357SAndroid Build Coastguard Worker       else if (offset == 2)
283*f6dc9357SAndroid Build Coastguard Worker       {
284*f6dc9357SAndroid Build Coastguard Worker         const Byte b1 = src[1];
285*f6dc9357SAndroid Build Coastguard Worker         {
286*f6dc9357SAndroid Build Coastguard Worker           do
287*f6dc9357SAndroid Build Coastguard Worker           {
288*f6dc9357SAndroid Build Coastguard Worker             dest[0] = (Byte)b0;
289*f6dc9357SAndroid Build Coastguard Worker             dest[1] = b1;
290*f6dc9357SAndroid Build Coastguard Worker             dest += 2;
291*f6dc9357SAndroid Build Coastguard Worker           }
292*f6dc9357SAndroid Build Coastguard Worker           while (dest < lim);
293*f6dc9357SAndroid Build Coastguard Worker         }
294*f6dc9357SAndroid Build Coastguard Worker       }
295*f6dc9357SAndroid Build Coastguard Worker       else // (offset == 3)
296*f6dc9357SAndroid Build Coastguard Worker       {
297*f6dc9357SAndroid Build Coastguard Worker         const Byte b1 = src[1];
298*f6dc9357SAndroid Build Coastguard Worker         const Byte b2 = src[2];
299*f6dc9357SAndroid Build Coastguard Worker         do
300*f6dc9357SAndroid Build Coastguard Worker         {
301*f6dc9357SAndroid Build Coastguard Worker           dest[0] = (Byte)b0;
302*f6dc9357SAndroid Build Coastguard Worker           dest[1] = b1;
303*f6dc9357SAndroid Build Coastguard Worker           dest[2] = b2;
304*f6dc9357SAndroid Build Coastguard Worker           dest += 3;
305*f6dc9357SAndroid Build Coastguard Worker         }
306*f6dc9357SAndroid Build Coastguard Worker         while (dest < lim);
307*f6dc9357SAndroid Build Coastguard Worker       }
308*f6dc9357SAndroid Build Coastguard Worker     }
309*f6dc9357SAndroid Build Coastguard Worker   }
310*f6dc9357SAndroid Build Coastguard Worker }
311*f6dc9357SAndroid Build Coastguard Worker 
312*f6dc9357SAndroid Build Coastguard Worker static const size_t kInputBufSize = 1 << 20;
313*f6dc9357SAndroid Build Coastguard Worker static const UInt32   k_Filter_BlockSize_MAX = 1 << 22;
314*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_Filter_AfterPad_Size = 64;
315*f6dc9357SAndroid Build Coastguard Worker 
316*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_RAR5_SHOW_STAT
317*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumStats1 = 10;
318*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumStats2 = (1 << 12) + 16;
319*f6dc9357SAndroid Build Coastguard Worker static UInt32 g_stats1[kNumStats1];
320*f6dc9357SAndroid Build Coastguard Worker static UInt32 g_stats2[kNumStats1][kNumStats2];
321*f6dc9357SAndroid Build Coastguard Worker #endif
322*f6dc9357SAndroid Build Coastguard Worker 
323*f6dc9357SAndroid Build Coastguard Worker #if 1
324*f6dc9357SAndroid Build Coastguard Worker MY_ALIGN(32)
325*f6dc9357SAndroid Build Coastguard Worker // DICT_SIZE_BITS_MAX-1 are required
326*f6dc9357SAndroid Build Coastguard Worker static const Byte k_LenPlusTable[DICT_SIZE_BITS_MAX] =
327*f6dc9357SAndroid Build Coastguard Worker   { 0,0,0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 };
328*f6dc9357SAndroid Build Coastguard Worker #endif
329*f6dc9357SAndroid Build Coastguard Worker 
330*f6dc9357SAndroid Build Coastguard Worker 
331*f6dc9357SAndroid Build Coastguard Worker 
332*f6dc9357SAndroid Build Coastguard Worker class CBitDecoder
333*f6dc9357SAndroid Build Coastguard Worker {
334*f6dc9357SAndroid Build Coastguard Worker public:
335*f6dc9357SAndroid Build Coastguard Worker   const Byte *_buf;
336*f6dc9357SAndroid Build Coastguard Worker   const Byte *_bufCheck_Block;  // min(ptr for _blockEnd, _bufCheck)
337*f6dc9357SAndroid Build Coastguard Worker   unsigned _bitPos;             // = [0 ... 7]
338*f6dc9357SAndroid Build Coastguard Worker   bool _wasFinished;
339*f6dc9357SAndroid Build Coastguard Worker   bool _minorError;
340*f6dc9357SAndroid Build Coastguard Worker   unsigned _blockEndBits7;      // = [0 ... 7] : the number of additional bits in (_blockEnd) poisition.
341*f6dc9357SAndroid Build Coastguard Worker   HRESULT _hres;
342*f6dc9357SAndroid Build Coastguard Worker   const Byte *_bufCheck;        // relaxed limit (16 bytes before real end of input data in buffer)
343*f6dc9357SAndroid Build Coastguard Worker   Byte *_bufLim;                // end if input data
344*f6dc9357SAndroid Build Coastguard Worker   Byte *_bufBase;
345*f6dc9357SAndroid Build Coastguard Worker   ISequentialInStream *_stream;
346*f6dc9357SAndroid Build Coastguard Worker 
347*f6dc9357SAndroid Build Coastguard Worker   UInt64 _processedSize;
348*f6dc9357SAndroid Build Coastguard Worker   UInt64 _blockEnd;     // absolute end of current block
349*f6dc9357SAndroid Build Coastguard Worker       // but it doesn't include additional _blockEndBits7 [0 ... 7] bits
350*f6dc9357SAndroid Build Coastguard Worker 
351*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE
CopyFrom(const CBitDecoder & a)352*f6dc9357SAndroid Build Coastguard Worker   void CopyFrom(const CBitDecoder &a)
353*f6dc9357SAndroid Build Coastguard Worker   {
354*f6dc9357SAndroid Build Coastguard Worker     _buf = a._buf;
355*f6dc9357SAndroid Build Coastguard Worker     _bufCheck_Block = a._bufCheck_Block;
356*f6dc9357SAndroid Build Coastguard Worker     _bitPos = a._bitPos;
357*f6dc9357SAndroid Build Coastguard Worker     _wasFinished = a._wasFinished;
358*f6dc9357SAndroid Build Coastguard Worker     _blockEndBits7 = a._blockEndBits7;
359*f6dc9357SAndroid Build Coastguard Worker     _bufCheck = a._bufCheck;
360*f6dc9357SAndroid Build Coastguard Worker     _bufLim = a._bufLim;
361*f6dc9357SAndroid Build Coastguard Worker     _bufBase = a._bufBase;
362*f6dc9357SAndroid Build Coastguard Worker 
363*f6dc9357SAndroid Build Coastguard Worker     _processedSize = a._processedSize;
364*f6dc9357SAndroid Build Coastguard Worker     _blockEnd = a._blockEnd;
365*f6dc9357SAndroid Build Coastguard Worker   }
366*f6dc9357SAndroid Build Coastguard Worker 
367*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE
RestoreFrom2(const CBitDecoder & a)368*f6dc9357SAndroid Build Coastguard Worker   void RestoreFrom2(const CBitDecoder &a)
369*f6dc9357SAndroid Build Coastguard Worker   {
370*f6dc9357SAndroid Build Coastguard Worker     _buf = a._buf;
371*f6dc9357SAndroid Build Coastguard Worker     _bitPos = a._bitPos;
372*f6dc9357SAndroid Build Coastguard Worker   }
373*f6dc9357SAndroid Build Coastguard Worker 
374*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE
SetCheck_forBlock()375*f6dc9357SAndroid Build Coastguard Worker   void SetCheck_forBlock()
376*f6dc9357SAndroid Build Coastguard Worker   {
377*f6dc9357SAndroid Build Coastguard Worker     _bufCheck_Block = _bufCheck;
378*f6dc9357SAndroid Build Coastguard Worker     if (_bufCheck > _buf)
379*f6dc9357SAndroid Build Coastguard Worker     {
380*f6dc9357SAndroid Build Coastguard Worker       const UInt64 processed = GetProcessedSize_Round();
381*f6dc9357SAndroid Build Coastguard Worker       if (_blockEnd < processed)
382*f6dc9357SAndroid Build Coastguard Worker         _bufCheck_Block = _buf;
383*f6dc9357SAndroid Build Coastguard Worker       else
384*f6dc9357SAndroid Build Coastguard Worker       {
385*f6dc9357SAndroid Build Coastguard Worker         const UInt64 delta = _blockEnd - processed;
386*f6dc9357SAndroid Build Coastguard Worker         if ((size_t)(_bufCheck - _buf) > delta)
387*f6dc9357SAndroid Build Coastguard Worker           _bufCheck_Block = _buf + (size_t)delta;
388*f6dc9357SAndroid Build Coastguard Worker       }
389*f6dc9357SAndroid Build Coastguard Worker     }
390*f6dc9357SAndroid Build Coastguard Worker   }
391*f6dc9357SAndroid Build Coastguard Worker 
392*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE
IsBlockOverRead() const393*f6dc9357SAndroid Build Coastguard Worker   bool IsBlockOverRead() const
394*f6dc9357SAndroid Build Coastguard Worker   {
395*f6dc9357SAndroid Build Coastguard Worker     const UInt64 v = GetProcessedSize_Round();
396*f6dc9357SAndroid Build Coastguard Worker     if (v < _blockEnd) return false;
397*f6dc9357SAndroid Build Coastguard Worker     if (v > _blockEnd) return true;
398*f6dc9357SAndroid Build Coastguard Worker     return _bitPos > _blockEndBits7;
399*f6dc9357SAndroid Build Coastguard Worker   }
400*f6dc9357SAndroid Build Coastguard Worker 
401*f6dc9357SAndroid Build Coastguard Worker   /*
402*f6dc9357SAndroid Build Coastguard Worker   CBitDecoder() throw():
403*f6dc9357SAndroid Build Coastguard Worker       _buf(0),
404*f6dc9357SAndroid Build Coastguard Worker       _bufLim(0),
405*f6dc9357SAndroid Build Coastguard Worker       _bufBase(0),
406*f6dc9357SAndroid Build Coastguard Worker       _stream(0),
407*f6dc9357SAndroid Build Coastguard Worker       _processedSize(0),
408*f6dc9357SAndroid Build Coastguard Worker       _wasFinished(false)
409*f6dc9357SAndroid Build Coastguard Worker       {}
410*f6dc9357SAndroid Build Coastguard Worker   */
411*f6dc9357SAndroid Build Coastguard Worker 
412*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE
Init()413*f6dc9357SAndroid Build Coastguard Worker   void Init() throw()
414*f6dc9357SAndroid Build Coastguard Worker   {
415*f6dc9357SAndroid Build Coastguard Worker     _blockEnd = 0;
416*f6dc9357SAndroid Build Coastguard Worker     _blockEndBits7 = 0;
417*f6dc9357SAndroid Build Coastguard Worker 
418*f6dc9357SAndroid Build Coastguard Worker     _bitPos = 0;
419*f6dc9357SAndroid Build Coastguard Worker     _processedSize = 0;
420*f6dc9357SAndroid Build Coastguard Worker     _buf = _bufBase;
421*f6dc9357SAndroid Build Coastguard Worker     _bufLim = _bufBase;
422*f6dc9357SAndroid Build Coastguard Worker     _bufCheck = _buf;
423*f6dc9357SAndroid Build Coastguard Worker     _bufCheck_Block = _buf;
424*f6dc9357SAndroid Build Coastguard Worker     _wasFinished = false;
425*f6dc9357SAndroid Build Coastguard Worker     _minorError = false;
426*f6dc9357SAndroid Build Coastguard Worker   }
427*f6dc9357SAndroid Build Coastguard Worker 
428*f6dc9357SAndroid Build Coastguard Worker   void Prepare2() throw();
429*f6dc9357SAndroid Build Coastguard Worker 
430*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE
Prepare()431*f6dc9357SAndroid Build Coastguard Worker   void Prepare() throw()
432*f6dc9357SAndroid Build Coastguard Worker   {
433*f6dc9357SAndroid Build Coastguard Worker     if (_buf >= _bufCheck)
434*f6dc9357SAndroid Build Coastguard Worker       Prepare2();
435*f6dc9357SAndroid Build Coastguard Worker   }
436*f6dc9357SAndroid Build Coastguard Worker 
437*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE
ExtraBitsWereRead() const438*f6dc9357SAndroid Build Coastguard Worker   bool ExtraBitsWereRead() const
439*f6dc9357SAndroid Build Coastguard Worker   {
440*f6dc9357SAndroid Build Coastguard Worker     return _buf >= _bufLim && (_buf > _bufLim || _bitPos != 0);
441*f6dc9357SAndroid Build Coastguard Worker   }
442*f6dc9357SAndroid Build Coastguard Worker 
InputEofError() const443*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE bool InputEofError() const { return ExtraBitsWereRead(); }
444*f6dc9357SAndroid Build Coastguard Worker 
GetProcessedBits7() const445*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE unsigned GetProcessedBits7() const { return _bitPos; }
GetProcessedSize_Round() const446*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE UInt64 GetProcessedSize_Round() const { return _processedSize + (size_t)(_buf - _bufBase); }
GetProcessedSize() const447*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE UInt64 GetProcessedSize() const { return _processedSize + (size_t)(_buf - _bufBase) + ((_bitPos + 7) >> 3); }
448*f6dc9357SAndroid Build Coastguard Worker 
449*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE
AlignToByte()450*f6dc9357SAndroid Build Coastguard Worker   void AlignToByte()
451*f6dc9357SAndroid Build Coastguard Worker   {
452*f6dc9357SAndroid Build Coastguard Worker     if (_bitPos != 0)
453*f6dc9357SAndroid Build Coastguard Worker     {
454*f6dc9357SAndroid Build Coastguard Worker #if 1
455*f6dc9357SAndroid Build Coastguard Worker       // optional check of unused bits for strict checking:
456*f6dc9357SAndroid Build Coastguard Worker       // original-unrar doesn't check it:
457*f6dc9357SAndroid Build Coastguard Worker       const unsigned b = (unsigned)*_buf << _bitPos;
458*f6dc9357SAndroid Build Coastguard Worker       if (b & 0xff)
459*f6dc9357SAndroid Build Coastguard Worker         _minorError = true;
460*f6dc9357SAndroid Build Coastguard Worker #endif
461*f6dc9357SAndroid Build Coastguard Worker       _buf++;
462*f6dc9357SAndroid Build Coastguard Worker       _bitPos = 0;
463*f6dc9357SAndroid Build Coastguard Worker     }
464*f6dc9357SAndroid Build Coastguard Worker     // _buf += (_bitPos + 7) >> 3;
465*f6dc9357SAndroid Build Coastguard Worker     // _bitPos = 0;
466*f6dc9357SAndroid Build Coastguard Worker   }
467*f6dc9357SAndroid Build Coastguard Worker 
468*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE
ReadByte_InAligned()469*f6dc9357SAndroid Build Coastguard Worker   Byte ReadByte_InAligned()
470*f6dc9357SAndroid Build Coastguard Worker   {
471*f6dc9357SAndroid Build Coastguard Worker     return *_buf++;
472*f6dc9357SAndroid Build Coastguard Worker   }
473*f6dc9357SAndroid Build Coastguard Worker 
474*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE
GetValue(unsigned numBits) const475*f6dc9357SAndroid Build Coastguard Worker   UInt32 GetValue(unsigned numBits) const
476*f6dc9357SAndroid Build Coastguard Worker   {
477*f6dc9357SAndroid Build Coastguard Worker     // 0 < numBits <= 17 : supported values
478*f6dc9357SAndroid Build Coastguard Worker #if defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE_UNALIGN)
479*f6dc9357SAndroid Build Coastguard Worker     UInt32 v = GetBe32(_buf);
480*f6dc9357SAndroid Build Coastguard Worker #if 1
481*f6dc9357SAndroid Build Coastguard Worker     return (v >> (32 - numBits - _bitPos)) & ((1u << numBits) - 1);
482*f6dc9357SAndroid Build Coastguard Worker #else
483*f6dc9357SAndroid Build Coastguard Worker     return (v << _bitPos) >> (32 - numBits);
484*f6dc9357SAndroid Build Coastguard Worker #endif
485*f6dc9357SAndroid Build Coastguard Worker #else
486*f6dc9357SAndroid Build Coastguard Worker     UInt32 v = ((UInt32)_buf[0] << 16) | ((UInt32)_buf[1] << 8) | (UInt32)_buf[2];
487*f6dc9357SAndroid Build Coastguard Worker     v >>= 24 - numBits - _bitPos;
488*f6dc9357SAndroid Build Coastguard Worker     return v & ((1 << numBits) - 1);
489*f6dc9357SAndroid Build Coastguard Worker #endif
490*f6dc9357SAndroid Build Coastguard Worker   }
491*f6dc9357SAndroid Build Coastguard Worker 
492*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE
GetValue_InHigh32bits() const493*f6dc9357SAndroid Build Coastguard Worker   UInt32 GetValue_InHigh32bits() const
494*f6dc9357SAndroid Build Coastguard Worker   {
495*f6dc9357SAndroid Build Coastguard Worker     // 0 < numBits <= 17 : supported vales
496*f6dc9357SAndroid Build Coastguard Worker #if defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE_UNALIGN)
497*f6dc9357SAndroid Build Coastguard Worker     return GetBe32(_buf) << _bitPos;
498*f6dc9357SAndroid Build Coastguard Worker #else
499*f6dc9357SAndroid Build Coastguard Worker     const UInt32 v = ((UInt32)_buf[0] << 16) | ((UInt32)_buf[1] << 8) | (UInt32)_buf[2];
500*f6dc9357SAndroid Build Coastguard Worker     return v << (_bitPos + 8);
501*f6dc9357SAndroid Build Coastguard Worker #endif
502*f6dc9357SAndroid Build Coastguard Worker   }
503*f6dc9357SAndroid Build Coastguard Worker 
504*f6dc9357SAndroid Build Coastguard Worker 
505*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE
MovePos(unsigned numBits)506*f6dc9357SAndroid Build Coastguard Worker   void MovePos(unsigned numBits)
507*f6dc9357SAndroid Build Coastguard Worker   {
508*f6dc9357SAndroid Build Coastguard Worker     numBits += _bitPos;
509*f6dc9357SAndroid Build Coastguard Worker     _buf += numBits >> 3;
510*f6dc9357SAndroid Build Coastguard Worker     _bitPos = numBits & 7;
511*f6dc9357SAndroid Build Coastguard Worker   }
512*f6dc9357SAndroid Build Coastguard Worker 
513*f6dc9357SAndroid Build Coastguard Worker 
514*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE
ReadBits9(unsigned numBits)515*f6dc9357SAndroid Build Coastguard Worker   UInt32 ReadBits9(unsigned numBits)
516*f6dc9357SAndroid Build Coastguard Worker   {
517*f6dc9357SAndroid Build Coastguard Worker     const Byte *buf = _buf;
518*f6dc9357SAndroid Build Coastguard Worker     UInt32 v = ((UInt32)buf[0] << 8) | (UInt32)buf[1];
519*f6dc9357SAndroid Build Coastguard Worker     v &= (UInt32)0xFFFF >> _bitPos;
520*f6dc9357SAndroid Build Coastguard Worker     numBits += _bitPos;
521*f6dc9357SAndroid Build Coastguard Worker     v >>= 16 - numBits;
522*f6dc9357SAndroid Build Coastguard Worker     _buf = buf + (numBits >> 3);
523*f6dc9357SAndroid Build Coastguard Worker     _bitPos = numBits & 7;
524*f6dc9357SAndroid Build Coastguard Worker     return v;
525*f6dc9357SAndroid Build Coastguard Worker   }
526*f6dc9357SAndroid Build Coastguard Worker 
527*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE
ReadBits_9fix(unsigned numBits)528*f6dc9357SAndroid Build Coastguard Worker   UInt32 ReadBits_9fix(unsigned numBits)
529*f6dc9357SAndroid Build Coastguard Worker   {
530*f6dc9357SAndroid Build Coastguard Worker     const Byte *buf = _buf;
531*f6dc9357SAndroid Build Coastguard Worker     UInt32 v = ((UInt32)buf[0] << 8) | (UInt32)buf[1];
532*f6dc9357SAndroid Build Coastguard Worker     const UInt32 mask = (1u << numBits) - 1;
533*f6dc9357SAndroid Build Coastguard Worker     numBits += _bitPos;
534*f6dc9357SAndroid Build Coastguard Worker     v >>= 16 - numBits;
535*f6dc9357SAndroid Build Coastguard Worker     _buf = buf + (numBits >> 3);
536*f6dc9357SAndroid Build Coastguard Worker     _bitPos = numBits & 7;
537*f6dc9357SAndroid Build Coastguard Worker     return v & mask;
538*f6dc9357SAndroid Build Coastguard Worker   }
539*f6dc9357SAndroid Build Coastguard Worker 
540*f6dc9357SAndroid Build Coastguard Worker #if 1 && defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 8)
541*f6dc9357SAndroid Build Coastguard Worker #define Z7_RAR5_USE_64BIT
542*f6dc9357SAndroid Build Coastguard Worker #endif
543*f6dc9357SAndroid Build Coastguard Worker 
544*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_RAR5_USE_64BIT
545*f6dc9357SAndroid Build Coastguard Worker #define MAX_DICT_LOG (sizeof(size_t) / 8 * 5 + 31)
546*f6dc9357SAndroid Build Coastguard Worker #else
547*f6dc9357SAndroid Build Coastguard Worker #define MAX_DICT_LOG 31
548*f6dc9357SAndroid Build Coastguard Worker #endif
549*f6dc9357SAndroid Build Coastguard Worker 
550*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_RAR5_USE_64BIT
551*f6dc9357SAndroid Build Coastguard Worker 
552*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE
ReadBits_Big(unsigned numBits,UInt64 v)553*f6dc9357SAndroid Build Coastguard Worker   size_t ReadBits_Big(unsigned numBits, UInt64 v)
554*f6dc9357SAndroid Build Coastguard Worker   {
555*f6dc9357SAndroid Build Coastguard Worker     const UInt64 mask = ((UInt64)1 << numBits) - 1;
556*f6dc9357SAndroid Build Coastguard Worker     numBits += _bitPos;
557*f6dc9357SAndroid Build Coastguard Worker     const Byte *buf = _buf;
558*f6dc9357SAndroid Build Coastguard Worker     // UInt64 v = GetBe64(buf);
559*f6dc9357SAndroid Build Coastguard Worker     v >>= 64 - numBits;
560*f6dc9357SAndroid Build Coastguard Worker     _buf = buf + (numBits >> 3);
561*f6dc9357SAndroid Build Coastguard Worker     _bitPos = numBits & 7;
562*f6dc9357SAndroid Build Coastguard Worker     return (size_t)(v & mask);
563*f6dc9357SAndroid Build Coastguard Worker   }
564*f6dc9357SAndroid Build Coastguard Worker   #define ReadBits_Big25 ReadBits_Big
565*f6dc9357SAndroid Build Coastguard Worker 
566*f6dc9357SAndroid Build Coastguard Worker #else
567*f6dc9357SAndroid Build Coastguard Worker 
568*f6dc9357SAndroid Build Coastguard Worker   // (numBits <= 25) for 32-bit mode
569*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE
ReadBits_Big25(unsigned numBits,UInt32 v)570*f6dc9357SAndroid Build Coastguard Worker   size_t ReadBits_Big25(unsigned numBits, UInt32 v)
571*f6dc9357SAndroid Build Coastguard Worker   {
572*f6dc9357SAndroid Build Coastguard Worker     const UInt32 mask = ((UInt32)1 << numBits) - 1;
573*f6dc9357SAndroid Build Coastguard Worker     numBits += _bitPos;
574*f6dc9357SAndroid Build Coastguard Worker     v >>= 32 - numBits;
575*f6dc9357SAndroid Build Coastguard Worker     _buf += numBits >> 3;
576*f6dc9357SAndroid Build Coastguard Worker     _bitPos = numBits & 7;
577*f6dc9357SAndroid Build Coastguard Worker     return v & mask;
578*f6dc9357SAndroid Build Coastguard Worker   }
579*f6dc9357SAndroid Build Coastguard Worker 
580*f6dc9357SAndroid Build Coastguard Worker   // numBits != 0
581*f6dc9357SAndroid Build Coastguard Worker   Z7_FORCE_INLINE
ReadBits_Big(unsigned numBits,UInt32 v)582*f6dc9357SAndroid Build Coastguard Worker   size_t ReadBits_Big(unsigned numBits, UInt32 v)
583*f6dc9357SAndroid Build Coastguard Worker   {
584*f6dc9357SAndroid Build Coastguard Worker     const Byte *buf = _buf;
585*f6dc9357SAndroid Build Coastguard Worker     // UInt32 v = GetBe32(buf);
586*f6dc9357SAndroid Build Coastguard Worker #if 0
587*f6dc9357SAndroid Build Coastguard Worker     const UInt32 mask = ((UInt32)1 << numBits) - 1;
588*f6dc9357SAndroid Build Coastguard Worker     numBits += _bitPos;
589*f6dc9357SAndroid Build Coastguard Worker     if (numBits > 32)
590*f6dc9357SAndroid Build Coastguard Worker     {
591*f6dc9357SAndroid Build Coastguard Worker       v <<= numBits - 32;
592*f6dc9357SAndroid Build Coastguard Worker       v |= (UInt32)buf[4] >> (40 - numBits);
593*f6dc9357SAndroid Build Coastguard Worker     }
594*f6dc9357SAndroid Build Coastguard Worker     else
595*f6dc9357SAndroid Build Coastguard Worker       v >>= 32 - numBits;
596*f6dc9357SAndroid Build Coastguard Worker     _buf = buf + (numBits >> 3);
597*f6dc9357SAndroid Build Coastguard Worker     _bitPos = numBits & 7;
598*f6dc9357SAndroid Build Coastguard Worker     return v & mask;
599*f6dc9357SAndroid Build Coastguard Worker #else
600*f6dc9357SAndroid Build Coastguard Worker     v <<= _bitPos;
601*f6dc9357SAndroid Build Coastguard Worker     v |= (UInt32)buf[4] >> (8 - _bitPos);
602*f6dc9357SAndroid Build Coastguard Worker     v >>= 32 - numBits;
603*f6dc9357SAndroid Build Coastguard Worker     numBits += _bitPos;
604*f6dc9357SAndroid Build Coastguard Worker     _buf = buf + (numBits >> 3);
605*f6dc9357SAndroid Build Coastguard Worker     _bitPos = numBits & 7;
606*f6dc9357SAndroid Build Coastguard Worker     return v;
607*f6dc9357SAndroid Build Coastguard Worker #endif
608*f6dc9357SAndroid Build Coastguard Worker   }
609*f6dc9357SAndroid Build Coastguard Worker #endif
610*f6dc9357SAndroid Build Coastguard Worker };
611*f6dc9357SAndroid Build Coastguard Worker 
612*f6dc9357SAndroid Build Coastguard Worker 
613*f6dc9357SAndroid Build Coastguard Worker static const unsigned kLookaheadSize = 16;
614*f6dc9357SAndroid Build Coastguard Worker static const unsigned kInputBufferPadZone = kLookaheadSize;
615*f6dc9357SAndroid Build Coastguard Worker 
616*f6dc9357SAndroid Build Coastguard Worker Z7_NO_INLINE
Prepare2()617*f6dc9357SAndroid Build Coastguard Worker void CBitDecoder::Prepare2() throw()
618*f6dc9357SAndroid Build Coastguard Worker {
619*f6dc9357SAndroid Build Coastguard Worker   if (_buf > _bufLim)
620*f6dc9357SAndroid Build Coastguard Worker     return;
621*f6dc9357SAndroid Build Coastguard Worker 
622*f6dc9357SAndroid Build Coastguard Worker   size_t rem = (size_t)(_bufLim - _buf);
623*f6dc9357SAndroid Build Coastguard Worker   if (rem != 0)
624*f6dc9357SAndroid Build Coastguard Worker     memmove(_bufBase, _buf, rem);
625*f6dc9357SAndroid Build Coastguard Worker 
626*f6dc9357SAndroid Build Coastguard Worker   _bufLim = _bufBase + rem;
627*f6dc9357SAndroid Build Coastguard Worker   _processedSize += (size_t)(_buf - _bufBase);
628*f6dc9357SAndroid Build Coastguard Worker   _buf = _bufBase;
629*f6dc9357SAndroid Build Coastguard Worker 
630*f6dc9357SAndroid Build Coastguard Worker   // we do not look ahead more than 16 bytes before limit checks.
631*f6dc9357SAndroid Build Coastguard Worker 
632*f6dc9357SAndroid Build Coastguard Worker   if (!_wasFinished)
633*f6dc9357SAndroid Build Coastguard Worker   {
634*f6dc9357SAndroid Build Coastguard Worker     while (rem <= kLookaheadSize)
635*f6dc9357SAndroid Build Coastguard Worker     {
636*f6dc9357SAndroid Build Coastguard Worker       UInt32 processed = (UInt32)(kInputBufSize - rem);
637*f6dc9357SAndroid Build Coastguard Worker       // processed = 33; // for debug
638*f6dc9357SAndroid Build Coastguard Worker       _hres = _stream->Read(_bufLim, processed, &processed);
639*f6dc9357SAndroid Build Coastguard Worker       _bufLim += processed;
640*f6dc9357SAndroid Build Coastguard Worker       rem += processed;
641*f6dc9357SAndroid Build Coastguard Worker       if (processed == 0 || _hres != S_OK)
642*f6dc9357SAndroid Build Coastguard Worker       {
643*f6dc9357SAndroid Build Coastguard Worker         _wasFinished = true;
644*f6dc9357SAndroid Build Coastguard Worker         // if (_hres != S_OK) throw CInBufferException(result);
645*f6dc9357SAndroid Build Coastguard Worker         break;
646*f6dc9357SAndroid Build Coastguard Worker       }
647*f6dc9357SAndroid Build Coastguard Worker     }
648*f6dc9357SAndroid Build Coastguard Worker   }
649*f6dc9357SAndroid Build Coastguard Worker 
650*f6dc9357SAndroid Build Coastguard Worker   // we always fill pad zone here.
651*f6dc9357SAndroid Build Coastguard Worker   // so we don't need to call Prepare2() if (_wasFinished == true)
652*f6dc9357SAndroid Build Coastguard Worker   memset(_bufLim, 0xFF, kLookaheadSize);
653*f6dc9357SAndroid Build Coastguard Worker 
654*f6dc9357SAndroid Build Coastguard Worker   if (rem < kLookaheadSize)
655*f6dc9357SAndroid Build Coastguard Worker   {
656*f6dc9357SAndroid Build Coastguard Worker     _bufCheck = _buf;
657*f6dc9357SAndroid Build Coastguard Worker     // memset(_bufLim, 0xFF, kLookaheadSize - rem);
658*f6dc9357SAndroid Build Coastguard Worker   }
659*f6dc9357SAndroid Build Coastguard Worker   else
660*f6dc9357SAndroid Build Coastguard Worker     _bufCheck = _bufLim - kLookaheadSize;
661*f6dc9357SAndroid Build Coastguard Worker 
662*f6dc9357SAndroid Build Coastguard Worker   SetCheck_forBlock();
663*f6dc9357SAndroid Build Coastguard Worker }
664*f6dc9357SAndroid Build Coastguard Worker 
665*f6dc9357SAndroid Build Coastguard Worker 
666*f6dc9357SAndroid Build Coastguard Worker enum FilterType
667*f6dc9357SAndroid Build Coastguard Worker {
668*f6dc9357SAndroid Build Coastguard Worker   FILTER_DELTA = 0,
669*f6dc9357SAndroid Build Coastguard Worker   FILTER_E8,
670*f6dc9357SAndroid Build Coastguard Worker   FILTER_E8E9,
671*f6dc9357SAndroid Build Coastguard Worker   FILTER_ARM
672*f6dc9357SAndroid Build Coastguard Worker };
673*f6dc9357SAndroid Build Coastguard Worker 
674*f6dc9357SAndroid Build Coastguard Worker static const size_t kWriteStep = (size_t)1 << 18;
675*f6dc9357SAndroid Build Coastguard Worker       // (size_t)1 << 22; // original-unrar
676*f6dc9357SAndroid Build Coastguard Worker 
677*f6dc9357SAndroid Build Coastguard Worker // Original unRAR claims that maximum possible filter block size is (1 << 16) now,
678*f6dc9357SAndroid Build Coastguard Worker // and (1 << 17) is minimum win size required to support filter.
679*f6dc9357SAndroid Build Coastguard Worker // Original unRAR uses (1u << 18) for "extra safety and possible filter area size expansion"
680*f6dc9357SAndroid Build Coastguard Worker // We can use any win size, but we use same (1u << 18) for compatibility
681*f6dc9357SAndroid Build Coastguard Worker // with WinRar
682*f6dc9357SAndroid Build Coastguard Worker 
683*f6dc9357SAndroid Build Coastguard Worker // static const unsigned kWinSize_Log_Min = 17;
684*f6dc9357SAndroid Build Coastguard Worker static const size_t kWinSize_Min = 1u << 18;
685*f6dc9357SAndroid Build Coastguard Worker 
CDecoder()686*f6dc9357SAndroid Build Coastguard Worker CDecoder::CDecoder():
687*f6dc9357SAndroid Build Coastguard Worker     _isSolid(false),
688*f6dc9357SAndroid Build Coastguard Worker     _is_v7(false),
689*f6dc9357SAndroid Build Coastguard Worker     _wasInit(false),
690*f6dc9357SAndroid Build Coastguard Worker     // _dictSizeLog(0),
691*f6dc9357SAndroid Build Coastguard Worker     _dictSize(kWinSize_Min),
692*f6dc9357SAndroid Build Coastguard Worker     _window(NULL),
693*f6dc9357SAndroid Build Coastguard Worker     _winPos(0),
694*f6dc9357SAndroid Build Coastguard Worker     _winSize(0),
695*f6dc9357SAndroid Build Coastguard Worker     _dictSize_forCheck(0),
696*f6dc9357SAndroid Build Coastguard Worker     _lzSize(0),
697*f6dc9357SAndroid Build Coastguard Worker     _lzEnd(0),
698*f6dc9357SAndroid Build Coastguard Worker     _writtenFileSize(0),
699*f6dc9357SAndroid Build Coastguard Worker     _filters(NULL),
700*f6dc9357SAndroid Build Coastguard Worker     _winSize_Allocated(0),
701*f6dc9357SAndroid Build Coastguard Worker     _inputBuf(NULL)
702*f6dc9357SAndroid Build Coastguard Worker {
703*f6dc9357SAndroid Build Coastguard Worker #if 1
704*f6dc9357SAndroid Build Coastguard Worker   memcpy(m_LenPlusTable, k_LenPlusTable, sizeof(k_LenPlusTable));
705*f6dc9357SAndroid Build Coastguard Worker #endif
706*f6dc9357SAndroid Build Coastguard Worker   // printf("\nsizeof(CDecoder) == %d\n", sizeof(CDecoder));
707*f6dc9357SAndroid Build Coastguard Worker }
708*f6dc9357SAndroid Build Coastguard Worker 
~CDecoder()709*f6dc9357SAndroid Build Coastguard Worker CDecoder::~CDecoder()
710*f6dc9357SAndroid Build Coastguard Worker {
711*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_RAR5_SHOW_STAT
712*f6dc9357SAndroid Build Coastguard Worker   printf("\n%4d :", 0);
713*f6dc9357SAndroid Build Coastguard Worker   for (unsigned k = 0; k < kNumStats1; k++)
714*f6dc9357SAndroid Build Coastguard Worker     printf(" %8u", (unsigned)g_stats1[k]);
715*f6dc9357SAndroid Build Coastguard Worker   printf("\n");
716*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < kNumStats2; i++)
717*f6dc9357SAndroid Build Coastguard Worker   {
718*f6dc9357SAndroid Build Coastguard Worker     printf("\n%4d :", i);
719*f6dc9357SAndroid Build Coastguard Worker     for (unsigned k = 0; k < kNumStats1; k++)
720*f6dc9357SAndroid Build Coastguard Worker       printf(" %8u", (unsigned)g_stats2[k][i]);
721*f6dc9357SAndroid Build Coastguard Worker   }
722*f6dc9357SAndroid Build Coastguard Worker   printf("\n");
723*f6dc9357SAndroid Build Coastguard Worker #endif
724*f6dc9357SAndroid Build Coastguard Worker 
725*f6dc9357SAndroid Build Coastguard Worker #define Z7_RAR_FREE_WINDOW ::BigFree(_window);
726*f6dc9357SAndroid Build Coastguard Worker 
727*f6dc9357SAndroid Build Coastguard Worker   Z7_RAR_FREE_WINDOW
728*f6dc9357SAndroid Build Coastguard Worker   z7_AlignedFree(_inputBuf);
729*f6dc9357SAndroid Build Coastguard Worker   z7_AlignedFree(_filters);
730*f6dc9357SAndroid Build Coastguard Worker }
731*f6dc9357SAndroid Build Coastguard Worker 
732*f6dc9357SAndroid Build Coastguard Worker Z7_NO_INLINE
DeleteUnusedFilters()733*f6dc9357SAndroid Build Coastguard Worker void CDecoder::DeleteUnusedFilters()
734*f6dc9357SAndroid Build Coastguard Worker {
735*f6dc9357SAndroid Build Coastguard Worker   if (_numUnusedFilters != 0)
736*f6dc9357SAndroid Build Coastguard Worker   {
737*f6dc9357SAndroid Build Coastguard Worker     // printf("\nDeleteUnusedFilters _numFilters = %6u\n", _numFilters);
738*f6dc9357SAndroid Build Coastguard Worker     const unsigned n = _numFilters - _numUnusedFilters;
739*f6dc9357SAndroid Build Coastguard Worker     _numFilters = n;
740*f6dc9357SAndroid Build Coastguard Worker     memmove(_filters, _filters + _numUnusedFilters, n * sizeof(CFilter));
741*f6dc9357SAndroid Build Coastguard Worker     _numUnusedFilters = 0;
742*f6dc9357SAndroid Build Coastguard Worker   }
743*f6dc9357SAndroid Build Coastguard Worker }
744*f6dc9357SAndroid Build Coastguard Worker 
745*f6dc9357SAndroid Build Coastguard Worker 
746*f6dc9357SAndroid Build Coastguard Worker Z7_NO_INLINE
WriteData(const Byte * data,size_t size)747*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::WriteData(const Byte *data, size_t size)
748*f6dc9357SAndroid Build Coastguard Worker {
749*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = S_OK;
750*f6dc9357SAndroid Build Coastguard Worker   if (!_unpackSize_Defined || _writtenFileSize < _unpackSize)
751*f6dc9357SAndroid Build Coastguard Worker   {
752*f6dc9357SAndroid Build Coastguard Worker     size_t cur = size;
753*f6dc9357SAndroid Build Coastguard Worker     if (_unpackSize_Defined)
754*f6dc9357SAndroid Build Coastguard Worker     {
755*f6dc9357SAndroid Build Coastguard Worker       const UInt64 rem = _unpackSize - _writtenFileSize;
756*f6dc9357SAndroid Build Coastguard Worker       if (cur > rem)
757*f6dc9357SAndroid Build Coastguard Worker         cur = (size_t)rem;
758*f6dc9357SAndroid Build Coastguard Worker     }
759*f6dc9357SAndroid Build Coastguard Worker     res = WriteStream(_outStream, data, cur);
760*f6dc9357SAndroid Build Coastguard Worker     if (res != S_OK)
761*f6dc9357SAndroid Build Coastguard Worker       _writeError = true;
762*f6dc9357SAndroid Build Coastguard Worker   }
763*f6dc9357SAndroid Build Coastguard Worker   _writtenFileSize += size;
764*f6dc9357SAndroid Build Coastguard Worker   return res;
765*f6dc9357SAndroid Build Coastguard Worker }
766*f6dc9357SAndroid Build Coastguard Worker 
767*f6dc9357SAndroid Build Coastguard Worker 
768*f6dc9357SAndroid Build Coastguard Worker #if defined(MY_CPU_SIZEOF_POINTER) \
769*f6dc9357SAndroid Build Coastguard Worker     && ( MY_CPU_SIZEOF_POINTER == 4 \
770*f6dc9357SAndroid Build Coastguard Worker       || MY_CPU_SIZEOF_POINTER == 8)
771*f6dc9357SAndroid Build Coastguard Worker   #define BR_CONV_USE_OPT_PC_PTR
772*f6dc9357SAndroid Build Coastguard Worker #endif
773*f6dc9357SAndroid Build Coastguard Worker 
774*f6dc9357SAndroid Build Coastguard Worker #ifdef BR_CONV_USE_OPT_PC_PTR
775*f6dc9357SAndroid Build Coastguard Worker #define BR_PC_INIT(lim_back)  pc -= (UInt32)(SizeT)data;
776*f6dc9357SAndroid Build Coastguard Worker #define BR_PC_GET        (pc + (UInt32)(SizeT)data)
777*f6dc9357SAndroid Build Coastguard Worker #else
778*f6dc9357SAndroid Build Coastguard Worker #define BR_PC_INIT(lim_back)  pc += (UInt32)dataSize - (lim_back);
779*f6dc9357SAndroid Build Coastguard Worker #define BR_PC_GET        (pc - (UInt32)(SizeT)(data_lim - data))
780*f6dc9357SAndroid Build Coastguard Worker #endif
781*f6dc9357SAndroid Build Coastguard Worker 
782*f6dc9357SAndroid Build Coastguard Worker #ifdef MY_CPU_LE_UNALIGN
783*f6dc9357SAndroid Build Coastguard Worker #define Z7_RAR5_FILTER_USE_LE_UNALIGN
784*f6dc9357SAndroid Build Coastguard Worker #endif
785*f6dc9357SAndroid Build Coastguard Worker 
786*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_RAR5_FILTER_USE_LE_UNALIGN
787*f6dc9357SAndroid Build Coastguard Worker #define RAR_E8_FILT(mask) \
788*f6dc9357SAndroid Build Coastguard Worker { \
789*f6dc9357SAndroid Build Coastguard Worker   for (;;) \
790*f6dc9357SAndroid Build Coastguard Worker   { UInt32 v; \
791*f6dc9357SAndroid Build Coastguard Worker     do { \
792*f6dc9357SAndroid Build Coastguard Worker       v = GetUi32(data) ^ (UInt32)0xe8e8e8e8; \
793*f6dc9357SAndroid Build Coastguard Worker       data += 4; \
794*f6dc9357SAndroid Build Coastguard Worker       if ((v & ((UInt32)(mask) << (8 * 0))) == 0) { data -= 3; break; } \
795*f6dc9357SAndroid Build Coastguard Worker       if ((v & ((UInt32)(mask) << (8 * 1))) == 0) { data -= 2; break; } \
796*f6dc9357SAndroid Build Coastguard Worker       if ((v & ((UInt32)(mask) << (8 * 2))) == 0) { data -= 1; break; } } \
797*f6dc9357SAndroid Build Coastguard Worker     while((v & ((UInt32)(mask) << (8 * 3)))); \
798*f6dc9357SAndroid Build Coastguard Worker     if (data > data_lim) break; \
799*f6dc9357SAndroid Build Coastguard Worker     const UInt32 offset = BR_PC_GET & (kFileSize - 1); \
800*f6dc9357SAndroid Build Coastguard Worker     const UInt32 addr = GetUi32(data); \
801*f6dc9357SAndroid Build Coastguard Worker     data += 4; \
802*f6dc9357SAndroid Build Coastguard Worker     if (addr < kFileSize) \
803*f6dc9357SAndroid Build Coastguard Worker       SetUi32(data - 4, addr - offset) \
804*f6dc9357SAndroid Build Coastguard Worker     else if (addr > ~offset) /* if (addr > ((UInt32)0xFFFFFFFF - offset)) */ \
805*f6dc9357SAndroid Build Coastguard Worker       SetUi32(data - 4, addr + kFileSize) \
806*f6dc9357SAndroid Build Coastguard Worker   } \
807*f6dc9357SAndroid Build Coastguard Worker }
808*f6dc9357SAndroid Build Coastguard Worker #else
809*f6dc9357SAndroid Build Coastguard Worker #define RAR_E8_FILT(get_byte) \
810*f6dc9357SAndroid Build Coastguard Worker { \
811*f6dc9357SAndroid Build Coastguard Worker   for (;;) \
812*f6dc9357SAndroid Build Coastguard Worker   { \
813*f6dc9357SAndroid Build Coastguard Worker     if ((get_byte) != 0xe8) \
814*f6dc9357SAndroid Build Coastguard Worker     if ((get_byte) != 0xe8) \
815*f6dc9357SAndroid Build Coastguard Worker     if ((get_byte) != 0xe8) \
816*f6dc9357SAndroid Build Coastguard Worker     if ((get_byte) != 0xe8) \
817*f6dc9357SAndroid Build Coastguard Worker       continue; \
818*f6dc9357SAndroid Build Coastguard Worker     { if (data > data_lim) break; \
819*f6dc9357SAndroid Build Coastguard Worker     const UInt32 offset = BR_PC_GET & (kFileSize - 1); \
820*f6dc9357SAndroid Build Coastguard Worker     const UInt32 addr = GetUi32(data); \
821*f6dc9357SAndroid Build Coastguard Worker     data += 4; \
822*f6dc9357SAndroid Build Coastguard Worker     if (addr < kFileSize) \
823*f6dc9357SAndroid Build Coastguard Worker       SetUi32(data - 4, addr - offset) \
824*f6dc9357SAndroid Build Coastguard Worker       else if (addr > ~offset) /* if (addr > ((UInt32)0xFFFFFFFF - offset)) */ \
825*f6dc9357SAndroid Build Coastguard Worker       SetUi32(data - 4, addr + kFileSize) \
826*f6dc9357SAndroid Build Coastguard Worker     } \
827*f6dc9357SAndroid Build Coastguard Worker   } \
828*f6dc9357SAndroid Build Coastguard Worker }
829*f6dc9357SAndroid Build Coastguard Worker #endif
830*f6dc9357SAndroid Build Coastguard Worker 
ExecuteFilter(const CFilter & f)831*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::ExecuteFilter(const CFilter &f)
832*f6dc9357SAndroid Build Coastguard Worker {
833*f6dc9357SAndroid Build Coastguard Worker   Byte *data = _filterSrc;
834*f6dc9357SAndroid Build Coastguard Worker   UInt32 dataSize = f.Size;
835*f6dc9357SAndroid Build Coastguard Worker   // printf("\nType = %d offset = %9d  size = %5d", f.Type, (unsigned)(f.Start - _lzFileStart), dataSize);
836*f6dc9357SAndroid Build Coastguard Worker 
837*f6dc9357SAndroid Build Coastguard Worker   if (f.Type == FILTER_DELTA)
838*f6dc9357SAndroid Build Coastguard Worker   {
839*f6dc9357SAndroid Build Coastguard Worker     // static unsigned g1 = 0, g2 = 0; g1 += dataSize;
840*f6dc9357SAndroid Build Coastguard Worker     // if (g2++ % 100 == 0) printf("DELTA  num %8u, size %8u MiB, channels = %2u curSize=%8u\n", g2, (g1 >> 20), f.Channels, dataSize);
841*f6dc9357SAndroid Build Coastguard Worker     _filterDst.AllocAtLeast_max((size_t)dataSize, k_Filter_BlockSize_MAX);
842*f6dc9357SAndroid Build Coastguard Worker     if (!_filterDst.IsAllocated())
843*f6dc9357SAndroid Build Coastguard Worker       return E_OUTOFMEMORY;
844*f6dc9357SAndroid Build Coastguard Worker 
845*f6dc9357SAndroid Build Coastguard Worker     Byte *dest = _filterDst;
846*f6dc9357SAndroid Build Coastguard Worker     const unsigned numChannels = f.Channels;
847*f6dc9357SAndroid Build Coastguard Worker     unsigned curChannel = 0;
848*f6dc9357SAndroid Build Coastguard Worker     do
849*f6dc9357SAndroid Build Coastguard Worker     {
850*f6dc9357SAndroid Build Coastguard Worker       Byte prevByte = 0;
851*f6dc9357SAndroid Build Coastguard Worker       Byte *dest2 = dest + curChannel;
852*f6dc9357SAndroid Build Coastguard Worker       const Byte *dest_lim = dest + dataSize;
853*f6dc9357SAndroid Build Coastguard Worker       for (; dest2 < dest_lim; dest2 += numChannels)
854*f6dc9357SAndroid Build Coastguard Worker         *dest2 = (prevByte = (Byte)(prevByte - *data++));
855*f6dc9357SAndroid Build Coastguard Worker     }
856*f6dc9357SAndroid Build Coastguard Worker     while (++curChannel != numChannels);
857*f6dc9357SAndroid Build Coastguard Worker     // return WriteData(dest, dataSize);
858*f6dc9357SAndroid Build Coastguard Worker     data = dest;
859*f6dc9357SAndroid Build Coastguard Worker   }
860*f6dc9357SAndroid Build Coastguard Worker   else if (f.Type < FILTER_ARM)
861*f6dc9357SAndroid Build Coastguard Worker   {
862*f6dc9357SAndroid Build Coastguard Worker     // FILTER_E8 or FILTER_E8E9
863*f6dc9357SAndroid Build Coastguard Worker     if (dataSize > 4)
864*f6dc9357SAndroid Build Coastguard Worker     {
865*f6dc9357SAndroid Build Coastguard Worker       UInt32 pc = (UInt32)(f.Start - _lzFileStart);
866*f6dc9357SAndroid Build Coastguard Worker       const UInt32 kFileSize = (UInt32)1 << 24;
867*f6dc9357SAndroid Build Coastguard Worker       const Byte *data_lim = data + dataSize - 4;
868*f6dc9357SAndroid Build Coastguard Worker       BR_PC_INIT(4) // because (data_lim) was moved back for 4 bytes
869*f6dc9357SAndroid Build Coastguard Worker       data[dataSize] = 0xe8;
870*f6dc9357SAndroid Build Coastguard Worker       if (f.Type == FILTER_E8)
871*f6dc9357SAndroid Build Coastguard Worker       {
872*f6dc9357SAndroid Build Coastguard Worker         // static unsigned g1 = 0; g1 += dataSize; printf("\n  FILTER_E8   %u", (g1 >> 20));
873*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_RAR5_FILTER_USE_LE_UNALIGN
874*f6dc9357SAndroid Build Coastguard Worker         RAR_E8_FILT (0xff)
875*f6dc9357SAndroid Build Coastguard Worker #else
876*f6dc9357SAndroid Build Coastguard Worker         RAR_E8_FILT (*data++)
877*f6dc9357SAndroid Build Coastguard Worker #endif
878*f6dc9357SAndroid Build Coastguard Worker       }
879*f6dc9357SAndroid Build Coastguard Worker       else
880*f6dc9357SAndroid Build Coastguard Worker       {
881*f6dc9357SAndroid Build Coastguard Worker         // static unsigned g1 = 0; g1 += dataSize; printf("\n  FILTER_E8_E9 %u", (g1 >> 20));
882*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_RAR5_FILTER_USE_LE_UNALIGN
883*f6dc9357SAndroid Build Coastguard Worker         RAR_E8_FILT (0xfe)
884*f6dc9357SAndroid Build Coastguard Worker #else
885*f6dc9357SAndroid Build Coastguard Worker         RAR_E8_FILT (*data++ & 0xfe)
886*f6dc9357SAndroid Build Coastguard Worker #endif
887*f6dc9357SAndroid Build Coastguard Worker       }
888*f6dc9357SAndroid Build Coastguard Worker     }
889*f6dc9357SAndroid Build Coastguard Worker     data = _filterSrc;
890*f6dc9357SAndroid Build Coastguard Worker   }
891*f6dc9357SAndroid Build Coastguard Worker   else if (f.Type == FILTER_ARM)
892*f6dc9357SAndroid Build Coastguard Worker   {
893*f6dc9357SAndroid Build Coastguard Worker     UInt32 pc = (UInt32)(f.Start - _lzFileStart);
894*f6dc9357SAndroid Build Coastguard Worker #if 0
895*f6dc9357SAndroid Build Coastguard Worker     // z7_BranchConv_ARM_Dec expects that (fileOffset & 3) == 0;
896*f6dc9357SAndroid Build Coastguard Worker     // but even if (fileOffset & 3) then current code
897*f6dc9357SAndroid Build Coastguard Worker     // in z7_BranchConv_ARM_Dec works same way as unrar's code still.
898*f6dc9357SAndroid Build Coastguard Worker     z7_BranchConv_ARM_Dec(data, dataSize, pc - 8);
899*f6dc9357SAndroid Build Coastguard Worker #else
900*f6dc9357SAndroid Build Coastguard Worker     dataSize &= ~(UInt32)3;
901*f6dc9357SAndroid Build Coastguard Worker     if (dataSize)
902*f6dc9357SAndroid Build Coastguard Worker     {
903*f6dc9357SAndroid Build Coastguard Worker       Byte *data_lim = data + dataSize;
904*f6dc9357SAndroid Build Coastguard Worker       data_lim[3] = 0xeb;
905*f6dc9357SAndroid Build Coastguard Worker       BR_PC_INIT(0)
906*f6dc9357SAndroid Build Coastguard Worker       pc -= 4;  // because (data) will point to next instruction
907*f6dc9357SAndroid Build Coastguard Worker       for (;;) // do
908*f6dc9357SAndroid Build Coastguard Worker       {
909*f6dc9357SAndroid Build Coastguard Worker         data += 4;
910*f6dc9357SAndroid Build Coastguard Worker         if (data[-1] != 0xeb)
911*f6dc9357SAndroid Build Coastguard Worker           continue;
912*f6dc9357SAndroid Build Coastguard Worker         if (data > data_lim)
913*f6dc9357SAndroid Build Coastguard Worker           break;
914*f6dc9357SAndroid Build Coastguard Worker         {
915*f6dc9357SAndroid Build Coastguard Worker           UInt32 v = GetUi32a(data - 4) - (BR_PC_GET >> 2);
916*f6dc9357SAndroid Build Coastguard Worker           v &= 0x00ffffff;
917*f6dc9357SAndroid Build Coastguard Worker           v |= 0xeb000000;
918*f6dc9357SAndroid Build Coastguard Worker           SetUi32a(data - 4, v)
919*f6dc9357SAndroid Build Coastguard Worker         }
920*f6dc9357SAndroid Build Coastguard Worker       }
921*f6dc9357SAndroid Build Coastguard Worker     }
922*f6dc9357SAndroid Build Coastguard Worker #endif
923*f6dc9357SAndroid Build Coastguard Worker     data = _filterSrc;
924*f6dc9357SAndroid Build Coastguard Worker   }
925*f6dc9357SAndroid Build Coastguard Worker   else
926*f6dc9357SAndroid Build Coastguard Worker   {
927*f6dc9357SAndroid Build Coastguard Worker     _unsupportedFilter = true;
928*f6dc9357SAndroid Build Coastguard Worker     My_ZeroMemory(data, dataSize);
929*f6dc9357SAndroid Build Coastguard Worker     // return S_OK;  // unrar
930*f6dc9357SAndroid Build Coastguard Worker   }
931*f6dc9357SAndroid Build Coastguard Worker   // return WriteData(_filterSrc, (size_t)f.Size);
932*f6dc9357SAndroid Build Coastguard Worker   return WriteData(data, (size_t)f.Size);
933*f6dc9357SAndroid Build Coastguard Worker }
934*f6dc9357SAndroid Build Coastguard Worker 
935*f6dc9357SAndroid Build Coastguard Worker 
WriteBuf()936*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::WriteBuf()
937*f6dc9357SAndroid Build Coastguard Worker {
938*f6dc9357SAndroid Build Coastguard Worker   DeleteUnusedFilters();
939*f6dc9357SAndroid Build Coastguard Worker 
940*f6dc9357SAndroid Build Coastguard Worker   const UInt64 lzSize = _lzSize + _winPos;
941*f6dc9357SAndroid Build Coastguard Worker 
942*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < _numFilters;)
943*f6dc9357SAndroid Build Coastguard Worker   {
944*f6dc9357SAndroid Build Coastguard Worker     const CFilter &f = _filters[i];
945*f6dc9357SAndroid Build Coastguard Worker     const UInt64 blockStart = f.Start;
946*f6dc9357SAndroid Build Coastguard Worker     const size_t lzAvail = (size_t)(lzSize - _lzWritten);
947*f6dc9357SAndroid Build Coastguard Worker     if (lzAvail == 0)
948*f6dc9357SAndroid Build Coastguard Worker       break;
949*f6dc9357SAndroid Build Coastguard Worker 
950*f6dc9357SAndroid Build Coastguard Worker     if (blockStart > _lzWritten)
951*f6dc9357SAndroid Build Coastguard Worker     {
952*f6dc9357SAndroid Build Coastguard Worker       const UInt64 rem = blockStart - _lzWritten;
953*f6dc9357SAndroid Build Coastguard Worker       size_t size = lzAvail;
954*f6dc9357SAndroid Build Coastguard Worker       if (size > rem)
955*f6dc9357SAndroid Build Coastguard Worker         size = (size_t)rem;
956*f6dc9357SAndroid Build Coastguard Worker       if (size != 0) // is it true always ?
957*f6dc9357SAndroid Build Coastguard Worker       {
958*f6dc9357SAndroid Build Coastguard Worker         RINOK(WriteData(_window + _winPos - lzAvail, size))
959*f6dc9357SAndroid Build Coastguard Worker         _lzWritten += size;
960*f6dc9357SAndroid Build Coastguard Worker       }
961*f6dc9357SAndroid Build Coastguard Worker       continue;
962*f6dc9357SAndroid Build Coastguard Worker     }
963*f6dc9357SAndroid Build Coastguard Worker 
964*f6dc9357SAndroid Build Coastguard Worker     const UInt32 blockSize = f.Size;
965*f6dc9357SAndroid Build Coastguard Worker     size_t offset = (size_t)(_lzWritten - blockStart);
966*f6dc9357SAndroid Build Coastguard Worker     if (offset == 0)
967*f6dc9357SAndroid Build Coastguard Worker     {
968*f6dc9357SAndroid Build Coastguard Worker       _filterSrc.AllocAtLeast_max(
969*f6dc9357SAndroid Build Coastguard Worker           (size_t)blockSize      + k_Filter_AfterPad_Size,
970*f6dc9357SAndroid Build Coastguard Worker           k_Filter_BlockSize_MAX + k_Filter_AfterPad_Size);
971*f6dc9357SAndroid Build Coastguard Worker       if (!_filterSrc.IsAllocated())
972*f6dc9357SAndroid Build Coastguard Worker         return E_OUTOFMEMORY;
973*f6dc9357SAndroid Build Coastguard Worker     }
974*f6dc9357SAndroid Build Coastguard Worker 
975*f6dc9357SAndroid Build Coastguard Worker     const size_t blockRem = (size_t)blockSize - offset;
976*f6dc9357SAndroid Build Coastguard Worker     size_t size = lzAvail;
977*f6dc9357SAndroid Build Coastguard Worker     if (size > blockRem)
978*f6dc9357SAndroid Build Coastguard Worker         size = blockRem;
979*f6dc9357SAndroid Build Coastguard Worker     memcpy(_filterSrc + offset, _window + _winPos - lzAvail, size);
980*f6dc9357SAndroid Build Coastguard Worker     _lzWritten += size;
981*f6dc9357SAndroid Build Coastguard Worker     offset += size;
982*f6dc9357SAndroid Build Coastguard Worker     if (offset != blockSize)
983*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
984*f6dc9357SAndroid Build Coastguard Worker 
985*f6dc9357SAndroid Build Coastguard Worker     _numUnusedFilters = ++i;
986*f6dc9357SAndroid Build Coastguard Worker     RINOK(ExecuteFilter(f))
987*f6dc9357SAndroid Build Coastguard Worker   }
988*f6dc9357SAndroid Build Coastguard Worker 
989*f6dc9357SAndroid Build Coastguard Worker   DeleteUnusedFilters();
990*f6dc9357SAndroid Build Coastguard Worker 
991*f6dc9357SAndroid Build Coastguard Worker   if (_numFilters)
992*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
993*f6dc9357SAndroid Build Coastguard Worker 
994*f6dc9357SAndroid Build Coastguard Worker   const size_t lzAvail = (size_t)(lzSize - _lzWritten);
995*f6dc9357SAndroid Build Coastguard Worker   RINOK(WriteData(_window + _winPos - lzAvail, lzAvail))
996*f6dc9357SAndroid Build Coastguard Worker   _lzWritten += lzAvail;
997*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
998*f6dc9357SAndroid Build Coastguard Worker }
999*f6dc9357SAndroid Build Coastguard Worker 
1000*f6dc9357SAndroid Build Coastguard Worker 
1001*f6dc9357SAndroid Build Coastguard Worker Z7_NO_INLINE
ReadUInt32(CBitDecoder & bi)1002*f6dc9357SAndroid Build Coastguard Worker static UInt32 ReadUInt32(CBitDecoder &bi)
1003*f6dc9357SAndroid Build Coastguard Worker {
1004*f6dc9357SAndroid Build Coastguard Worker   const unsigned numBits = (unsigned)bi.ReadBits_9fix(2) * 8 + 8;
1005*f6dc9357SAndroid Build Coastguard Worker   UInt32 v = 0;
1006*f6dc9357SAndroid Build Coastguard Worker   unsigned i = 0;
1007*f6dc9357SAndroid Build Coastguard Worker   do
1008*f6dc9357SAndroid Build Coastguard Worker   {
1009*f6dc9357SAndroid Build Coastguard Worker     v += (UInt32)bi.ReadBits_9fix(8) << i;
1010*f6dc9357SAndroid Build Coastguard Worker     i += 8;
1011*f6dc9357SAndroid Build Coastguard Worker   }
1012*f6dc9357SAndroid Build Coastguard Worker   while (i != numBits);
1013*f6dc9357SAndroid Build Coastguard Worker   return v;
1014*f6dc9357SAndroid Build Coastguard Worker }
1015*f6dc9357SAndroid Build Coastguard Worker 
1016*f6dc9357SAndroid Build Coastguard Worker 
1017*f6dc9357SAndroid Build Coastguard Worker static const unsigned MAX_UNPACK_FILTERS = 8192;
1018*f6dc9357SAndroid Build Coastguard Worker 
AddFilter(CBitDecoder & _bitStream)1019*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::AddFilter(CBitDecoder &_bitStream)
1020*f6dc9357SAndroid Build Coastguard Worker {
1021*f6dc9357SAndroid Build Coastguard Worker   DeleteUnusedFilters();
1022*f6dc9357SAndroid Build Coastguard Worker 
1023*f6dc9357SAndroid Build Coastguard Worker   if (_numFilters >= MAX_UNPACK_FILTERS)
1024*f6dc9357SAndroid Build Coastguard Worker   {
1025*f6dc9357SAndroid Build Coastguard Worker     RINOK(WriteBuf())
1026*f6dc9357SAndroid Build Coastguard Worker     DeleteUnusedFilters();
1027*f6dc9357SAndroid Build Coastguard Worker     if (_numFilters >= MAX_UNPACK_FILTERS)
1028*f6dc9357SAndroid Build Coastguard Worker     {
1029*f6dc9357SAndroid Build Coastguard Worker       _unsupportedFilter = true;
1030*f6dc9357SAndroid Build Coastguard Worker       InitFilters();
1031*f6dc9357SAndroid Build Coastguard Worker     }
1032*f6dc9357SAndroid Build Coastguard Worker   }
1033*f6dc9357SAndroid Build Coastguard Worker 
1034*f6dc9357SAndroid Build Coastguard Worker   _bitStream.Prepare();
1035*f6dc9357SAndroid Build Coastguard Worker 
1036*f6dc9357SAndroid Build Coastguard Worker   CFilter f;
1037*f6dc9357SAndroid Build Coastguard Worker   const UInt32 blockStart = ReadUInt32(_bitStream);
1038*f6dc9357SAndroid Build Coastguard Worker   f.Size = ReadUInt32(_bitStream);
1039*f6dc9357SAndroid Build Coastguard Worker 
1040*f6dc9357SAndroid Build Coastguard Worker   if (f.Size > k_Filter_BlockSize_MAX)
1041*f6dc9357SAndroid Build Coastguard Worker   {
1042*f6dc9357SAndroid Build Coastguard Worker     _unsupportedFilter = true;
1043*f6dc9357SAndroid Build Coastguard Worker     f.Size = 0;  // unrar 5.5.5
1044*f6dc9357SAndroid Build Coastguard Worker   }
1045*f6dc9357SAndroid Build Coastguard Worker 
1046*f6dc9357SAndroid Build Coastguard Worker   f.Type = (Byte)_bitStream.ReadBits_9fix(3);
1047*f6dc9357SAndroid Build Coastguard Worker   f.Channels = 0;
1048*f6dc9357SAndroid Build Coastguard Worker   if (f.Type == FILTER_DELTA)
1049*f6dc9357SAndroid Build Coastguard Worker     f.Channels = (Byte)(_bitStream.ReadBits_9fix(5) + 1);
1050*f6dc9357SAndroid Build Coastguard Worker   f.Start = _lzSize + _winPos + blockStart;
1051*f6dc9357SAndroid Build Coastguard Worker 
1052*f6dc9357SAndroid Build Coastguard Worker #if 0
1053*f6dc9357SAndroid Build Coastguard Worker   static unsigned z_cnt = 0; if (z_cnt++ % 100 == 0)
1054*f6dc9357SAndroid Build Coastguard Worker     printf ("\nFilter %7u : %4u : %8p, st=%8x, size=%8x, type=%u ch=%2u",
1055*f6dc9357SAndroid Build Coastguard Worker       z_cnt, (unsigned)_filters.Size(), (void *)(size_t)(_lzSize + _winPos),
1056*f6dc9357SAndroid Build Coastguard Worker       (unsigned)blockStart, (unsigned)f.Size, (unsigned)f.Type, (unsigned)f.Channels);
1057*f6dc9357SAndroid Build Coastguard Worker #endif
1058*f6dc9357SAndroid Build Coastguard Worker 
1059*f6dc9357SAndroid Build Coastguard Worker   if (f.Start < _filterEnd)
1060*f6dc9357SAndroid Build Coastguard Worker     _unsupportedFilter = true;
1061*f6dc9357SAndroid Build Coastguard Worker   else
1062*f6dc9357SAndroid Build Coastguard Worker   {
1063*f6dc9357SAndroid Build Coastguard Worker     _filterEnd = f.Start + f.Size;
1064*f6dc9357SAndroid Build Coastguard Worker     if (f.Size != 0)
1065*f6dc9357SAndroid Build Coastguard Worker     {
1066*f6dc9357SAndroid Build Coastguard Worker       if (!_filters)
1067*f6dc9357SAndroid Build Coastguard Worker       {
1068*f6dc9357SAndroid Build Coastguard Worker         _filters = (CFilter *)z7_AlignedAlloc(MAX_UNPACK_FILTERS * sizeof(CFilter));
1069*f6dc9357SAndroid Build Coastguard Worker         if (!_filters)
1070*f6dc9357SAndroid Build Coastguard Worker           return E_OUTOFMEMORY;
1071*f6dc9357SAndroid Build Coastguard Worker       }
1072*f6dc9357SAndroid Build Coastguard Worker       // printf("\n_numFilters = %6u\n", _numFilters);
1073*f6dc9357SAndroid Build Coastguard Worker       const unsigned i = _numFilters++;
1074*f6dc9357SAndroid Build Coastguard Worker       _filters[i] = f;
1075*f6dc9357SAndroid Build Coastguard Worker     }
1076*f6dc9357SAndroid Build Coastguard Worker   }
1077*f6dc9357SAndroid Build Coastguard Worker 
1078*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1079*f6dc9357SAndroid Build Coastguard Worker }
1080*f6dc9357SAndroid Build Coastguard Worker 
1081*f6dc9357SAndroid Build Coastguard Worker 
1082*f6dc9357SAndroid Build Coastguard Worker #define RIF(x) { if (!(x)) return S_FALSE; }
1083*f6dc9357SAndroid Build Coastguard Worker 
1084*f6dc9357SAndroid Build Coastguard Worker #if 1
1085*f6dc9357SAndroid Build Coastguard Worker #define PRINT_CNT(name, skip)
1086*f6dc9357SAndroid Build Coastguard Worker #else
1087*f6dc9357SAndroid Build Coastguard Worker #define PRINT_CNT(name, skip) \
1088*f6dc9357SAndroid Build Coastguard Worker   { static unsigned g_cnt = 0; if (g_cnt++ % skip == 0) printf("\n%16s:  %8u", name, g_cnt); }
1089*f6dc9357SAndroid Build Coastguard Worker #endif
1090*f6dc9357SAndroid Build Coastguard Worker 
ReadTables(CBitDecoder & _bitStream)1091*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream)
1092*f6dc9357SAndroid Build Coastguard Worker {
1093*f6dc9357SAndroid Build Coastguard Worker   if (_progress)
1094*f6dc9357SAndroid Build Coastguard Worker   {
1095*f6dc9357SAndroid Build Coastguard Worker     const UInt64 packSize = _bitStream.GetProcessedSize();
1096*f6dc9357SAndroid Build Coastguard Worker     if (packSize - _progress_Pack >= (1u << 24)
1097*f6dc9357SAndroid Build Coastguard Worker         || _writtenFileSize - _progress_Unpack >= (1u << 26))
1098*f6dc9357SAndroid Build Coastguard Worker     {
1099*f6dc9357SAndroid Build Coastguard Worker       _progress_Pack = packSize;
1100*f6dc9357SAndroid Build Coastguard Worker       _progress_Unpack = _writtenFileSize;
1101*f6dc9357SAndroid Build Coastguard Worker       RINOK(_progress->SetRatioInfo(&_progress_Pack, &_writtenFileSize))
1102*f6dc9357SAndroid Build Coastguard Worker     }
1103*f6dc9357SAndroid Build Coastguard Worker     // printf("\ntable read pos=%p packSize=%p _writtenFileSize = %p\n", (size_t)_winPos, (size_t)packSize, (size_t)_writtenFileSize);
1104*f6dc9357SAndroid Build Coastguard Worker   }
1105*f6dc9357SAndroid Build Coastguard Worker 
1106*f6dc9357SAndroid Build Coastguard Worker   // _bitStream is aligned already
1107*f6dc9357SAndroid Build Coastguard Worker   _bitStream.Prepare();
1108*f6dc9357SAndroid Build Coastguard Worker   {
1109*f6dc9357SAndroid Build Coastguard Worker     const unsigned flags = _bitStream.ReadByte_InAligned();
1110*f6dc9357SAndroid Build Coastguard Worker     /* ((flags & 20) == 0) in all rar archives now,
1111*f6dc9357SAndroid Build Coastguard Worker        but (flags & 20) flag can be used as some decoding hint in future versions of original rar.
1112*f6dc9357SAndroid Build Coastguard Worker        So we ignore that bit here. */
1113*f6dc9357SAndroid Build Coastguard Worker     unsigned checkSum = _bitStream.ReadByte_InAligned();
1114*f6dc9357SAndroid Build Coastguard Worker     checkSum ^= flags;
1115*f6dc9357SAndroid Build Coastguard Worker     const unsigned num = (flags >> 3) & 3;
1116*f6dc9357SAndroid Build Coastguard Worker     if (num >= 3)
1117*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1118*f6dc9357SAndroid Build Coastguard Worker     UInt32 blockSize = _bitStream.ReadByte_InAligned();
1119*f6dc9357SAndroid Build Coastguard Worker     checkSum ^= blockSize;
1120*f6dc9357SAndroid Build Coastguard Worker     if (num != 0)
1121*f6dc9357SAndroid Build Coastguard Worker     {
1122*f6dc9357SAndroid Build Coastguard Worker       {
1123*f6dc9357SAndroid Build Coastguard Worker         const unsigned b = _bitStream.ReadByte_InAligned();
1124*f6dc9357SAndroid Build Coastguard Worker         checkSum ^= b;
1125*f6dc9357SAndroid Build Coastguard Worker         blockSize += (UInt32)b << 8;
1126*f6dc9357SAndroid Build Coastguard Worker       }
1127*f6dc9357SAndroid Build Coastguard Worker       if (num > 1)
1128*f6dc9357SAndroid Build Coastguard Worker       {
1129*f6dc9357SAndroid Build Coastguard Worker         const unsigned b = _bitStream.ReadByte_InAligned();
1130*f6dc9357SAndroid Build Coastguard Worker         checkSum ^= b;
1131*f6dc9357SAndroid Build Coastguard Worker         blockSize += (UInt32)b << 16;
1132*f6dc9357SAndroid Build Coastguard Worker       }
1133*f6dc9357SAndroid Build Coastguard Worker     }
1134*f6dc9357SAndroid Build Coastguard Worker     if (checkSum != 0x5A)
1135*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1136*f6dc9357SAndroid Build Coastguard Worker     unsigned blockSizeBits7 = (flags & 7) + 1;
1137*f6dc9357SAndroid Build Coastguard Worker     blockSize += (UInt32)(blockSizeBits7 >> 3);
1138*f6dc9357SAndroid Build Coastguard Worker     if (blockSize == 0)
1139*f6dc9357SAndroid Build Coastguard Worker     {
1140*f6dc9357SAndroid Build Coastguard Worker       // it's error in data stream
1141*f6dc9357SAndroid Build Coastguard Worker       // but original-unrar ignores that error
1142*f6dc9357SAndroid Build Coastguard Worker       _bitStream._minorError = true;
1143*f6dc9357SAndroid Build Coastguard Worker #if 1
1144*f6dc9357SAndroid Build Coastguard Worker       // we ignore that error as original-unrar:
1145*f6dc9357SAndroid Build Coastguard Worker       blockSizeBits7 = 0;
1146*f6dc9357SAndroid Build Coastguard Worker       blockSize = 1;
1147*f6dc9357SAndroid Build Coastguard Worker #else
1148*f6dc9357SAndroid Build Coastguard Worker       // we can stop decoding:
1149*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1150*f6dc9357SAndroid Build Coastguard Worker #endif
1151*f6dc9357SAndroid Build Coastguard Worker     }
1152*f6dc9357SAndroid Build Coastguard Worker     blockSize--;
1153*f6dc9357SAndroid Build Coastguard Worker     blockSizeBits7 &= 7;
1154*f6dc9357SAndroid Build Coastguard Worker     PRINT_CNT("Blocks", 100)
1155*f6dc9357SAndroid Build Coastguard Worker     /*
1156*f6dc9357SAndroid Build Coastguard Worker     {
1157*f6dc9357SAndroid Build Coastguard Worker       static unsigned g_prev = 0;
1158*f6dc9357SAndroid Build Coastguard Worker       static unsigned g_cnt = 0;
1159*f6dc9357SAndroid Build Coastguard Worker       unsigned proc = unsigned(_winPos);
1160*f6dc9357SAndroid Build Coastguard Worker       if (g_cnt++ % 100 == 0) printf("  c_size = %8u  ", blockSize);
1161*f6dc9357SAndroid Build Coastguard Worker       if (g_cnt++ % 100 == 1) printf("  unp_size = %8u", proc - g_prev);
1162*f6dc9357SAndroid Build Coastguard Worker       g_prev = proc;
1163*f6dc9357SAndroid Build Coastguard Worker     }
1164*f6dc9357SAndroid Build Coastguard Worker     */
1165*f6dc9357SAndroid Build Coastguard Worker     _bitStream._blockEndBits7 = blockSizeBits7;
1166*f6dc9357SAndroid Build Coastguard Worker     _bitStream._blockEnd = _bitStream.GetProcessedSize_Round() + blockSize;
1167*f6dc9357SAndroid Build Coastguard Worker     _bitStream.SetCheck_forBlock();
1168*f6dc9357SAndroid Build Coastguard Worker     _isLastBlock = ((flags & 0x40) != 0);
1169*f6dc9357SAndroid Build Coastguard Worker     if ((flags & 0x80) == 0)
1170*f6dc9357SAndroid Build Coastguard Worker     {
1171*f6dc9357SAndroid Build Coastguard Worker       if (!_tableWasFilled)
1172*f6dc9357SAndroid Build Coastguard Worker         // if (blockSize != 0 || blockSizeBits7 != 0)
1173*f6dc9357SAndroid Build Coastguard Worker         if (blockSize + blockSizeBits7 != 0)
1174*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
1175*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
1176*f6dc9357SAndroid Build Coastguard Worker     }
1177*f6dc9357SAndroid Build Coastguard Worker     _tableWasFilled = false;
1178*f6dc9357SAndroid Build Coastguard Worker   }
1179*f6dc9357SAndroid Build Coastguard Worker 
1180*f6dc9357SAndroid Build Coastguard Worker   PRINT_CNT("Tables", 100);
1181*f6dc9357SAndroid Build Coastguard Worker 
1182*f6dc9357SAndroid Build Coastguard Worker   const unsigned kLevelTableSize = 20;
1183*f6dc9357SAndroid Build Coastguard Worker   const unsigned k_NumHufTableBits_Level = 6;
1184*f6dc9357SAndroid Build Coastguard Worker   NHuffman::CDecoder256<kNumHufBits, kLevelTableSize, k_NumHufTableBits_Level> m_LevelDecoder;
1185*f6dc9357SAndroid Build Coastguard Worker   const unsigned kTablesSizesSum_MAX = kMainTableSize + kDistTableSize_MAX + kAlignTableSize + kLenTableSize;
1186*f6dc9357SAndroid Build Coastguard Worker   Byte lens[kTablesSizesSum_MAX];
1187*f6dc9357SAndroid Build Coastguard Worker   {
1188*f6dc9357SAndroid Build Coastguard Worker     // (kLevelTableSize + 16 < kTablesSizesSum). So we use lens[] array for (Level) table
1189*f6dc9357SAndroid Build Coastguard Worker     // Byte lens2[kLevelTableSize + 16];
1190*f6dc9357SAndroid Build Coastguard Worker     unsigned i = 0;
1191*f6dc9357SAndroid Build Coastguard Worker     do
1192*f6dc9357SAndroid Build Coastguard Worker     {
1193*f6dc9357SAndroid Build Coastguard Worker       if (_bitStream._buf >= _bitStream._bufCheck_Block)
1194*f6dc9357SAndroid Build Coastguard Worker       {
1195*f6dc9357SAndroid Build Coastguard Worker         _bitStream.Prepare();
1196*f6dc9357SAndroid Build Coastguard Worker         if (_bitStream.IsBlockOverRead())
1197*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
1198*f6dc9357SAndroid Build Coastguard Worker       }
1199*f6dc9357SAndroid Build Coastguard Worker       const unsigned len = (unsigned)_bitStream.ReadBits_9fix(4);
1200*f6dc9357SAndroid Build Coastguard Worker       if (len == 15)
1201*f6dc9357SAndroid Build Coastguard Worker       {
1202*f6dc9357SAndroid Build Coastguard Worker         unsigned num = (unsigned)_bitStream.ReadBits_9fix(4);
1203*f6dc9357SAndroid Build Coastguard Worker         if (num != 0)
1204*f6dc9357SAndroid Build Coastguard Worker         {
1205*f6dc9357SAndroid Build Coastguard Worker           num += 2;
1206*f6dc9357SAndroid Build Coastguard Worker           num += i;
1207*f6dc9357SAndroid Build Coastguard Worker           // we are allowed to overwrite to lens[] for extra 16 bytes after kLevelTableSize
1208*f6dc9357SAndroid Build Coastguard Worker #if 0
1209*f6dc9357SAndroid Build Coastguard Worker           if (num > kLevelTableSize)
1210*f6dc9357SAndroid Build Coastguard Worker           {
1211*f6dc9357SAndroid Build Coastguard Worker             // we ignore this error as original-unrar
1212*f6dc9357SAndroid Build Coastguard Worker             num = kLevelTableSize;
1213*f6dc9357SAndroid Build Coastguard Worker             // return S_FALSE;
1214*f6dc9357SAndroid Build Coastguard Worker           }
1215*f6dc9357SAndroid Build Coastguard Worker #endif
1216*f6dc9357SAndroid Build Coastguard Worker           do
1217*f6dc9357SAndroid Build Coastguard Worker             lens[i++] = 0;
1218*f6dc9357SAndroid Build Coastguard Worker           while (i < num);
1219*f6dc9357SAndroid Build Coastguard Worker           continue;
1220*f6dc9357SAndroid Build Coastguard Worker         }
1221*f6dc9357SAndroid Build Coastguard Worker       }
1222*f6dc9357SAndroid Build Coastguard Worker       lens[i++] = (Byte)len;
1223*f6dc9357SAndroid Build Coastguard Worker     }
1224*f6dc9357SAndroid Build Coastguard Worker     while (i < kLevelTableSize);
1225*f6dc9357SAndroid Build Coastguard Worker     if (_bitStream.IsBlockOverRead())
1226*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1227*f6dc9357SAndroid Build Coastguard Worker     RIF(m_LevelDecoder.Build(lens, NHuffman::k_BuildMode_Full))
1228*f6dc9357SAndroid Build Coastguard Worker   }
1229*f6dc9357SAndroid Build Coastguard Worker 
1230*f6dc9357SAndroid Build Coastguard Worker   unsigned i = 0;
1231*f6dc9357SAndroid Build Coastguard Worker   const unsigned tableSize = _is_v7 ?
1232*f6dc9357SAndroid Build Coastguard Worker       kTablesSizesSum_MAX :
1233*f6dc9357SAndroid Build Coastguard Worker       kTablesSizesSum_MAX - kExtraDistSymbols_v7;
1234*f6dc9357SAndroid Build Coastguard Worker   do
1235*f6dc9357SAndroid Build Coastguard Worker   {
1236*f6dc9357SAndroid Build Coastguard Worker     if (_bitStream._buf >= _bitStream._bufCheck_Block)
1237*f6dc9357SAndroid Build Coastguard Worker     {
1238*f6dc9357SAndroid Build Coastguard Worker       // if (_bitStream._buf >= _bitStream._bufCheck)
1239*f6dc9357SAndroid Build Coastguard Worker       _bitStream.Prepare();
1240*f6dc9357SAndroid Build Coastguard Worker       if (_bitStream.IsBlockOverRead())
1241*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1242*f6dc9357SAndroid Build Coastguard Worker     }
1243*f6dc9357SAndroid Build Coastguard Worker     const unsigned sym = m_LevelDecoder.DecodeFull(&_bitStream);
1244*f6dc9357SAndroid Build Coastguard Worker     if (sym < 16)
1245*f6dc9357SAndroid Build Coastguard Worker       lens[i++] = (Byte)sym;
1246*f6dc9357SAndroid Build Coastguard Worker #if 0
1247*f6dc9357SAndroid Build Coastguard Worker     else if (sym > kLevelTableSize)
1248*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1249*f6dc9357SAndroid Build Coastguard Worker #endif
1250*f6dc9357SAndroid Build Coastguard Worker     else
1251*f6dc9357SAndroid Build Coastguard Worker     {
1252*f6dc9357SAndroid Build Coastguard Worker       unsigned num = ((sym /* - 16 */) & 1) * 4;
1253*f6dc9357SAndroid Build Coastguard Worker       num += num + 3 + (unsigned)_bitStream.ReadBits9(num + 3);
1254*f6dc9357SAndroid Build Coastguard Worker       num += i;
1255*f6dc9357SAndroid Build Coastguard Worker       if (num > tableSize)
1256*f6dc9357SAndroid Build Coastguard Worker       {
1257*f6dc9357SAndroid Build Coastguard Worker         // we ignore this error as original-unrar
1258*f6dc9357SAndroid Build Coastguard Worker         num = tableSize;
1259*f6dc9357SAndroid Build Coastguard Worker         // return S_FALSE;
1260*f6dc9357SAndroid Build Coastguard Worker       }
1261*f6dc9357SAndroid Build Coastguard Worker       unsigned v = 0;
1262*f6dc9357SAndroid Build Coastguard Worker       if (sym < 16 + 2)
1263*f6dc9357SAndroid Build Coastguard Worker       {
1264*f6dc9357SAndroid Build Coastguard Worker         if (i == 0)
1265*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
1266*f6dc9357SAndroid Build Coastguard Worker         v = lens[(size_t)i - 1];
1267*f6dc9357SAndroid Build Coastguard Worker       }
1268*f6dc9357SAndroid Build Coastguard Worker       do
1269*f6dc9357SAndroid Build Coastguard Worker         lens[i++] = (Byte)v;
1270*f6dc9357SAndroid Build Coastguard Worker       while (i < num);
1271*f6dc9357SAndroid Build Coastguard Worker     }
1272*f6dc9357SAndroid Build Coastguard Worker   }
1273*f6dc9357SAndroid Build Coastguard Worker   while (i < tableSize);
1274*f6dc9357SAndroid Build Coastguard Worker 
1275*f6dc9357SAndroid Build Coastguard Worker   if (_bitStream.IsBlockOverRead())
1276*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1277*f6dc9357SAndroid Build Coastguard Worker   if (_bitStream.InputEofError())
1278*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1279*f6dc9357SAndroid Build Coastguard Worker 
1280*f6dc9357SAndroid Build Coastguard Worker   /* We suppose that original-rar encoder can create only two cases for Huffman:
1281*f6dc9357SAndroid Build Coastguard Worker       1) Empty Huffman tree (if num_used_symbols == 0)
1282*f6dc9357SAndroid Build Coastguard Worker       2) Full  Huffman tree (if num_used_symbols != 0)
1283*f6dc9357SAndroid Build Coastguard Worker      Usually the block contains at least one symbol for m_MainDecoder.
1284*f6dc9357SAndroid Build Coastguard Worker      So original-rar-encoder creates full Huffman tree for m_MainDecoder.
1285*f6dc9357SAndroid Build Coastguard Worker      But we suppose that (num_used_symbols == 0) is possible for m_MainDecoder,
1286*f6dc9357SAndroid Build Coastguard Worker      because file must be finished with (_isLastBlock) flag,
1287*f6dc9357SAndroid Build Coastguard Worker      even if there are no symbols in m_MainDecoder.
1288*f6dc9357SAndroid Build Coastguard Worker      So we use k_BuildMode_Full_or_Empty for m_MainDecoder.
1289*f6dc9357SAndroid Build Coastguard Worker   */
1290*f6dc9357SAndroid Build Coastguard Worker   const NHuffman::enum_BuildMode buildMode = NHuffman::
1291*f6dc9357SAndroid Build Coastguard Worker       k_BuildMode_Full_or_Empty; // strict check
1292*f6dc9357SAndroid Build Coastguard Worker       // k_BuildMode_Partial;    // non-strict check (ignore errors)
1293*f6dc9357SAndroid Build Coastguard Worker 
1294*f6dc9357SAndroid Build Coastguard Worker   RIF(m_MainDecoder.Build(&lens[0], buildMode))
1295*f6dc9357SAndroid Build Coastguard Worker   if (!_is_v7)
1296*f6dc9357SAndroid Build Coastguard Worker   {
1297*f6dc9357SAndroid Build Coastguard Worker #if 1
1298*f6dc9357SAndroid Build Coastguard Worker     /* we use this manual loop to avoid compiler BUG.
1299*f6dc9357SAndroid Build Coastguard Worker        GCC 4.9.2 compiler has BUG with overlapping memmove() to right in local array. */
1300*f6dc9357SAndroid Build Coastguard Worker     Byte *dest = lens + kMainTableSize + kDistTableSize_v6 +
1301*f6dc9357SAndroid Build Coastguard Worker                    kAlignTableSize + kLenTableSize - 1;
1302*f6dc9357SAndroid Build Coastguard Worker     unsigned num = kAlignTableSize + kLenTableSize;
1303*f6dc9357SAndroid Build Coastguard Worker     do
1304*f6dc9357SAndroid Build Coastguard Worker     {
1305*f6dc9357SAndroid Build Coastguard Worker       dest[kExtraDistSymbols_v7] = dest[0];
1306*f6dc9357SAndroid Build Coastguard Worker       dest--;
1307*f6dc9357SAndroid Build Coastguard Worker     }
1308*f6dc9357SAndroid Build Coastguard Worker     while (--num);
1309*f6dc9357SAndroid Build Coastguard Worker #else
1310*f6dc9357SAndroid Build Coastguard Worker     memmove(lens + kMainTableSize + kDistTableSize_v6 + kExtraDistSymbols_v7,
1311*f6dc9357SAndroid Build Coastguard Worker             lens + kMainTableSize + kDistTableSize_v6,
1312*f6dc9357SAndroid Build Coastguard Worker             kAlignTableSize + kLenTableSize);
1313*f6dc9357SAndroid Build Coastguard Worker #endif
1314*f6dc9357SAndroid Build Coastguard Worker     memset(lens + kMainTableSize + kDistTableSize_v6, 0, kExtraDistSymbols_v7);
1315*f6dc9357SAndroid Build Coastguard Worker   }
1316*f6dc9357SAndroid Build Coastguard Worker 
1317*f6dc9357SAndroid Build Coastguard Worker   RIF(m_DistDecoder.Build(&lens[kMainTableSize], buildMode))
1318*f6dc9357SAndroid Build Coastguard Worker   RIF( m_LenDecoder.Build(&lens[kMainTableSize
1319*f6dc9357SAndroid Build Coastguard Worker         + kDistTableSize_MAX + kAlignTableSize], buildMode))
1320*f6dc9357SAndroid Build Coastguard Worker 
1321*f6dc9357SAndroid Build Coastguard Worker   _useAlignBits = false;
1322*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < kAlignTableSize; i++)
1323*f6dc9357SAndroid Build Coastguard Worker     if (lens[kMainTableSize + kDistTableSize_MAX + (size_t)i] != kNumAlignBits)
1324*f6dc9357SAndroid Build Coastguard Worker     {
1325*f6dc9357SAndroid Build Coastguard Worker       RIF(m_AlignDecoder.Build(&lens[kMainTableSize + kDistTableSize_MAX], buildMode))
1326*f6dc9357SAndroid Build Coastguard Worker       _useAlignBits = true;
1327*f6dc9357SAndroid Build Coastguard Worker       break;
1328*f6dc9357SAndroid Build Coastguard Worker     }
1329*f6dc9357SAndroid Build Coastguard Worker 
1330*f6dc9357SAndroid Build Coastguard Worker   _tableWasFilled = true;
1331*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1332*f6dc9357SAndroid Build Coastguard Worker }
1333*f6dc9357SAndroid Build Coastguard Worker 
SlotToLen(CBitDecoder & _bitStream,CLenType slot)1334*f6dc9357SAndroid Build Coastguard Worker static inline CLenType SlotToLen(CBitDecoder &_bitStream, CLenType slot)
1335*f6dc9357SAndroid Build Coastguard Worker {
1336*f6dc9357SAndroid Build Coastguard Worker   const unsigned numBits = ((unsigned)slot >> 2) - 1;
1337*f6dc9357SAndroid Build Coastguard Worker   return ((4 | (slot & 3)) << numBits) + (CLenType)_bitStream.ReadBits9(numBits);
1338*f6dc9357SAndroid Build Coastguard Worker }
1339*f6dc9357SAndroid Build Coastguard Worker 
1340*f6dc9357SAndroid Build Coastguard Worker 
1341*f6dc9357SAndroid Build Coastguard Worker static const unsigned kSymbolRep = 258;
1342*f6dc9357SAndroid Build Coastguard Worker static const unsigned kMaxMatchLen = 0x1001 + 3;
1343*f6dc9357SAndroid Build Coastguard Worker 
1344*f6dc9357SAndroid Build Coastguard Worker enum enum_exit_type
1345*f6dc9357SAndroid Build Coastguard Worker {
1346*f6dc9357SAndroid Build Coastguard Worker   Z7_RAR_EXIT_TYPE_NONE,
1347*f6dc9357SAndroid Build Coastguard Worker   Z7_RAR_EXIT_TYPE_ADD_FILTER
1348*f6dc9357SAndroid Build Coastguard Worker };
1349*f6dc9357SAndroid Build Coastguard Worker 
1350*f6dc9357SAndroid Build Coastguard Worker 
1351*f6dc9357SAndroid Build Coastguard Worker #define LZ_RESTORE \
1352*f6dc9357SAndroid Build Coastguard Worker { \
1353*f6dc9357SAndroid Build Coastguard Worker   _reps[0] = rep0; \
1354*f6dc9357SAndroid Build Coastguard Worker   _winPos = (size_t)(winPos - _window); \
1355*f6dc9357SAndroid Build Coastguard Worker   _buf_Res = _bitStream._buf; \
1356*f6dc9357SAndroid Build Coastguard Worker   _bitPos_Res = _bitStream._bitPos; \
1357*f6dc9357SAndroid Build Coastguard Worker }
1358*f6dc9357SAndroid Build Coastguard Worker 
1359*f6dc9357SAndroid Build Coastguard Worker #define LZ_LOOP_BREAK_OK { break; }
1360*f6dc9357SAndroid Build Coastguard Worker // #define LZ_LOOP_BREAK_ERROR { _lzError = LZ_ERROR_TYPE_SYM; break; }
1361*f6dc9357SAndroid Build Coastguard Worker // #define LZ_LOOP_BREAK_ERROR { LZ_RESTORE; return S_FALSE; }
1362*f6dc9357SAndroid Build Coastguard Worker #define LZ_LOOP_BREAK_ERROR { goto decode_error; }
1363*f6dc9357SAndroid Build Coastguard Worker // goto decode_error; }
1364*f6dc9357SAndroid Build Coastguard Worker // #define LZ_LOOP_BREAK_ERROR { break; }
1365*f6dc9357SAndroid Build Coastguard Worker 
1366*f6dc9357SAndroid Build Coastguard Worker #define Z7_RAR_HUFF_DECODE_CHECK_break(sym, huf, kNumTableBits, bitStream) \
1367*f6dc9357SAndroid Build Coastguard Worker   Z7_HUFF_DECODE_CHECK(sym, huf, kNumHufBits, kNumTableBits, bitStream, { LZ_LOOP_BREAK_ERROR })
1368*f6dc9357SAndroid Build Coastguard Worker 
1369*f6dc9357SAndroid Build Coastguard Worker 
DecodeLZ2(const CBitDecoder & bitStream)1370*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::DecodeLZ2(const CBitDecoder &bitStream) throw()
1371*f6dc9357SAndroid Build Coastguard Worker {
1372*f6dc9357SAndroid Build Coastguard Worker #if 0
1373*f6dc9357SAndroid Build Coastguard Worker   Byte k_LenPlusTable_LOC[DICT_SIZE_BITS_MAX];
1374*f6dc9357SAndroid Build Coastguard Worker   memcpy(k_LenPlusTable_LOC, k_LenPlusTable, sizeof(k_LenPlusTable));
1375*f6dc9357SAndroid Build Coastguard Worker #endif
1376*f6dc9357SAndroid Build Coastguard Worker 
1377*f6dc9357SAndroid Build Coastguard Worker   PRINT_CNT("DecodeLZ2", 2000);
1378*f6dc9357SAndroid Build Coastguard Worker 
1379*f6dc9357SAndroid Build Coastguard Worker   CBitDecoder _bitStream;
1380*f6dc9357SAndroid Build Coastguard Worker   _bitStream.CopyFrom(bitStream);
1381*f6dc9357SAndroid Build Coastguard Worker   // _bitStream._stream = _inStream;
1382*f6dc9357SAndroid Build Coastguard Worker   // _bitStream._bufBase = _inputBuf;
1383*f6dc9357SAndroid Build Coastguard Worker   // _bitStream.Init();
1384*f6dc9357SAndroid Build Coastguard Worker 
1385*f6dc9357SAndroid Build Coastguard Worker   // _reps[*] can be larger than _winSize, if _winSize was reduced in solid stream.
1386*f6dc9357SAndroid Build Coastguard Worker   size_t rep0 = _reps[0];
1387*f6dc9357SAndroid Build Coastguard Worker   // size_t rep1 = _reps[1];
1388*f6dc9357SAndroid Build Coastguard Worker   // Byte *win = _window;
1389*f6dc9357SAndroid Build Coastguard Worker   Byte *winPos = _window + _winPos;
1390*f6dc9357SAndroid Build Coastguard Worker   const Byte *limit = _window + _limit;
1391*f6dc9357SAndroid Build Coastguard Worker   _exitType = Z7_RAR_EXIT_TYPE_NONE;
1392*f6dc9357SAndroid Build Coastguard Worker 
1393*f6dc9357SAndroid Build Coastguard Worker   for (;;)
1394*f6dc9357SAndroid Build Coastguard Worker   {
1395*f6dc9357SAndroid Build Coastguard Worker     if (winPos >= limit)
1396*f6dc9357SAndroid Build Coastguard Worker       LZ_LOOP_BREAK_OK
1397*f6dc9357SAndroid Build Coastguard Worker     // (winPos < limit)
1398*f6dc9357SAndroid Build Coastguard Worker     if (_bitStream._buf >= _bitStream._bufCheck_Block)
1399*f6dc9357SAndroid Build Coastguard Worker     {
1400*f6dc9357SAndroid Build Coastguard Worker       if (_bitStream.InputEofError())
1401*f6dc9357SAndroid Build Coastguard Worker         LZ_LOOP_BREAK_OK
1402*f6dc9357SAndroid Build Coastguard Worker       if (_bitStream._buf >= _bitStream._bufCheck)
1403*f6dc9357SAndroid Build Coastguard Worker       {
1404*f6dc9357SAndroid Build Coastguard Worker         if (!_bitStream._wasFinished)
1405*f6dc9357SAndroid Build Coastguard Worker           LZ_LOOP_BREAK_OK
1406*f6dc9357SAndroid Build Coastguard Worker         // _bitStream._wasFinished == true
1407*f6dc9357SAndroid Build Coastguard Worker         // we don't need Prepare() here, because all data was read
1408*f6dc9357SAndroid Build Coastguard Worker         // and PadZone (16 bytes) after data was filled.
1409*f6dc9357SAndroid Build Coastguard Worker       }
1410*f6dc9357SAndroid Build Coastguard Worker       const UInt64 processed = _bitStream.GetProcessedSize_Round();
1411*f6dc9357SAndroid Build Coastguard Worker       // some cases are error, but the caller will process such error cases.
1412*f6dc9357SAndroid Build Coastguard Worker       if (processed >= _bitStream._blockEnd &&
1413*f6dc9357SAndroid Build Coastguard Worker           (processed > _bitStream._blockEnd
1414*f6dc9357SAndroid Build Coastguard Worker             || _bitStream.GetProcessedBits7() >= _bitStream._blockEndBits7))
1415*f6dc9357SAndroid Build Coastguard Worker           LZ_LOOP_BREAK_OK
1416*f6dc9357SAndroid Build Coastguard Worker       // that check is not required, but it can help, if there is BUG in another code
1417*f6dc9357SAndroid Build Coastguard Worker       if (!_tableWasFilled)
1418*f6dc9357SAndroid Build Coastguard Worker         LZ_LOOP_BREAK_ERROR
1419*f6dc9357SAndroid Build Coastguard Worker     }
1420*f6dc9357SAndroid Build Coastguard Worker 
1421*f6dc9357SAndroid Build Coastguard Worker #if 0
1422*f6dc9357SAndroid Build Coastguard Worker     const unsigned sym = m_MainDecoder.Decode(&_bitStream);
1423*f6dc9357SAndroid Build Coastguard Worker #else
1424*f6dc9357SAndroid Build Coastguard Worker     unsigned sym;
1425*f6dc9357SAndroid Build Coastguard Worker     Z7_RAR_HUFF_DECODE_CHECK_break(sym, &m_MainDecoder, k_NumHufTableBits_Main, &_bitStream)
1426*f6dc9357SAndroid Build Coastguard Worker #endif
1427*f6dc9357SAndroid Build Coastguard Worker 
1428*f6dc9357SAndroid Build Coastguard Worker     if (sym < 256)
1429*f6dc9357SAndroid Build Coastguard Worker     {
1430*f6dc9357SAndroid Build Coastguard Worker       *winPos++ = (Byte)sym;
1431*f6dc9357SAndroid Build Coastguard Worker       // _lzSize++;
1432*f6dc9357SAndroid Build Coastguard Worker       continue;
1433*f6dc9357SAndroid Build Coastguard Worker     }
1434*f6dc9357SAndroid Build Coastguard Worker 
1435*f6dc9357SAndroid Build Coastguard Worker     CLenType len;
1436*f6dc9357SAndroid Build Coastguard Worker 
1437*f6dc9357SAndroid Build Coastguard Worker     if (sym < kSymbolRep + kNumReps)
1438*f6dc9357SAndroid Build Coastguard Worker     {
1439*f6dc9357SAndroid Build Coastguard Worker       if (sym >= kSymbolRep)
1440*f6dc9357SAndroid Build Coastguard Worker       {
1441*f6dc9357SAndroid Build Coastguard Worker         if (sym != kSymbolRep)
1442*f6dc9357SAndroid Build Coastguard Worker         {
1443*f6dc9357SAndroid Build Coastguard Worker           size_t dist = _reps[1];
1444*f6dc9357SAndroid Build Coastguard Worker           _reps[1] = rep0;
1445*f6dc9357SAndroid Build Coastguard Worker           rep0 = dist;
1446*f6dc9357SAndroid Build Coastguard Worker           if (sym >= kSymbolRep + 2)
1447*f6dc9357SAndroid Build Coastguard Worker           {
1448*f6dc9357SAndroid Build Coastguard Worker             #if 1
1449*f6dc9357SAndroid Build Coastguard Worker               rep0 = _reps[(size_t)sym - kSymbolRep];
1450*f6dc9357SAndroid Build Coastguard Worker               _reps[(size_t)sym - kSymbolRep] = _reps[2];
1451*f6dc9357SAndroid Build Coastguard Worker               _reps[2] = dist;
1452*f6dc9357SAndroid Build Coastguard Worker             #else
1453*f6dc9357SAndroid Build Coastguard Worker               if (sym != kSymbolRep + 2)
1454*f6dc9357SAndroid Build Coastguard Worker               {
1455*f6dc9357SAndroid Build Coastguard Worker                 rep0 = _reps[3];
1456*f6dc9357SAndroid Build Coastguard Worker                 _reps[3] = _reps[2];
1457*f6dc9357SAndroid Build Coastguard Worker                 _reps[2] = dist;
1458*f6dc9357SAndroid Build Coastguard Worker               }
1459*f6dc9357SAndroid Build Coastguard Worker               else
1460*f6dc9357SAndroid Build Coastguard Worker               {
1461*f6dc9357SAndroid Build Coastguard Worker                 rep0 = _reps[2];
1462*f6dc9357SAndroid Build Coastguard Worker                 _reps[2] = dist;
1463*f6dc9357SAndroid Build Coastguard Worker               }
1464*f6dc9357SAndroid Build Coastguard Worker             #endif
1465*f6dc9357SAndroid Build Coastguard Worker           }
1466*f6dc9357SAndroid Build Coastguard Worker         }
1467*f6dc9357SAndroid Build Coastguard Worker #if 0
1468*f6dc9357SAndroid Build Coastguard Worker         len = m_LenDecoder.Decode(&_bitStream);
1469*f6dc9357SAndroid Build Coastguard Worker         if (len >= kLenTableSize)
1470*f6dc9357SAndroid Build Coastguard Worker           LZ_LOOP_BREAK_ERROR
1471*f6dc9357SAndroid Build Coastguard Worker #else
1472*f6dc9357SAndroid Build Coastguard Worker         Z7_RAR_HUFF_DECODE_CHECK_break(len, &m_LenDecoder, k_NumHufTableBits_Len, &_bitStream)
1473*f6dc9357SAndroid Build Coastguard Worker #endif
1474*f6dc9357SAndroid Build Coastguard Worker         if (len >= 8)
1475*f6dc9357SAndroid Build Coastguard Worker           len = SlotToLen(_bitStream, len);
1476*f6dc9357SAndroid Build Coastguard Worker         len += 2;
1477*f6dc9357SAndroid Build Coastguard Worker         // _lastLen = (UInt32)len;
1478*f6dc9357SAndroid Build Coastguard Worker       }
1479*f6dc9357SAndroid Build Coastguard Worker       else if (sym != 256)
1480*f6dc9357SAndroid Build Coastguard Worker       {
1481*f6dc9357SAndroid Build Coastguard Worker         len = (CLenType)_lastLen;
1482*f6dc9357SAndroid Build Coastguard Worker         if (len == 0)
1483*f6dc9357SAndroid Build Coastguard Worker         {
1484*f6dc9357SAndroid Build Coastguard Worker           // we ignore (_lastLen == 0) case, like original-unrar.
1485*f6dc9357SAndroid Build Coastguard Worker           // that case can mean error in stream.
1486*f6dc9357SAndroid Build Coastguard Worker           // lzError = true;
1487*f6dc9357SAndroid Build Coastguard Worker           // return S_FALSE;
1488*f6dc9357SAndroid Build Coastguard Worker           continue;
1489*f6dc9357SAndroid Build Coastguard Worker         }
1490*f6dc9357SAndroid Build Coastguard Worker       }
1491*f6dc9357SAndroid Build Coastguard Worker       else
1492*f6dc9357SAndroid Build Coastguard Worker       {
1493*f6dc9357SAndroid Build Coastguard Worker         _exitType = Z7_RAR_EXIT_TYPE_ADD_FILTER;
1494*f6dc9357SAndroid Build Coastguard Worker         LZ_LOOP_BREAK_OK
1495*f6dc9357SAndroid Build Coastguard Worker       }
1496*f6dc9357SAndroid Build Coastguard Worker     }
1497*f6dc9357SAndroid Build Coastguard Worker #if 0
1498*f6dc9357SAndroid Build Coastguard Worker     else if (sym >= kMainTableSize)
1499*f6dc9357SAndroid Build Coastguard Worker       LZ_LOOP_BREAK_ERROR
1500*f6dc9357SAndroid Build Coastguard Worker #endif
1501*f6dc9357SAndroid Build Coastguard Worker     else
1502*f6dc9357SAndroid Build Coastguard Worker     {
1503*f6dc9357SAndroid Build Coastguard Worker       _reps[3] = _reps[2];
1504*f6dc9357SAndroid Build Coastguard Worker       _reps[2] = _reps[1];
1505*f6dc9357SAndroid Build Coastguard Worker       _reps[1] = rep0;
1506*f6dc9357SAndroid Build Coastguard Worker       len = sym - (kSymbolRep + kNumReps);
1507*f6dc9357SAndroid Build Coastguard Worker       if (len >= 8)
1508*f6dc9357SAndroid Build Coastguard Worker         len = SlotToLen(_bitStream, len);
1509*f6dc9357SAndroid Build Coastguard Worker       len += 2;
1510*f6dc9357SAndroid Build Coastguard Worker       // _lastLen = (UInt32)len;
1511*f6dc9357SAndroid Build Coastguard Worker 
1512*f6dc9357SAndroid Build Coastguard Worker #if 0
1513*f6dc9357SAndroid Build Coastguard Worker       rep0 = (UInt32)m_DistDecoder.Decode(&_bitStream);
1514*f6dc9357SAndroid Build Coastguard Worker #else
1515*f6dc9357SAndroid Build Coastguard Worker       Z7_RAR_HUFF_DECODE_CHECK_break(rep0, &m_DistDecoder, k_NumHufTableBits_Dist, &_bitStream)
1516*f6dc9357SAndroid Build Coastguard Worker #endif
1517*f6dc9357SAndroid Build Coastguard Worker 
1518*f6dc9357SAndroid Build Coastguard Worker       if (rep0 >= 4)
1519*f6dc9357SAndroid Build Coastguard Worker       {
1520*f6dc9357SAndroid Build Coastguard Worker #if 0
1521*f6dc9357SAndroid Build Coastguard Worker         if (rep0 >= kDistTableSize_MAX)
1522*f6dc9357SAndroid Build Coastguard Worker           LZ_LOOP_BREAK_ERROR
1523*f6dc9357SAndroid Build Coastguard Worker #endif
1524*f6dc9357SAndroid Build Coastguard Worker         const unsigned numBits = ((unsigned)rep0 - 2) >> 1;
1525*f6dc9357SAndroid Build Coastguard Worker         rep0 = (2 | (rep0 & 1)) << numBits;
1526*f6dc9357SAndroid Build Coastguard Worker 
1527*f6dc9357SAndroid Build Coastguard Worker         const Byte *buf = _bitStream._buf;
1528*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_RAR5_USE_64BIT
1529*f6dc9357SAndroid Build Coastguard Worker         const UInt64 v = GetBe64(buf);
1530*f6dc9357SAndroid Build Coastguard Worker #else
1531*f6dc9357SAndroid Build Coastguard Worker         const UInt32 v = GetBe32(buf);
1532*f6dc9357SAndroid Build Coastguard Worker #endif
1533*f6dc9357SAndroid Build Coastguard Worker 
1534*f6dc9357SAndroid Build Coastguard Worker         // _lastLen = (UInt32)len;
1535*f6dc9357SAndroid Build Coastguard Worker         if (numBits < kNumAlignBits)
1536*f6dc9357SAndroid Build Coastguard Worker         {
1537*f6dc9357SAndroid Build Coastguard Worker           rep0 += // _bitStream.ReadBits9(numBits);
1538*f6dc9357SAndroid Build Coastguard Worker             _bitStream.ReadBits_Big25(numBits, v);
1539*f6dc9357SAndroid Build Coastguard Worker         }
1540*f6dc9357SAndroid Build Coastguard Worker         else
1541*f6dc9357SAndroid Build Coastguard Worker         {
1542*f6dc9357SAndroid Build Coastguard Worker           #if !defined(MY_CPU_AMD64)
1543*f6dc9357SAndroid Build Coastguard Worker             len += k_LenPlusTable[numBits];
1544*f6dc9357SAndroid Build Coastguard Worker           #elif 0
1545*f6dc9357SAndroid Build Coastguard Worker             len += k_LenPlusTable_LOC[numBits];
1546*f6dc9357SAndroid Build Coastguard Worker           #elif 1
1547*f6dc9357SAndroid Build Coastguard Worker             len += m_LenPlusTable[numBits];
1548*f6dc9357SAndroid Build Coastguard Worker           #elif 1 && defined(MY_CPU_64BIT) && defined(MY_CPU_AMD64)
1549*f6dc9357SAndroid Build Coastguard Worker             // len += (unsigned)((UInt64)0xfffffffeaa554000 >> (numBits * 2)) & 3;
1550*f6dc9357SAndroid Build Coastguard Worker             len += (unsigned)((UInt64)0xfffffffffeaa5540 >> (numBits * 2 - 8)) & 3;
1551*f6dc9357SAndroid Build Coastguard Worker           #elif 1
1552*f6dc9357SAndroid Build Coastguard Worker             len += 3;
1553*f6dc9357SAndroid Build Coastguard Worker             len -= (unsigned)(numBits -  7) >> (sizeof(unsigned) * 8 - 1);
1554*f6dc9357SAndroid Build Coastguard Worker             len -= (unsigned)(numBits - 12) >> (sizeof(unsigned) * 8 - 1);
1555*f6dc9357SAndroid Build Coastguard Worker             len -= (unsigned)(numBits - 17) >> (sizeof(unsigned) * 8 - 1);
1556*f6dc9357SAndroid Build Coastguard Worker           #elif 1
1557*f6dc9357SAndroid Build Coastguard Worker             len += 3;
1558*f6dc9357SAndroid Build Coastguard Worker             len -= (0x155aabf >> (numBits - 4) >> (numBits - 4)) & 3;
1559*f6dc9357SAndroid Build Coastguard Worker           #elif 1
1560*f6dc9357SAndroid Build Coastguard Worker             len += (numBits >= 7);
1561*f6dc9357SAndroid Build Coastguard Worker             len += (numBits >= 12);
1562*f6dc9357SAndroid Build Coastguard Worker             len += (numBits >= 17);
1563*f6dc9357SAndroid Build Coastguard Worker           #endif
1564*f6dc9357SAndroid Build Coastguard Worker           // _lastLen = (UInt32)len;
1565*f6dc9357SAndroid Build Coastguard Worker           if (_useAlignBits)
1566*f6dc9357SAndroid Build Coastguard Worker           {
1567*f6dc9357SAndroid Build Coastguard Worker             // if (numBits > kNumAlignBits)
1568*f6dc9357SAndroid Build Coastguard Worker             rep0 += (_bitStream.ReadBits_Big25(numBits - kNumAlignBits, v) << kNumAlignBits);
1569*f6dc9357SAndroid Build Coastguard Worker #if 0
1570*f6dc9357SAndroid Build Coastguard Worker             const unsigned a = m_AlignDecoder.Decode(&_bitStream);
1571*f6dc9357SAndroid Build Coastguard Worker             if (a >= kAlignTableSize)
1572*f6dc9357SAndroid Build Coastguard Worker               LZ_LOOP_BREAK_ERROR
1573*f6dc9357SAndroid Build Coastguard Worker #else
1574*f6dc9357SAndroid Build Coastguard Worker             unsigned a;
1575*f6dc9357SAndroid Build Coastguard Worker             Z7_RAR_HUFF_DECODE_CHECK_break(a, &m_AlignDecoder, k_NumHufTableBits_Align, &_bitStream)
1576*f6dc9357SAndroid Build Coastguard Worker #endif
1577*f6dc9357SAndroid Build Coastguard Worker             rep0 += a;
1578*f6dc9357SAndroid Build Coastguard Worker           }
1579*f6dc9357SAndroid Build Coastguard Worker           else
1580*f6dc9357SAndroid Build Coastguard Worker             rep0 += _bitStream.ReadBits_Big(numBits, v);
1581*f6dc9357SAndroid Build Coastguard Worker #ifndef Z7_RAR5_USE_64BIT
1582*f6dc9357SAndroid Build Coastguard Worker           if (numBits >= 30) // we don't want 32-bit overflow case
1583*f6dc9357SAndroid Build Coastguard Worker             rep0 = (size_t)0 - 1 - 1;
1584*f6dc9357SAndroid Build Coastguard Worker #endif
1585*f6dc9357SAndroid Build Coastguard Worker         }
1586*f6dc9357SAndroid Build Coastguard Worker       }
1587*f6dc9357SAndroid Build Coastguard Worker       rep0++;
1588*f6dc9357SAndroid Build Coastguard Worker     }
1589*f6dc9357SAndroid Build Coastguard Worker 
1590*f6dc9357SAndroid Build Coastguard Worker     {
1591*f6dc9357SAndroid Build Coastguard Worker       _lastLen = (UInt32)len;
1592*f6dc9357SAndroid Build Coastguard Worker       // len != 0
1593*f6dc9357SAndroid Build Coastguard Worker 
1594*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_RAR5_SHOW_STAT
1595*f6dc9357SAndroid Build Coastguard Worker       {
1596*f6dc9357SAndroid Build Coastguard Worker         size_t index = rep0;
1597*f6dc9357SAndroid Build Coastguard Worker         if (index >= kNumStats1)
1598*f6dc9357SAndroid Build Coastguard Worker           index = kNumStats1 - 1;
1599*f6dc9357SAndroid Build Coastguard Worker         g_stats1[index]++;
1600*f6dc9357SAndroid Build Coastguard Worker         g_stats2[index][len]++;
1601*f6dc9357SAndroid Build Coastguard Worker       }
1602*f6dc9357SAndroid Build Coastguard Worker #endif
1603*f6dc9357SAndroid Build Coastguard Worker 
1604*f6dc9357SAndroid Build Coastguard Worker       Byte *dest = winPos;
1605*f6dc9357SAndroid Build Coastguard Worker       winPos += len;
1606*f6dc9357SAndroid Build Coastguard Worker       if (rep0 <= _dictSize_forCheck)
1607*f6dc9357SAndroid Build Coastguard Worker       {
1608*f6dc9357SAndroid Build Coastguard Worker         const Byte *src;
1609*f6dc9357SAndroid Build Coastguard Worker         const size_t winPos_temp = (size_t)(dest - _window);
1610*f6dc9357SAndroid Build Coastguard Worker         if (rep0 > winPos_temp)
1611*f6dc9357SAndroid Build Coastguard Worker         {
1612*f6dc9357SAndroid Build Coastguard Worker           if (_lzSize == 0)
1613*f6dc9357SAndroid Build Coastguard Worker             goto error_dist;
1614*f6dc9357SAndroid Build Coastguard Worker           size_t back = rep0 - winPos_temp;
1615*f6dc9357SAndroid Build Coastguard Worker           // STAT_INC(g_NumOver)
1616*f6dc9357SAndroid Build Coastguard Worker           src = dest + (_winSize - rep0);
1617*f6dc9357SAndroid Build Coastguard Worker           if (back < len)
1618*f6dc9357SAndroid Build Coastguard Worker           {
1619*f6dc9357SAndroid Build Coastguard Worker             // len -= (CLenType)back;
1620*f6dc9357SAndroid Build Coastguard Worker             Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
1621*f6dc9357SAndroid Build Coastguard Worker             do
1622*f6dc9357SAndroid Build Coastguard Worker               *dest++ = *src++;
1623*f6dc9357SAndroid Build Coastguard Worker             while (--back);
1624*f6dc9357SAndroid Build Coastguard Worker             src = dest - rep0;
1625*f6dc9357SAndroid Build Coastguard Worker           }
1626*f6dc9357SAndroid Build Coastguard Worker         }
1627*f6dc9357SAndroid Build Coastguard Worker         else
1628*f6dc9357SAndroid Build Coastguard Worker           src = dest - rep0;
1629*f6dc9357SAndroid Build Coastguard Worker         CopyMatch(rep0, dest, src, winPos);
1630*f6dc9357SAndroid Build Coastguard Worker         continue;
1631*f6dc9357SAndroid Build Coastguard Worker       }
1632*f6dc9357SAndroid Build Coastguard Worker 
1633*f6dc9357SAndroid Build Coastguard Worker error_dist:
1634*f6dc9357SAndroid Build Coastguard Worker       // LZ_LOOP_BREAK_ERROR;
1635*f6dc9357SAndroid Build Coastguard Worker       _lzError = LZ_ERROR_TYPE_DIST;
1636*f6dc9357SAndroid Build Coastguard Worker       do
1637*f6dc9357SAndroid Build Coastguard Worker         *dest++ = 0;
1638*f6dc9357SAndroid Build Coastguard Worker       while (dest < winPos);
1639*f6dc9357SAndroid Build Coastguard Worker       continue;
1640*f6dc9357SAndroid Build Coastguard Worker     }
1641*f6dc9357SAndroid Build Coastguard Worker   }
1642*f6dc9357SAndroid Build Coastguard Worker 
1643*f6dc9357SAndroid Build Coastguard Worker   LZ_RESTORE
1644*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1645*f6dc9357SAndroid Build Coastguard Worker 
1646*f6dc9357SAndroid Build Coastguard Worker #if 1
1647*f6dc9357SAndroid Build Coastguard Worker decode_error:
1648*f6dc9357SAndroid Build Coastguard Worker   /*
1649*f6dc9357SAndroid Build Coastguard Worker   if (_bitStream._hres != S_OK)
1650*f6dc9357SAndroid Build Coastguard Worker     return _bitStream._hres;
1651*f6dc9357SAndroid Build Coastguard Worker   */
1652*f6dc9357SAndroid Build Coastguard Worker   LZ_RESTORE
1653*f6dc9357SAndroid Build Coastguard Worker   return S_FALSE;
1654*f6dc9357SAndroid Build Coastguard Worker #endif
1655*f6dc9357SAndroid Build Coastguard Worker }
1656*f6dc9357SAndroid Build Coastguard Worker 
1657*f6dc9357SAndroid Build Coastguard Worker 
1658*f6dc9357SAndroid Build Coastguard Worker 
DecodeLZ()1659*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::DecodeLZ()
1660*f6dc9357SAndroid Build Coastguard Worker {
1661*f6dc9357SAndroid Build Coastguard Worker   CBitDecoder _bitStream;
1662*f6dc9357SAndroid Build Coastguard Worker   _bitStream._stream = _inStream;
1663*f6dc9357SAndroid Build Coastguard Worker   _bitStream._bufBase = _inputBuf;
1664*f6dc9357SAndroid Build Coastguard Worker   _bitStream.Init();
1665*f6dc9357SAndroid Build Coastguard Worker 
1666*f6dc9357SAndroid Build Coastguard Worker   // _reps[*] can be larger than _winSize, if _winSize was reduced in solid stream.
1667*f6dc9357SAndroid Build Coastguard Worker   size_t winPos = _winPos;
1668*f6dc9357SAndroid Build Coastguard Worker   Byte *win = _window;
1669*f6dc9357SAndroid Build Coastguard Worker   size_t limit;
1670*f6dc9357SAndroid Build Coastguard Worker   {
1671*f6dc9357SAndroid Build Coastguard Worker     size_t rem = _winSize - winPos;
1672*f6dc9357SAndroid Build Coastguard Worker     if (rem > kWriteStep)
1673*f6dc9357SAndroid Build Coastguard Worker         rem = kWriteStep;
1674*f6dc9357SAndroid Build Coastguard Worker     limit = winPos + rem;
1675*f6dc9357SAndroid Build Coastguard Worker   }
1676*f6dc9357SAndroid Build Coastguard Worker 
1677*f6dc9357SAndroid Build Coastguard Worker   for (;;)
1678*f6dc9357SAndroid Build Coastguard Worker   {
1679*f6dc9357SAndroid Build Coastguard Worker     if (winPos >= limit)
1680*f6dc9357SAndroid Build Coastguard Worker     {
1681*f6dc9357SAndroid Build Coastguard Worker       _winPos = winPos < _winSize ? winPos : _winSize;
1682*f6dc9357SAndroid Build Coastguard Worker       RINOK(WriteBuf())
1683*f6dc9357SAndroid Build Coastguard Worker       if (_unpackSize_Defined && _writtenFileSize > _unpackSize)
1684*f6dc9357SAndroid Build Coastguard Worker         break; // return S_FALSE;
1685*f6dc9357SAndroid Build Coastguard Worker       const size_t wp = _winPos;
1686*f6dc9357SAndroid Build Coastguard Worker       size_t rem = _winSize - wp;
1687*f6dc9357SAndroid Build Coastguard Worker       if (rem == 0)
1688*f6dc9357SAndroid Build Coastguard Worker       {
1689*f6dc9357SAndroid Build Coastguard Worker         _lzSize += wp;
1690*f6dc9357SAndroid Build Coastguard Worker         winPos -= wp;
1691*f6dc9357SAndroid Build Coastguard Worker         // (winPos < kMaxMatchLen < _winSize)
1692*f6dc9357SAndroid Build Coastguard Worker         // so memmove is not required here
1693*f6dc9357SAndroid Build Coastguard Worker         if (winPos)
1694*f6dc9357SAndroid Build Coastguard Worker           memcpy(win, win + _winSize, winPos);
1695*f6dc9357SAndroid Build Coastguard Worker         limit = _winSize;
1696*f6dc9357SAndroid Build Coastguard Worker         if (limit >= kWriteStep)
1697*f6dc9357SAndroid Build Coastguard Worker         {
1698*f6dc9357SAndroid Build Coastguard Worker           limit = kWriteStep;
1699*f6dc9357SAndroid Build Coastguard Worker           continue;
1700*f6dc9357SAndroid Build Coastguard Worker         }
1701*f6dc9357SAndroid Build Coastguard Worker         rem = _winSize - winPos;
1702*f6dc9357SAndroid Build Coastguard Worker       }
1703*f6dc9357SAndroid Build Coastguard Worker       if (rem > kWriteStep)
1704*f6dc9357SAndroid Build Coastguard Worker           rem = kWriteStep;
1705*f6dc9357SAndroid Build Coastguard Worker       limit = winPos + rem;
1706*f6dc9357SAndroid Build Coastguard Worker       continue;
1707*f6dc9357SAndroid Build Coastguard Worker     }
1708*f6dc9357SAndroid Build Coastguard Worker 
1709*f6dc9357SAndroid Build Coastguard Worker     // (winPos < limit)
1710*f6dc9357SAndroid Build Coastguard Worker 
1711*f6dc9357SAndroid Build Coastguard Worker     if (_bitStream._buf >= _bitStream._bufCheck_Block)
1712*f6dc9357SAndroid Build Coastguard Worker     {
1713*f6dc9357SAndroid Build Coastguard Worker       _winPos = winPos;
1714*f6dc9357SAndroid Build Coastguard Worker       if (_bitStream.InputEofError())
1715*f6dc9357SAndroid Build Coastguard Worker         break; // return S_FALSE;
1716*f6dc9357SAndroid Build Coastguard Worker       _bitStream.Prepare();
1717*f6dc9357SAndroid Build Coastguard Worker 
1718*f6dc9357SAndroid Build Coastguard Worker       const UInt64 processed = _bitStream.GetProcessedSize_Round();
1719*f6dc9357SAndroid Build Coastguard Worker       if (processed >= _bitStream._blockEnd)
1720*f6dc9357SAndroid Build Coastguard Worker       {
1721*f6dc9357SAndroid Build Coastguard Worker         if (processed > _bitStream._blockEnd)
1722*f6dc9357SAndroid Build Coastguard Worker           break; // return S_FALSE;
1723*f6dc9357SAndroid Build Coastguard Worker         {
1724*f6dc9357SAndroid Build Coastguard Worker           const unsigned bits7 = _bitStream.GetProcessedBits7();
1725*f6dc9357SAndroid Build Coastguard Worker           if (bits7 >= _bitStream._blockEndBits7)
1726*f6dc9357SAndroid Build Coastguard Worker           {
1727*f6dc9357SAndroid Build Coastguard Worker             if (bits7 > _bitStream._blockEndBits7)
1728*f6dc9357SAndroid Build Coastguard Worker             {
1729*f6dc9357SAndroid Build Coastguard Worker #if 1
1730*f6dc9357SAndroid Build Coastguard Worker               // we ignore thar error as original unrar
1731*f6dc9357SAndroid Build Coastguard Worker               _bitStream._minorError = true;
1732*f6dc9357SAndroid Build Coastguard Worker #else
1733*f6dc9357SAndroid Build Coastguard Worker               break; // return S_FALSE;
1734*f6dc9357SAndroid Build Coastguard Worker #endif
1735*f6dc9357SAndroid Build Coastguard Worker             }
1736*f6dc9357SAndroid Build Coastguard Worker             _bitStream.AlignToByte();
1737*f6dc9357SAndroid Build Coastguard Worker             // if (!_bitStream.AlignToByte()) break;
1738*f6dc9357SAndroid Build Coastguard Worker             if (_isLastBlock)
1739*f6dc9357SAndroid Build Coastguard Worker             {
1740*f6dc9357SAndroid Build Coastguard Worker               if (_bitStream.InputEofError())
1741*f6dc9357SAndroid Build Coastguard Worker                 break;
1742*f6dc9357SAndroid Build Coastguard Worker               /*
1743*f6dc9357SAndroid Build Coastguard Worker               // packSize can be 15 bytes larger for encrypted archive
1744*f6dc9357SAndroid Build Coastguard Worker               if (_packSize_Defined && _packSize < _bitStream.GetProcessedSize())
1745*f6dc9357SAndroid Build Coastguard Worker                 break;
1746*f6dc9357SAndroid Build Coastguard Worker               */
1747*f6dc9357SAndroid Build Coastguard Worker               if (_bitStream._minorError)
1748*f6dc9357SAndroid Build Coastguard Worker                 return S_FALSE;
1749*f6dc9357SAndroid Build Coastguard Worker               return _bitStream._hres;
1750*f6dc9357SAndroid Build Coastguard Worker               // break;
1751*f6dc9357SAndroid Build Coastguard Worker             }
1752*f6dc9357SAndroid Build Coastguard Worker             RINOK(ReadTables(_bitStream))
1753*f6dc9357SAndroid Build Coastguard Worker             continue;
1754*f6dc9357SAndroid Build Coastguard Worker           }
1755*f6dc9357SAndroid Build Coastguard Worker         }
1756*f6dc9357SAndroid Build Coastguard Worker       }
1757*f6dc9357SAndroid Build Coastguard Worker 
1758*f6dc9357SAndroid Build Coastguard Worker       // end of block was not reached.
1759*f6dc9357SAndroid Build Coastguard Worker       // so we must decode more symbols
1760*f6dc9357SAndroid Build Coastguard Worker       // that check is not required, but it can help, if there is BUG in another code
1761*f6dc9357SAndroid Build Coastguard Worker       if (!_tableWasFilled)
1762*f6dc9357SAndroid Build Coastguard Worker         break; // return S_FALSE;
1763*f6dc9357SAndroid Build Coastguard Worker     }
1764*f6dc9357SAndroid Build Coastguard Worker 
1765*f6dc9357SAndroid Build Coastguard Worker     _limit = limit;
1766*f6dc9357SAndroid Build Coastguard Worker     _winPos = winPos;
1767*f6dc9357SAndroid Build Coastguard Worker     RINOK(DecodeLZ2(_bitStream))
1768*f6dc9357SAndroid Build Coastguard Worker     _bitStream._buf = _buf_Res;
1769*f6dc9357SAndroid Build Coastguard Worker     _bitStream._bitPos = _bitPos_Res;
1770*f6dc9357SAndroid Build Coastguard Worker 
1771*f6dc9357SAndroid Build Coastguard Worker     winPos = _winPos;
1772*f6dc9357SAndroid Build Coastguard Worker     if (_exitType == Z7_RAR_EXIT_TYPE_ADD_FILTER)
1773*f6dc9357SAndroid Build Coastguard Worker     {
1774*f6dc9357SAndroid Build Coastguard Worker       RINOK(AddFilter(_bitStream))
1775*f6dc9357SAndroid Build Coastguard Worker       continue;
1776*f6dc9357SAndroid Build Coastguard Worker     }
1777*f6dc9357SAndroid Build Coastguard Worker   }
1778*f6dc9357SAndroid Build Coastguard Worker 
1779*f6dc9357SAndroid Build Coastguard Worker   _winPos = winPos;
1780*f6dc9357SAndroid Build Coastguard Worker 
1781*f6dc9357SAndroid Build Coastguard Worker   if (_bitStream._hres != S_OK)
1782*f6dc9357SAndroid Build Coastguard Worker     return _bitStream._hres;
1783*f6dc9357SAndroid Build Coastguard Worker 
1784*f6dc9357SAndroid Build Coastguard Worker   return S_FALSE;
1785*f6dc9357SAndroid Build Coastguard Worker }
1786*f6dc9357SAndroid Build Coastguard Worker 
1787*f6dc9357SAndroid Build Coastguard Worker 
1788*f6dc9357SAndroid Build Coastguard Worker 
CodeReal()1789*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::CodeReal()
1790*f6dc9357SAndroid Build Coastguard Worker {
1791*f6dc9357SAndroid Build Coastguard Worker   _unsupportedFilter = false;
1792*f6dc9357SAndroid Build Coastguard Worker   _writeError = false;
1793*f6dc9357SAndroid Build Coastguard Worker   /*
1794*f6dc9357SAndroid Build Coastguard Worker   if (!_isSolid || !_wasInit)
1795*f6dc9357SAndroid Build Coastguard Worker   {
1796*f6dc9357SAndroid Build Coastguard Worker     _wasInit = true;
1797*f6dc9357SAndroid Build Coastguard Worker     // _lzSize = 0;
1798*f6dc9357SAndroid Build Coastguard Worker     _lzWritten = 0;
1799*f6dc9357SAndroid Build Coastguard Worker     _winPos = 0;
1800*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = 0; i < kNumReps; i++)
1801*f6dc9357SAndroid Build Coastguard Worker       _reps[i] = (size_t)0 - 1;
1802*f6dc9357SAndroid Build Coastguard Worker     _lastLen = 0;
1803*f6dc9357SAndroid Build Coastguard Worker     _tableWasFilled = false;
1804*f6dc9357SAndroid Build Coastguard Worker   }
1805*f6dc9357SAndroid Build Coastguard Worker   */
1806*f6dc9357SAndroid Build Coastguard Worker   _isLastBlock = false;
1807*f6dc9357SAndroid Build Coastguard Worker 
1808*f6dc9357SAndroid Build Coastguard Worker   InitFilters();
1809*f6dc9357SAndroid Build Coastguard Worker 
1810*f6dc9357SAndroid Build Coastguard Worker   _filterEnd = 0;
1811*f6dc9357SAndroid Build Coastguard Worker   _writtenFileSize = 0;
1812*f6dc9357SAndroid Build Coastguard Worker   const UInt64 lzSize = _lzSize + _winPos;
1813*f6dc9357SAndroid Build Coastguard Worker   _lzFileStart = lzSize;
1814*f6dc9357SAndroid Build Coastguard Worker   _lzWritten = lzSize;
1815*f6dc9357SAndroid Build Coastguard Worker 
1816*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = DecodeLZ();
1817*f6dc9357SAndroid Build Coastguard Worker 
1818*f6dc9357SAndroid Build Coastguard Worker   HRESULT res2 = S_OK;
1819*f6dc9357SAndroid Build Coastguard Worker   if (!_writeError && res != E_OUTOFMEMORY)
1820*f6dc9357SAndroid Build Coastguard Worker     res2 = WriteBuf();
1821*f6dc9357SAndroid Build Coastguard Worker   /*
1822*f6dc9357SAndroid Build Coastguard Worker   if (res == S_OK)
1823*f6dc9357SAndroid Build Coastguard Worker     if (InputEofError())
1824*f6dc9357SAndroid Build Coastguard Worker       res = S_FALSE;
1825*f6dc9357SAndroid Build Coastguard Worker   */
1826*f6dc9357SAndroid Build Coastguard Worker   if (res == S_OK)
1827*f6dc9357SAndroid Build Coastguard Worker   {
1828*f6dc9357SAndroid Build Coastguard Worker     // _solidAllowed = true;
1829*f6dc9357SAndroid Build Coastguard Worker     res = res2;
1830*f6dc9357SAndroid Build Coastguard Worker   }
1831*f6dc9357SAndroid Build Coastguard Worker   if (res == S_OK && _unpackSize_Defined && _writtenFileSize != _unpackSize)
1832*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1833*f6dc9357SAndroid Build Coastguard Worker   return res;
1834*f6dc9357SAndroid Build Coastguard Worker }
1835*f6dc9357SAndroid Build Coastguard Worker 
1836*f6dc9357SAndroid Build Coastguard Worker 
1837*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CDecoder::Code (ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 * outSize,ICompressProgressInfo * progress))1838*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
1839*f6dc9357SAndroid Build Coastguard Worker     const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress))
1840*f6dc9357SAndroid Build Coastguard Worker {
1841*f6dc9357SAndroid Build Coastguard Worker   _lzError = LZ_ERROR_TYPE_NO;
1842*f6dc9357SAndroid Build Coastguard Worker /*
1843*f6dc9357SAndroid Build Coastguard Worker   if file is soild, but decoding of previous file was not finished,
1844*f6dc9357SAndroid Build Coastguard Worker   we still try to decode new file.
1845*f6dc9357SAndroid Build Coastguard Worker   We need correct huffman table at starting block.
1846*f6dc9357SAndroid Build Coastguard Worker   And rar encoder probably writes huffman table at start block, if file is big.
1847*f6dc9357SAndroid Build Coastguard Worker   So we have good chance to get correct huffman table in some file after corruption.
1848*f6dc9357SAndroid Build Coastguard Worker   Also we try to recover window by filling zeros, if previous file
1849*f6dc9357SAndroid Build Coastguard Worker   was decoded to smaller size than required.
1850*f6dc9357SAndroid Build Coastguard Worker   But if filling size is big, we do full reset of window instead.
1851*f6dc9357SAndroid Build Coastguard Worker */
1852*f6dc9357SAndroid Build Coastguard Worker   #define Z7_RAR_RECOVER_SOLID_LIMIT (1 << 20)
1853*f6dc9357SAndroid Build Coastguard Worker   // #define Z7_RAR_RECOVER_SOLID_LIMIT 0 // do not fill zeros
1854*f6dc9357SAndroid Build Coastguard Worker   {
1855*f6dc9357SAndroid Build Coastguard Worker     // if (_winPos > 100) _winPos -= 100; // for debug: corruption
1856*f6dc9357SAndroid Build Coastguard Worker     const UInt64 lzSize = _lzSize + _winPos;
1857*f6dc9357SAndroid Build Coastguard Worker     if (!_isSolid || !_wasInit
1858*f6dc9357SAndroid Build Coastguard Worker         || (lzSize < _lzEnd
1859*f6dc9357SAndroid Build Coastguard Worker #if Z7_RAR_RECOVER_SOLID_LIMIT != 0
1860*f6dc9357SAndroid Build Coastguard Worker          && lzSize + Z7_RAR_RECOVER_SOLID_LIMIT < _lzEnd
1861*f6dc9357SAndroid Build Coastguard Worker #endif
1862*f6dc9357SAndroid Build Coastguard Worker         ))
1863*f6dc9357SAndroid Build Coastguard Worker     {
1864*f6dc9357SAndroid Build Coastguard Worker       if (_isSolid)
1865*f6dc9357SAndroid Build Coastguard Worker         _lzError = LZ_ERROR_TYPE_HEADER;
1866*f6dc9357SAndroid Build Coastguard Worker       _lzEnd = 0;
1867*f6dc9357SAndroid Build Coastguard Worker       _lzSize = 0;
1868*f6dc9357SAndroid Build Coastguard Worker       _lzWritten = 0;
1869*f6dc9357SAndroid Build Coastguard Worker       _winPos = 0;
1870*f6dc9357SAndroid Build Coastguard Worker       for (unsigned i = 0; i < kNumReps; i++)
1871*f6dc9357SAndroid Build Coastguard Worker         _reps[i] = (size_t)0 - 1;
1872*f6dc9357SAndroid Build Coastguard Worker       _lastLen = 0;
1873*f6dc9357SAndroid Build Coastguard Worker       _tableWasFilled = false;
1874*f6dc9357SAndroid Build Coastguard Worker       _wasInit = true;
1875*f6dc9357SAndroid Build Coastguard Worker     }
1876*f6dc9357SAndroid Build Coastguard Worker #if Z7_RAR_RECOVER_SOLID_LIMIT != 0
1877*f6dc9357SAndroid Build Coastguard Worker     else if (lzSize < _lzEnd)
1878*f6dc9357SAndroid Build Coastguard Worker     {
1879*f6dc9357SAndroid Build Coastguard Worker #if 0
1880*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1881*f6dc9357SAndroid Build Coastguard Worker #else
1882*f6dc9357SAndroid Build Coastguard Worker       // we can report that recovering was made:
1883*f6dc9357SAndroid Build Coastguard Worker       // _lzError = LZ_ERROR_TYPE_HEADER;
1884*f6dc9357SAndroid Build Coastguard Worker       // We write zeros to area after corruption:
1885*f6dc9357SAndroid Build Coastguard Worker       if (_window)
1886*f6dc9357SAndroid Build Coastguard Worker       {
1887*f6dc9357SAndroid Build Coastguard Worker         UInt64 rem = _lzEnd - lzSize;
1888*f6dc9357SAndroid Build Coastguard Worker         const size_t ws = _winSize;
1889*f6dc9357SAndroid Build Coastguard Worker         if (rem >= ws)
1890*f6dc9357SAndroid Build Coastguard Worker         {
1891*f6dc9357SAndroid Build Coastguard Worker           My_ZeroMemory(_window, ws);
1892*f6dc9357SAndroid Build Coastguard Worker           _lzSize = ws;
1893*f6dc9357SAndroid Build Coastguard Worker           _winPos = 0;
1894*f6dc9357SAndroid Build Coastguard Worker         }
1895*f6dc9357SAndroid Build Coastguard Worker         else
1896*f6dc9357SAndroid Build Coastguard Worker         {
1897*f6dc9357SAndroid Build Coastguard Worker           const size_t cur = ws - _winPos;
1898*f6dc9357SAndroid Build Coastguard Worker           if (cur <= rem)
1899*f6dc9357SAndroid Build Coastguard Worker           {
1900*f6dc9357SAndroid Build Coastguard Worker             rem -= cur;
1901*f6dc9357SAndroid Build Coastguard Worker             My_ZeroMemory(_window + _winPos, cur);
1902*f6dc9357SAndroid Build Coastguard Worker             _lzSize += _winPos;
1903*f6dc9357SAndroid Build Coastguard Worker             _winPos = 0;
1904*f6dc9357SAndroid Build Coastguard Worker           }
1905*f6dc9357SAndroid Build Coastguard Worker           My_ZeroMemory(_window + _winPos, (size_t)rem);
1906*f6dc9357SAndroid Build Coastguard Worker           _winPos += (size_t)rem;
1907*f6dc9357SAndroid Build Coastguard Worker         }
1908*f6dc9357SAndroid Build Coastguard Worker       }
1909*f6dc9357SAndroid Build Coastguard Worker       // else return S_FALSE;
1910*f6dc9357SAndroid Build Coastguard Worker #endif
1911*f6dc9357SAndroid Build Coastguard Worker     }
1912*f6dc9357SAndroid Build Coastguard Worker #endif
1913*f6dc9357SAndroid Build Coastguard Worker   }
1914*f6dc9357SAndroid Build Coastguard Worker 
1915*f6dc9357SAndroid Build Coastguard Worker   // we don't want _lzSize overflow
1916*f6dc9357SAndroid Build Coastguard Worker   if (_lzSize >= DICT_SIZE_MAX)
1917*f6dc9357SAndroid Build Coastguard Worker       _lzSize  = DICT_SIZE_MAX;
1918*f6dc9357SAndroid Build Coastguard Worker   _lzEnd = _lzSize + _winPos;
1919*f6dc9357SAndroid Build Coastguard Worker   // _lzSize <= DICT_SIZE_MAX
1920*f6dc9357SAndroid Build Coastguard Worker   // _lzEnd  <= DICT_SIZE_MAX * 2
1921*f6dc9357SAndroid Build Coastguard Worker 
1922*f6dc9357SAndroid Build Coastguard Worker   size_t newSize = _dictSize;
1923*f6dc9357SAndroid Build Coastguard Worker   if (newSize < kWinSize_Min)
1924*f6dc9357SAndroid Build Coastguard Worker       newSize = kWinSize_Min;
1925*f6dc9357SAndroid Build Coastguard Worker 
1926*f6dc9357SAndroid Build Coastguard Worker   _unpackSize = 0;
1927*f6dc9357SAndroid Build Coastguard Worker   _unpackSize_Defined = (outSize != NULL);
1928*f6dc9357SAndroid Build Coastguard Worker   if (_unpackSize_Defined)
1929*f6dc9357SAndroid Build Coastguard Worker     _unpackSize = *outSize;
1930*f6dc9357SAndroid Build Coastguard Worker 
1931*f6dc9357SAndroid Build Coastguard Worker   if ((Int64)_unpackSize >= 0)
1932*f6dc9357SAndroid Build Coastguard Worker     _lzEnd += _unpackSize; // known end after current file
1933*f6dc9357SAndroid Build Coastguard Worker   else
1934*f6dc9357SAndroid Build Coastguard Worker     _lzEnd = 0; // unknown end
1935*f6dc9357SAndroid Build Coastguard Worker 
1936*f6dc9357SAndroid Build Coastguard Worker   if (_isSolid && _window)
1937*f6dc9357SAndroid Build Coastguard Worker   {
1938*f6dc9357SAndroid Build Coastguard Worker     // If dictionary was decreased in solid, we use old dictionary.
1939*f6dc9357SAndroid Build Coastguard Worker     if (newSize > _dictSize_forCheck)
1940*f6dc9357SAndroid Build Coastguard Worker     {
1941*f6dc9357SAndroid Build Coastguard Worker       // If dictionary was increased in solid, we don't want grow.
1942*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE; // E_OUTOFMEMORY
1943*f6dc9357SAndroid Build Coastguard Worker     }
1944*f6dc9357SAndroid Build Coastguard Worker     // (newSize <= _winSize)
1945*f6dc9357SAndroid Build Coastguard Worker   }
1946*f6dc9357SAndroid Build Coastguard Worker   else
1947*f6dc9357SAndroid Build Coastguard Worker   {
1948*f6dc9357SAndroid Build Coastguard Worker     _dictSize_forCheck = newSize;
1949*f6dc9357SAndroid Build Coastguard Worker     {
1950*f6dc9357SAndroid Build Coastguard Worker       size_t newSize_small = newSize;
1951*f6dc9357SAndroid Build Coastguard Worker       const size_t k_Win_AlignSize = 1u << 18;
1952*f6dc9357SAndroid Build Coastguard Worker       /* here we add (1 << 7) instead of (COPY_CHUNK_SIZE - 1), because
1953*f6dc9357SAndroid Build Coastguard Worker       we want to get same (_winSize) for different COPY_CHUNK_SIZE values. */
1954*f6dc9357SAndroid Build Coastguard Worker       // newSize += (COPY_CHUNK_SIZE - 1) + (k_Win_AlignSize - 1); // for debug : we can get smallest (_winSize)
1955*f6dc9357SAndroid Build Coastguard Worker       newSize += (1 << 7) + k_Win_AlignSize;
1956*f6dc9357SAndroid Build Coastguard Worker       newSize &= ~(size_t)(k_Win_AlignSize - 1);
1957*f6dc9357SAndroid Build Coastguard Worker       if (newSize < newSize_small)
1958*f6dc9357SAndroid Build Coastguard Worker         return E_OUTOFMEMORY;
1959*f6dc9357SAndroid Build Coastguard Worker     }
1960*f6dc9357SAndroid Build Coastguard Worker     // (!_isSolid || !_window)
1961*f6dc9357SAndroid Build Coastguard Worker     const size_t allocSize = newSize + kMaxMatchLen + 64;
1962*f6dc9357SAndroid Build Coastguard Worker     if (allocSize < newSize)
1963*f6dc9357SAndroid Build Coastguard Worker       return E_OUTOFMEMORY;
1964*f6dc9357SAndroid Build Coastguard Worker     if (!_window || allocSize > _winSize_Allocated)
1965*f6dc9357SAndroid Build Coastguard Worker     {
1966*f6dc9357SAndroid Build Coastguard Worker       Z7_RAR_FREE_WINDOW
1967*f6dc9357SAndroid Build Coastguard Worker         _window = NULL;
1968*f6dc9357SAndroid Build Coastguard Worker       _winSize_Allocated = 0;
1969*f6dc9357SAndroid Build Coastguard Worker       Byte *win = (Byte *)::BigAlloc(allocSize);
1970*f6dc9357SAndroid Build Coastguard Worker       if (!win)
1971*f6dc9357SAndroid Build Coastguard Worker         return E_OUTOFMEMORY;
1972*f6dc9357SAndroid Build Coastguard Worker       _window = win;
1973*f6dc9357SAndroid Build Coastguard Worker       _winSize_Allocated = allocSize;
1974*f6dc9357SAndroid Build Coastguard Worker     }
1975*f6dc9357SAndroid Build Coastguard Worker     _winSize = newSize;
1976*f6dc9357SAndroid Build Coastguard Worker   }
1977*f6dc9357SAndroid Build Coastguard Worker 
1978*f6dc9357SAndroid Build Coastguard Worker   if (!_inputBuf)
1979*f6dc9357SAndroid Build Coastguard Worker   {
1980*f6dc9357SAndroid Build Coastguard Worker     _inputBuf = (Byte *)z7_AlignedAlloc(kInputBufSize + kInputBufferPadZone);
1981*f6dc9357SAndroid Build Coastguard Worker     if (!_inputBuf)
1982*f6dc9357SAndroid Build Coastguard Worker       return E_OUTOFMEMORY;
1983*f6dc9357SAndroid Build Coastguard Worker   }
1984*f6dc9357SAndroid Build Coastguard Worker 
1985*f6dc9357SAndroid Build Coastguard Worker   _inStream = inStream;
1986*f6dc9357SAndroid Build Coastguard Worker   _outStream = outStream;
1987*f6dc9357SAndroid Build Coastguard Worker   _progress = progress;
1988*f6dc9357SAndroid Build Coastguard Worker   _progress_Pack = 0;
1989*f6dc9357SAndroid Build Coastguard Worker   _progress_Unpack = 0;
1990*f6dc9357SAndroid Build Coastguard Worker 
1991*f6dc9357SAndroid Build Coastguard Worker   const HRESULT res = CodeReal();
1992*f6dc9357SAndroid Build Coastguard Worker 
1993*f6dc9357SAndroid Build Coastguard Worker   if (res != S_OK)
1994*f6dc9357SAndroid Build Coastguard Worker     return res;
1995*f6dc9357SAndroid Build Coastguard Worker   // _lzError = LZ_ERROR_TYPE_HEADER; // for debug
1996*f6dc9357SAndroid Build Coastguard Worker   if (_lzError)
1997*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1998*f6dc9357SAndroid Build Coastguard Worker   if (_unsupportedFilter)
1999*f6dc9357SAndroid Build Coastguard Worker     return E_NOTIMPL;
2000*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2001*f6dc9357SAndroid Build Coastguard Worker }
2002*f6dc9357SAndroid Build Coastguard Worker 
2003*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CDecoder::SetDecoderProperties2 (const Byte * data,UInt32 size))2004*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size))
2005*f6dc9357SAndroid Build Coastguard Worker {
2006*f6dc9357SAndroid Build Coastguard Worker   if (size != 2)
2007*f6dc9357SAndroid Build Coastguard Worker     return E_INVALIDARG;
2008*f6dc9357SAndroid Build Coastguard Worker   const unsigned pow = data[0];
2009*f6dc9357SAndroid Build Coastguard Worker   const unsigned b1 = data[1];
2010*f6dc9357SAndroid Build Coastguard Worker   const unsigned frac = b1 >> 3;
2011*f6dc9357SAndroid Build Coastguard Worker   // unsigned pow = 15 + 8;
2012*f6dc9357SAndroid Build Coastguard Worker   // unsigned frac = 1;
2013*f6dc9357SAndroid Build Coastguard Worker   if (pow + ((frac + 31) >> 5) > MAX_DICT_LOG - 17)
2014*f6dc9357SAndroid Build Coastguard Worker   // if (frac + (pow << 8) >= ((8 * 2 + 7) << 5) + 8 / 8)
2015*f6dc9357SAndroid Build Coastguard Worker     return E_NOTIMPL;
2016*f6dc9357SAndroid Build Coastguard Worker   _dictSize = (size_t)(frac + 32) << (pow + 12);
2017*f6dc9357SAndroid Build Coastguard Worker   _isSolid = (b1 & 1) != 0;
2018*f6dc9357SAndroid Build Coastguard Worker   _is_v7   = (b1 & 2) != 0;
2019*f6dc9357SAndroid Build Coastguard Worker   // printf("\ndict size = %p\n", (void *)(size_t)_dictSize);
2020*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2021*f6dc9357SAndroid Build Coastguard Worker }
2022*f6dc9357SAndroid Build Coastguard Worker 
2023*f6dc9357SAndroid Build Coastguard Worker }}
2024