blob: c45e13170814ac0da8577a57a713901ce2b38e64 [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"
Elyes HAOUASb12ece92019-05-15 21:01:02 +020023#include <types.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. */
Lee Leahy73402172017-03-10 15:23:24 -080036#define RC_READ_BYTE \
37 (look_ahead_ptr < 4 ? look_ahead.raw[look_ahead_ptr++] \
38 : ((((uintptr_t) Buffer & 3) \
39 || ((SizeT) (BufferLim - Buffer) <= 4)) ? (*Buffer++) \
40 : ((look_ahead.dw = *(UInt32 *)Buffer), (Buffer += 4), \
41 (look_ahead_ptr = 1), look_ahead.raw[0])))
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000042
Lee Leahy35af5c42017-03-09 17:35:28 -080043#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
44{ \
45 int i; \
46 \
47 for (i = 0; i < 5; i++) { \
48 RC_TEST; \
49 Code = (Code << 8) | RC_READ_BYTE; \
50 } \
51}
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000052
53
54#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; }
55
Lee Leahy73402172017-03-10 15:23:24 -080056#define RC_INIT(buffer, bufferSize) Buffer = buffer; \
57 BufferLim = buffer + bufferSize; RC_INIT2
Stefan Reinauer14e22772010-04-27 06:56:47 +000058
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000059
Lee Leahy73402172017-03-10 15:23:24 -080060#define RC_NORMALIZE \
61 if (Range < kTopValue) { \
62 RC_TEST; \
63 Range <<= 8; \
64 Code = (Code << 8) | RC_READ_BYTE; \
65 }
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000066
Lee Leahy73402172017-03-10 15:23:24 -080067#define IfBit0(p) \
68 RC_NORMALIZE; \
69 bound = (Range >> kNumBitModelTotalBits) * *(p); \
70 if (Code < bound)
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000071
Lee Leahy73402172017-03-10 15:23:24 -080072#define UpdateBit0(p) \
73 Range = bound; \
Lee Leahyf59a75c2017-03-10 18:07:11 -080074 *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits
Lee Leahy73402172017-03-10 15:23:24 -080075
76#define UpdateBit1(p) \
77 Range -= bound; \
78 Code -= bound; \
Lee Leahyf59a75c2017-03-10 18:07:11 -080079 *(p) -= (*(p)) >> kNumMoveBits
Lee Leahy73402172017-03-10 15:23:24 -080080
81#define RC_GET_BIT2(p, mi, A0, A1) \
82 IfBit0(p) { \
83 UpdateBit0(p); \
84 mi <<= 1; \
85 A0; \
86 } else { \
87 UpdateBit1(p); \
88 mi = (mi + mi) + 1; \
89 A1; \
90 }
Stefan Reinauer14e22772010-04-27 06:56:47 +000091
Lee Leahy35af5c42017-03-09 17:35:28 -080092#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ;, ;)
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000093
Lee Leahye20a3192017-03-09 16:21:34 -080094#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
95{ \
96 int i = numLevels; \
97 \
98 res = 1; \
99 do { \
100 CProb *cp = probs + res; \
101 RC_GET_BIT(cp, res) \
102 } while (--i != 0); \
103 res -= (1 << numLevels); \
104}
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000105
106
107#define kNumPosBitsMax 4
108#define kNumPosStatesMax (1 << kNumPosBitsMax)
109
110#define kLenNumLowBits 3
111#define kLenNumLowSymbols (1 << kLenNumLowBits)
112#define kLenNumMidBits 3
113#define kLenNumMidSymbols (1 << kLenNumMidBits)
114#define kLenNumHighBits 8
115#define kLenNumHighSymbols (1 << kLenNumHighBits)
116
117#define LenChoice 0
118#define LenChoice2 (LenChoice + 1)
119#define LenLow (LenChoice2 + 1)
120#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
121#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
Stefan Reinauer14e22772010-04-27 06:56:47 +0000122#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000123
124
125#define kNumStates 12
126#define kNumLitStates 7
127
128#define kStartPosModelIndex 4
129#define kEndPosModelIndex 14
130#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
131
132#define kNumPosSlotBits 6
133#define kNumLenToPosStates 4
134
135#define kNumAlignBits 4
136#define kAlignTableSize (1 << kNumAlignBits)
137
138#define kMatchMinLen 2
139
140#define IsMatch 0
141#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
142#define IsRepG0 (IsRep + kNumStates)
143#define IsRepG1 (IsRepG0 + kNumStates)
144#define IsRepG2 (IsRepG1 + kNumStates)
145#define IsRep0Long (IsRepG2 + kNumStates)
146#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
147#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
148#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
149#define LenCoder (Align + kAlignTableSize)
150#define RepLenCoder (LenCoder + kNumLenProbs)
151#define Literal (RepLenCoder + kNumLenProbs)
152
153#if Literal != LZMA_BASE_SIZE
154StopCompilingDueBUG
155#endif
156
Lee Leahy73402172017-03-10 15:23:24 -0800157int LzmaDecodeProperties(CLzmaProperties *propsRes,
158 const unsigned char *propsData, int size)
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000159{
Lee Leahye20a3192017-03-09 16:21:34 -0800160 unsigned char prop0;
161 if (size < LZMA_PROPERTIES_SIZE)
162 return LZMA_RESULT_DATA_ERROR;
163 prop0 = propsData[0];
164 if (prop0 >= (9 * 5 * 5))
165 return LZMA_RESULT_DATA_ERROR;
166 {
167 for (propsRes->pb = 0; prop0 >= (9 * 5);
168 propsRes->pb++, prop0 -= (9 * 5))
169 ;
170 for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9)
171 ;
172 propsRes->lc = prop0;
173 /*
174 * unsigned char remainder = (unsigned char)(prop0 / 9);
175 * propsRes->lc = prop0 % 9;
176 * propsRes->pb = remainder / 5;
177 * propsRes->lp = remainder % 5;
178 */
179 }
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000180
Lee Leahye20a3192017-03-09 16:21:34 -0800181 return LZMA_RESULT_OK;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000182}
183
184#define kLzmaStreamWasFinishedId (-1)
185
186int LzmaDecode(CLzmaDecoderState *vs,
Lee Leahye20a3192017-03-09 16:21:34 -0800187 const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
188 unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000189{
Lee Leahye20a3192017-03-09 16:21:34 -0800190 CProb *p = vs->Probs;
191 SizeT nowPos = 0;
192 Byte previousByte = 0;
193 UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
194 UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
195 int lc = vs->Properties.lc;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000196
197
Lee Leahye20a3192017-03-09 16:21:34 -0800198 int state = 0;
199 UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
200 int len = 0;
201 const Byte *Buffer;
202 const Byte *BufferLim;
203 int look_ahead_ptr = 4;
204 union {
205 Byte raw[4];
206 UInt32 dw;
207 } look_ahead;
208 UInt32 Range;
209 UInt32 Code;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000210
Lee Leahye20a3192017-03-09 16:21:34 -0800211 *inSizeProcessed = 0;
212 *outSizeProcessed = 0;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000213
Lee Leahye20a3192017-03-09 16:21:34 -0800214 {
215 UInt32 i;
216 UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc
217 + vs->Properties.lp));
218 for (i = 0; i < numProbs; i++)
219 p[i] = kBitModelTotal >> 1;
220 }
Stefan Reinauer14e22772010-04-27 06:56:47 +0000221
Lee Leahye20a3192017-03-09 16:21:34 -0800222 RC_INIT(inStream, inSize);
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000223
224
Lee Leahye20a3192017-03-09 16:21:34 -0800225 while (nowPos < outSize) {
226 CProb *prob;
227 UInt32 bound;
Lee Leahy35af5c42017-03-09 17:35:28 -0800228 int posState = (int)((nowPos)&posStateMask);
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000229
Lee Leahye20a3192017-03-09 16:21:34 -0800230 prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
231 IfBit0(prob) {
232 int symbol = 1;
Lee Leahyf59a75c2017-03-10 18:07:11 -0800233 UpdateBit0(prob);
Lee Leahye20a3192017-03-09 16:21:34 -0800234 prob = p + Literal + (LZMA_LIT_SIZE *
235 ((((nowPos) & literalPosMask) << lc)
236 + (previousByte >> (8 - lc))));
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000237
Lee Leahye20a3192017-03-09 16:21:34 -0800238 if (state >= kNumLitStates) {
239 int matchByte;
240 matchByte = outStream[nowPos - rep0];
241 do {
242 int bit;
243 CProb *probLit;
244 matchByte <<= 1;
245 bit = (matchByte & 0x100);
246 probLit = prob + 0x100 + bit + symbol;
247 RC_GET_BIT2(probLit, symbol,
248 if (bit != 0)
249 break,
250 if (bit == 0)
251 break)
252 } while (symbol < 0x100);
253 }
254 while (symbol < 0x100) {
255 CProb *probLit = prob + symbol;
256 RC_GET_BIT(probLit, symbol)
257 }
258 previousByte = (Byte)symbol;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000259
Lee Leahye20a3192017-03-09 16:21:34 -0800260 outStream[nowPos++] = previousByte;
261 if (state < 4)
262 state = 0;
263 else if (state < 10)
264 state -= 3;
265 else
266 state -= 6;
267 } else {
268 UpdateBit1(prob);
269 prob = p + IsRep + state;
270 IfBit0(prob) {
271 UpdateBit0(prob);
272 rep3 = rep2;
273 rep2 = rep1;
274 rep1 = rep0;
275 state = state < kNumLitStates ? 0 : 3;
276 prob = p + LenCoder;
277 } else {
278 UpdateBit1(prob);
279 prob = p + IsRepG0 + state;
280 IfBit0(prob) {
281 UpdateBit0(prob);
Lee Leahy73402172017-03-10 15:23:24 -0800282 prob = p + IsRep0Long
283 + (state << kNumPosBitsMax)
284 + posState;
Lee Leahye20a3192017-03-09 16:21:34 -0800285 IfBit0(prob) {
286 UpdateBit0(prob);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000287
Lee Leahye20a3192017-03-09 16:21:34 -0800288 if (nowPos == 0)
289 return LZMA_RESULT_DATA_ERROR;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000290
Lee Leahy73402172017-03-10 15:23:24 -0800291 state = state < kNumLitStates
292 ? 9 : 11;
293 previousByte = outStream[nowPos
294 - rep0];
295 outStream[nowPos++] =
296 previousByte;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000297
Lee Leahye20a3192017-03-09 16:21:34 -0800298 continue;
Paul Menzeld538dd12018-03-30 10:25:56 +0200299 } else {
Lee Leahye20a3192017-03-09 16:21:34 -0800300 UpdateBit1(prob);
Paul Menzeld538dd12018-03-30 10:25:56 +0200301 }
Lee Leahye20a3192017-03-09 16:21:34 -0800302 } else {
303 UInt32 distance;
304 UpdateBit1(prob);
305 prob = p + IsRepG1 + state;
306 IfBit0(prob) {
307 UpdateBit0(prob);
308 distance = rep1;
309 } else {
310 UpdateBit1(prob);
311 prob = p + IsRepG2 + state;
312 IfBit0(prob) {
313 UpdateBit0(prob);
314 distance = rep2;
315 } else {
316 UpdateBit1(prob);
317 distance = rep3;
318 rep3 = rep2;
319 }
320 rep2 = rep1;
321 }
322 rep1 = rep0;
323 rep0 = distance;
324 }
325 state = state < kNumLitStates ? 8 : 11;
326 prob = p + RepLenCoder;
327 }
328 {
329 int numBits, offset;
330 CProb *probLen = prob + LenChoice;
331 IfBit0(probLen) {
332 UpdateBit0(probLen);
Lee Leahy73402172017-03-10 15:23:24 -0800333 probLen = prob + LenLow
334 + (posState << kLenNumLowBits);
Lee Leahye20a3192017-03-09 16:21:34 -0800335 offset = 0;
336 numBits = kLenNumLowBits;
337 } else {
338 UpdateBit1(probLen);
339 probLen = prob + LenChoice2;
340 IfBit0(probLen) {
341 UpdateBit0(probLen);
Lee Leahy73402172017-03-10 15:23:24 -0800342 probLen = prob + LenMid
343 + (posState <<
344 kLenNumMidBits);
Lee Leahye20a3192017-03-09 16:21:34 -0800345 offset = kLenNumLowSymbols;
346 numBits = kLenNumMidBits;
347 } else {
348 UpdateBit1(probLen);
349 probLen = prob + LenHigh;
Lee Leahy73402172017-03-10 15:23:24 -0800350 offset = kLenNumLowSymbols
351 + kLenNumMidSymbols;
Lee Leahye20a3192017-03-09 16:21:34 -0800352 numBits = kLenNumHighBits;
353 }
354 }
Lee Leahy73402172017-03-10 15:23:24 -0800355 RangeDecoderBitTreeDecode(probLen, numBits,
356 len);
Lee Leahye20a3192017-03-09 16:21:34 -0800357 len += offset;
358 }
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000359
Lee Leahye20a3192017-03-09 16:21:34 -0800360 if (state < 4) {
361 int posSlot;
362 state += kNumLitStates;
363 prob = p + PosSlot +
Lee Leahy73402172017-03-10 15:23:24 -0800364 ((len < kNumLenToPosStates ? len :
365 kNumLenToPosStates - 1) <<
Lee Leahye20a3192017-03-09 16:21:34 -0800366 kNumPosSlotBits);
Lee Leahy73402172017-03-10 15:23:24 -0800367 RangeDecoderBitTreeDecode(prob, kNumPosSlotBits,
368 posSlot);
Lee Leahye20a3192017-03-09 16:21:34 -0800369 if (posSlot >= kStartPosModelIndex) {
Lee Leahy73402172017-03-10 15:23:24 -0800370 int numDirectBits = ((posSlot >> 1)
371 - 1);
Lee Leahye20a3192017-03-09 16:21:34 -0800372 rep0 = (2 | ((UInt32)posSlot & 1));
373 if (posSlot < kEndPosModelIndex) {
374 rep0 <<= numDirectBits;
Lee Leahy73402172017-03-10 15:23:24 -0800375 prob = p + SpecPos + rep0
376 - posSlot - 1;
Lee Leahye20a3192017-03-09 16:21:34 -0800377 } else {
378 numDirectBits -= kNumAlignBits;
379 do {
380 RC_NORMALIZE
381 Range >>= 1;
382 rep0 <<= 1;
383 if (Code >= Range) {
384 Code -= Range;
385 rep0 |= 1;
386 }
387 } while (--numDirectBits != 0);
388 prob = p + Align;
389 rep0 <<= kNumAlignBits;
390 numDirectBits = kNumAlignBits;
391 }
392 {
393 int i = 1;
394 int mi = 1;
395 do {
Lee Leahy73402172017-03-10 15:23:24 -0800396 CProb *prob3 = prob
397 + mi;
398 RC_GET_BIT2(prob3, mi,
399 ;, rep0 |= i);
Lee Leahye20a3192017-03-09 16:21:34 -0800400 i <<= 1;
401 } while (--numDirectBits != 0);
402 }
403 } else
404 rep0 = posSlot;
405 if (++rep0 == (UInt32)(0)) {
406 /* it's for stream version */
407 len = kLzmaStreamWasFinishedId;
408 break;
409 }
410 }
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000411
Lee Leahye20a3192017-03-09 16:21:34 -0800412 len += kMatchMinLen;
413 if (rep0 > nowPos)
414 return LZMA_RESULT_DATA_ERROR;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000415
416
Lee Leahye20a3192017-03-09 16:21:34 -0800417 do {
418 previousByte = outStream[nowPos - rep0];
419 len--;
420 outStream[nowPos++] = previousByte;
421 } while (len != 0 && nowPos < outSize);
422 }
423 }
424 RC_NORMALIZE;
Richard Spiegelfb096932018-08-10 15:45:43 -0700425 /*
426 * Tell static analysis we know len can have a dead assignment.
427 */
428 (void)len;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000429
430
Lee Leahye20a3192017-03-09 16:21:34 -0800431 *inSizeProcessed = (SizeT)(Buffer - inStream);
432 *outSizeProcessed = nowPos;
433 return LZMA_RESULT_OK;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000434}