blob: cb868290aaaa10a1892675e1cf3943fe67402b57 [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
Zheng Baod91f3a42022-08-03 17:57:47 +080022#if CONFIG(DECOMPRESS_OFAST)
23 #define __lzma_attribute_Ofast__ __attribute__((optimize("Ofast")))
24#else
25 #define __lzma_attribute_Ofast__
26#endif
27
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000028#include "lzmadecode.h"
Elyes HAOUASb12ece92019-05-15 21:01:02 +020029#include <types.h>
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000030
31#define kNumTopBits 24
32#define kTopValue ((UInt32)1 << kNumTopBits)
33
34#define kNumBitModelTotalBits 11
35#define kBitModelTotal (1 << kNumBitModelTotalBits)
36#define kNumMoveBits 5
37
Julius Wernera25b5d22016-02-08 11:46:22 -080038/* Use 32-bit reads whenever possible to avoid bad flash performance. Fall back
39 * to byte reads for last 4 bytes since RC_TEST returns an error when BufferLim
40 * is *reached* (not surpassed!), meaning we can't allow that to happen while
41 * there are still bytes to decode from the algorithm's point of view. */
Lee Leahy73402172017-03-10 15:23:24 -080042#define RC_READ_BYTE \
43 (look_ahead_ptr < 4 ? look_ahead.raw[look_ahead_ptr++] \
44 : ((((uintptr_t) Buffer & 3) \
45 || ((SizeT) (BufferLim - Buffer) <= 4)) ? (*Buffer++) \
46 : ((look_ahead.dw = *(UInt32 *)Buffer), (Buffer += 4), \
47 (look_ahead_ptr = 1), look_ahead.raw[0])))
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000048
Lee Leahy35af5c42017-03-09 17:35:28 -080049#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
50{ \
51 int i; \
52 \
53 for (i = 0; i < 5; i++) { \
54 RC_TEST; \
55 Code = (Code << 8) | RC_READ_BYTE; \
56 } \
57}
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000058
59
60#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; }
61
Lee Leahy73402172017-03-10 15:23:24 -080062#define RC_INIT(buffer, bufferSize) Buffer = buffer; \
63 BufferLim = buffer + bufferSize; RC_INIT2
Stefan Reinauer14e22772010-04-27 06:56:47 +000064
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000065
Lee Leahy73402172017-03-10 15:23:24 -080066#define RC_NORMALIZE \
67 if (Range < kTopValue) { \
68 RC_TEST; \
69 Range <<= 8; \
70 Code = (Code << 8) | RC_READ_BYTE; \
71 }
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000072
Lee Leahy73402172017-03-10 15:23:24 -080073#define IfBit0(p) \
74 RC_NORMALIZE; \
75 bound = (Range >> kNumBitModelTotalBits) * *(p); \
76 if (Code < bound)
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000077
Lee Leahy73402172017-03-10 15:23:24 -080078#define UpdateBit0(p) \
79 Range = bound; \
Lee Leahyf59a75c2017-03-10 18:07:11 -080080 *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits
Lee Leahy73402172017-03-10 15:23:24 -080081
82#define UpdateBit1(p) \
83 Range -= bound; \
84 Code -= bound; \
Lee Leahyf59a75c2017-03-10 18:07:11 -080085 *(p) -= (*(p)) >> kNumMoveBits
Lee Leahy73402172017-03-10 15:23:24 -080086
87#define RC_GET_BIT2(p, mi, A0, A1) \
88 IfBit0(p) { \
89 UpdateBit0(p); \
90 mi <<= 1; \
91 A0; \
92 } else { \
93 UpdateBit1(p); \
94 mi = (mi + mi) + 1; \
95 A1; \
96 }
Stefan Reinauer14e22772010-04-27 06:56:47 +000097
Lee Leahy35af5c42017-03-09 17:35:28 -080098#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ;, ;)
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +000099
Lee Leahye20a3192017-03-09 16:21:34 -0800100#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
101{ \
102 int i = numLevels; \
103 \
104 res = 1; \
105 do { \
106 CProb *cp = probs + res; \
107 RC_GET_BIT(cp, res) \
108 } while (--i != 0); \
109 res -= (1 << numLevels); \
110}
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000111
112
113#define kNumPosBitsMax 4
114#define kNumPosStatesMax (1 << kNumPosBitsMax)
115
116#define kLenNumLowBits 3
117#define kLenNumLowSymbols (1 << kLenNumLowBits)
118#define kLenNumMidBits 3
119#define kLenNumMidSymbols (1 << kLenNumMidBits)
120#define kLenNumHighBits 8
121#define kLenNumHighSymbols (1 << kLenNumHighBits)
122
123#define LenChoice 0
124#define LenChoice2 (LenChoice + 1)
125#define LenLow (LenChoice2 + 1)
126#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
127#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
Stefan Reinauer14e22772010-04-27 06:56:47 +0000128#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000129
130
131#define kNumStates 12
132#define kNumLitStates 7
133
134#define kStartPosModelIndex 4
135#define kEndPosModelIndex 14
136#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
137
138#define kNumPosSlotBits 6
139#define kNumLenToPosStates 4
140
141#define kNumAlignBits 4
142#define kAlignTableSize (1 << kNumAlignBits)
143
144#define kMatchMinLen 2
145
146#define IsMatch 0
147#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
148#define IsRepG0 (IsRep + kNumStates)
149#define IsRepG1 (IsRepG0 + kNumStates)
150#define IsRepG2 (IsRepG1 + kNumStates)
151#define IsRep0Long (IsRepG2 + kNumStates)
152#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
153#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
154#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
155#define LenCoder (Align + kAlignTableSize)
156#define RepLenCoder (LenCoder + kNumLenProbs)
157#define Literal (RepLenCoder + kNumLenProbs)
158
159#if Literal != LZMA_BASE_SIZE
160StopCompilingDueBUG
161#endif
162
Lee Leahy73402172017-03-10 15:23:24 -0800163int LzmaDecodeProperties(CLzmaProperties *propsRes,
164 const unsigned char *propsData, int size)
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000165{
Lee Leahye20a3192017-03-09 16:21:34 -0800166 unsigned char prop0;
167 if (size < LZMA_PROPERTIES_SIZE)
168 return LZMA_RESULT_DATA_ERROR;
169 prop0 = propsData[0];
170 if (prop0 >= (9 * 5 * 5))
171 return LZMA_RESULT_DATA_ERROR;
172 {
173 for (propsRes->pb = 0; prop0 >= (9 * 5);
174 propsRes->pb++, prop0 -= (9 * 5))
175 ;
176 for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9)
177 ;
178 propsRes->lc = prop0;
179 /*
180 * unsigned char remainder = (unsigned char)(prop0 / 9);
181 * propsRes->lc = prop0 % 9;
182 * propsRes->pb = remainder / 5;
183 * propsRes->lp = remainder % 5;
184 */
185 }
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000186
Lee Leahye20a3192017-03-09 16:21:34 -0800187 return LZMA_RESULT_OK;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000188}
189
190#define kLzmaStreamWasFinishedId (-1)
191
Zheng Baod91f3a42022-08-03 17:57:47 +0800192__lzma_attribute_Ofast__
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000193int LzmaDecode(CLzmaDecoderState *vs,
Lee Leahye20a3192017-03-09 16:21:34 -0800194 const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
195 unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000196{
Lee Leahye20a3192017-03-09 16:21:34 -0800197 CProb *p = vs->Probs;
198 SizeT nowPos = 0;
199 Byte previousByte = 0;
200 UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
201 UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
202 int lc = vs->Properties.lc;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000203
204
Lee Leahye20a3192017-03-09 16:21:34 -0800205 int state = 0;
206 UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
207 int len = 0;
208 const Byte *Buffer;
209 const Byte *BufferLim;
210 int look_ahead_ptr = 4;
211 union {
212 Byte raw[4];
213 UInt32 dw;
214 } look_ahead;
215 UInt32 Range;
216 UInt32 Code;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000217
Lee Leahye20a3192017-03-09 16:21:34 -0800218 *inSizeProcessed = 0;
219 *outSizeProcessed = 0;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000220
Lee Leahye20a3192017-03-09 16:21:34 -0800221 {
222 UInt32 i;
223 UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc
224 + vs->Properties.lp));
225 for (i = 0; i < numProbs; i++)
226 p[i] = kBitModelTotal >> 1;
227 }
Stefan Reinauer14e22772010-04-27 06:56:47 +0000228
Lee Leahye20a3192017-03-09 16:21:34 -0800229 RC_INIT(inStream, inSize);
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000230
231
Lee Leahye20a3192017-03-09 16:21:34 -0800232 while (nowPos < outSize) {
233 CProb *prob;
234 UInt32 bound;
Lee Leahy35af5c42017-03-09 17:35:28 -0800235 int posState = (int)((nowPos)&posStateMask);
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000236
Lee Leahye20a3192017-03-09 16:21:34 -0800237 prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
238 IfBit0(prob) {
239 int symbol = 1;
Lee Leahyf59a75c2017-03-10 18:07:11 -0800240 UpdateBit0(prob);
Lee Leahye20a3192017-03-09 16:21:34 -0800241 prob = p + Literal + (LZMA_LIT_SIZE *
242 ((((nowPos) & literalPosMask) << lc)
243 + (previousByte >> (8 - lc))));
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000244
Lee Leahye20a3192017-03-09 16:21:34 -0800245 if (state >= kNumLitStates) {
246 int matchByte;
247 matchByte = outStream[nowPos - rep0];
248 do {
249 int bit;
250 CProb *probLit;
251 matchByte <<= 1;
252 bit = (matchByte & 0x100);
253 probLit = prob + 0x100 + bit + symbol;
254 RC_GET_BIT2(probLit, symbol,
255 if (bit != 0)
256 break,
257 if (bit == 0)
258 break)
259 } while (symbol < 0x100);
260 }
261 while (symbol < 0x100) {
262 CProb *probLit = prob + symbol;
263 RC_GET_BIT(probLit, symbol)
264 }
265 previousByte = (Byte)symbol;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000266
Lee Leahye20a3192017-03-09 16:21:34 -0800267 outStream[nowPos++] = previousByte;
268 if (state < 4)
269 state = 0;
270 else if (state < 10)
271 state -= 3;
272 else
273 state -= 6;
274 } else {
275 UpdateBit1(prob);
276 prob = p + IsRep + state;
277 IfBit0(prob) {
278 UpdateBit0(prob);
279 rep3 = rep2;
280 rep2 = rep1;
281 rep1 = rep0;
282 state = state < kNumLitStates ? 0 : 3;
283 prob = p + LenCoder;
284 } else {
285 UpdateBit1(prob);
286 prob = p + IsRepG0 + state;
287 IfBit0(prob) {
288 UpdateBit0(prob);
Lee Leahy73402172017-03-10 15:23:24 -0800289 prob = p + IsRep0Long
290 + (state << kNumPosBitsMax)
291 + posState;
Lee Leahye20a3192017-03-09 16:21:34 -0800292 IfBit0(prob) {
293 UpdateBit0(prob);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000294
Lee Leahye20a3192017-03-09 16:21:34 -0800295 if (nowPos == 0)
296 return LZMA_RESULT_DATA_ERROR;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000297
Lee Leahy73402172017-03-10 15:23:24 -0800298 state = state < kNumLitStates
299 ? 9 : 11;
300 previousByte = outStream[nowPos
301 - rep0];
302 outStream[nowPos++] =
303 previousByte;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000304
Lee Leahye20a3192017-03-09 16:21:34 -0800305 continue;
Paul Menzeld538dd12018-03-30 10:25:56 +0200306 } else {
Lee Leahye20a3192017-03-09 16:21:34 -0800307 UpdateBit1(prob);
Paul Menzeld538dd12018-03-30 10:25:56 +0200308 }
Lee Leahye20a3192017-03-09 16:21:34 -0800309 } else {
310 UInt32 distance;
311 UpdateBit1(prob);
312 prob = p + IsRepG1 + state;
313 IfBit0(prob) {
314 UpdateBit0(prob);
315 distance = rep1;
316 } else {
317 UpdateBit1(prob);
318 prob = p + IsRepG2 + state;
319 IfBit0(prob) {
320 UpdateBit0(prob);
321 distance = rep2;
322 } else {
323 UpdateBit1(prob);
324 distance = rep3;
325 rep3 = rep2;
326 }
327 rep2 = rep1;
328 }
329 rep1 = rep0;
330 rep0 = distance;
331 }
332 state = state < kNumLitStates ? 8 : 11;
333 prob = p + RepLenCoder;
334 }
335 {
336 int numBits, offset;
337 CProb *probLen = prob + LenChoice;
338 IfBit0(probLen) {
339 UpdateBit0(probLen);
Lee Leahy73402172017-03-10 15:23:24 -0800340 probLen = prob + LenLow
341 + (posState << kLenNumLowBits);
Lee Leahye20a3192017-03-09 16:21:34 -0800342 offset = 0;
343 numBits = kLenNumLowBits;
344 } else {
345 UpdateBit1(probLen);
346 probLen = prob + LenChoice2;
347 IfBit0(probLen) {
348 UpdateBit0(probLen);
Lee Leahy73402172017-03-10 15:23:24 -0800349 probLen = prob + LenMid
350 + (posState <<
351 kLenNumMidBits);
Lee Leahye20a3192017-03-09 16:21:34 -0800352 offset = kLenNumLowSymbols;
353 numBits = kLenNumMidBits;
354 } else {
355 UpdateBit1(probLen);
356 probLen = prob + LenHigh;
Lee Leahy73402172017-03-10 15:23:24 -0800357 offset = kLenNumLowSymbols
358 + kLenNumMidSymbols;
Lee Leahye20a3192017-03-09 16:21:34 -0800359 numBits = kLenNumHighBits;
360 }
361 }
Lee Leahy73402172017-03-10 15:23:24 -0800362 RangeDecoderBitTreeDecode(probLen, numBits,
363 len);
Lee Leahye20a3192017-03-09 16:21:34 -0800364 len += offset;
365 }
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000366
Lee Leahye20a3192017-03-09 16:21:34 -0800367 if (state < 4) {
368 int posSlot;
369 state += kNumLitStates;
370 prob = p + PosSlot +
Lee Leahy73402172017-03-10 15:23:24 -0800371 ((len < kNumLenToPosStates ? len :
372 kNumLenToPosStates - 1) <<
Lee Leahye20a3192017-03-09 16:21:34 -0800373 kNumPosSlotBits);
Lee Leahy73402172017-03-10 15:23:24 -0800374 RangeDecoderBitTreeDecode(prob, kNumPosSlotBits,
375 posSlot);
Lee Leahye20a3192017-03-09 16:21:34 -0800376 if (posSlot >= kStartPosModelIndex) {
Lee Leahy73402172017-03-10 15:23:24 -0800377 int numDirectBits = ((posSlot >> 1)
378 - 1);
Lee Leahye20a3192017-03-09 16:21:34 -0800379 rep0 = (2 | ((UInt32)posSlot & 1));
380 if (posSlot < kEndPosModelIndex) {
381 rep0 <<= numDirectBits;
Lee Leahy73402172017-03-10 15:23:24 -0800382 prob = p + SpecPos + rep0
383 - posSlot - 1;
Lee Leahye20a3192017-03-09 16:21:34 -0800384 } else {
385 numDirectBits -= kNumAlignBits;
386 do {
387 RC_NORMALIZE
388 Range >>= 1;
389 rep0 <<= 1;
390 if (Code >= Range) {
391 Code -= Range;
392 rep0 |= 1;
393 }
394 } while (--numDirectBits != 0);
395 prob = p + Align;
396 rep0 <<= kNumAlignBits;
397 numDirectBits = kNumAlignBits;
398 }
399 {
400 int i = 1;
401 int mi = 1;
402 do {
Lee Leahy73402172017-03-10 15:23:24 -0800403 CProb *prob3 = prob
404 + mi;
405 RC_GET_BIT2(prob3, mi,
406 ;, rep0 |= i);
Lee Leahye20a3192017-03-09 16:21:34 -0800407 i <<= 1;
408 } while (--numDirectBits != 0);
409 }
410 } else
411 rep0 = posSlot;
412 if (++rep0 == (UInt32)(0)) {
413 /* it's for stream version */
414 len = kLzmaStreamWasFinishedId;
415 break;
416 }
417 }
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000418
Lee Leahye20a3192017-03-09 16:21:34 -0800419 len += kMatchMinLen;
420 if (rep0 > nowPos)
421 return LZMA_RESULT_DATA_ERROR;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000422
423
Lee Leahye20a3192017-03-09 16:21:34 -0800424 do {
425 previousByte = outStream[nowPos - rep0];
426 len--;
427 outStream[nowPos++] = previousByte;
428 } while (len != 0 && nowPos < outSize);
429 }
430 }
431 RC_NORMALIZE;
Richard Spiegelfb096932018-08-10 15:45:43 -0700432 /*
433 * Tell static analysis we know len can have a dead assignment.
434 */
435 (void)len;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000436
437
Lee Leahye20a3192017-03-09 16:21:34 -0800438 *inSizeProcessed = (SizeT)(Buffer - inStream);
439 *outSizeProcessed = nowPos;
440 return LZMA_RESULT_OK;
Carl-Daniel Hailfingercba07dd2006-09-14 15:12:36 +0000441}