1/* 2 LZ4 - Fast LZ compression algorithm 3 Copyright (C) 2011-2015, Yann Collet. 4 5 BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) 6 7 Redistribution and use in source and binary forms, with or without 8 modification, are permitted provided that the following conditions are 9 met: 10 11 * Redistributions of source code must retain the above copyright 12 notice, this list of conditions and the following disclaimer. 13 * Redistributions in binary form must reproduce the above 14 copyright notice, this list of conditions and the following disclaimer 15 in the documentation and/or other materials provided with the 16 distribution. 17 18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30 You can contact the author at : 31 - LZ4 source repository : https://github.com/Cyan4973/lz4 32 - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c 33*/ 34 35 36/************************************** 37* Reading and writing into memory 38**************************************/ 39 40/* customized variant of memcpy, which can overwrite up to 7 bytes beyond dstEnd */ 41static void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd) 42{ 43 BYTE* d = (BYTE*)dstPtr; 44 const BYTE* s = (const BYTE*)srcPtr; 45 BYTE* const e = (BYTE*)dstEnd; 46 47#if 0 48 const size_t l2 = 8 - (((size_t)d) & (sizeof(void*)-1)); 49 LZ4_copy8(d,s); if (d>e-9) return; 50 d+=l2; s+=l2; 51#endif /* join to align */ 52 53 do { LZ4_copy8(d,s); d+=8; s+=8; } while (d<e); 54} 55 56 57/************************************** 58* Common Constants 59**************************************/ 60#define MINMATCH 4 61 62#define WILDCOPYLENGTH 8 63#define LASTLITERALS 5 64#define MFLIMIT (WILDCOPYLENGTH+MINMATCH) 65static const int LZ4_minLength = (MFLIMIT+1); 66 67#define KB *(1 << 10) 68#define MB *(1 << 20) 69#define GB *(1U << 30) 70 71#define MAXD_LOG 16 72#define MAX_DISTANCE ((1 << MAXD_LOG) - 1) 73 74#define ML_BITS 4 75#define ML_MASK ((1U << ML_BITS)-1) 76#define RUN_BITS (8-ML_BITS) 77#define RUN_MASK ((1U << RUN_BITS)-1) 78 79 80/************************************** 81* Local Structures and types 82**************************************/ 83typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive; 84typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive; 85typedef enum { full = 0, partial = 1 } earlyEnd_directive; 86 87 88 89/******************************* 90* Decompression functions 91*******************************/ 92/* 93 * This generic decompression function cover all use cases. 94 * It shall be instantiated several times, using different sets of directives 95 * Note that it is essential this generic function is really inlined, 96 * in order to remove useless branches during compilation optimization. 97 */ 98FORCE_INLINE int LZ4_decompress_generic( 99 const char* const source, 100 char* const dest, 101 int inputSize, 102 int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */ 103 104 int endOnInput, /* endOnOutputSize, endOnInputSize */ 105 int partialDecoding, /* full, partial */ 106 int targetOutputSize, /* only used if partialDecoding==partial */ 107 int dict, /* noDict, withPrefix64k, usingExtDict */ 108 const BYTE* const lowPrefix, /* == dest if dict == noDict */ 109 const BYTE* const dictStart, /* only if dict==usingExtDict */ 110 const size_t dictSize /* note : = 0 if noDict */ 111 ) 112{ 113 /* Local Variables */ 114 const BYTE* ip = (const BYTE*) source; 115 const BYTE* const iend = ip + inputSize; 116 117 BYTE* op = (BYTE*) dest; 118 BYTE* const oend = op + outputSize; 119 BYTE* cpy; 120 BYTE* oexit = op + targetOutputSize; 121 const BYTE* const lowLimit = lowPrefix - dictSize; 122 123 const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; 124 const unsigned dec32table[] = {4, 1, 2, 1, 4, 4, 4, 4}; 125 const int dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3}; 126 127 const int safeDecode = (endOnInput==endOnInputSize); 128 const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); 129 const int inPlaceDecode = ((ip >= op) && (ip < oend)); 130 131 132 /* Special cases */ 133 if ((partialDecoding) && (oexit> oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */ 134 if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */ 135 if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1); 136 137 138 /* Main Loop */ 139 while (1) 140 { 141 unsigned token; 142 size_t length; 143 const BYTE* match; 144 size_t offset; 145 146 if (unlikely((inPlaceDecode) && (op + WILDCOPYLENGTH > ip))) goto _output_error; /* output stream ran over input stream */ 147 148 /* get literal length */ 149 token = *ip++; 150 if ((length=(token>>ML_BITS)) == RUN_MASK) 151 { 152 unsigned s; 153 if ((endOnInput) && unlikely(ip>=iend-RUN_MASK)) goto _output_error; /* overflow detection */ 154 do 155 { 156 s = *ip++; 157 length += s; 158 } 159 while ( likely(endOnInput ? ip<iend-RUN_MASK : 1) && (s==255) ); 160 if ((safeDecode) && unlikely((size_t)(op+length)<(size_t)(op))) goto _output_error; /* overflow detection */ 161 if ((safeDecode) && unlikely((size_t)(ip+length)<(size_t)(ip))) goto _output_error; /* overflow detection */ 162 } 163 164 /* copy literals */ 165 cpy = op+length; 166 if (((endOnInput) && ((cpy>(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) 167 || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH))) 168 { 169 if (partialDecoding) 170 { 171 if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */ 172 if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */ 173 } 174 else 175 { 176 if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */ 177 if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */ 178 } 179 memmove(op, ip, length); 180 ip += length; 181 op += length; 182 break; /* Necessarily EOF, due to parsing restrictions */ 183 } 184 LZ4_wildCopy(op, ip, cpy); 185 ip += length; op = cpy; 186 187 /* get offset */ 188 offset = LZ4_readLE16(ip); ip+=2; 189 match = op - offset; 190 if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside buffers */ 191 192 /* get matchlength */ 193 length = token & ML_MASK; 194 if (length == ML_MASK) 195 { 196 unsigned s; 197 do 198 { 199 if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error; 200 s = *ip++; 201 length += s; 202 } while (s==255); 203 if ((safeDecode) && unlikely((size_t)(op+length)<(size_t)op)) goto _output_error; /* overflow detection */ 204 } 205 length += MINMATCH; 206 207 /* check external dictionary */ 208 if ((dict==usingExtDict) && (match < lowPrefix)) 209 { 210 if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */ 211 212 if (length <= (size_t)(lowPrefix-match)) 213 { 214 /* match can be copied as a single segment from external dictionary */ 215 match = dictEnd - (lowPrefix-match); 216 memmove(op, match, length); op += length; 217 } 218 else 219 { 220 /* match encompass external dictionary and current block */ 221 size_t copySize = (size_t)(lowPrefix-match); 222 memcpy(op, dictEnd - copySize, copySize); 223 op += copySize; 224 copySize = length - copySize; 225 if (copySize > (size_t)(op-lowPrefix)) /* overlap copy */ 226 { 227 BYTE* const endOfMatch = op + copySize; 228 const BYTE* copyFrom = lowPrefix; 229 while (op < endOfMatch) *op++ = *copyFrom++; 230 } 231 else 232 { 233 memcpy(op, lowPrefix, copySize); 234 op += copySize; 235 } 236 } 237 continue; 238 } 239 240 /* copy match within block */ 241 cpy = op + length; 242 if (unlikely(offset<8)) 243 { 244 const int dec64 = dec64table[offset]; 245 op[0] = match[0]; 246 op[1] = match[1]; 247 op[2] = match[2]; 248 op[3] = match[3]; 249 match += dec32table[offset]; 250 memcpy(op+4, match, 4); 251 match -= dec64; 252 } else { LZ4_copy8(op, match); match+=8; } 253 op += 8; 254 255 if (unlikely(cpy>oend-12)) 256 { 257 BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1); 258 if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ 259 if (op < oCopyLimit) 260 { 261 LZ4_wildCopy(op, match, oCopyLimit); 262 match += oCopyLimit - op; 263 op = oCopyLimit; 264 } 265 while (op<cpy) *op++ = *match++; 266 } 267 else 268 LZ4_wildCopy(op, match, cpy); 269 op=cpy; /* correction */ 270 } 271 272 /* end of decoding */ 273 if (endOnInput) 274 return (int) (((char*)op)-dest); /* Nb of output bytes decoded */ 275 else 276 return (int) (((const char*)ip)-source); /* Nb of input bytes read */ 277 278 /* Overflow error detected */ 279_output_error: 280 return (int) (-(((const char*)ip)-source))-1; 281} 282