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