1*027b728dSJulius Werner /*
2*027b728dSJulius Werner LZ4 - Fast LZ compression algorithm
3*027b728dSJulius Werner Copyright (C) 2011-2015, Yann Collet.
4*027b728dSJulius Werner
5*027b728dSJulius Werner SPDX-License-Identifier: BSD-2-Clause
6*027b728dSJulius Werner
7*027b728dSJulius Werner You can contact the author at :
8*027b728dSJulius Werner - LZ4 source repository : https://github.com/Cyan4973/lz4
9*027b728dSJulius Werner - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
10*027b728dSJulius Werner */
11*027b728dSJulius Werner
12*027b728dSJulius Werner
13*027b728dSJulius Werner /**************************************
14*027b728dSJulius Werner * Reading and writing into memory
15*027b728dSJulius Werner **************************************/
16*027b728dSJulius Werner
17*027b728dSJulius Werner /* customized version of memcpy, which may overwrite up to 7 bytes beyond dstEnd */
LZ4_wildCopy(void * dstPtr,const void * srcPtr,void * dstEnd)18*027b728dSJulius Werner static void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd)
19*027b728dSJulius Werner {
20*027b728dSJulius Werner BYTE* d = (BYTE*)dstPtr;
21*027b728dSJulius Werner const BYTE* s = (const BYTE*)srcPtr;
22*027b728dSJulius Werner BYTE* e = (BYTE*)dstEnd;
23*027b728dSJulius Werner do { LZ4_copy8(d,s); d+=8; s+=8; } while (d<e);
24*027b728dSJulius Werner }
25*027b728dSJulius Werner
26*027b728dSJulius Werner
27*027b728dSJulius Werner /**************************************
28*027b728dSJulius Werner * Common Constants
29*027b728dSJulius Werner **************************************/
30*027b728dSJulius Werner #define MINMATCH 4
31*027b728dSJulius Werner
32*027b728dSJulius Werner #define COPYLENGTH 8
33*027b728dSJulius Werner #define LASTLITERALS 5
34*027b728dSJulius Werner #define MFLIMIT (COPYLENGTH+MINMATCH)
35*027b728dSJulius Werner static const int LZ4_minLength = (MFLIMIT+1);
36*027b728dSJulius Werner
37*027b728dSJulius Werner #define KB *(1 <<10)
38*027b728dSJulius Werner #define MB *(1 <<20)
39*027b728dSJulius Werner #define GB *(1U<<30)
40*027b728dSJulius Werner
41*027b728dSJulius Werner #define MAXD_LOG 16
42*027b728dSJulius Werner #define MAX_DISTANCE ((1 << MAXD_LOG) - 1)
43*027b728dSJulius Werner
44*027b728dSJulius Werner #define ML_BITS 4
45*027b728dSJulius Werner #define ML_MASK ((1U<<ML_BITS)-1)
46*027b728dSJulius Werner #define RUN_BITS (8-ML_BITS)
47*027b728dSJulius Werner #define RUN_MASK ((1U<<RUN_BITS)-1)
48*027b728dSJulius Werner
49*027b728dSJulius Werner
50*027b728dSJulius Werner /**************************************
51*027b728dSJulius Werner * Local Structures and types
52*027b728dSJulius Werner **************************************/
53*027b728dSJulius Werner typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive;
54*027b728dSJulius Werner typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive;
55*027b728dSJulius Werner typedef enum { full = 0, partial = 1 } earlyEnd_directive;
56*027b728dSJulius Werner
57*027b728dSJulius Werner
58*027b728dSJulius Werner
59*027b728dSJulius Werner /*******************************
60*027b728dSJulius Werner * Decompression functions
61*027b728dSJulius Werner *******************************/
62*027b728dSJulius Werner /*
63*027b728dSJulius Werner * This generic decompression function cover all use cases.
64*027b728dSJulius Werner * It shall be instantiated several times, using different sets of directives
65*027b728dSJulius Werner * Note that it is essential this generic function is really inlined,
66*027b728dSJulius Werner * in order to remove useless branches during compilation optimization.
67*027b728dSJulius Werner */
LZ4_decompress_generic(const char * const source,char * const dest,int inputSize,int outputSize,int endOnInput,int partialDecoding,int targetOutputSize,int dict,const BYTE * const lowPrefix,const BYTE * const dictStart,const size_t dictSize)68*027b728dSJulius Werner FORCE_INLINE int LZ4_decompress_generic(
69*027b728dSJulius Werner const char* const source,
70*027b728dSJulius Werner char* const dest,
71*027b728dSJulius Werner int inputSize,
72*027b728dSJulius Werner int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */
73*027b728dSJulius Werner
74*027b728dSJulius Werner int endOnInput, /* endOnOutputSize, endOnInputSize */
75*027b728dSJulius Werner int partialDecoding, /* full, partial */
76*027b728dSJulius Werner int targetOutputSize, /* only used if partialDecoding==partial */
77*027b728dSJulius Werner int dict, /* noDict, withPrefix64k, usingExtDict */
78*027b728dSJulius Werner const BYTE* const lowPrefix, /* == dest if dict == noDict */
79*027b728dSJulius Werner const BYTE* const dictStart, /* only if dict==usingExtDict */
80*027b728dSJulius Werner const size_t dictSize /* note : = 0 if noDict */
81*027b728dSJulius Werner )
82*027b728dSJulius Werner {
83*027b728dSJulius Werner /* Local Variables */
84*027b728dSJulius Werner const BYTE* ip = (const BYTE*) source;
85*027b728dSJulius Werner const BYTE* const iend = ip + inputSize;
86*027b728dSJulius Werner
87*027b728dSJulius Werner BYTE* op = (BYTE*) dest;
88*027b728dSJulius Werner BYTE* const oend = op + outputSize;
89*027b728dSJulius Werner BYTE* cpy;
90*027b728dSJulius Werner BYTE* oexit = op + targetOutputSize;
91*027b728dSJulius Werner const BYTE* const lowLimit = lowPrefix - dictSize;
92*027b728dSJulius Werner
93*027b728dSJulius Werner const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize;
94*027b728dSJulius Werner const size_t dec32table[] = {4, 1, 2, 1, 4, 4, 4, 4};
95*027b728dSJulius Werner const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3};
96*027b728dSJulius Werner
97*027b728dSJulius Werner const int safeDecode = (endOnInput==endOnInputSize);
98*027b728dSJulius Werner const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB)));
99*027b728dSJulius Werner
100*027b728dSJulius Werner
101*027b728dSJulius Werner /* Special cases */
102*027b728dSJulius Werner if ((partialDecoding) && (oexit> oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */
103*027b728dSJulius Werner if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */
104*027b728dSJulius Werner if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1);
105*027b728dSJulius Werner
106*027b728dSJulius Werner
107*027b728dSJulius Werner /* Main Loop */
108*027b728dSJulius Werner while (1)
109*027b728dSJulius Werner {
110*027b728dSJulius Werner unsigned token;
111*027b728dSJulius Werner size_t length;
112*027b728dSJulius Werner const BYTE* match;
113*027b728dSJulius Werner
114*027b728dSJulius Werner /* get literal length */
115*027b728dSJulius Werner token = *ip++;
116*027b728dSJulius Werner if ((length=(token>>ML_BITS)) == RUN_MASK)
117*027b728dSJulius Werner {
118*027b728dSJulius Werner unsigned s;
119*027b728dSJulius Werner do
120*027b728dSJulius Werner {
121*027b728dSJulius Werner s = *ip++;
122*027b728dSJulius Werner length += s;
123*027b728dSJulius Werner }
124*027b728dSJulius Werner while (likely((endOnInput)?ip<iend-RUN_MASK:1) && (s==255));
125*027b728dSJulius Werner if ((safeDecode) && unlikely((size_t)(op+length)<(size_t)(op))) goto _output_error; /* overflow detection */
126*027b728dSJulius Werner if ((safeDecode) && unlikely((size_t)(ip+length)<(size_t)(ip))) goto _output_error; /* overflow detection */
127*027b728dSJulius Werner }
128*027b728dSJulius Werner
129*027b728dSJulius Werner /* copy literals */
130*027b728dSJulius Werner cpy = op+length;
131*027b728dSJulius Werner if (((endOnInput) && ((cpy>(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) )
132*027b728dSJulius Werner || ((!endOnInput) && (cpy>oend-COPYLENGTH)))
133*027b728dSJulius Werner {
134*027b728dSJulius Werner if (partialDecoding)
135*027b728dSJulius Werner {
136*027b728dSJulius Werner if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */
137*027b728dSJulius Werner if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */
138*027b728dSJulius Werner }
139*027b728dSJulius Werner else
140*027b728dSJulius Werner {
141*027b728dSJulius Werner if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */
142*027b728dSJulius Werner if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */
143*027b728dSJulius Werner }
144*027b728dSJulius Werner memcpy(op, ip, length);
145*027b728dSJulius Werner ip += length;
146*027b728dSJulius Werner op += length;
147*027b728dSJulius Werner break; /* Necessarily EOF, due to parsing restrictions */
148*027b728dSJulius Werner }
149*027b728dSJulius Werner LZ4_wildCopy(op, ip, cpy);
150*027b728dSJulius Werner ip += length; op = cpy;
151*027b728dSJulius Werner
152*027b728dSJulius Werner /* get offset */
153*027b728dSJulius Werner match = cpy - LZ4_readLE16(ip); ip+=2;
154*027b728dSJulius Werner if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside destination buffer */
155*027b728dSJulius Werner
156*027b728dSJulius Werner /* get matchlength */
157*027b728dSJulius Werner length = token & ML_MASK;
158*027b728dSJulius Werner if (length == ML_MASK)
159*027b728dSJulius Werner {
160*027b728dSJulius Werner unsigned s;
161*027b728dSJulius Werner do
162*027b728dSJulius Werner {
163*027b728dSJulius Werner if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error;
164*027b728dSJulius Werner s = *ip++;
165*027b728dSJulius Werner length += s;
166*027b728dSJulius Werner } while (s==255);
167*027b728dSJulius Werner if ((safeDecode) && unlikely((size_t)(op+length)<(size_t)op)) goto _output_error; /* overflow detection */
168*027b728dSJulius Werner }
169*027b728dSJulius Werner length += MINMATCH;
170*027b728dSJulius Werner
171*027b728dSJulius Werner /* check external dictionary */
172*027b728dSJulius Werner if ((dict==usingExtDict) && (match < lowPrefix))
173*027b728dSJulius Werner {
174*027b728dSJulius Werner if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */
175*027b728dSJulius Werner
176*027b728dSJulius Werner if (length <= (size_t)(lowPrefix-match))
177*027b728dSJulius Werner {
178*027b728dSJulius Werner /* match can be copied as a single segment from external dictionary */
179*027b728dSJulius Werner match = dictEnd - (lowPrefix-match);
180*027b728dSJulius Werner memmove(op, match, length); op += length;
181*027b728dSJulius Werner }
182*027b728dSJulius Werner else
183*027b728dSJulius Werner {
184*027b728dSJulius Werner /* match encompass external dictionary and current segment */
185*027b728dSJulius Werner size_t copySize = (size_t)(lowPrefix-match);
186*027b728dSJulius Werner memcpy(op, dictEnd - copySize, copySize);
187*027b728dSJulius Werner op += copySize;
188*027b728dSJulius Werner copySize = length - copySize;
189*027b728dSJulius Werner if (copySize > (size_t)(op-lowPrefix)) /* overlap within current segment */
190*027b728dSJulius Werner {
191*027b728dSJulius Werner BYTE* const endOfMatch = op + copySize;
192*027b728dSJulius Werner const BYTE* copyFrom = lowPrefix;
193*027b728dSJulius Werner while (op < endOfMatch) *op++ = *copyFrom++;
194*027b728dSJulius Werner }
195*027b728dSJulius Werner else
196*027b728dSJulius Werner {
197*027b728dSJulius Werner memcpy(op, lowPrefix, copySize);
198*027b728dSJulius Werner op += copySize;
199*027b728dSJulius Werner }
200*027b728dSJulius Werner }
201*027b728dSJulius Werner continue;
202*027b728dSJulius Werner }
203*027b728dSJulius Werner
204*027b728dSJulius Werner /* copy repeated sequence */
205*027b728dSJulius Werner cpy = op + length;
206*027b728dSJulius Werner if (unlikely((op-match)<8))
207*027b728dSJulius Werner {
208*027b728dSJulius Werner const size_t dec64 = dec64table[op-match];
209*027b728dSJulius Werner op[0] = match[0];
210*027b728dSJulius Werner op[1] = match[1];
211*027b728dSJulius Werner op[2] = match[2];
212*027b728dSJulius Werner op[3] = match[3];
213*027b728dSJulius Werner match += dec32table[op-match];
214*027b728dSJulius Werner LZ4_copy4(op+4, match);
215*027b728dSJulius Werner op += 8; match -= dec64;
216*027b728dSJulius Werner } else { LZ4_copy8(op, match); op+=8; match+=8; }
217*027b728dSJulius Werner
218*027b728dSJulius Werner if (unlikely(cpy>oend-12))
219*027b728dSJulius Werner {
220*027b728dSJulius Werner if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals */
221*027b728dSJulius Werner if (op < oend-8)
222*027b728dSJulius Werner {
223*027b728dSJulius Werner LZ4_wildCopy(op, match, oend-8);
224*027b728dSJulius Werner match += (oend-8) - op;
225*027b728dSJulius Werner op = oend-8;
226*027b728dSJulius Werner }
227*027b728dSJulius Werner while (op<cpy) *op++ = *match++;
228*027b728dSJulius Werner }
229*027b728dSJulius Werner else
230*027b728dSJulius Werner LZ4_wildCopy(op, match, cpy);
231*027b728dSJulius Werner op=cpy; /* correction */
232*027b728dSJulius Werner }
233*027b728dSJulius Werner
234*027b728dSJulius Werner /* end of decoding */
235*027b728dSJulius Werner if (endOnInput)
236*027b728dSJulius Werner return (int) (((char*)op)-dest); /* Nb of output bytes decoded */
237*027b728dSJulius Werner else
238*027b728dSJulius Werner return (int) (((const char*)ip)-source); /* Nb of input bytes read */
239*027b728dSJulius Werner
240*027b728dSJulius Werner /* Overflow error detected */
241*027b728dSJulius Werner _output_error:
242*027b728dSJulius Werner return (int) (-(((const char*)ip)-source))-1;
243*027b728dSJulius Werner }
244