blob: c0efda5f8d01456d5a0c20bb090773a6adc7b029 [file] [log] [blame]
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +00001/*
2 LzmaDecode.c
3 LZMA Decoder (optimized for Speed version)
Stefan Reinauer14e22772010-04-27 06:56:47 +00004
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +00005 LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
6 http://www.7-zip.org/
7
8 LZMA SDK is licensed under two licenses:
9 1) GNU Lesser General Public License (GNU LGPL)
10 2) Common Public License (CPL)
Stefan Reinauer14e22772010-04-27 06:56:47 +000011 It means that you can select one of these two licenses and
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000012 follow rules of that license.
13
14 SPECIAL EXCEPTION:
Stefan Reinauer14e22772010-04-27 06:56:47 +000015 Igor Pavlov, as the author of this Code, expressly permits you to
16 statically or dynamically link your Code (or bind by name) to the
17 interfaces of this file without subjecting your linked Code to the
18 terms of the CPL or GNU LGPL. Any modifications or additions
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000019 to this file, however, are subject to the LGPL or CPL terms.
20*/
21
22#include "lzmadecode.h"
Ronald G. Minnichfc5dc1c2014-12-02 04:07:02 +000023#include <stdint.h>
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000024
25#define kNumTopBits 24
26#define kTopValue ((UInt32)1 << kNumTopBits)
27
28#define kNumBitModelTotalBits 11
29#define kBitModelTotal (1 << kNumBitModelTotalBits)
30#define kNumMoveBits 5
31
Julius Wernera25b5d22016-02-08 11:46:22 -080032/* Use 32-bit reads whenever possible to avoid bad flash performance. Fall back
33 * to byte reads for last 4 bytes since RC_TEST returns an error when BufferLim
34 * is *reached* (not surpassed!), meaning we can't allow that to happen while
35 * there are still bytes to decode from the algorithm's point of view. */
Vladimir Serbinenko3d6ffe72014-02-05 17:00:40 +010036#define RC_READ_BYTE (look_ahead_ptr < 4 ? look_ahead.raw[look_ahead_ptr++] \
Julius Wernera25b5d22016-02-08 11:46:22 -080037 : ((((uintptr_t) Buffer & 3) || ((SizeT) (BufferLim - Buffer) <= 4)) ? (*Buffer++) \
Vladimir Serbinenko3d6ffe72014-02-05 17:00:40 +010038 : ((look_ahead.dw = *(UInt32 *)Buffer), (Buffer += 4), (look_ahead_ptr = 1), look_ahead.raw[0])))
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000039
40#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
Lee Leahye20a3192017-03-09 16:21:34 -080041 { int i; for (i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) \
42 | RC_READ_BYTE; }}
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000043
44
45#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; }
46
47#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
Stefan Reinauer14e22772010-04-27 06:56:47 +000048
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000049
50#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
51
52#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
53#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
54#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
55
56#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \
Lee Leahye20a3192017-03-09 16:21:34 -080057 { UpdateBit0(p); mi <<= 1; A0; } else \
58 { UpdateBit1(p); mi = (mi + mi) + 1; A1; }
Stefan Reinauer14e22772010-04-27 06:56:47 +000059
60#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000061
Lee Leahye20a3192017-03-09 16:21:34 -080062#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
63{ \
64 int i = numLevels; \
65 \
66 res = 1; \
67 do { \
68 CProb *cp = probs + res; \
69 RC_GET_BIT(cp, res) \
70 } while (--i != 0); \
71 res -= (1 << numLevels); \
72}
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000073
74
75#define kNumPosBitsMax 4
76#define kNumPosStatesMax (1 << kNumPosBitsMax)
77
78#define kLenNumLowBits 3
79#define kLenNumLowSymbols (1 << kLenNumLowBits)
80#define kLenNumMidBits 3
81#define kLenNumMidSymbols (1 << kLenNumMidBits)
82#define kLenNumHighBits 8
83#define kLenNumHighSymbols (1 << kLenNumHighBits)
84
85#define LenChoice 0
86#define LenChoice2 (LenChoice + 1)
87#define LenLow (LenChoice2 + 1)
88#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
89#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
Stefan Reinauer14e22772010-04-27 06:56:47 +000090#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000091
92
93#define kNumStates 12
94#define kNumLitStates 7
95
96#define kStartPosModelIndex 4
97#define kEndPosModelIndex 14
98#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
99
100#define kNumPosSlotBits 6
101#define kNumLenToPosStates 4
102
103#define kNumAlignBits 4
104#define kAlignTableSize (1 << kNumAlignBits)
105
106#define kMatchMinLen 2
107
108#define IsMatch 0
109#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
110#define IsRepG0 (IsRep + kNumStates)
111#define IsRepG1 (IsRepG0 + kNumStates)
112#define IsRepG2 (IsRepG1 + kNumStates)
113#define IsRep0Long (IsRepG2 + kNumStates)
114#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
115#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
116#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
117#define LenCoder (Align + kAlignTableSize)
118#define RepLenCoder (LenCoder + kNumLenProbs)
119#define Literal (RepLenCoder + kNumLenProbs)
120
121#if Literal != LZMA_BASE_SIZE
122StopCompilingDueBUG
123#endif
124
125int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
126{
Lee Leahye20a3192017-03-09 16:21:34 -0800127 unsigned char prop0;
128 if (size < LZMA_PROPERTIES_SIZE)
129 return LZMA_RESULT_DATA_ERROR;
130 prop0 = propsData[0];
131 if (prop0 >= (9 * 5 * 5))
132 return LZMA_RESULT_DATA_ERROR;
133 {
134 for (propsRes->pb = 0; prop0 >= (9 * 5);
135 propsRes->pb++, prop0 -= (9 * 5))
136 ;
137 for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9)
138 ;
139 propsRes->lc = prop0;
140 /*
141 * unsigned char remainder = (unsigned char)(prop0 / 9);
142 * propsRes->lc = prop0 % 9;
143 * propsRes->pb = remainder / 5;
144 * propsRes->lp = remainder % 5;
145 */
146 }
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000147
Lee Leahye20a3192017-03-09 16:21:34 -0800148 return LZMA_RESULT_OK;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000149}
150
151#define kLzmaStreamWasFinishedId (-1)
152
153int LzmaDecode(CLzmaDecoderState *vs,
Lee Leahye20a3192017-03-09 16:21:34 -0800154 const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
155 unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000156{
Lee Leahye20a3192017-03-09 16:21:34 -0800157 CProb *p = vs->Probs;
158 SizeT nowPos = 0;
159 Byte previousByte = 0;
160 UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
161 UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
162 int lc = vs->Properties.lc;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000163
164
Lee Leahye20a3192017-03-09 16:21:34 -0800165 int state = 0;
166 UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
167 int len = 0;
168 const Byte *Buffer;
169 const Byte *BufferLim;
170 int look_ahead_ptr = 4;
171 union {
172 Byte raw[4];
173 UInt32 dw;
174 } look_ahead;
175 UInt32 Range;
176 UInt32 Code;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000177
Lee Leahye20a3192017-03-09 16:21:34 -0800178 *inSizeProcessed = 0;
179 *outSizeProcessed = 0;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000180
Lee Leahye20a3192017-03-09 16:21:34 -0800181 {
182 UInt32 i;
183 UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc
184 + vs->Properties.lp));
185 for (i = 0; i < numProbs; i++)
186 p[i] = kBitModelTotal >> 1;
187 }
Stefan Reinauer14e22772010-04-27 06:56:47 +0000188
Lee Leahye20a3192017-03-09 16:21:34 -0800189 RC_INIT(inStream, inSize);
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000190
191
Lee Leahye20a3192017-03-09 16:21:34 -0800192 while (nowPos < outSize) {
193 CProb *prob;
194 UInt32 bound;
195 int posState = (int)((nowPos)& posStateMask);
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000196
Lee Leahye20a3192017-03-09 16:21:34 -0800197 prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
198 IfBit0(prob) {
199 int symbol = 1;
200 UpdateBit0(prob)
201 prob = p + Literal + (LZMA_LIT_SIZE *
202 ((((nowPos) & literalPosMask) << lc)
203 + (previousByte >> (8 - lc))));
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000204
Lee Leahye20a3192017-03-09 16:21:34 -0800205 if (state >= kNumLitStates) {
206 int matchByte;
207 matchByte = outStream[nowPos - rep0];
208 do {
209 int bit;
210 CProb *probLit;
211 matchByte <<= 1;
212 bit = (matchByte & 0x100);
213 probLit = prob + 0x100 + bit + symbol;
214 RC_GET_BIT2(probLit, symbol,
215 if (bit != 0)
216 break,
217 if (bit == 0)
218 break)
219 } while (symbol < 0x100);
220 }
221 while (symbol < 0x100) {
222 CProb *probLit = prob + symbol;
223 RC_GET_BIT(probLit, symbol)
224 }
225 previousByte = (Byte)symbol;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000226
Lee Leahye20a3192017-03-09 16:21:34 -0800227 outStream[nowPos++] = previousByte;
228 if (state < 4)
229 state = 0;
230 else if (state < 10)
231 state -= 3;
232 else
233 state -= 6;
234 } else {
235 UpdateBit1(prob);
236 prob = p + IsRep + state;
237 IfBit0(prob) {
238 UpdateBit0(prob);
239 rep3 = rep2;
240 rep2 = rep1;
241 rep1 = rep0;
242 state = state < kNumLitStates ? 0 : 3;
243 prob = p + LenCoder;
244 } else {
245 UpdateBit1(prob);
246 prob = p + IsRepG0 + state;
247 IfBit0(prob) {
248 UpdateBit0(prob);
249 prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;
250 IfBit0(prob) {
251 UpdateBit0(prob);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000252
Lee Leahye20a3192017-03-09 16:21:34 -0800253 if (nowPos == 0)
254 return LZMA_RESULT_DATA_ERROR;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000255
Lee Leahye20a3192017-03-09 16:21:34 -0800256 state = state < kNumLitStates ? 9 : 11;
257 previousByte = outStream[nowPos - rep0];
258 outStream[nowPos++] = previousByte;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000259
Lee Leahye20a3192017-03-09 16:21:34 -0800260 continue;
261 } else
262 UpdateBit1(prob);
263 } else {
264 UInt32 distance;
265 UpdateBit1(prob);
266 prob = p + IsRepG1 + state;
267 IfBit0(prob) {
268 UpdateBit0(prob);
269 distance = rep1;
270 } else {
271 UpdateBit1(prob);
272 prob = p + IsRepG2 + state;
273 IfBit0(prob) {
274 UpdateBit0(prob);
275 distance = rep2;
276 } else {
277 UpdateBit1(prob);
278 distance = rep3;
279 rep3 = rep2;
280 }
281 rep2 = rep1;
282 }
283 rep1 = rep0;
284 rep0 = distance;
285 }
286 state = state < kNumLitStates ? 8 : 11;
287 prob = p + RepLenCoder;
288 }
289 {
290 int numBits, offset;
291 CProb *probLen = prob + LenChoice;
292 IfBit0(probLen) {
293 UpdateBit0(probLen);
294 probLen = prob + LenLow + (posState << kLenNumLowBits);
295 offset = 0;
296 numBits = kLenNumLowBits;
297 } else {
298 UpdateBit1(probLen);
299 probLen = prob + LenChoice2;
300 IfBit0(probLen) {
301 UpdateBit0(probLen);
302 probLen = prob + LenMid + (posState << kLenNumMidBits);
303 offset = kLenNumLowSymbols;
304 numBits = kLenNumMidBits;
305 } else {
306 UpdateBit1(probLen);
307 probLen = prob + LenHigh;
308 offset = kLenNumLowSymbols + kLenNumMidSymbols;
309 numBits = kLenNumHighBits;
310 }
311 }
312 RangeDecoderBitTreeDecode(probLen, numBits, len);
313 len += offset;
314 }
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000315
Lee Leahye20a3192017-03-09 16:21:34 -0800316 if (state < 4) {
317 int posSlot;
318 state += kNumLitStates;
319 prob = p + PosSlot +
320 ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
321 kNumPosSlotBits);
322 RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);
323 if (posSlot >= kStartPosModelIndex) {
324 int numDirectBits = ((posSlot >> 1) - 1);
325 rep0 = (2 | ((UInt32)posSlot & 1));
326 if (posSlot < kEndPosModelIndex) {
327 rep0 <<= numDirectBits;
328 prob = p + SpecPos + rep0 - posSlot - 1;
329 } else {
330 numDirectBits -= kNumAlignBits;
331 do {
332 RC_NORMALIZE
333 Range >>= 1;
334 rep0 <<= 1;
335 if (Code >= Range) {
336 Code -= Range;
337 rep0 |= 1;
338 }
339 } while (--numDirectBits != 0);
340 prob = p + Align;
341 rep0 <<= kNumAlignBits;
342 numDirectBits = kNumAlignBits;
343 }
344 {
345 int i = 1;
346 int mi = 1;
347 do {
348 CProb *prob3 = prob + mi;
349 RC_GET_BIT2(prob3, mi, ; , rep0 |= i);
350 i <<= 1;
351 } while (--numDirectBits != 0);
352 }
353 } else
354 rep0 = posSlot;
355 if (++rep0 == (UInt32)(0)) {
356 /* it's for stream version */
357 len = kLzmaStreamWasFinishedId;
358 break;
359 }
360 }
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000361
Lee Leahye20a3192017-03-09 16:21:34 -0800362 len += kMatchMinLen;
363 if (rep0 > nowPos)
364 return LZMA_RESULT_DATA_ERROR;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000365
366
Lee Leahye20a3192017-03-09 16:21:34 -0800367 do {
368 previousByte = outStream[nowPos - rep0];
369 len--;
370 outStream[nowPos++] = previousByte;
371 } while (len != 0 && nowPos < outSize);
372 }
373 }
374 RC_NORMALIZE;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000375
376
Lee Leahye20a3192017-03-09 16:21:34 -0800377 *inSizeProcessed = (SizeT)(Buffer - inStream);
378 *outSizeProcessed = nowPos;
379 return LZMA_RESULT_OK;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000380}