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