xref: /aosp_15_r20/external/lzma/CPP/7zip/Compress/LzfseDecoder.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // LzfseDecoder.cpp
2*f6dc9357SAndroid Build Coastguard Worker 
3*f6dc9357SAndroid Build Coastguard Worker /*
4*f6dc9357SAndroid Build Coastguard Worker This code implements LZFSE data decompressing.
5*f6dc9357SAndroid Build Coastguard Worker The code from "LZFSE compression library" was used.
6*f6dc9357SAndroid Build Coastguard Worker 
7*f6dc9357SAndroid Build Coastguard Worker 2018      : Igor Pavlov : BSD 3-clause License : the code in this file
8*f6dc9357SAndroid Build Coastguard Worker 2015-2017 : Apple Inc   : BSD 3-clause License : original "LZFSE compression library" code
9*f6dc9357SAndroid Build Coastguard Worker 
10*f6dc9357SAndroid Build Coastguard Worker The code in the "LZFSE compression library" is licensed under the "BSD 3-clause License":
11*f6dc9357SAndroid Build Coastguard Worker ----
12*f6dc9357SAndroid Build Coastguard Worker Copyright (c) 2015-2016, Apple Inc. All rights reserved.
13*f6dc9357SAndroid Build Coastguard Worker 
14*f6dc9357SAndroid Build Coastguard Worker Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
15*f6dc9357SAndroid Build Coastguard Worker 
16*f6dc9357SAndroid Build Coastguard Worker 1.  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
17*f6dc9357SAndroid Build Coastguard Worker 
18*f6dc9357SAndroid Build Coastguard Worker 2.  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
19*f6dc9357SAndroid Build Coastguard Worker     in the documentation and/or other materials provided with the distribution.
20*f6dc9357SAndroid Build Coastguard Worker 
21*f6dc9357SAndroid Build Coastguard Worker 3.  Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
22*f6dc9357SAndroid Build Coastguard Worker     from this software without specific prior written permission.
23*f6dc9357SAndroid Build Coastguard Worker 
24*f6dc9357SAndroid Build Coastguard Worker THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25*f6dc9357SAndroid Build Coastguard Worker LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26*f6dc9357SAndroid Build Coastguard Worker COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27*f6dc9357SAndroid Build Coastguard Worker (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28*f6dc9357SAndroid Build Coastguard Worker HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29*f6dc9357SAndroid Build Coastguard Worker ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*f6dc9357SAndroid Build Coastguard Worker ----
31*f6dc9357SAndroid Build Coastguard Worker */
32*f6dc9357SAndroid Build Coastguard Worker 
33*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
34*f6dc9357SAndroid Build Coastguard Worker 
35*f6dc9357SAndroid Build Coastguard Worker // #define SHOW_DEBUG_INFO
36*f6dc9357SAndroid Build Coastguard Worker 
37*f6dc9357SAndroid Build Coastguard Worker #ifdef SHOW_DEBUG_INFO
38*f6dc9357SAndroid Build Coastguard Worker #include <stdio.h>
39*f6dc9357SAndroid Build Coastguard Worker #endif
40*f6dc9357SAndroid Build Coastguard Worker 
41*f6dc9357SAndroid Build Coastguard Worker #ifdef SHOW_DEBUG_INFO
42*f6dc9357SAndroid Build Coastguard Worker #define PRF(x) x
43*f6dc9357SAndroid Build Coastguard Worker #else
44*f6dc9357SAndroid Build Coastguard Worker #define PRF(x)
45*f6dc9357SAndroid Build Coastguard Worker #endif
46*f6dc9357SAndroid Build Coastguard Worker 
47*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/CpuArch.h"
48*f6dc9357SAndroid Build Coastguard Worker 
49*f6dc9357SAndroid Build Coastguard Worker #include "LzfseDecoder.h"
50*f6dc9357SAndroid Build Coastguard Worker 
51*f6dc9357SAndroid Build Coastguard Worker namespace NCompress {
52*f6dc9357SAndroid Build Coastguard Worker namespace NLzfse {
53*f6dc9357SAndroid Build Coastguard Worker 
54*f6dc9357SAndroid Build Coastguard Worker static const Byte kSignature_LZFSE_V1 = 0x31; // '1'
55*f6dc9357SAndroid Build Coastguard Worker static const Byte kSignature_LZFSE_V2 = 0x32; // '2'
56*f6dc9357SAndroid Build Coastguard Worker 
57*f6dc9357SAndroid Build Coastguard Worker 
GetUInt32(UInt32 & val)58*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::GetUInt32(UInt32 &val)
59*f6dc9357SAndroid Build Coastguard Worker {
60*f6dc9357SAndroid Build Coastguard Worker   Byte b[4];
61*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < 4; i++)
62*f6dc9357SAndroid Build Coastguard Worker     if (!m_InStream.ReadByte(b[i]))
63*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
64*f6dc9357SAndroid Build Coastguard Worker   val = GetUi32(b);
65*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
66*f6dc9357SAndroid Build Coastguard Worker }
67*f6dc9357SAndroid Build Coastguard Worker 
68*f6dc9357SAndroid Build Coastguard Worker 
69*f6dc9357SAndroid Build Coastguard Worker 
DecodeUncompressed(UInt32 unpackSize)70*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::DecodeUncompressed(UInt32 unpackSize)
71*f6dc9357SAndroid Build Coastguard Worker {
72*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\nUncompressed %7u\n", unpackSize));
73*f6dc9357SAndroid Build Coastguard Worker 
74*f6dc9357SAndroid Build Coastguard Worker   const unsigned kBufSize = 1 << 8;
75*f6dc9357SAndroid Build Coastguard Worker   Byte buf[kBufSize];
76*f6dc9357SAndroid Build Coastguard Worker   for (;;)
77*f6dc9357SAndroid Build Coastguard Worker   {
78*f6dc9357SAndroid Build Coastguard Worker     if (unpackSize == 0)
79*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
80*f6dc9357SAndroid Build Coastguard Worker     UInt32 cur = unpackSize;
81*f6dc9357SAndroid Build Coastguard Worker     if (cur > kBufSize)
82*f6dc9357SAndroid Build Coastguard Worker       cur = kBufSize;
83*f6dc9357SAndroid Build Coastguard Worker     const UInt32 cur2 = (UInt32)m_InStream.ReadBytes(buf, cur);
84*f6dc9357SAndroid Build Coastguard Worker     m_OutWindowStream.PutBytes(buf, cur2);
85*f6dc9357SAndroid Build Coastguard Worker     if (cur != cur2)
86*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
87*f6dc9357SAndroid Build Coastguard Worker   }
88*f6dc9357SAndroid Build Coastguard Worker }
89*f6dc9357SAndroid Build Coastguard Worker 
90*f6dc9357SAndroid Build Coastguard Worker 
91*f6dc9357SAndroid Build Coastguard Worker 
DecodeLzvn(UInt32 unpackSize,UInt32 packSize)92*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::DecodeLzvn(UInt32 unpackSize, UInt32 packSize)
93*f6dc9357SAndroid Build Coastguard Worker {
94*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\nLZVN 0x%07x 0x%07x\n", unpackSize, packSize));
95*f6dc9357SAndroid Build Coastguard Worker 
96*f6dc9357SAndroid Build Coastguard Worker   UInt32 D = 0;
97*f6dc9357SAndroid Build Coastguard Worker 
98*f6dc9357SAndroid Build Coastguard Worker   for (;;)
99*f6dc9357SAndroid Build Coastguard Worker   {
100*f6dc9357SAndroid Build Coastguard Worker     if (packSize == 0)
101*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
102*f6dc9357SAndroid Build Coastguard Worker     Byte b;
103*f6dc9357SAndroid Build Coastguard Worker     if (!m_InStream.ReadByte(b))
104*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
105*f6dc9357SAndroid Build Coastguard Worker     packSize--;
106*f6dc9357SAndroid Build Coastguard Worker 
107*f6dc9357SAndroid Build Coastguard Worker     UInt32 M;
108*f6dc9357SAndroid Build Coastguard Worker     UInt32 L;
109*f6dc9357SAndroid Build Coastguard Worker 
110*f6dc9357SAndroid Build Coastguard Worker     if (b >= 0xE0)
111*f6dc9357SAndroid Build Coastguard Worker     {
112*f6dc9357SAndroid Build Coastguard Worker       /*
113*f6dc9357SAndroid Build Coastguard Worker       large L   - 11100000 LLLLLLLL <LITERALS>
114*f6dc9357SAndroid Build Coastguard Worker       small L   - 1110LLLL <LITERALS>
115*f6dc9357SAndroid Build Coastguard Worker 
116*f6dc9357SAndroid Build Coastguard Worker       large Rep - 11110000 MMMMMMMM
117*f6dc9357SAndroid Build Coastguard Worker       small Rep - 1111MMMM
118*f6dc9357SAndroid Build Coastguard Worker       */
119*f6dc9357SAndroid Build Coastguard Worker 
120*f6dc9357SAndroid Build Coastguard Worker       M = b & 0xF;
121*f6dc9357SAndroid Build Coastguard Worker       if (M == 0)
122*f6dc9357SAndroid Build Coastguard Worker       {
123*f6dc9357SAndroid Build Coastguard Worker         if (packSize == 0)
124*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
125*f6dc9357SAndroid Build Coastguard Worker         Byte b1;
126*f6dc9357SAndroid Build Coastguard Worker         if (!m_InStream.ReadByte(b1))
127*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
128*f6dc9357SAndroid Build Coastguard Worker         packSize--;
129*f6dc9357SAndroid Build Coastguard Worker         M = (UInt32)b1 + 16;
130*f6dc9357SAndroid Build Coastguard Worker       }
131*f6dc9357SAndroid Build Coastguard Worker       L = 0;
132*f6dc9357SAndroid Build Coastguard Worker       if ((b & 0x10) == 0)
133*f6dc9357SAndroid Build Coastguard Worker       {
134*f6dc9357SAndroid Build Coastguard Worker         // Literals only
135*f6dc9357SAndroid Build Coastguard Worker         L = M;
136*f6dc9357SAndroid Build Coastguard Worker         M = 0;
137*f6dc9357SAndroid Build Coastguard Worker       }
138*f6dc9357SAndroid Build Coastguard Worker     }
139*f6dc9357SAndroid Build Coastguard Worker 
140*f6dc9357SAndroid Build Coastguard Worker     // ERROR codes
141*f6dc9357SAndroid Build Coastguard Worker     else if ((b & 0xF0) == 0x70) // 0111xxxx
142*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
143*f6dc9357SAndroid Build Coastguard Worker     else if ((b & 0xF0) == 0xD0) // 1101xxxx
144*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
145*f6dc9357SAndroid Build Coastguard Worker 
146*f6dc9357SAndroid Build Coastguard Worker     else
147*f6dc9357SAndroid Build Coastguard Worker     {
148*f6dc9357SAndroid Build Coastguard Worker       if ((b & 0xE0) == 0xA0)
149*f6dc9357SAndroid Build Coastguard Worker       {
150*f6dc9357SAndroid Build Coastguard Worker         // medium  - 101LLMMM DDDDDDMM DDDDDDDD <LITERALS>
151*f6dc9357SAndroid Build Coastguard Worker         if (packSize < 2)
152*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
153*f6dc9357SAndroid Build Coastguard Worker         Byte b1;
154*f6dc9357SAndroid Build Coastguard Worker         if (!m_InStream.ReadByte(b1))
155*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
156*f6dc9357SAndroid Build Coastguard Worker         packSize--;
157*f6dc9357SAndroid Build Coastguard Worker 
158*f6dc9357SAndroid Build Coastguard Worker         Byte b2;
159*f6dc9357SAndroid Build Coastguard Worker         if (!m_InStream.ReadByte(b2))
160*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
161*f6dc9357SAndroid Build Coastguard Worker         packSize--;
162*f6dc9357SAndroid Build Coastguard Worker         L = (((UInt32)b >> 3) & 3);
163*f6dc9357SAndroid Build Coastguard Worker         M = (((UInt32)b & 7) << 2) + (b1 & 3);
164*f6dc9357SAndroid Build Coastguard Worker         D = ((UInt32)b1 >> 2) + ((UInt32)b2 << 6);
165*f6dc9357SAndroid Build Coastguard Worker       }
166*f6dc9357SAndroid Build Coastguard Worker       else
167*f6dc9357SAndroid Build Coastguard Worker       {
168*f6dc9357SAndroid Build Coastguard Worker         L = (UInt32)b >> 6;
169*f6dc9357SAndroid Build Coastguard Worker         M = ((UInt32)b >> 3) & 7;
170*f6dc9357SAndroid Build Coastguard Worker         if ((b & 0x7) == 6)
171*f6dc9357SAndroid Build Coastguard Worker         {
172*f6dc9357SAndroid Build Coastguard Worker           // REP - LLMMM110 <LITERALS>
173*f6dc9357SAndroid Build Coastguard Worker           if (L == 0)
174*f6dc9357SAndroid Build Coastguard Worker           {
175*f6dc9357SAndroid Build Coastguard Worker             // spec
176*f6dc9357SAndroid Build Coastguard Worker             if (M == 0)
177*f6dc9357SAndroid Build Coastguard Worker               break; // EOS
178*f6dc9357SAndroid Build Coastguard Worker             if (M <= 2)
179*f6dc9357SAndroid Build Coastguard Worker               continue; // NOP
180*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE; // UNDEFINED
181*f6dc9357SAndroid Build Coastguard Worker           }
182*f6dc9357SAndroid Build Coastguard Worker         }
183*f6dc9357SAndroid Build Coastguard Worker         else
184*f6dc9357SAndroid Build Coastguard Worker         {
185*f6dc9357SAndroid Build Coastguard Worker           if (packSize == 0)
186*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
187*f6dc9357SAndroid Build Coastguard Worker           Byte b1;
188*f6dc9357SAndroid Build Coastguard Worker           if (!m_InStream.ReadByte(b1))
189*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
190*f6dc9357SAndroid Build Coastguard Worker           packSize--;
191*f6dc9357SAndroid Build Coastguard Worker 
192*f6dc9357SAndroid Build Coastguard Worker           // large - LLMMM111 DDDDDDDD DDDDDDDD <LITERALS>
193*f6dc9357SAndroid Build Coastguard Worker           // small - LLMMMDDD DDDDDDDD <LITERALS>
194*f6dc9357SAndroid Build Coastguard Worker           D  = ((UInt32)b & 7);
195*f6dc9357SAndroid Build Coastguard Worker           if (D == 7)
196*f6dc9357SAndroid Build Coastguard Worker           {
197*f6dc9357SAndroid Build Coastguard Worker             if (packSize == 0)
198*f6dc9357SAndroid Build Coastguard Worker               return S_FALSE;
199*f6dc9357SAndroid Build Coastguard Worker             Byte b2;
200*f6dc9357SAndroid Build Coastguard Worker             if (!m_InStream.ReadByte(b2))
201*f6dc9357SAndroid Build Coastguard Worker               return S_FALSE;
202*f6dc9357SAndroid Build Coastguard Worker             packSize--;
203*f6dc9357SAndroid Build Coastguard Worker             D = b2;
204*f6dc9357SAndroid Build Coastguard Worker           }
205*f6dc9357SAndroid Build Coastguard Worker           D = (D << 8) + b1;
206*f6dc9357SAndroid Build Coastguard Worker         }
207*f6dc9357SAndroid Build Coastguard Worker       }
208*f6dc9357SAndroid Build Coastguard Worker 
209*f6dc9357SAndroid Build Coastguard Worker       M += 3;
210*f6dc9357SAndroid Build Coastguard Worker     }
211*f6dc9357SAndroid Build Coastguard Worker     {
212*f6dc9357SAndroid Build Coastguard Worker       for (unsigned i = 0; i < L; i++)
213*f6dc9357SAndroid Build Coastguard Worker       {
214*f6dc9357SAndroid Build Coastguard Worker         if (packSize == 0 || unpackSize == 0)
215*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
216*f6dc9357SAndroid Build Coastguard Worker         Byte b1;
217*f6dc9357SAndroid Build Coastguard Worker         if (!m_InStream.ReadByte(b1))
218*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
219*f6dc9357SAndroid Build Coastguard Worker         packSize--;
220*f6dc9357SAndroid Build Coastguard Worker         m_OutWindowStream.PutByte(b1);
221*f6dc9357SAndroid Build Coastguard Worker         unpackSize--;
222*f6dc9357SAndroid Build Coastguard Worker       }
223*f6dc9357SAndroid Build Coastguard Worker     }
224*f6dc9357SAndroid Build Coastguard Worker 
225*f6dc9357SAndroid Build Coastguard Worker     if (M != 0)
226*f6dc9357SAndroid Build Coastguard Worker     {
227*f6dc9357SAndroid Build Coastguard Worker       if (unpackSize == 0 || D == 0)
228*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
229*f6dc9357SAndroid Build Coastguard Worker       unsigned cur = M;
230*f6dc9357SAndroid Build Coastguard Worker       if (cur > unpackSize)
231*f6dc9357SAndroid Build Coastguard Worker         cur = (unsigned)unpackSize;
232*f6dc9357SAndroid Build Coastguard Worker       if (!m_OutWindowStream.CopyBlock(D - 1, cur))
233*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
234*f6dc9357SAndroid Build Coastguard Worker       unpackSize -= cur;
235*f6dc9357SAndroid Build Coastguard Worker       if (cur != M)
236*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
237*f6dc9357SAndroid Build Coastguard Worker     }
238*f6dc9357SAndroid Build Coastguard Worker   }
239*f6dc9357SAndroid Build Coastguard Worker 
240*f6dc9357SAndroid Build Coastguard Worker   if (unpackSize != 0)
241*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
242*f6dc9357SAndroid Build Coastguard Worker 
243*f6dc9357SAndroid Build Coastguard Worker   // LZVN encoder writes 7 additional zero bytes
244*f6dc9357SAndroid Build Coastguard Worker   if (packSize < 7)
245*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
246*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < 7; i++)
247*f6dc9357SAndroid Build Coastguard Worker   {
248*f6dc9357SAndroid Build Coastguard Worker     Byte b;
249*f6dc9357SAndroid Build Coastguard Worker     if (!m_InStream.ReadByte(b))
250*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
251*f6dc9357SAndroid Build Coastguard Worker     if (b != 0)
252*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
253*f6dc9357SAndroid Build Coastguard Worker   }
254*f6dc9357SAndroid Build Coastguard Worker   packSize -= 7;
255*f6dc9357SAndroid Build Coastguard Worker   if (packSize)
256*f6dc9357SAndroid Build Coastguard Worker   {
257*f6dc9357SAndroid Build Coastguard Worker     PRF(printf("packSize after unused = %u\n", packSize));
258*f6dc9357SAndroid Build Coastguard Worker     // if (packSize <= 0x100) { Byte buf[0x100]; m_InStream.ReadBytes(buf, packSize); }
259*f6dc9357SAndroid Build Coastguard Worker     /* Lzvn block that is used in HFS can contain junk data
260*f6dc9357SAndroid Build Coastguard Worker        (at least 256 bytes) after payload data. Why?
261*f6dc9357SAndroid Build Coastguard Worker        We ignore that junk data, if it's HFS (LzvnMode) mode. */
262*f6dc9357SAndroid Build Coastguard Worker     if (!LzvnMode)
263*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
264*f6dc9357SAndroid Build Coastguard Worker   }
265*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
266*f6dc9357SAndroid Build Coastguard Worker }
267*f6dc9357SAndroid Build Coastguard Worker 
268*f6dc9357SAndroid Build Coastguard Worker 
269*f6dc9357SAndroid Build Coastguard Worker 
270*f6dc9357SAndroid Build Coastguard Worker // ---------- LZFSE ----------
271*f6dc9357SAndroid Build Coastguard Worker 
272*f6dc9357SAndroid Build Coastguard Worker #define MATCHES_PER_BLOCK 10000
273*f6dc9357SAndroid Build Coastguard Worker #define LITERALS_PER_BLOCK (4 * MATCHES_PER_BLOCK)
274*f6dc9357SAndroid Build Coastguard Worker 
275*f6dc9357SAndroid Build Coastguard Worker #define NUM_L_SYMBOLS 20
276*f6dc9357SAndroid Build Coastguard Worker #define NUM_M_SYMBOLS 20
277*f6dc9357SAndroid Build Coastguard Worker #define NUM_D_SYMBOLS 64
278*f6dc9357SAndroid Build Coastguard Worker #define NUM_LIT_SYMBOLS 256
279*f6dc9357SAndroid Build Coastguard Worker 
280*f6dc9357SAndroid Build Coastguard Worker #define NUM_SYMBOLS ( \
281*f6dc9357SAndroid Build Coastguard Worker     NUM_L_SYMBOLS + \
282*f6dc9357SAndroid Build Coastguard Worker     NUM_M_SYMBOLS + \
283*f6dc9357SAndroid Build Coastguard Worker     NUM_D_SYMBOLS + \
284*f6dc9357SAndroid Build Coastguard Worker     NUM_LIT_SYMBOLS)
285*f6dc9357SAndroid Build Coastguard Worker 
286*f6dc9357SAndroid Build Coastguard Worker #define NUM_L_STATES (1 << 6)
287*f6dc9357SAndroid Build Coastguard Worker #define NUM_M_STATES (1 << 6)
288*f6dc9357SAndroid Build Coastguard Worker #define NUM_D_STATES (1 << 8)
289*f6dc9357SAndroid Build Coastguard Worker #define NUM_LIT_STATES (1 << 10)
290*f6dc9357SAndroid Build Coastguard Worker 
291*f6dc9357SAndroid Build Coastguard Worker 
292*f6dc9357SAndroid Build Coastguard Worker typedef UInt32 CFseState;
293*f6dc9357SAndroid Build Coastguard Worker 
294*f6dc9357SAndroid Build Coastguard Worker 
SumFreqs(const UInt16 * freqs,unsigned num)295*f6dc9357SAndroid Build Coastguard Worker static UInt32 SumFreqs(const UInt16 *freqs, unsigned num)
296*f6dc9357SAndroid Build Coastguard Worker {
297*f6dc9357SAndroid Build Coastguard Worker   UInt32 sum = 0;
298*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < num; i++)
299*f6dc9357SAndroid Build Coastguard Worker     sum += (UInt32)freqs[i];
300*f6dc9357SAndroid Build Coastguard Worker   return sum;
301*f6dc9357SAndroid Build Coastguard Worker }
302*f6dc9357SAndroid Build Coastguard Worker 
303*f6dc9357SAndroid Build Coastguard Worker 
CountZeroBits(UInt32 val,UInt32 mask)304*f6dc9357SAndroid Build Coastguard Worker static Z7_FORCE_INLINE unsigned CountZeroBits(UInt32 val, UInt32 mask)
305*f6dc9357SAndroid Build Coastguard Worker {
306*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0;;)
307*f6dc9357SAndroid Build Coastguard Worker   {
308*f6dc9357SAndroid Build Coastguard Worker     if (val & mask)
309*f6dc9357SAndroid Build Coastguard Worker       return i;
310*f6dc9357SAndroid Build Coastguard Worker     i++;
311*f6dc9357SAndroid Build Coastguard Worker     mask >>= 1;
312*f6dc9357SAndroid Build Coastguard Worker   }
313*f6dc9357SAndroid Build Coastguard Worker }
314*f6dc9357SAndroid Build Coastguard Worker 
315*f6dc9357SAndroid Build Coastguard Worker 
InitLitTable(const UInt16 * freqs,UInt32 * table)316*f6dc9357SAndroid Build Coastguard Worker static Z7_FORCE_INLINE void InitLitTable(const UInt16 *freqs, UInt32 *table)
317*f6dc9357SAndroid Build Coastguard Worker {
318*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < NUM_LIT_SYMBOLS; i++)
319*f6dc9357SAndroid Build Coastguard Worker   {
320*f6dc9357SAndroid Build Coastguard Worker     unsigned f = freqs[i];
321*f6dc9357SAndroid Build Coastguard Worker     if (f == 0)
322*f6dc9357SAndroid Build Coastguard Worker       continue;
323*f6dc9357SAndroid Build Coastguard Worker 
324*f6dc9357SAndroid Build Coastguard Worker     //         0 <   f     <= numStates
325*f6dc9357SAndroid Build Coastguard Worker     //         0 <=  k     <= numStatesLog
326*f6dc9357SAndroid Build Coastguard Worker     // numStates <= (f<<k) <  numStates * 2
327*f6dc9357SAndroid Build Coastguard Worker     //         0 <  j0     <= f
328*f6dc9357SAndroid Build Coastguard Worker     // (f + j0) = next_power_of_2 for f
329*f6dc9357SAndroid Build Coastguard Worker     unsigned k = CountZeroBits(f, NUM_LIT_STATES);
330*f6dc9357SAndroid Build Coastguard Worker     unsigned j0 = (((unsigned)NUM_LIT_STATES * 2) >> k) - f;
331*f6dc9357SAndroid Build Coastguard Worker 
332*f6dc9357SAndroid Build Coastguard Worker     /*
333*f6dc9357SAndroid Build Coastguard Worker     CEntry
334*f6dc9357SAndroid Build Coastguard Worker     {
335*f6dc9357SAndroid Build Coastguard Worker       Byte k;
336*f6dc9357SAndroid Build Coastguard Worker       Byte symbol;
337*f6dc9357SAndroid Build Coastguard Worker       UInt16 delta;
338*f6dc9357SAndroid Build Coastguard Worker     };
339*f6dc9357SAndroid Build Coastguard Worker     */
340*f6dc9357SAndroid Build Coastguard Worker 
341*f6dc9357SAndroid Build Coastguard Worker     UInt32 e = ((UInt32)i << 8) + k;
342*f6dc9357SAndroid Build Coastguard Worker     k += 16;
343*f6dc9357SAndroid Build Coastguard Worker     UInt32 d = e + ((UInt32)f << k) - ((UInt32)NUM_LIT_STATES << 16);
344*f6dc9357SAndroid Build Coastguard Worker     UInt32 step = (UInt32)1 << k;
345*f6dc9357SAndroid Build Coastguard Worker 
346*f6dc9357SAndroid Build Coastguard Worker     unsigned j = 0;
347*f6dc9357SAndroid Build Coastguard Worker     do
348*f6dc9357SAndroid Build Coastguard Worker     {
349*f6dc9357SAndroid Build Coastguard Worker       *table++ = d;
350*f6dc9357SAndroid Build Coastguard Worker       d += step;
351*f6dc9357SAndroid Build Coastguard Worker     }
352*f6dc9357SAndroid Build Coastguard Worker     while (++j < j0);
353*f6dc9357SAndroid Build Coastguard Worker 
354*f6dc9357SAndroid Build Coastguard Worker     e--;
355*f6dc9357SAndroid Build Coastguard Worker     step >>= 1;
356*f6dc9357SAndroid Build Coastguard Worker 
357*f6dc9357SAndroid Build Coastguard Worker     for (j = j0; j < f; j++)
358*f6dc9357SAndroid Build Coastguard Worker     {
359*f6dc9357SAndroid Build Coastguard Worker       *table++ = e;
360*f6dc9357SAndroid Build Coastguard Worker       e += step;
361*f6dc9357SAndroid Build Coastguard Worker     }
362*f6dc9357SAndroid Build Coastguard Worker   }
363*f6dc9357SAndroid Build Coastguard Worker }
364*f6dc9357SAndroid Build Coastguard Worker 
365*f6dc9357SAndroid Build Coastguard Worker 
366*f6dc9357SAndroid Build Coastguard Worker typedef struct
367*f6dc9357SAndroid Build Coastguard Worker {
368*f6dc9357SAndroid Build Coastguard Worker   Byte totalBits;
369*f6dc9357SAndroid Build Coastguard Worker   Byte extraBits;
370*f6dc9357SAndroid Build Coastguard Worker   UInt16 delta;
371*f6dc9357SAndroid Build Coastguard Worker   UInt32 vbase;
372*f6dc9357SAndroid Build Coastguard Worker } CExtraEntry;
373*f6dc9357SAndroid Build Coastguard Worker 
374*f6dc9357SAndroid Build Coastguard Worker 
InitExtraDecoderTable(unsigned numStates,unsigned numSymbols,const UInt16 * freqs,const Byte * vbits,CExtraEntry * table)375*f6dc9357SAndroid Build Coastguard Worker static void InitExtraDecoderTable(unsigned numStates,
376*f6dc9357SAndroid Build Coastguard Worker     unsigned numSymbols,
377*f6dc9357SAndroid Build Coastguard Worker     const UInt16 *freqs,
378*f6dc9357SAndroid Build Coastguard Worker     const Byte *vbits,
379*f6dc9357SAndroid Build Coastguard Worker     CExtraEntry *table)
380*f6dc9357SAndroid Build Coastguard Worker {
381*f6dc9357SAndroid Build Coastguard Worker   UInt32 vbase = 0;
382*f6dc9357SAndroid Build Coastguard Worker 
383*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < numSymbols; i++)
384*f6dc9357SAndroid Build Coastguard Worker   {
385*f6dc9357SAndroid Build Coastguard Worker     unsigned f = freqs[i];
386*f6dc9357SAndroid Build Coastguard Worker     unsigned extraBits = vbits[i];
387*f6dc9357SAndroid Build Coastguard Worker 
388*f6dc9357SAndroid Build Coastguard Worker     if (f != 0)
389*f6dc9357SAndroid Build Coastguard Worker     {
390*f6dc9357SAndroid Build Coastguard Worker       unsigned k = CountZeroBits(f, numStates);
391*f6dc9357SAndroid Build Coastguard Worker       unsigned j0 = ((2 * numStates) >> k) - f;
392*f6dc9357SAndroid Build Coastguard Worker 
393*f6dc9357SAndroid Build Coastguard Worker       unsigned j = 0;
394*f6dc9357SAndroid Build Coastguard Worker       do
395*f6dc9357SAndroid Build Coastguard Worker       {
396*f6dc9357SAndroid Build Coastguard Worker         CExtraEntry *e = table++;
397*f6dc9357SAndroid Build Coastguard Worker         e->totalBits = (Byte)(k + extraBits);
398*f6dc9357SAndroid Build Coastguard Worker         e->extraBits = (Byte)extraBits;
399*f6dc9357SAndroid Build Coastguard Worker         e->delta = (UInt16)(((f + j) << k) - numStates);
400*f6dc9357SAndroid Build Coastguard Worker         e->vbase = vbase;
401*f6dc9357SAndroid Build Coastguard Worker       }
402*f6dc9357SAndroid Build Coastguard Worker       while (++j < j0);
403*f6dc9357SAndroid Build Coastguard Worker 
404*f6dc9357SAndroid Build Coastguard Worker       f -= j0;
405*f6dc9357SAndroid Build Coastguard Worker       k--;
406*f6dc9357SAndroid Build Coastguard Worker 
407*f6dc9357SAndroid Build Coastguard Worker       for (j = 0; j < f; j++)
408*f6dc9357SAndroid Build Coastguard Worker       {
409*f6dc9357SAndroid Build Coastguard Worker         CExtraEntry *e = table++;
410*f6dc9357SAndroid Build Coastguard Worker         e->totalBits = (Byte)(k + extraBits);
411*f6dc9357SAndroid Build Coastguard Worker         e->extraBits = (Byte)extraBits;
412*f6dc9357SAndroid Build Coastguard Worker         e->delta = (UInt16)(j << k);
413*f6dc9357SAndroid Build Coastguard Worker         e->vbase = vbase;
414*f6dc9357SAndroid Build Coastguard Worker       }
415*f6dc9357SAndroid Build Coastguard Worker     }
416*f6dc9357SAndroid Build Coastguard Worker 
417*f6dc9357SAndroid Build Coastguard Worker     vbase += ((UInt32)1 << extraBits);
418*f6dc9357SAndroid Build Coastguard Worker   }
419*f6dc9357SAndroid Build Coastguard Worker }
420*f6dc9357SAndroid Build Coastguard Worker 
421*f6dc9357SAndroid Build Coastguard Worker 
422*f6dc9357SAndroid Build Coastguard Worker static const Byte k_L_extra[NUM_L_SYMBOLS] =
423*f6dc9357SAndroid Build Coastguard Worker {
424*f6dc9357SAndroid Build Coastguard Worker   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 5, 8
425*f6dc9357SAndroid Build Coastguard Worker };
426*f6dc9357SAndroid Build Coastguard Worker 
427*f6dc9357SAndroid Build Coastguard Worker static const Byte k_M_extra[NUM_M_SYMBOLS] =
428*f6dc9357SAndroid Build Coastguard Worker {
429*f6dc9357SAndroid Build Coastguard Worker   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11
430*f6dc9357SAndroid Build Coastguard Worker };
431*f6dc9357SAndroid Build Coastguard Worker 
432*f6dc9357SAndroid Build Coastguard Worker static const Byte k_D_extra[NUM_D_SYMBOLS] =
433*f6dc9357SAndroid Build Coastguard Worker {
434*f6dc9357SAndroid Build Coastguard Worker    0,  0,  0,  0,  1,  1,  1,  1,  2,  2,  2,  2,  3,  3,  3,  3,
435*f6dc9357SAndroid Build Coastguard Worker    4,  4,  4,  4,  5,  5,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,
436*f6dc9357SAndroid Build Coastguard Worker    8,  8,  8,  8,  9,  9,  9,  9, 10, 10, 10, 10, 11, 11, 11, 11,
437*f6dc9357SAndroid Build Coastguard Worker   12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15
438*f6dc9357SAndroid Build Coastguard Worker };
439*f6dc9357SAndroid Build Coastguard Worker 
440*f6dc9357SAndroid Build Coastguard Worker 
441*f6dc9357SAndroid Build Coastguard Worker 
442*f6dc9357SAndroid Build Coastguard Worker // ---------- CBitStream ----------
443*f6dc9357SAndroid Build Coastguard Worker 
444*f6dc9357SAndroid Build Coastguard Worker typedef struct
445*f6dc9357SAndroid Build Coastguard Worker {
446*f6dc9357SAndroid Build Coastguard Worker   UInt32 accum;
447*f6dc9357SAndroid Build Coastguard Worker   unsigned numBits; // [0, 31] - Number of valid bits in (accum), other bits are 0
448*f6dc9357SAndroid Build Coastguard Worker } CBitStream;
449*f6dc9357SAndroid Build Coastguard Worker 
450*f6dc9357SAndroid Build Coastguard Worker 
FseInStream_Init(CBitStream * s,int n,const Byte ** pbuf)451*f6dc9357SAndroid Build Coastguard Worker static Z7_FORCE_INLINE int FseInStream_Init(CBitStream *s,
452*f6dc9357SAndroid Build Coastguard Worker     int n, // [-7, 0], (-n == number_of_unused_bits) in last byte
453*f6dc9357SAndroid Build Coastguard Worker     const Byte **pbuf)
454*f6dc9357SAndroid Build Coastguard Worker {
455*f6dc9357SAndroid Build Coastguard Worker   *pbuf -= 4;
456*f6dc9357SAndroid Build Coastguard Worker   s->accum = GetUi32(*pbuf);
457*f6dc9357SAndroid Build Coastguard Worker   if (n)
458*f6dc9357SAndroid Build Coastguard Worker   {
459*f6dc9357SAndroid Build Coastguard Worker     s->numBits = (unsigned)(n + 32);
460*f6dc9357SAndroid Build Coastguard Worker     if ((s->accum >> s->numBits) != 0)
461*f6dc9357SAndroid Build Coastguard Worker       return -1; // ERROR, encoder should have zeroed the upper bits
462*f6dc9357SAndroid Build Coastguard Worker   }
463*f6dc9357SAndroid Build Coastguard Worker   else
464*f6dc9357SAndroid Build Coastguard Worker   {
465*f6dc9357SAndroid Build Coastguard Worker     *pbuf += 1;
466*f6dc9357SAndroid Build Coastguard Worker     s->accum >>= 8;
467*f6dc9357SAndroid Build Coastguard Worker     s->numBits = 24;
468*f6dc9357SAndroid Build Coastguard Worker   }
469*f6dc9357SAndroid Build Coastguard Worker   return 0; // OK
470*f6dc9357SAndroid Build Coastguard Worker }
471*f6dc9357SAndroid Build Coastguard Worker 
472*f6dc9357SAndroid Build Coastguard Worker 
473*f6dc9357SAndroid Build Coastguard Worker // 0 <= numBits < 32
474*f6dc9357SAndroid Build Coastguard Worker #define mask31(x, numBits) ((x) & (((UInt32)1 << (numBits)) - 1))
475*f6dc9357SAndroid Build Coastguard Worker 
476*f6dc9357SAndroid Build Coastguard Worker #define FseInStream_FLUSH \
477*f6dc9357SAndroid Build Coastguard Worker   { const unsigned nbits = (31 - in.numBits) & (unsigned)-8; \
478*f6dc9357SAndroid Build Coastguard Worker   if (nbits) { \
479*f6dc9357SAndroid Build Coastguard Worker     buf -= (nbits >> 3); \
480*f6dc9357SAndroid Build Coastguard Worker     if (buf < buf_check) return S_FALSE; \
481*f6dc9357SAndroid Build Coastguard Worker     UInt32 v = GetUi32(buf); \
482*f6dc9357SAndroid Build Coastguard Worker     in.accum = (in.accum << nbits) | mask31(v, nbits); \
483*f6dc9357SAndroid Build Coastguard Worker     in.numBits += nbits; }}
484*f6dc9357SAndroid Build Coastguard Worker 
485*f6dc9357SAndroid Build Coastguard Worker 
486*f6dc9357SAndroid Build Coastguard Worker 
BitStream_Pull(CBitStream * s,unsigned numBits)487*f6dc9357SAndroid Build Coastguard Worker static Z7_FORCE_INLINE UInt32 BitStream_Pull(CBitStream *s, unsigned numBits)
488*f6dc9357SAndroid Build Coastguard Worker {
489*f6dc9357SAndroid Build Coastguard Worker   s->numBits -= numBits;
490*f6dc9357SAndroid Build Coastguard Worker   const UInt32 v = s->accum >> s->numBits;
491*f6dc9357SAndroid Build Coastguard Worker   s->accum = mask31(s->accum, s->numBits);
492*f6dc9357SAndroid Build Coastguard Worker   return v;
493*f6dc9357SAndroid Build Coastguard Worker }
494*f6dc9357SAndroid Build Coastguard Worker 
495*f6dc9357SAndroid Build Coastguard Worker 
496*f6dc9357SAndroid Build Coastguard Worker #define DECODE_LIT(dest, pstate) { \
497*f6dc9357SAndroid Build Coastguard Worker   UInt32 e = lit_decoder[pstate]; \
498*f6dc9357SAndroid Build Coastguard Worker   pstate = (CFseState)((e >> 16) + BitStream_Pull(&in, e & 0xff)); \
499*f6dc9357SAndroid Build Coastguard Worker   dest = (Byte)(e >> 8); }
500*f6dc9357SAndroid Build Coastguard Worker 
501*f6dc9357SAndroid Build Coastguard Worker 
FseDecodeExtra(CFseState * pstate,const CExtraEntry * table,CBitStream * s)502*f6dc9357SAndroid Build Coastguard Worker static Z7_FORCE_INLINE UInt32 FseDecodeExtra(CFseState *pstate,
503*f6dc9357SAndroid Build Coastguard Worker     const CExtraEntry *table,
504*f6dc9357SAndroid Build Coastguard Worker     CBitStream *s)
505*f6dc9357SAndroid Build Coastguard Worker {
506*f6dc9357SAndroid Build Coastguard Worker   const CExtraEntry *e = &table[*pstate];
507*f6dc9357SAndroid Build Coastguard Worker   UInt32 v = BitStream_Pull(s, e->totalBits);
508*f6dc9357SAndroid Build Coastguard Worker   unsigned extraBits = e->extraBits;
509*f6dc9357SAndroid Build Coastguard Worker   *pstate = (CFseState)(e->delta + (v >> extraBits));
510*f6dc9357SAndroid Build Coastguard Worker   return e->vbase + mask31(v, extraBits);
511*f6dc9357SAndroid Build Coastguard Worker }
512*f6dc9357SAndroid Build Coastguard Worker 
513*f6dc9357SAndroid Build Coastguard Worker 
514*f6dc9357SAndroid Build Coastguard Worker #define freqs_L (freqs)
515*f6dc9357SAndroid Build Coastguard Worker #define freqs_M (freqs_L + NUM_L_SYMBOLS)
516*f6dc9357SAndroid Build Coastguard Worker #define freqs_D (freqs_M + NUM_M_SYMBOLS)
517*f6dc9357SAndroid Build Coastguard Worker #define freqs_LIT (freqs_D + NUM_D_SYMBOLS)
518*f6dc9357SAndroid Build Coastguard Worker 
519*f6dc9357SAndroid Build Coastguard Worker #define GET_BITS_64(v, offset, num, dest) dest = (UInt32)   ((v >> (offset)) & ((1 << (num)) - 1));
520*f6dc9357SAndroid Build Coastguard Worker #define GET_BITS_64_Int32(v, offset, num, dest) dest = (Int32)((v >> (offset)) & ((1 << (num)) - 1));
521*f6dc9357SAndroid Build Coastguard Worker #define GET_BITS_32(v, offset, num, dest) dest = (CFseState)((v >> (offset)) & ((1 << (num)) - 1));
522*f6dc9357SAndroid Build Coastguard Worker 
523*f6dc9357SAndroid Build Coastguard Worker 
DecodeLzfse(UInt32 unpackSize,Byte version)524*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::DecodeLzfse(UInt32 unpackSize, Byte version)
525*f6dc9357SAndroid Build Coastguard Worker {
526*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\nLZFSE-%d %7u", version - '0', unpackSize));
527*f6dc9357SAndroid Build Coastguard Worker 
528*f6dc9357SAndroid Build Coastguard Worker   UInt32 numLiterals;
529*f6dc9357SAndroid Build Coastguard Worker   UInt32 litPayloadSize;
530*f6dc9357SAndroid Build Coastguard Worker   Int32 literal_bits;
531*f6dc9357SAndroid Build Coastguard Worker 
532*f6dc9357SAndroid Build Coastguard Worker   UInt32 lit_state_0;
533*f6dc9357SAndroid Build Coastguard Worker   UInt32 lit_state_1;
534*f6dc9357SAndroid Build Coastguard Worker   UInt32 lit_state_2;
535*f6dc9357SAndroid Build Coastguard Worker   UInt32 lit_state_3;
536*f6dc9357SAndroid Build Coastguard Worker 
537*f6dc9357SAndroid Build Coastguard Worker   UInt32 numMatches;
538*f6dc9357SAndroid Build Coastguard Worker   UInt32 lmdPayloadSize;
539*f6dc9357SAndroid Build Coastguard Worker   Int32 lmd_bits;
540*f6dc9357SAndroid Build Coastguard Worker 
541*f6dc9357SAndroid Build Coastguard Worker   CFseState l_state;
542*f6dc9357SAndroid Build Coastguard Worker   CFseState m_state;
543*f6dc9357SAndroid Build Coastguard Worker   CFseState d_state;
544*f6dc9357SAndroid Build Coastguard Worker 
545*f6dc9357SAndroid Build Coastguard Worker   UInt16 freqs[NUM_SYMBOLS];
546*f6dc9357SAndroid Build Coastguard Worker 
547*f6dc9357SAndroid Build Coastguard Worker   if (version == kSignature_LZFSE_V1)
548*f6dc9357SAndroid Build Coastguard Worker   {
549*f6dc9357SAndroid Build Coastguard Worker     return E_NOTIMPL;
550*f6dc9357SAndroid Build Coastguard Worker     // we need examples to test LZFSE-V1 code
551*f6dc9357SAndroid Build Coastguard Worker     /*
552*f6dc9357SAndroid Build Coastguard Worker     const unsigned k_v1_SubHeaderSize = 7 * 4 + 7 * 2;
553*f6dc9357SAndroid Build Coastguard Worker     const unsigned k_v1_HeaderSize = k_v1_SubHeaderSize + NUM_SYMBOLS * 2;
554*f6dc9357SAndroid Build Coastguard Worker     _buffer.AllocAtLeast(k_v1_HeaderSize);
555*f6dc9357SAndroid Build Coastguard Worker     if (m_InStream.ReadBytes(_buffer, k_v1_HeaderSize) != k_v1_HeaderSize)
556*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
557*f6dc9357SAndroid Build Coastguard Worker 
558*f6dc9357SAndroid Build Coastguard Worker     const Byte *buf = _buffer;
559*f6dc9357SAndroid Build Coastguard Worker     #define GET_32(offs, dest) dest = GetUi32(buf + offs)
560*f6dc9357SAndroid Build Coastguard Worker     #define GET_16(offs, dest) dest = GetUi16(buf + offs)
561*f6dc9357SAndroid Build Coastguard Worker 
562*f6dc9357SAndroid Build Coastguard Worker     UInt32 payload_bytes;
563*f6dc9357SAndroid Build Coastguard Worker     GET_32(0, payload_bytes);
564*f6dc9357SAndroid Build Coastguard Worker     GET_32(4, numLiterals);
565*f6dc9357SAndroid Build Coastguard Worker     GET_32(8, numMatches);
566*f6dc9357SAndroid Build Coastguard Worker     GET_32(12, litPayloadSize);
567*f6dc9357SAndroid Build Coastguard Worker     GET_32(16, lmdPayloadSize);
568*f6dc9357SAndroid Build Coastguard Worker     if (litPayloadSize > (1 << 20) || lmdPayloadSize > (1 << 20))
569*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
570*f6dc9357SAndroid Build Coastguard Worker     GET_32(20, literal_bits);
571*f6dc9357SAndroid Build Coastguard Worker     if (literal_bits < -7 || literal_bits > 0)
572*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
573*f6dc9357SAndroid Build Coastguard Worker 
574*f6dc9357SAndroid Build Coastguard Worker     GET_16(24, lit_state_0);
575*f6dc9357SAndroid Build Coastguard Worker     GET_16(26, lit_state_1);
576*f6dc9357SAndroid Build Coastguard Worker     GET_16(28, lit_state_2);
577*f6dc9357SAndroid Build Coastguard Worker     GET_16(30, lit_state_3);
578*f6dc9357SAndroid Build Coastguard Worker 
579*f6dc9357SAndroid Build Coastguard Worker     GET_32(32, lmd_bits);
580*f6dc9357SAndroid Build Coastguard Worker     if (lmd_bits < -7 || lmd_bits > 0)
581*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
582*f6dc9357SAndroid Build Coastguard Worker 
583*f6dc9357SAndroid Build Coastguard Worker     GET_16(36, l_state);
584*f6dc9357SAndroid Build Coastguard Worker     GET_16(38, m_state);
585*f6dc9357SAndroid Build Coastguard Worker     GET_16(40, d_state);
586*f6dc9357SAndroid Build Coastguard Worker 
587*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = 0; i < NUM_SYMBOLS; i++)
588*f6dc9357SAndroid Build Coastguard Worker       freqs[i] = GetUi16(buf + k_v1_SubHeaderSize + i * 2);
589*f6dc9357SAndroid Build Coastguard Worker     */
590*f6dc9357SAndroid Build Coastguard Worker   }
591*f6dc9357SAndroid Build Coastguard Worker   else
592*f6dc9357SAndroid Build Coastguard Worker   {
593*f6dc9357SAndroid Build Coastguard Worker     UInt32 headerSize;
594*f6dc9357SAndroid Build Coastguard Worker     {
595*f6dc9357SAndroid Build Coastguard Worker       const unsigned kPreHeaderSize = 4 * 2; // signature and upackSize
596*f6dc9357SAndroid Build Coastguard Worker       const unsigned kHeaderSize = 8 * 3;
597*f6dc9357SAndroid Build Coastguard Worker       Byte temp[kHeaderSize];
598*f6dc9357SAndroid Build Coastguard Worker       if (m_InStream.ReadBytes(temp, kHeaderSize) != kHeaderSize)
599*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
600*f6dc9357SAndroid Build Coastguard Worker 
601*f6dc9357SAndroid Build Coastguard Worker       UInt64 v;
602*f6dc9357SAndroid Build Coastguard Worker 
603*f6dc9357SAndroid Build Coastguard Worker       v = GetUi64(temp);
604*f6dc9357SAndroid Build Coastguard Worker       GET_BITS_64(v,  0, 20, numLiterals)
605*f6dc9357SAndroid Build Coastguard Worker       GET_BITS_64(v, 20, 20, litPayloadSize)
606*f6dc9357SAndroid Build Coastguard Worker       GET_BITS_64(v, 40, 20, numMatches)
607*f6dc9357SAndroid Build Coastguard Worker       GET_BITS_64_Int32(v, 60, 3 + 1, literal_bits) // (NumberOfUsedBits - 1)
608*f6dc9357SAndroid Build Coastguard Worker       literal_bits -= 7; // (-NumberOfUnusedBits)
609*f6dc9357SAndroid Build Coastguard Worker       if (literal_bits > 0)
610*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
611*f6dc9357SAndroid Build Coastguard Worker       // GET_BITS_64(v, 63, 1, unused);
612*f6dc9357SAndroid Build Coastguard Worker 
613*f6dc9357SAndroid Build Coastguard Worker       v = GetUi64(temp + 8);
614*f6dc9357SAndroid Build Coastguard Worker       GET_BITS_64(v,  0, 10, lit_state_0)
615*f6dc9357SAndroid Build Coastguard Worker       GET_BITS_64(v, 10, 10, lit_state_1)
616*f6dc9357SAndroid Build Coastguard Worker       GET_BITS_64(v, 20, 10, lit_state_2)
617*f6dc9357SAndroid Build Coastguard Worker       GET_BITS_64(v, 30, 10, lit_state_3)
618*f6dc9357SAndroid Build Coastguard Worker       GET_BITS_64(v, 40, 20, lmdPayloadSize)
619*f6dc9357SAndroid Build Coastguard Worker       GET_BITS_64_Int32(v, 60, 3 + 1, lmd_bits)
620*f6dc9357SAndroid Build Coastguard Worker       lmd_bits -= 7;
621*f6dc9357SAndroid Build Coastguard Worker       if (lmd_bits > 0)
622*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
623*f6dc9357SAndroid Build Coastguard Worker       // GET_BITS_64(v, 63, 1, unused)
624*f6dc9357SAndroid Build Coastguard Worker 
625*f6dc9357SAndroid Build Coastguard Worker       UInt32 v32 = GetUi32(temp + 20);
626*f6dc9357SAndroid Build Coastguard Worker       // (total header size in bytes; this does not
627*f6dc9357SAndroid Build Coastguard Worker       // correspond to a field in the uncompressed header version,
628*f6dc9357SAndroid Build Coastguard Worker       // but is required; we wouldn't know the size of the
629*f6dc9357SAndroid Build Coastguard Worker       // compresssed header otherwise.
630*f6dc9357SAndroid Build Coastguard Worker       GET_BITS_32(v32, 0, 10, l_state)
631*f6dc9357SAndroid Build Coastguard Worker       GET_BITS_32(v32, 10, 10, m_state)
632*f6dc9357SAndroid Build Coastguard Worker       GET_BITS_32(v32, 20, 10 + 2, d_state)
633*f6dc9357SAndroid Build Coastguard Worker       // GET_BITS_64(v, 62, 2, unused)
634*f6dc9357SAndroid Build Coastguard Worker 
635*f6dc9357SAndroid Build Coastguard Worker       headerSize = GetUi32(temp + 16);
636*f6dc9357SAndroid Build Coastguard Worker       if (headerSize <= kPreHeaderSize + kHeaderSize)
637*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
638*f6dc9357SAndroid Build Coastguard Worker       headerSize -= kPreHeaderSize + kHeaderSize;
639*f6dc9357SAndroid Build Coastguard Worker     }
640*f6dc9357SAndroid Build Coastguard Worker 
641*f6dc9357SAndroid Build Coastguard Worker     // no freqs case is not allowed ?
642*f6dc9357SAndroid Build Coastguard Worker     // memset(freqs, 0, sizeof(freqs));
643*f6dc9357SAndroid Build Coastguard Worker     // if (headerSize != 0)
644*f6dc9357SAndroid Build Coastguard Worker     {
645*f6dc9357SAndroid Build Coastguard Worker       static const Byte numBitsTable[32] =
646*f6dc9357SAndroid Build Coastguard Worker       {
647*f6dc9357SAndroid Build Coastguard Worker         2, 3, 2, 5, 2, 3, 2, 8, 2, 3, 2, 5, 2, 3, 2, 14,
648*f6dc9357SAndroid Build Coastguard Worker         2, 3, 2, 5, 2, 3, 2, 8, 2, 3, 2, 5, 2, 3, 2, 14
649*f6dc9357SAndroid Build Coastguard Worker       };
650*f6dc9357SAndroid Build Coastguard Worker 
651*f6dc9357SAndroid Build Coastguard Worker       static const Byte valueTable[32] =
652*f6dc9357SAndroid Build Coastguard Worker       {
653*f6dc9357SAndroid Build Coastguard Worker         0, 2, 1, 4, 0, 3, 1, 8, 0, 2, 1, 5, 0, 3, 1, 24,
654*f6dc9357SAndroid Build Coastguard Worker         0, 2, 1, 6, 0, 3, 1, 8, 0, 2, 1, 7, 0, 3, 1, 24
655*f6dc9357SAndroid Build Coastguard Worker       };
656*f6dc9357SAndroid Build Coastguard Worker 
657*f6dc9357SAndroid Build Coastguard Worker       UInt32 accum = 0;
658*f6dc9357SAndroid Build Coastguard Worker       unsigned numBits = 0;
659*f6dc9357SAndroid Build Coastguard Worker 
660*f6dc9357SAndroid Build Coastguard Worker       for (unsigned i = 0; i < NUM_SYMBOLS; i++)
661*f6dc9357SAndroid Build Coastguard Worker       {
662*f6dc9357SAndroid Build Coastguard Worker         while (numBits <= 14 && headerSize != 0)
663*f6dc9357SAndroid Build Coastguard Worker         {
664*f6dc9357SAndroid Build Coastguard Worker           Byte b;
665*f6dc9357SAndroid Build Coastguard Worker           if (!m_InStream.ReadByte(b))
666*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
667*f6dc9357SAndroid Build Coastguard Worker           accum |= (UInt32)b << numBits;
668*f6dc9357SAndroid Build Coastguard Worker           numBits += 8;
669*f6dc9357SAndroid Build Coastguard Worker           headerSize--;
670*f6dc9357SAndroid Build Coastguard Worker         }
671*f6dc9357SAndroid Build Coastguard Worker 
672*f6dc9357SAndroid Build Coastguard Worker         unsigned b = (unsigned)accum & 31;
673*f6dc9357SAndroid Build Coastguard Worker         unsigned n = numBitsTable[b];
674*f6dc9357SAndroid Build Coastguard Worker         if (numBits < n)
675*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
676*f6dc9357SAndroid Build Coastguard Worker         numBits -= n;
677*f6dc9357SAndroid Build Coastguard Worker         UInt32 f = valueTable[b];
678*f6dc9357SAndroid Build Coastguard Worker         if (n >= 8)
679*f6dc9357SAndroid Build Coastguard Worker           f += ((accum >> 4) & (0x3ff >> (14 - n)));
680*f6dc9357SAndroid Build Coastguard Worker         accum >>= n;
681*f6dc9357SAndroid Build Coastguard Worker         freqs[i] = (UInt16)f;
682*f6dc9357SAndroid Build Coastguard Worker       }
683*f6dc9357SAndroid Build Coastguard Worker 
684*f6dc9357SAndroid Build Coastguard Worker       if (numBits >= 8 || headerSize != 0)
685*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
686*f6dc9357SAndroid Build Coastguard Worker     }
687*f6dc9357SAndroid Build Coastguard Worker   }
688*f6dc9357SAndroid Build Coastguard Worker 
689*f6dc9357SAndroid Build Coastguard Worker   PRF(printf(" Literals=%6u Matches=%6u", numLiterals, numMatches));
690*f6dc9357SAndroid Build Coastguard Worker 
691*f6dc9357SAndroid Build Coastguard Worker   if (numLiterals > LITERALS_PER_BLOCK
692*f6dc9357SAndroid Build Coastguard Worker       || (numLiterals & 3) != 0
693*f6dc9357SAndroid Build Coastguard Worker       || numMatches > MATCHES_PER_BLOCK
694*f6dc9357SAndroid Build Coastguard Worker       || lit_state_0 >= NUM_LIT_STATES
695*f6dc9357SAndroid Build Coastguard Worker       || lit_state_1 >= NUM_LIT_STATES
696*f6dc9357SAndroid Build Coastguard Worker       || lit_state_2 >= NUM_LIT_STATES
697*f6dc9357SAndroid Build Coastguard Worker       || lit_state_3 >= NUM_LIT_STATES
698*f6dc9357SAndroid Build Coastguard Worker       || l_state >= NUM_L_STATES
699*f6dc9357SAndroid Build Coastguard Worker       || m_state >= NUM_M_STATES
700*f6dc9357SAndroid Build Coastguard Worker       || d_state >= NUM_D_STATES)
701*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
702*f6dc9357SAndroid Build Coastguard Worker 
703*f6dc9357SAndroid Build Coastguard Worker   // only full table is allowed ?
704*f6dc9357SAndroid Build Coastguard Worker   if (   SumFreqs(freqs_L, NUM_L_SYMBOLS) != NUM_L_STATES
705*f6dc9357SAndroid Build Coastguard Worker       || SumFreqs(freqs_M, NUM_M_SYMBOLS) != NUM_M_STATES
706*f6dc9357SAndroid Build Coastguard Worker       || SumFreqs(freqs_D, NUM_D_SYMBOLS) != NUM_D_STATES
707*f6dc9357SAndroid Build Coastguard Worker       || SumFreqs(freqs_LIT, NUM_LIT_SYMBOLS) != NUM_LIT_STATES)
708*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
709*f6dc9357SAndroid Build Coastguard Worker 
710*f6dc9357SAndroid Build Coastguard Worker 
711*f6dc9357SAndroid Build Coastguard Worker   const unsigned kPad = 16;
712*f6dc9357SAndroid Build Coastguard Worker 
713*f6dc9357SAndroid Build Coastguard Worker   // ---------- Decode literals ----------
714*f6dc9357SAndroid Build Coastguard Worker 
715*f6dc9357SAndroid Build Coastguard Worker   {
716*f6dc9357SAndroid Build Coastguard Worker     _literals.AllocAtLeast(LITERALS_PER_BLOCK + 16);
717*f6dc9357SAndroid Build Coastguard Worker     _buffer.AllocAtLeast(kPad + litPayloadSize);
718*f6dc9357SAndroid Build Coastguard Worker     memset(_buffer, 0, kPad);
719*f6dc9357SAndroid Build Coastguard Worker 
720*f6dc9357SAndroid Build Coastguard Worker     if (m_InStream.ReadBytes(_buffer + kPad, litPayloadSize) != litPayloadSize)
721*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
722*f6dc9357SAndroid Build Coastguard Worker 
723*f6dc9357SAndroid Build Coastguard Worker     UInt32 lit_decoder[NUM_LIT_STATES];
724*f6dc9357SAndroid Build Coastguard Worker     InitLitTable(freqs_LIT, lit_decoder);
725*f6dc9357SAndroid Build Coastguard Worker 
726*f6dc9357SAndroid Build Coastguard Worker     const Byte *buf_start = _buffer + kPad;
727*f6dc9357SAndroid Build Coastguard Worker     const Byte *buf_check = buf_start - 4;
728*f6dc9357SAndroid Build Coastguard Worker     const Byte *buf = buf_start + litPayloadSize;
729*f6dc9357SAndroid Build Coastguard Worker     CBitStream in;
730*f6dc9357SAndroid Build Coastguard Worker     if (FseInStream_Init(&in, literal_bits, &buf) != 0)
731*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
732*f6dc9357SAndroid Build Coastguard Worker 
733*f6dc9357SAndroid Build Coastguard Worker     Byte *lit = _literals;
734*f6dc9357SAndroid Build Coastguard Worker     const Byte *lit_limit = lit + numLiterals;
735*f6dc9357SAndroid Build Coastguard Worker     for (; lit < lit_limit; lit += 4)
736*f6dc9357SAndroid Build Coastguard Worker     {
737*f6dc9357SAndroid Build Coastguard Worker       FseInStream_FLUSH
738*f6dc9357SAndroid Build Coastguard Worker       DECODE_LIT (lit[0], lit_state_0)
739*f6dc9357SAndroid Build Coastguard Worker       DECODE_LIT (lit[1], lit_state_1)
740*f6dc9357SAndroid Build Coastguard Worker       FseInStream_FLUSH
741*f6dc9357SAndroid Build Coastguard Worker       DECODE_LIT (lit[2], lit_state_2)
742*f6dc9357SAndroid Build Coastguard Worker       DECODE_LIT (lit[3], lit_state_3)
743*f6dc9357SAndroid Build Coastguard Worker     }
744*f6dc9357SAndroid Build Coastguard Worker 
745*f6dc9357SAndroid Build Coastguard Worker     if ((buf_start - buf) * 8 != (int)in.numBits)
746*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
747*f6dc9357SAndroid Build Coastguard Worker   }
748*f6dc9357SAndroid Build Coastguard Worker 
749*f6dc9357SAndroid Build Coastguard Worker 
750*f6dc9357SAndroid Build Coastguard Worker   // ---------- Decode LMD ----------
751*f6dc9357SAndroid Build Coastguard Worker 
752*f6dc9357SAndroid Build Coastguard Worker   _buffer.AllocAtLeast(kPad + lmdPayloadSize);
753*f6dc9357SAndroid Build Coastguard Worker   memset(_buffer, 0, kPad);
754*f6dc9357SAndroid Build Coastguard Worker   if (m_InStream.ReadBytes(_buffer + kPad, lmdPayloadSize) != lmdPayloadSize)
755*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
756*f6dc9357SAndroid Build Coastguard Worker 
757*f6dc9357SAndroid Build Coastguard Worker   CExtraEntry l_decoder[NUM_L_STATES];
758*f6dc9357SAndroid Build Coastguard Worker   CExtraEntry m_decoder[NUM_M_STATES];
759*f6dc9357SAndroid Build Coastguard Worker   CExtraEntry d_decoder[NUM_D_STATES];
760*f6dc9357SAndroid Build Coastguard Worker 
761*f6dc9357SAndroid Build Coastguard Worker   InitExtraDecoderTable(NUM_L_STATES, NUM_L_SYMBOLS, freqs_L, k_L_extra, l_decoder);
762*f6dc9357SAndroid Build Coastguard Worker   InitExtraDecoderTable(NUM_M_STATES, NUM_M_SYMBOLS, freqs_M, k_M_extra, m_decoder);
763*f6dc9357SAndroid Build Coastguard Worker   InitExtraDecoderTable(NUM_D_STATES, NUM_D_SYMBOLS, freqs_D, k_D_extra, d_decoder);
764*f6dc9357SAndroid Build Coastguard Worker 
765*f6dc9357SAndroid Build Coastguard Worker   const Byte *buf_start = _buffer + kPad;
766*f6dc9357SAndroid Build Coastguard Worker   const Byte *buf_check = buf_start - 4;
767*f6dc9357SAndroid Build Coastguard Worker   const Byte *buf = buf_start + lmdPayloadSize;
768*f6dc9357SAndroid Build Coastguard Worker   CBitStream in;
769*f6dc9357SAndroid Build Coastguard Worker   if (FseInStream_Init(&in, lmd_bits, &buf))
770*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
771*f6dc9357SAndroid Build Coastguard Worker 
772*f6dc9357SAndroid Build Coastguard Worker   const Byte *lit = _literals;
773*f6dc9357SAndroid Build Coastguard Worker   const Byte *lit_limit = lit + numLiterals;
774*f6dc9357SAndroid Build Coastguard Worker 
775*f6dc9357SAndroid Build Coastguard Worker   UInt32 D = 0;
776*f6dc9357SAndroid Build Coastguard Worker 
777*f6dc9357SAndroid Build Coastguard Worker   for (;;)
778*f6dc9357SAndroid Build Coastguard Worker   {
779*f6dc9357SAndroid Build Coastguard Worker     if (numMatches == 0)
780*f6dc9357SAndroid Build Coastguard Worker       break;
781*f6dc9357SAndroid Build Coastguard Worker     numMatches--;
782*f6dc9357SAndroid Build Coastguard Worker 
783*f6dc9357SAndroid Build Coastguard Worker     FseInStream_FLUSH
784*f6dc9357SAndroid Build Coastguard Worker 
785*f6dc9357SAndroid Build Coastguard Worker     unsigned L = (unsigned)FseDecodeExtra(&l_state, l_decoder, &in);
786*f6dc9357SAndroid Build Coastguard Worker 
787*f6dc9357SAndroid Build Coastguard Worker     FseInStream_FLUSH
788*f6dc9357SAndroid Build Coastguard Worker 
789*f6dc9357SAndroid Build Coastguard Worker     unsigned M = (unsigned)FseDecodeExtra(&m_state, m_decoder, &in);
790*f6dc9357SAndroid Build Coastguard Worker 
791*f6dc9357SAndroid Build Coastguard Worker     FseInStream_FLUSH
792*f6dc9357SAndroid Build Coastguard Worker 
793*f6dc9357SAndroid Build Coastguard Worker     {
794*f6dc9357SAndroid Build Coastguard Worker       UInt32 new_D = FseDecodeExtra(&d_state, d_decoder, &in);
795*f6dc9357SAndroid Build Coastguard Worker       if (new_D)
796*f6dc9357SAndroid Build Coastguard Worker         D = new_D;
797*f6dc9357SAndroid Build Coastguard Worker     }
798*f6dc9357SAndroid Build Coastguard Worker 
799*f6dc9357SAndroid Build Coastguard Worker     if (L != 0)
800*f6dc9357SAndroid Build Coastguard Worker     {
801*f6dc9357SAndroid Build Coastguard Worker       if (L > (size_t)(lit_limit - lit))
802*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
803*f6dc9357SAndroid Build Coastguard Worker       unsigned cur = L;
804*f6dc9357SAndroid Build Coastguard Worker       if (cur > unpackSize)
805*f6dc9357SAndroid Build Coastguard Worker         cur = (unsigned)unpackSize;
806*f6dc9357SAndroid Build Coastguard Worker       m_OutWindowStream.PutBytes(lit, cur);
807*f6dc9357SAndroid Build Coastguard Worker       unpackSize -= cur;
808*f6dc9357SAndroid Build Coastguard Worker       lit += cur;
809*f6dc9357SAndroid Build Coastguard Worker       if (cur != L)
810*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
811*f6dc9357SAndroid Build Coastguard Worker     }
812*f6dc9357SAndroid Build Coastguard Worker 
813*f6dc9357SAndroid Build Coastguard Worker     if (M != 0)
814*f6dc9357SAndroid Build Coastguard Worker     {
815*f6dc9357SAndroid Build Coastguard Worker       if (unpackSize == 0 || D == 0)
816*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
817*f6dc9357SAndroid Build Coastguard Worker       unsigned cur = M;
818*f6dc9357SAndroid Build Coastguard Worker       if (cur > unpackSize)
819*f6dc9357SAndroid Build Coastguard Worker         cur = (unsigned)unpackSize;
820*f6dc9357SAndroid Build Coastguard Worker       if (!m_OutWindowStream.CopyBlock(D - 1, cur))
821*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
822*f6dc9357SAndroid Build Coastguard Worker       unpackSize -= cur;
823*f6dc9357SAndroid Build Coastguard Worker       if (cur != M)
824*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
825*f6dc9357SAndroid Build Coastguard Worker     }
826*f6dc9357SAndroid Build Coastguard Worker   }
827*f6dc9357SAndroid Build Coastguard Worker 
828*f6dc9357SAndroid Build Coastguard Worker   if (unpackSize != 0)
829*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
830*f6dc9357SAndroid Build Coastguard Worker 
831*f6dc9357SAndroid Build Coastguard Worker   // LZFSE encoder writes 8 additional zero bytes before LMD payload
832*f6dc9357SAndroid Build Coastguard Worker   // We test it:
833*f6dc9357SAndroid Build Coastguard Worker   if ((size_t)(buf - buf_start) * 8 + in.numBits != 64)
834*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
835*f6dc9357SAndroid Build Coastguard Worker   if (GetUi64(buf_start) != 0)
836*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
837*f6dc9357SAndroid Build Coastguard Worker 
838*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
839*f6dc9357SAndroid Build Coastguard Worker }
840*f6dc9357SAndroid Build Coastguard Worker 
841*f6dc9357SAndroid Build Coastguard Worker 
CodeReal(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress)842*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
843*f6dc9357SAndroid Build Coastguard Worker     const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
844*f6dc9357SAndroid Build Coastguard Worker {
845*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n\nLzfseDecoder %7u %7u\n", (unsigned)*outSize, (unsigned)*inSize));
846*f6dc9357SAndroid Build Coastguard Worker 
847*f6dc9357SAndroid Build Coastguard Worker   const UInt32 kLzfseDictSize = 1 << 18;
848*f6dc9357SAndroid Build Coastguard Worker   if (!m_OutWindowStream.Create(kLzfseDictSize))
849*f6dc9357SAndroid Build Coastguard Worker     return E_OUTOFMEMORY;
850*f6dc9357SAndroid Build Coastguard Worker   if (!m_InStream.Create(1 << 18))
851*f6dc9357SAndroid Build Coastguard Worker     return E_OUTOFMEMORY;
852*f6dc9357SAndroid Build Coastguard Worker 
853*f6dc9357SAndroid Build Coastguard Worker   m_OutWindowStream.SetStream(outStream);
854*f6dc9357SAndroid Build Coastguard Worker   m_OutWindowStream.Init(false);
855*f6dc9357SAndroid Build Coastguard Worker   m_InStream.SetStream(inStream);
856*f6dc9357SAndroid Build Coastguard Worker   m_InStream.Init();
857*f6dc9357SAndroid Build Coastguard Worker 
858*f6dc9357SAndroid Build Coastguard Worker   CCoderReleaser coderReleaser(this);
859*f6dc9357SAndroid Build Coastguard Worker 
860*f6dc9357SAndroid Build Coastguard Worker   UInt64 prevOut = 0;
861*f6dc9357SAndroid Build Coastguard Worker   UInt64 prevIn = 0;
862*f6dc9357SAndroid Build Coastguard Worker 
863*f6dc9357SAndroid Build Coastguard Worker   if (LzvnMode)
864*f6dc9357SAndroid Build Coastguard Worker   {
865*f6dc9357SAndroid Build Coastguard Worker     if (!outSize || !inSize)
866*f6dc9357SAndroid Build Coastguard Worker       return E_NOTIMPL;
867*f6dc9357SAndroid Build Coastguard Worker     const UInt64 unpackSize = *outSize;
868*f6dc9357SAndroid Build Coastguard Worker     const UInt64 packSize = *inSize;
869*f6dc9357SAndroid Build Coastguard Worker     if (unpackSize > (UInt32)(Int32)-1
870*f6dc9357SAndroid Build Coastguard Worker         || packSize > (UInt32)(Int32)-1)
871*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
872*f6dc9357SAndroid Build Coastguard Worker     RINOK(DecodeLzvn((UInt32)unpackSize, (UInt32)packSize))
873*f6dc9357SAndroid Build Coastguard Worker   }
874*f6dc9357SAndroid Build Coastguard Worker   else
875*f6dc9357SAndroid Build Coastguard Worker   for (;;)
876*f6dc9357SAndroid Build Coastguard Worker   {
877*f6dc9357SAndroid Build Coastguard Worker     const UInt64 pos = m_OutWindowStream.GetProcessedSize();
878*f6dc9357SAndroid Build Coastguard Worker     const UInt64 packPos = m_InStream.GetProcessedSize();
879*f6dc9357SAndroid Build Coastguard Worker 
880*f6dc9357SAndroid Build Coastguard Worker     if (progress && ((pos - prevOut) >= (1 << 22) || (packPos - prevIn) >= (1 << 22)))
881*f6dc9357SAndroid Build Coastguard Worker     {
882*f6dc9357SAndroid Build Coastguard Worker       RINOK(progress->SetRatioInfo(&packPos, &pos))
883*f6dc9357SAndroid Build Coastguard Worker       prevIn = packPos;
884*f6dc9357SAndroid Build Coastguard Worker       prevOut = pos;
885*f6dc9357SAndroid Build Coastguard Worker     }
886*f6dc9357SAndroid Build Coastguard Worker 
887*f6dc9357SAndroid Build Coastguard Worker     UInt32 v;
888*f6dc9357SAndroid Build Coastguard Worker     RINOK(GetUInt32(v))
889*f6dc9357SAndroid Build Coastguard Worker     if ((v & 0xFFFFFF) != 0x787662) // bvx
890*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
891*f6dc9357SAndroid Build Coastguard Worker     v >>= 24;
892*f6dc9357SAndroid Build Coastguard Worker 
893*f6dc9357SAndroid Build Coastguard Worker     if (v == 0x24) // '$', end of stream
894*f6dc9357SAndroid Build Coastguard Worker       break;
895*f6dc9357SAndroid Build Coastguard Worker 
896*f6dc9357SAndroid Build Coastguard Worker     UInt32 unpackSize;
897*f6dc9357SAndroid Build Coastguard Worker     RINOK(GetUInt32(unpackSize))
898*f6dc9357SAndroid Build Coastguard Worker 
899*f6dc9357SAndroid Build Coastguard Worker     UInt32 cur = unpackSize;
900*f6dc9357SAndroid Build Coastguard Worker     if (outSize)
901*f6dc9357SAndroid Build Coastguard Worker     {
902*f6dc9357SAndroid Build Coastguard Worker       const UInt64 rem = *outSize - pos;
903*f6dc9357SAndroid Build Coastguard Worker       if (cur > rem)
904*f6dc9357SAndroid Build Coastguard Worker         cur = (UInt32)rem;
905*f6dc9357SAndroid Build Coastguard Worker     }
906*f6dc9357SAndroid Build Coastguard Worker     unpackSize -= cur;
907*f6dc9357SAndroid Build Coastguard Worker 
908*f6dc9357SAndroid Build Coastguard Worker     HRESULT res;
909*f6dc9357SAndroid Build Coastguard Worker     if (v == kSignature_LZFSE_V1 || v == kSignature_LZFSE_V2)
910*f6dc9357SAndroid Build Coastguard Worker       res = DecodeLzfse(cur, (Byte)v);
911*f6dc9357SAndroid Build Coastguard Worker     else if (v == 0x6E) // 'n'
912*f6dc9357SAndroid Build Coastguard Worker     {
913*f6dc9357SAndroid Build Coastguard Worker       UInt32 packSize;
914*f6dc9357SAndroid Build Coastguard Worker       res = GetUInt32(packSize);
915*f6dc9357SAndroid Build Coastguard Worker       if (res == S_OK)
916*f6dc9357SAndroid Build Coastguard Worker         res = DecodeLzvn(cur, packSize);
917*f6dc9357SAndroid Build Coastguard Worker     }
918*f6dc9357SAndroid Build Coastguard Worker     else if (v == 0x2D) // '-'
919*f6dc9357SAndroid Build Coastguard Worker       res = DecodeUncompressed(cur);
920*f6dc9357SAndroid Build Coastguard Worker     else
921*f6dc9357SAndroid Build Coastguard Worker       return E_NOTIMPL;
922*f6dc9357SAndroid Build Coastguard Worker 
923*f6dc9357SAndroid Build Coastguard Worker     if (res != S_OK)
924*f6dc9357SAndroid Build Coastguard Worker       return res;
925*f6dc9357SAndroid Build Coastguard Worker 
926*f6dc9357SAndroid Build Coastguard Worker     if (unpackSize != 0)
927*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
928*f6dc9357SAndroid Build Coastguard Worker   }
929*f6dc9357SAndroid Build Coastguard Worker 
930*f6dc9357SAndroid Build Coastguard Worker   coderReleaser.NeedFlush = false;
931*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = m_OutWindowStream.Flush();
932*f6dc9357SAndroid Build Coastguard Worker   if (res == S_OK)
933*f6dc9357SAndroid Build Coastguard Worker     if ((!LzvnMode && inSize && *inSize != m_InStream.GetProcessedSize())
934*f6dc9357SAndroid Build Coastguard Worker         || (outSize && *outSize != m_OutWindowStream.GetProcessedSize()))
935*f6dc9357SAndroid Build Coastguard Worker       res = S_FALSE;
936*f6dc9357SAndroid Build Coastguard Worker   return res;
937*f6dc9357SAndroid Build Coastguard Worker }
938*f6dc9357SAndroid Build Coastguard Worker 
939*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CDecoder::Code (ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress))940*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
941*f6dc9357SAndroid Build Coastguard Worker     const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
942*f6dc9357SAndroid Build Coastguard Worker {
943*f6dc9357SAndroid Build Coastguard Worker   try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
944*f6dc9357SAndroid Build Coastguard Worker   catch(const CInBufferException &e) { return e.ErrorCode; }
945*f6dc9357SAndroid Build Coastguard Worker   catch(const CLzOutWindowException &e) { return e.ErrorCode; }
946*f6dc9357SAndroid Build Coastguard Worker   catch(...) { return E_OUTOFMEMORY; }
947*f6dc9357SAndroid Build Coastguard Worker   // catch(...) { return S_FALSE; }
948*f6dc9357SAndroid Build Coastguard Worker }
949*f6dc9357SAndroid Build Coastguard Worker 
950*f6dc9357SAndroid Build Coastguard Worker }}
951