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 */ 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 */ 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