xref: /aosp_15_r20/external/lzma/CPP/7zip/Compress/XpressDecoder.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // XpressDecoder.cpp
2*f6dc9357SAndroid Build Coastguard Worker 
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker 
5*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/CpuArch.h"
6*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/RotateDefs.h"
7*f6dc9357SAndroid Build Coastguard Worker 
8*f6dc9357SAndroid Build Coastguard Worker #include "HuffmanDecoder.h"
9*f6dc9357SAndroid Build Coastguard Worker #include "XpressDecoder.h"
10*f6dc9357SAndroid Build Coastguard Worker 
11*f6dc9357SAndroid Build Coastguard Worker #ifdef MY_CPU_LE_UNALIGN
12*f6dc9357SAndroid Build Coastguard Worker   #define Z7_XPRESS_DEC_USE_UNALIGNED_COPY
13*f6dc9357SAndroid Build Coastguard Worker #endif
14*f6dc9357SAndroid Build Coastguard Worker 
15*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_XPRESS_DEC_USE_UNALIGNED_COPY
16*f6dc9357SAndroid Build Coastguard Worker 
17*f6dc9357SAndroid Build Coastguard Worker   #define COPY_CHUNK_SIZE 16
18*f6dc9357SAndroid Build Coastguard Worker 
19*f6dc9357SAndroid Build Coastguard Worker     #define COPY_CHUNK_4_2(dest, src) \
20*f6dc9357SAndroid Build Coastguard Worker     { \
21*f6dc9357SAndroid Build Coastguard Worker       ((UInt32 *)(void *)dest)[0] = ((const UInt32 *)(const void *)src)[0]; \
22*f6dc9357SAndroid Build Coastguard Worker       ((UInt32 *)(void *)dest)[1] = ((const UInt32 *)(const void *)src)[1]; \
23*f6dc9357SAndroid Build Coastguard Worker       src += 4 * 2; \
24*f6dc9357SAndroid Build Coastguard Worker       dest += 4 * 2; \
25*f6dc9357SAndroid Build Coastguard Worker     }
26*f6dc9357SAndroid Build Coastguard Worker 
27*f6dc9357SAndroid Build Coastguard Worker   /* sse2 doesn't help here in GCC and CLANG.
28*f6dc9357SAndroid Build Coastguard Worker      so we disabled sse2 here */
29*f6dc9357SAndroid Build Coastguard Worker #if 0
30*f6dc9357SAndroid Build Coastguard Worker   #if defined(MY_CPU_AMD64)
31*f6dc9357SAndroid Build Coastguard Worker     #define Z7_XPRESS_DEC_USE_SSE2
32*f6dc9357SAndroid Build Coastguard Worker   #elif defined(MY_CPU_X86)
33*f6dc9357SAndroid Build Coastguard Worker     #if defined(_MSC_VER) && _MSC_VER >= 1300 && defined(_M_IX86_FP) && (_M_IX86_FP >= 2) \
34*f6dc9357SAndroid Build Coastguard Worker       || defined(__SSE2__) \
35*f6dc9357SAndroid Build Coastguard Worker       // || 1 == 1  // for debug only
36*f6dc9357SAndroid Build Coastguard Worker       #define Z7_XPRESS_DEC_USE_SSE2
37*f6dc9357SAndroid Build Coastguard Worker     #endif
38*f6dc9357SAndroid Build Coastguard Worker   #endif
39*f6dc9357SAndroid Build Coastguard Worker #endif
40*f6dc9357SAndroid Build Coastguard Worker 
41*f6dc9357SAndroid Build Coastguard Worker   #if defined(MY_CPU_ARM64)
42*f6dc9357SAndroid Build Coastguard Worker   #include <arm_neon.h>
43*f6dc9357SAndroid Build Coastguard Worker     #define COPY_OFFSET_MIN  16
44*f6dc9357SAndroid Build Coastguard Worker     #define COPY_CHUNK1(dest, src) \
45*f6dc9357SAndroid Build Coastguard Worker     { \
46*f6dc9357SAndroid Build Coastguard Worker       vst1q_u8((uint8_t *)(void *)dest, \
47*f6dc9357SAndroid Build Coastguard Worker       vld1q_u8((const uint8_t *)(const void *)src)); \
48*f6dc9357SAndroid Build Coastguard Worker       src += 16; \
49*f6dc9357SAndroid Build Coastguard Worker       dest += 16; \
50*f6dc9357SAndroid Build Coastguard Worker     }
51*f6dc9357SAndroid Build Coastguard Worker 
52*f6dc9357SAndroid Build Coastguard Worker     #define COPY_CHUNK(dest, src) \
53*f6dc9357SAndroid Build Coastguard Worker     { \
54*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNK1(dest, src) \
55*f6dc9357SAndroid Build Coastguard Worker       if (dest >= dest_lim) break; \
56*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNK1(dest, src) \
57*f6dc9357SAndroid Build Coastguard Worker     }
58*f6dc9357SAndroid Build Coastguard Worker 
59*f6dc9357SAndroid Build Coastguard Worker   #elif defined(Z7_XPRESS_DEC_USE_SSE2)
60*f6dc9357SAndroid Build Coastguard Worker     #include <emmintrin.h> // sse2
61*f6dc9357SAndroid Build Coastguard Worker     #define COPY_OFFSET_MIN  16
62*f6dc9357SAndroid Build Coastguard Worker 
63*f6dc9357SAndroid Build Coastguard Worker     #define COPY_CHUNK1(dest, src) \
64*f6dc9357SAndroid Build Coastguard Worker     { \
65*f6dc9357SAndroid Build Coastguard Worker       _mm_storeu_si128((__m128i *)(void *)dest, \
66*f6dc9357SAndroid Build Coastguard Worker       _mm_loadu_si128((const __m128i *)(const void *)src)); \
67*f6dc9357SAndroid Build Coastguard Worker       src += 16; \
68*f6dc9357SAndroid Build Coastguard Worker       dest += 16; \
69*f6dc9357SAndroid Build Coastguard Worker     }
70*f6dc9357SAndroid Build Coastguard Worker 
71*f6dc9357SAndroid Build Coastguard Worker     #define COPY_CHUNK(dest, src) \
72*f6dc9357SAndroid Build Coastguard Worker     { \
73*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNK1(dest, src) \
74*f6dc9357SAndroid Build Coastguard Worker       if (dest >= dest_lim) break; \
75*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNK1(dest, src) \
76*f6dc9357SAndroid Build Coastguard Worker     }
77*f6dc9357SAndroid Build Coastguard Worker 
78*f6dc9357SAndroid Build Coastguard Worker   #elif defined(MY_CPU_64BIT)
79*f6dc9357SAndroid Build Coastguard Worker     #define COPY_OFFSET_MIN  8
80*f6dc9357SAndroid Build Coastguard Worker 
81*f6dc9357SAndroid Build Coastguard Worker     #define COPY_CHUNK(dest, src) \
82*f6dc9357SAndroid Build Coastguard Worker     { \
83*f6dc9357SAndroid Build Coastguard Worker       ((UInt64 *)(void *)dest)[0] = ((const UInt64 *)(const void *)src)[0]; \
84*f6dc9357SAndroid Build Coastguard Worker       ((UInt64 *)(void *)dest)[1] = ((const UInt64 *)(const void *)src)[1]; \
85*f6dc9357SAndroid Build Coastguard Worker       src += 8 * 2; \
86*f6dc9357SAndroid Build Coastguard Worker       dest += 8 * 2; \
87*f6dc9357SAndroid Build Coastguard Worker     }
88*f6dc9357SAndroid Build Coastguard Worker 
89*f6dc9357SAndroid Build Coastguard Worker   #else
90*f6dc9357SAndroid Build Coastguard Worker     #define COPY_OFFSET_MIN  4
91*f6dc9357SAndroid Build Coastguard Worker 
92*f6dc9357SAndroid Build Coastguard Worker     #define COPY_CHUNK(dest, src) \
93*f6dc9357SAndroid Build Coastguard Worker     { \
94*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNK_4_2(dest, src); \
95*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNK_4_2(dest, src); \
96*f6dc9357SAndroid Build Coastguard Worker     }
97*f6dc9357SAndroid Build Coastguard Worker 
98*f6dc9357SAndroid Build Coastguard Worker   #endif
99*f6dc9357SAndroid Build Coastguard Worker #endif
100*f6dc9357SAndroid Build Coastguard Worker 
101*f6dc9357SAndroid Build Coastguard Worker 
102*f6dc9357SAndroid Build Coastguard Worker #ifndef COPY_CHUNK_SIZE
103*f6dc9357SAndroid Build Coastguard Worker     #define COPY_OFFSET_MIN  4
104*f6dc9357SAndroid Build Coastguard Worker     #define COPY_CHUNK_SIZE  8
105*f6dc9357SAndroid Build Coastguard Worker     #define COPY_CHUNK_2(dest, src) \
106*f6dc9357SAndroid Build Coastguard Worker     { \
107*f6dc9357SAndroid Build Coastguard Worker       const Byte a0 = src[0]; \
108*f6dc9357SAndroid Build Coastguard Worker       const Byte a1 = src[1]; \
109*f6dc9357SAndroid Build Coastguard Worker       dest[0] = a0; \
110*f6dc9357SAndroid Build Coastguard Worker       dest[1] = a1; \
111*f6dc9357SAndroid Build Coastguard Worker       src += 2; \
112*f6dc9357SAndroid Build Coastguard Worker       dest += 2; \
113*f6dc9357SAndroid Build Coastguard Worker     }
114*f6dc9357SAndroid Build Coastguard Worker     #define COPY_CHUNK(dest, src) \
115*f6dc9357SAndroid Build Coastguard Worker     { \
116*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNK_2(dest, src) \
117*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNK_2(dest, src) \
118*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNK_2(dest, src) \
119*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNK_2(dest, src) \
120*f6dc9357SAndroid Build Coastguard Worker     }
121*f6dc9357SAndroid Build Coastguard Worker #endif
122*f6dc9357SAndroid Build Coastguard Worker 
123*f6dc9357SAndroid Build Coastguard Worker 
124*f6dc9357SAndroid Build Coastguard Worker #define COPY_CHUNKS \
125*f6dc9357SAndroid Build Coastguard Worker { \
126*f6dc9357SAndroid Build Coastguard Worker   Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \
127*f6dc9357SAndroid Build Coastguard Worker   do { COPY_CHUNK(dest, src) } \
128*f6dc9357SAndroid Build Coastguard Worker   while (dest < dest_lim); \
129*f6dc9357SAndroid Build Coastguard Worker }
130*f6dc9357SAndroid Build Coastguard Worker 
131*f6dc9357SAndroid Build Coastguard Worker 
132*f6dc9357SAndroid Build Coastguard Worker static
133*f6dc9357SAndroid Build Coastguard Worker Z7_FORCE_INLINE
134*f6dc9357SAndroid Build Coastguard Worker // Z7_ATTRIB_NO_VECTOR
CopyMatch_1(Byte * dest,const Byte * dest_lim)135*f6dc9357SAndroid Build Coastguard Worker void CopyMatch_1(Byte *dest, const Byte *dest_lim)
136*f6dc9357SAndroid Build Coastguard Worker {
137*f6dc9357SAndroid Build Coastguard Worker       const unsigned b0 = dest[-1];
138*f6dc9357SAndroid Build Coastguard Worker       {
139*f6dc9357SAndroid Build Coastguard Worker #if defined(Z7_XPRESS_DEC_USE_UNALIGNED_COPY) && (COPY_CHUNK_SIZE == 16)
140*f6dc9357SAndroid Build Coastguard Worker         #if defined(MY_CPU_64BIT)
141*f6dc9357SAndroid Build Coastguard Worker         {
142*f6dc9357SAndroid Build Coastguard Worker           const UInt64 v64 = (UInt64)b0 * 0x0101010101010101;
143*f6dc9357SAndroid Build Coastguard Worker           Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
144*f6dc9357SAndroid Build Coastguard Worker           do
145*f6dc9357SAndroid Build Coastguard Worker           {
146*f6dc9357SAndroid Build Coastguard Worker             ((UInt64 *)(void *)dest)[0] = v64;
147*f6dc9357SAndroid Build Coastguard Worker             ((UInt64 *)(void *)dest)[1] = v64;
148*f6dc9357SAndroid Build Coastguard Worker             dest += 16;
149*f6dc9357SAndroid Build Coastguard Worker           }
150*f6dc9357SAndroid Build Coastguard Worker           while (dest < dest_lim);
151*f6dc9357SAndroid Build Coastguard Worker         }
152*f6dc9357SAndroid Build Coastguard Worker         #else
153*f6dc9357SAndroid Build Coastguard Worker         {
154*f6dc9357SAndroid Build Coastguard Worker           UInt32 v = b0;
155*f6dc9357SAndroid Build Coastguard Worker           v |= v << 8;
156*f6dc9357SAndroid Build Coastguard Worker           v |= v << 16;
157*f6dc9357SAndroid Build Coastguard Worker           do
158*f6dc9357SAndroid Build Coastguard Worker           {
159*f6dc9357SAndroid Build Coastguard Worker             ((UInt32 *)(void *)dest)[0] = v;
160*f6dc9357SAndroid Build Coastguard Worker             ((UInt32 *)(void *)dest)[1] = v;
161*f6dc9357SAndroid Build Coastguard Worker             dest += 8;
162*f6dc9357SAndroid Build Coastguard Worker             ((UInt32 *)(void *)dest)[0] = v;
163*f6dc9357SAndroid Build Coastguard Worker             ((UInt32 *)(void *)dest)[1] = v;
164*f6dc9357SAndroid Build Coastguard Worker             dest += 8;
165*f6dc9357SAndroid Build Coastguard Worker           }
166*f6dc9357SAndroid Build Coastguard Worker           while (dest < dest_lim);
167*f6dc9357SAndroid Build Coastguard Worker         }
168*f6dc9357SAndroid Build Coastguard Worker         #endif
169*f6dc9357SAndroid Build Coastguard Worker #else
170*f6dc9357SAndroid Build Coastguard Worker         do
171*f6dc9357SAndroid Build Coastguard Worker         {
172*f6dc9357SAndroid Build Coastguard Worker           dest[0] = (Byte)b0;
173*f6dc9357SAndroid Build Coastguard Worker           dest[1] = (Byte)b0;
174*f6dc9357SAndroid Build Coastguard Worker           dest += 2;
175*f6dc9357SAndroid Build Coastguard Worker           dest[0] = (Byte)b0;
176*f6dc9357SAndroid Build Coastguard Worker           dest[1] = (Byte)b0;
177*f6dc9357SAndroid Build Coastguard Worker           dest += 2;
178*f6dc9357SAndroid Build Coastguard Worker         }
179*f6dc9357SAndroid Build Coastguard Worker         while (dest < dest_lim);
180*f6dc9357SAndroid Build Coastguard Worker #endif
181*f6dc9357SAndroid Build Coastguard Worker       }
182*f6dc9357SAndroid Build Coastguard Worker }
183*f6dc9357SAndroid Build Coastguard Worker 
184*f6dc9357SAndroid Build Coastguard Worker 
185*f6dc9357SAndroid Build Coastguard Worker // (offset != 1)
186*f6dc9357SAndroid Build Coastguard Worker static
187*f6dc9357SAndroid Build Coastguard Worker Z7_FORCE_INLINE
188*f6dc9357SAndroid Build Coastguard Worker // Z7_ATTRIB_NO_VECTOR
CopyMatch_Non1(Byte * dest,size_t offset,const Byte * dest_lim)189*f6dc9357SAndroid Build Coastguard Worker void CopyMatch_Non1(Byte *dest, size_t offset, const Byte *dest_lim)
190*f6dc9357SAndroid Build Coastguard Worker {
191*f6dc9357SAndroid Build Coastguard Worker   const Byte *src = dest - offset;
192*f6dc9357SAndroid Build Coastguard Worker   {
193*f6dc9357SAndroid Build Coastguard Worker     // (COPY_OFFSET_MIN >= 4)
194*f6dc9357SAndroid Build Coastguard Worker     if (offset >= COPY_OFFSET_MIN)
195*f6dc9357SAndroid Build Coastguard Worker     {
196*f6dc9357SAndroid Build Coastguard Worker       COPY_CHUNKS
197*f6dc9357SAndroid Build Coastguard Worker       // return;
198*f6dc9357SAndroid Build Coastguard Worker     }
199*f6dc9357SAndroid Build Coastguard Worker     else
200*f6dc9357SAndroid Build Coastguard Worker #if (COPY_OFFSET_MIN > 4)
201*f6dc9357SAndroid Build Coastguard Worker     #if COPY_CHUNK_SIZE < 8
202*f6dc9357SAndroid Build Coastguard Worker       #error Stop_Compiling_Bad_COPY_CHUNK_SIZE
203*f6dc9357SAndroid Build Coastguard Worker     #endif
204*f6dc9357SAndroid Build Coastguard Worker     if (offset >= 4)
205*f6dc9357SAndroid Build Coastguard Worker     {
206*f6dc9357SAndroid Build Coastguard Worker       Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
207*f6dc9357SAndroid Build Coastguard Worker       do
208*f6dc9357SAndroid Build Coastguard Worker       {
209*f6dc9357SAndroid Build Coastguard Worker         COPY_CHUNK_4_2(dest, src)
210*f6dc9357SAndroid Build Coastguard Worker         #if COPY_CHUNK_SIZE != 16
211*f6dc9357SAndroid Build Coastguard Worker           if (dest >= dest_lim) break;
212*f6dc9357SAndroid Build Coastguard Worker         #endif
213*f6dc9357SAndroid Build Coastguard Worker         COPY_CHUNK_4_2(dest, src)
214*f6dc9357SAndroid Build Coastguard Worker       }
215*f6dc9357SAndroid Build Coastguard Worker       while (dest < dest_lim);
216*f6dc9357SAndroid Build Coastguard Worker       // return;
217*f6dc9357SAndroid Build Coastguard Worker     }
218*f6dc9357SAndroid Build Coastguard Worker     else
219*f6dc9357SAndroid Build Coastguard Worker #endif
220*f6dc9357SAndroid Build Coastguard Worker     {
221*f6dc9357SAndroid Build Coastguard Worker       // (offset < 4)
222*f6dc9357SAndroid Build Coastguard Worker       if (offset == 2)
223*f6dc9357SAndroid Build Coastguard Worker       {
224*f6dc9357SAndroid Build Coastguard Worker #if defined(Z7_XPRESS_DEC_USE_UNALIGNED_COPY)
225*f6dc9357SAndroid Build Coastguard Worker         UInt32 w0 = GetUi16(src);
226*f6dc9357SAndroid Build Coastguard Worker         w0 += w0 << 16;
227*f6dc9357SAndroid Build Coastguard Worker         do
228*f6dc9357SAndroid Build Coastguard Worker         {
229*f6dc9357SAndroid Build Coastguard Worker           SetUi32(dest, w0)
230*f6dc9357SAndroid Build Coastguard Worker           dest += 4;
231*f6dc9357SAndroid Build Coastguard Worker         }
232*f6dc9357SAndroid Build Coastguard Worker         while (dest < dest_lim);
233*f6dc9357SAndroid Build Coastguard Worker #else
234*f6dc9357SAndroid Build Coastguard Worker         const unsigned b0 = src[0];
235*f6dc9357SAndroid Build Coastguard Worker         const Byte b1 = src[1];
236*f6dc9357SAndroid Build Coastguard Worker         do
237*f6dc9357SAndroid Build Coastguard Worker         {
238*f6dc9357SAndroid Build Coastguard Worker           dest[0] = (Byte)b0;
239*f6dc9357SAndroid Build Coastguard Worker           dest[1] = b1;
240*f6dc9357SAndroid Build Coastguard Worker           dest += 2;
241*f6dc9357SAndroid Build Coastguard Worker         }
242*f6dc9357SAndroid Build Coastguard Worker         while (dest < dest_lim);
243*f6dc9357SAndroid Build Coastguard Worker #endif
244*f6dc9357SAndroid Build Coastguard Worker       }
245*f6dc9357SAndroid Build Coastguard Worker       else // (offset == 3)
246*f6dc9357SAndroid Build Coastguard Worker       {
247*f6dc9357SAndroid Build Coastguard Worker         const unsigned b0 = src[0];
248*f6dc9357SAndroid Build Coastguard Worker #if defined(Z7_XPRESS_DEC_USE_UNALIGNED_COPY)
249*f6dc9357SAndroid Build Coastguard Worker         const unsigned w1 = GetUi16(src + 1);
250*f6dc9357SAndroid Build Coastguard Worker         do
251*f6dc9357SAndroid Build Coastguard Worker         {
252*f6dc9357SAndroid Build Coastguard Worker           dest[0] = (Byte)b0;
253*f6dc9357SAndroid Build Coastguard Worker           SetUi16(dest + 1, (UInt16)w1)
254*f6dc9357SAndroid Build Coastguard Worker           dest += 3;
255*f6dc9357SAndroid Build Coastguard Worker         }
256*f6dc9357SAndroid Build Coastguard Worker         while (dest < dest_lim);
257*f6dc9357SAndroid Build Coastguard Worker #else
258*f6dc9357SAndroid Build Coastguard Worker         const Byte b1 = src[1];
259*f6dc9357SAndroid Build Coastguard Worker         const Byte b2 = src[2];
260*f6dc9357SAndroid Build Coastguard Worker         do
261*f6dc9357SAndroid Build Coastguard Worker         {
262*f6dc9357SAndroid Build Coastguard Worker           dest[0] = (Byte)b0;
263*f6dc9357SAndroid Build Coastguard Worker           dest[1] = b1;
264*f6dc9357SAndroid Build Coastguard Worker           dest[2] = b2;
265*f6dc9357SAndroid Build Coastguard Worker           dest += 3;
266*f6dc9357SAndroid Build Coastguard Worker         }
267*f6dc9357SAndroid Build Coastguard Worker         while (dest < dest_lim);
268*f6dc9357SAndroid Build Coastguard Worker #endif
269*f6dc9357SAndroid Build Coastguard Worker       }
270*f6dc9357SAndroid Build Coastguard Worker     }
271*f6dc9357SAndroid Build Coastguard Worker   }
272*f6dc9357SAndroid Build Coastguard Worker }
273*f6dc9357SAndroid Build Coastguard Worker 
274*f6dc9357SAndroid Build Coastguard Worker 
275*f6dc9357SAndroid Build Coastguard Worker namespace NCompress {
276*f6dc9357SAndroid Build Coastguard Worker namespace NXpress {
277*f6dc9357SAndroid Build Coastguard Worker 
278*f6dc9357SAndroid Build Coastguard Worker #define BIT_STREAM_NORMALIZE \
279*f6dc9357SAndroid Build Coastguard Worker     if (BitPos > 16) { \
280*f6dc9357SAndroid Build Coastguard Worker       if (in >= lim) return S_FALSE; \
281*f6dc9357SAndroid Build Coastguard Worker       BitPos -= 16; \
282*f6dc9357SAndroid Build Coastguard Worker       Value |= (UInt32)GetUi16(in) << BitPos; \
283*f6dc9357SAndroid Build Coastguard Worker       in += 2; }
284*f6dc9357SAndroid Build Coastguard Worker 
285*f6dc9357SAndroid Build Coastguard Worker #define MOVE_POS(bs, numBits) \
286*f6dc9357SAndroid Build Coastguard Worker     BitPos += (unsigned)numBits; \
287*f6dc9357SAndroid Build Coastguard Worker     Value <<= numBits; \
288*f6dc9357SAndroid Build Coastguard Worker 
289*f6dc9357SAndroid Build Coastguard Worker 
290*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumHuffBits = 15;
291*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumTableBits = 10;
292*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumLenBits = 4;
293*f6dc9357SAndroid Build Coastguard Worker static const unsigned kLenMask = (1 << kNumLenBits) - 1;
294*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumPosSlots = 16;
295*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumSyms = 256 + (kNumPosSlots << kNumLenBits);
296*f6dc9357SAndroid Build Coastguard Worker 
Decode_WithExceedWrite(const Byte * in,size_t inSize,Byte * out,size_t outSize)297*f6dc9357SAndroid Build Coastguard Worker HRESULT Decode_WithExceedWrite(const Byte *in, size_t inSize, Byte *out, size_t outSize)
298*f6dc9357SAndroid Build Coastguard Worker {
299*f6dc9357SAndroid Build Coastguard Worker   NCompress::NHuffman::CDecoder<kNumHuffBits, kNumSyms, kNumTableBits> huff;
300*f6dc9357SAndroid Build Coastguard Worker 
301*f6dc9357SAndroid Build Coastguard Worker   if (inSize < kNumSyms / 2 + 4)
302*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
303*f6dc9357SAndroid Build Coastguard Worker   {
304*f6dc9357SAndroid Build Coastguard Worker     Byte levels[kNumSyms];
305*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = 0; i < kNumSyms / 2; i++)
306*f6dc9357SAndroid Build Coastguard Worker     {
307*f6dc9357SAndroid Build Coastguard Worker       const unsigned b = in[i];
308*f6dc9357SAndroid Build Coastguard Worker       levels[(size_t)i * 2    ] = (Byte)(b & 0xf);
309*f6dc9357SAndroid Build Coastguard Worker       levels[(size_t)i * 2 + 1] = (Byte)(b >> 4);
310*f6dc9357SAndroid Build Coastguard Worker     }
311*f6dc9357SAndroid Build Coastguard Worker     if (!huff.Build(levels, NHuffman::k_BuildMode_Full))
312*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
313*f6dc9357SAndroid Build Coastguard Worker   }
314*f6dc9357SAndroid Build Coastguard Worker 
315*f6dc9357SAndroid Build Coastguard Worker   UInt32 Value;
316*f6dc9357SAndroid Build Coastguard Worker   unsigned BitPos;  // how many bits in (Value) were processed
317*f6dc9357SAndroid Build Coastguard Worker 
318*f6dc9357SAndroid Build Coastguard Worker   const Byte *lim = in + inSize - 1;  // points to last byte
319*f6dc9357SAndroid Build Coastguard Worker   in += kNumSyms / 2;
320*f6dc9357SAndroid Build Coastguard Worker #ifdef MY_CPU_LE_UNALIGN
321*f6dc9357SAndroid Build Coastguard Worker   Value = GetUi32(in);
322*f6dc9357SAndroid Build Coastguard Worker   Value = rotlFixed(Value, 16);
323*f6dc9357SAndroid Build Coastguard Worker #else
324*f6dc9357SAndroid Build Coastguard Worker   Value = ((UInt32)GetUi16(in) << 16) | GetUi16(in + 2);
325*f6dc9357SAndroid Build Coastguard Worker #endif
326*f6dc9357SAndroid Build Coastguard Worker 
327*f6dc9357SAndroid Build Coastguard Worker   in += 4;
328*f6dc9357SAndroid Build Coastguard Worker   BitPos = 0;
329*f6dc9357SAndroid Build Coastguard Worker   Byte *dest = out;
330*f6dc9357SAndroid Build Coastguard Worker   const Byte *outLim = out + outSize;
331*f6dc9357SAndroid Build Coastguard Worker 
332*f6dc9357SAndroid Build Coastguard Worker   for (;;)
333*f6dc9357SAndroid Build Coastguard Worker   {
334*f6dc9357SAndroid Build Coastguard Worker     unsigned sym;
335*f6dc9357SAndroid Build Coastguard Worker     Z7_HUFF_DECODE_VAL_IN_HIGH32(sym, &huff, kNumHuffBits, kNumTableBits,
336*f6dc9357SAndroid Build Coastguard Worker         Value, Z7_HUFF_DECODE_ERROR_SYM_CHECK_NO, {}, MOVE_POS, {}, bs)
337*f6dc9357SAndroid Build Coastguard Worker     // 0 < BitPos <= 31
338*f6dc9357SAndroid Build Coastguard Worker     BIT_STREAM_NORMALIZE
339*f6dc9357SAndroid Build Coastguard Worker     // 0 < BitPos <= 16
340*f6dc9357SAndroid Build Coastguard Worker 
341*f6dc9357SAndroid Build Coastguard Worker     if (dest >= outLim)
342*f6dc9357SAndroid Build Coastguard Worker       return (sym == 256 && Value == 0 && in == lim + 1) ? S_OK : S_FALSE;
343*f6dc9357SAndroid Build Coastguard Worker 
344*f6dc9357SAndroid Build Coastguard Worker     if (sym < 256)
345*f6dc9357SAndroid Build Coastguard Worker       *dest++ = (Byte)sym;
346*f6dc9357SAndroid Build Coastguard Worker     else
347*f6dc9357SAndroid Build Coastguard Worker     {
348*f6dc9357SAndroid Build Coastguard Worker       const unsigned distBits = (unsigned)(Byte)sym >> kNumLenBits; // (sym - 256) >> kNumLenBits;
349*f6dc9357SAndroid Build Coastguard Worker       UInt32 len = (UInt32)(sym & kLenMask);
350*f6dc9357SAndroid Build Coastguard Worker 
351*f6dc9357SAndroid Build Coastguard Worker       if (len == kLenMask)
352*f6dc9357SAndroid Build Coastguard Worker       {
353*f6dc9357SAndroid Build Coastguard Worker         if (in > lim)
354*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
355*f6dc9357SAndroid Build Coastguard Worker         // here we read input bytes in out-of-order related to main input stream (bits in Value):
356*f6dc9357SAndroid Build Coastguard Worker         len = *in++;
357*f6dc9357SAndroid Build Coastguard Worker         if (len == 0xff)
358*f6dc9357SAndroid Build Coastguard Worker         {
359*f6dc9357SAndroid Build Coastguard Worker           if (in >= lim)
360*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
361*f6dc9357SAndroid Build Coastguard Worker           len = GetUi16(in);
362*f6dc9357SAndroid Build Coastguard Worker           in += 2;
363*f6dc9357SAndroid Build Coastguard Worker         }
364*f6dc9357SAndroid Build Coastguard Worker         else
365*f6dc9357SAndroid Build Coastguard Worker           len += kLenMask;
366*f6dc9357SAndroid Build Coastguard Worker       }
367*f6dc9357SAndroid Build Coastguard Worker 
368*f6dc9357SAndroid Build Coastguard Worker       len += 3;
369*f6dc9357SAndroid Build Coastguard Worker       if (len > (size_t)(outLim - dest))
370*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
371*f6dc9357SAndroid Build Coastguard Worker 
372*f6dc9357SAndroid Build Coastguard Worker       if (distBits == 0)
373*f6dc9357SAndroid Build Coastguard Worker       {
374*f6dc9357SAndroid Build Coastguard Worker         // d == 1
375*f6dc9357SAndroid Build Coastguard Worker         if (dest == out)
376*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
377*f6dc9357SAndroid Build Coastguard Worker         Byte *destTemp = dest;
378*f6dc9357SAndroid Build Coastguard Worker         dest += len;
379*f6dc9357SAndroid Build Coastguard Worker         CopyMatch_1(destTemp, dest);
380*f6dc9357SAndroid Build Coastguard Worker       }
381*f6dc9357SAndroid Build Coastguard Worker       else
382*f6dc9357SAndroid Build Coastguard Worker       {
383*f6dc9357SAndroid Build Coastguard Worker         unsigned d = (unsigned)(Value >> (32 - distBits));
384*f6dc9357SAndroid Build Coastguard Worker         MOVE_POS(bs, distBits)
385*f6dc9357SAndroid Build Coastguard Worker         d += 1u << distBits;
386*f6dc9357SAndroid Build Coastguard Worker         // 0 < BitPos <= 31
387*f6dc9357SAndroid Build Coastguard Worker         BIT_STREAM_NORMALIZE
388*f6dc9357SAndroid Build Coastguard Worker         // 0 < BitPos <= 16
389*f6dc9357SAndroid Build Coastguard Worker         if (d > (size_t)(dest - out))
390*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
391*f6dc9357SAndroid Build Coastguard Worker         Byte *destTemp = dest;
392*f6dc9357SAndroid Build Coastguard Worker         dest += len;
393*f6dc9357SAndroid Build Coastguard Worker         CopyMatch_Non1(destTemp, d, dest);
394*f6dc9357SAndroid Build Coastguard Worker       }
395*f6dc9357SAndroid Build Coastguard Worker     }
396*f6dc9357SAndroid Build Coastguard Worker   }
397*f6dc9357SAndroid Build Coastguard Worker }
398*f6dc9357SAndroid Build Coastguard Worker 
399*f6dc9357SAndroid Build Coastguard Worker }}
400