162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * LZ4 - Fast LZ compression algorithm 362306a36Sopenharmony_ci * Copyright (C) 2011 - 2016, Yann Collet. 462306a36Sopenharmony_ci * BSD 2 - Clause License (http://www.opensource.org/licenses/bsd - license.php) 562306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 662306a36Sopenharmony_ci * modification, are permitted provided that the following conditions are 762306a36Sopenharmony_ci * met: 862306a36Sopenharmony_ci * * Redistributions of source code must retain the above copyright 962306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 1062306a36Sopenharmony_ci * * Redistributions in binary form must reproduce the above 1162306a36Sopenharmony_ci * copyright notice, this list of conditions and the following disclaimer 1262306a36Sopenharmony_ci * in the documentation and/or other materials provided with the 1362306a36Sopenharmony_ci * distribution. 1462306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1562306a36Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1662306a36Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1762306a36Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1862306a36Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1962306a36Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2062306a36Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2162306a36Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2262306a36Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2362306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2462306a36Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2562306a36Sopenharmony_ci * You can contact the author at : 2662306a36Sopenharmony_ci * - LZ4 homepage : http://www.lz4.org 2762306a36Sopenharmony_ci * - LZ4 source repository : https://github.com/lz4/lz4 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * Changed for kernel usage by: 3062306a36Sopenharmony_ci * Sven Schmidt <4sschmid@informatik.uni-hamburg.de> 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/*-************************************ 3462306a36Sopenharmony_ci * Dependencies 3562306a36Sopenharmony_ci **************************************/ 3662306a36Sopenharmony_ci#include <linux/lz4.h> 3762306a36Sopenharmony_ci#include "lz4defs.h" 3862306a36Sopenharmony_ci#include <linux/init.h> 3962306a36Sopenharmony_ci#include <linux/module.h> 4062306a36Sopenharmony_ci#include <linux/kernel.h> 4162306a36Sopenharmony_ci#include <asm/unaligned.h> 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/*-***************************** 4462306a36Sopenharmony_ci * Decompression functions 4562306a36Sopenharmony_ci *******************************/ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define DEBUGLOG(l, ...) {} /* disabled */ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#ifndef assert 5062306a36Sopenharmony_ci#define assert(condition) ((void)0) 5162306a36Sopenharmony_ci#endif 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* 5462306a36Sopenharmony_ci * LZ4_decompress_generic() : 5562306a36Sopenharmony_ci * This generic decompression function covers all use cases. 5662306a36Sopenharmony_ci * It shall be instantiated several times, using different sets of directives. 5762306a36Sopenharmony_ci * Note that it is important for performance that this function really get inlined, 5862306a36Sopenharmony_ci * in order to remove useless branches during compilation optimization. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_cistatic FORCE_INLINE int LZ4_decompress_generic( 6162306a36Sopenharmony_ci const char * const src, 6262306a36Sopenharmony_ci char * const dst, 6362306a36Sopenharmony_ci int srcSize, 6462306a36Sopenharmony_ci /* 6562306a36Sopenharmony_ci * If endOnInput == endOnInputSize, 6662306a36Sopenharmony_ci * this value is `dstCapacity` 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci int outputSize, 6962306a36Sopenharmony_ci /* endOnOutputSize, endOnInputSize */ 7062306a36Sopenharmony_ci endCondition_directive endOnInput, 7162306a36Sopenharmony_ci /* full, partial */ 7262306a36Sopenharmony_ci earlyEnd_directive partialDecoding, 7362306a36Sopenharmony_ci /* noDict, withPrefix64k, usingExtDict */ 7462306a36Sopenharmony_ci dict_directive dict, 7562306a36Sopenharmony_ci /* always <= dst, == dst when no prefix */ 7662306a36Sopenharmony_ci const BYTE * const lowPrefix, 7762306a36Sopenharmony_ci /* only if dict == usingExtDict */ 7862306a36Sopenharmony_ci const BYTE * const dictStart, 7962306a36Sopenharmony_ci /* note : = 0 if noDict */ 8062306a36Sopenharmony_ci const size_t dictSize 8162306a36Sopenharmony_ci ) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci const BYTE *ip = (const BYTE *) src; 8462306a36Sopenharmony_ci const BYTE * const iend = ip + srcSize; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci BYTE *op = (BYTE *) dst; 8762306a36Sopenharmony_ci BYTE * const oend = op + outputSize; 8862306a36Sopenharmony_ci BYTE *cpy; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci const BYTE * const dictEnd = (const BYTE *)dictStart + dictSize; 9162306a36Sopenharmony_ci static const unsigned int inc32table[8] = {0, 1, 2, 1, 0, 4, 4, 4}; 9262306a36Sopenharmony_ci static const int dec64table[8] = {0, 0, 0, -1, -4, 1, 2, 3}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci const int safeDecode = (endOnInput == endOnInputSize); 9562306a36Sopenharmony_ci const int checkOffset = ((safeDecode) && (dictSize < (int)(64 * KB))); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* Set up the "end" pointers for the shortcut. */ 9862306a36Sopenharmony_ci const BYTE *const shortiend = iend - 9962306a36Sopenharmony_ci (endOnInput ? 14 : 8) /*maxLL*/ - 2 /*offset*/; 10062306a36Sopenharmony_ci const BYTE *const shortoend = oend - 10162306a36Sopenharmony_ci (endOnInput ? 14 : 8) /*maxLL*/ - 18 /*maxML*/; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci DEBUGLOG(5, "%s (srcSize:%i, dstSize:%i)", __func__, 10462306a36Sopenharmony_ci srcSize, outputSize); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* Special cases */ 10762306a36Sopenharmony_ci assert(lowPrefix <= op); 10862306a36Sopenharmony_ci assert(src != NULL); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* Empty output buffer */ 11162306a36Sopenharmony_ci if ((endOnInput) && (unlikely(outputSize == 0))) 11262306a36Sopenharmony_ci return ((srcSize == 1) && (*ip == 0)) ? 0 : -1; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if ((!endOnInput) && (unlikely(outputSize == 0))) 11562306a36Sopenharmony_ci return (*ip == 0 ? 1 : -1); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if ((endOnInput) && unlikely(srcSize == 0)) 11862306a36Sopenharmony_ci return -1; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci /* Main Loop : decode sequences */ 12162306a36Sopenharmony_ci while (1) { 12262306a36Sopenharmony_ci size_t length; 12362306a36Sopenharmony_ci const BYTE *match; 12462306a36Sopenharmony_ci size_t offset; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* get literal length */ 12762306a36Sopenharmony_ci unsigned int const token = *ip++; 12862306a36Sopenharmony_ci length = token>>ML_BITS; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* ip < iend before the increment */ 13162306a36Sopenharmony_ci assert(!endOnInput || ip <= iend); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* 13462306a36Sopenharmony_ci * A two-stage shortcut for the most common case: 13562306a36Sopenharmony_ci * 1) If the literal length is 0..14, and there is enough 13662306a36Sopenharmony_ci * space, enter the shortcut and copy 16 bytes on behalf 13762306a36Sopenharmony_ci * of the literals (in the fast mode, only 8 bytes can be 13862306a36Sopenharmony_ci * safely copied this way). 13962306a36Sopenharmony_ci * 2) Further if the match length is 4..18, copy 18 bytes 14062306a36Sopenharmony_ci * in a similar manner; but we ensure that there's enough 14162306a36Sopenharmony_ci * space in the output for those 18 bytes earlier, upon 14262306a36Sopenharmony_ci * entering the shortcut (in other words, there is a 14362306a36Sopenharmony_ci * combined check for both stages). 14462306a36Sopenharmony_ci * 14562306a36Sopenharmony_ci * The & in the likely() below is intentionally not && so that 14662306a36Sopenharmony_ci * some compilers can produce better parallelized runtime code 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_ci if ((endOnInput ? length != RUN_MASK : length <= 8) 14962306a36Sopenharmony_ci /* 15062306a36Sopenharmony_ci * strictly "less than" on input, to re-enter 15162306a36Sopenharmony_ci * the loop with at least one byte 15262306a36Sopenharmony_ci */ 15362306a36Sopenharmony_ci && likely((endOnInput ? ip < shortiend : 1) & 15462306a36Sopenharmony_ci (op <= shortoend))) { 15562306a36Sopenharmony_ci /* Copy the literals */ 15662306a36Sopenharmony_ci LZ4_memcpy(op, ip, endOnInput ? 16 : 8); 15762306a36Sopenharmony_ci op += length; ip += length; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* 16062306a36Sopenharmony_ci * The second stage: 16162306a36Sopenharmony_ci * prepare for match copying, decode full info. 16262306a36Sopenharmony_ci * If it doesn't work out, the info won't be wasted. 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_ci length = token & ML_MASK; /* match length */ 16562306a36Sopenharmony_ci offset = LZ4_readLE16(ip); 16662306a36Sopenharmony_ci ip += 2; 16762306a36Sopenharmony_ci match = op - offset; 16862306a36Sopenharmony_ci assert(match <= op); /* check overflow */ 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* Do not deal with overlapping matches. */ 17162306a36Sopenharmony_ci if ((length != ML_MASK) && 17262306a36Sopenharmony_ci (offset >= 8) && 17362306a36Sopenharmony_ci (dict == withPrefix64k || match >= lowPrefix)) { 17462306a36Sopenharmony_ci /* Copy the match. */ 17562306a36Sopenharmony_ci LZ4_memcpy(op + 0, match + 0, 8); 17662306a36Sopenharmony_ci LZ4_memcpy(op + 8, match + 8, 8); 17762306a36Sopenharmony_ci LZ4_memcpy(op + 16, match + 16, 2); 17862306a36Sopenharmony_ci op += length + MINMATCH; 17962306a36Sopenharmony_ci /* Both stages worked, load the next token. */ 18062306a36Sopenharmony_ci continue; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci /* 18462306a36Sopenharmony_ci * The second stage didn't work out, but the info 18562306a36Sopenharmony_ci * is ready. Propel it right to the point of match 18662306a36Sopenharmony_ci * copying. 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_ci goto _copy_match; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci /* decode literal length */ 19262306a36Sopenharmony_ci if (length == RUN_MASK) { 19362306a36Sopenharmony_ci unsigned int s; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (unlikely(endOnInput ? ip >= iend - RUN_MASK : 0)) { 19662306a36Sopenharmony_ci /* overflow detection */ 19762306a36Sopenharmony_ci goto _output_error; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci do { 20062306a36Sopenharmony_ci s = *ip++; 20162306a36Sopenharmony_ci length += s; 20262306a36Sopenharmony_ci } while (likely(endOnInput 20362306a36Sopenharmony_ci ? ip < iend - RUN_MASK 20462306a36Sopenharmony_ci : 1) & (s == 255)); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if ((safeDecode) 20762306a36Sopenharmony_ci && unlikely((uptrval)(op) + 20862306a36Sopenharmony_ci length < (uptrval)(op))) { 20962306a36Sopenharmony_ci /* overflow detection */ 21062306a36Sopenharmony_ci goto _output_error; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci if ((safeDecode) 21362306a36Sopenharmony_ci && unlikely((uptrval)(ip) + 21462306a36Sopenharmony_ci length < (uptrval)(ip))) { 21562306a36Sopenharmony_ci /* overflow detection */ 21662306a36Sopenharmony_ci goto _output_error; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci /* copy literals */ 22162306a36Sopenharmony_ci cpy = op + length; 22262306a36Sopenharmony_ci LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci if (((endOnInput) && ((cpy > oend - MFLIMIT) 22562306a36Sopenharmony_ci || (ip + length > iend - (2 + 1 + LASTLITERALS)))) 22662306a36Sopenharmony_ci || ((!endOnInput) && (cpy > oend - WILDCOPYLENGTH))) { 22762306a36Sopenharmony_ci if (partialDecoding) { 22862306a36Sopenharmony_ci if (cpy > oend) { 22962306a36Sopenharmony_ci /* 23062306a36Sopenharmony_ci * Partial decoding : 23162306a36Sopenharmony_ci * stop in the middle of literal segment 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ci cpy = oend; 23462306a36Sopenharmony_ci length = oend - op; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci if ((endOnInput) 23762306a36Sopenharmony_ci && (ip + length > iend)) { 23862306a36Sopenharmony_ci /* 23962306a36Sopenharmony_ci * Error : 24062306a36Sopenharmony_ci * read attempt beyond 24162306a36Sopenharmony_ci * end of input buffer 24262306a36Sopenharmony_ci */ 24362306a36Sopenharmony_ci goto _output_error; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci } else { 24662306a36Sopenharmony_ci if ((!endOnInput) 24762306a36Sopenharmony_ci && (cpy != oend)) { 24862306a36Sopenharmony_ci /* 24962306a36Sopenharmony_ci * Error : 25062306a36Sopenharmony_ci * block decoding must 25162306a36Sopenharmony_ci * stop exactly there 25262306a36Sopenharmony_ci */ 25362306a36Sopenharmony_ci goto _output_error; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci if ((endOnInput) 25662306a36Sopenharmony_ci && ((ip + length != iend) 25762306a36Sopenharmony_ci || (cpy > oend))) { 25862306a36Sopenharmony_ci /* 25962306a36Sopenharmony_ci * Error : 26062306a36Sopenharmony_ci * input must be consumed 26162306a36Sopenharmony_ci */ 26262306a36Sopenharmony_ci goto _output_error; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* 26762306a36Sopenharmony_ci * supports overlapping memory regions; only matters 26862306a36Sopenharmony_ci * for in-place decompression scenarios 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_ci LZ4_memmove(op, ip, length); 27162306a36Sopenharmony_ci ip += length; 27262306a36Sopenharmony_ci op += length; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* Necessarily EOF when !partialDecoding. 27562306a36Sopenharmony_ci * When partialDecoding, it is EOF if we've either 27662306a36Sopenharmony_ci * filled the output buffer or 27762306a36Sopenharmony_ci * can't proceed with reading an offset for following match. 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_ci if (!partialDecoding || (cpy == oend) || (ip >= (iend - 2))) 28062306a36Sopenharmony_ci break; 28162306a36Sopenharmony_ci } else { 28262306a36Sopenharmony_ci /* may overwrite up to WILDCOPYLENGTH beyond cpy */ 28362306a36Sopenharmony_ci LZ4_wildCopy(op, ip, cpy); 28462306a36Sopenharmony_ci ip += length; 28562306a36Sopenharmony_ci op = cpy; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* get offset */ 28962306a36Sopenharmony_ci offset = LZ4_readLE16(ip); 29062306a36Sopenharmony_ci ip += 2; 29162306a36Sopenharmony_ci match = op - offset; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci /* get matchlength */ 29462306a36Sopenharmony_ci length = token & ML_MASK; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci_copy_match: 29762306a36Sopenharmony_ci if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) { 29862306a36Sopenharmony_ci /* Error : offset outside buffers */ 29962306a36Sopenharmony_ci goto _output_error; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci /* costs ~1%; silence an msan warning when offset == 0 */ 30362306a36Sopenharmony_ci /* 30462306a36Sopenharmony_ci * note : when partialDecoding, there is no guarantee that 30562306a36Sopenharmony_ci * at least 4 bytes remain available in output buffer 30662306a36Sopenharmony_ci */ 30762306a36Sopenharmony_ci if (!partialDecoding) { 30862306a36Sopenharmony_ci assert(oend > op); 30962306a36Sopenharmony_ci assert(oend - op >= 4); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci LZ4_write32(op, (U32)offset); 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (length == ML_MASK) { 31562306a36Sopenharmony_ci unsigned int s; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci do { 31862306a36Sopenharmony_ci s = *ip++; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if ((endOnInput) && (ip > iend - LASTLITERALS)) 32162306a36Sopenharmony_ci goto _output_error; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci length += s; 32462306a36Sopenharmony_ci } while (s == 255); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if ((safeDecode) 32762306a36Sopenharmony_ci && unlikely( 32862306a36Sopenharmony_ci (uptrval)(op) + length < (uptrval)op)) { 32962306a36Sopenharmony_ci /* overflow detection */ 33062306a36Sopenharmony_ci goto _output_error; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci length += MINMATCH; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* match starting within external dictionary */ 33762306a36Sopenharmony_ci if ((dict == usingExtDict) && (match < lowPrefix)) { 33862306a36Sopenharmony_ci if (unlikely(op + length > oend - LASTLITERALS)) { 33962306a36Sopenharmony_ci /* doesn't respect parsing restriction */ 34062306a36Sopenharmony_ci if (!partialDecoding) 34162306a36Sopenharmony_ci goto _output_error; 34262306a36Sopenharmony_ci length = min(length, (size_t)(oend - op)); 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (length <= (size_t)(lowPrefix - match)) { 34662306a36Sopenharmony_ci /* 34762306a36Sopenharmony_ci * match fits entirely within external 34862306a36Sopenharmony_ci * dictionary : just copy 34962306a36Sopenharmony_ci */ 35062306a36Sopenharmony_ci memmove(op, dictEnd - (lowPrefix - match), 35162306a36Sopenharmony_ci length); 35262306a36Sopenharmony_ci op += length; 35362306a36Sopenharmony_ci } else { 35462306a36Sopenharmony_ci /* 35562306a36Sopenharmony_ci * match stretches into both external 35662306a36Sopenharmony_ci * dictionary and current block 35762306a36Sopenharmony_ci */ 35862306a36Sopenharmony_ci size_t const copySize = (size_t)(lowPrefix - match); 35962306a36Sopenharmony_ci size_t const restSize = length - copySize; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci LZ4_memcpy(op, dictEnd - copySize, copySize); 36262306a36Sopenharmony_ci op += copySize; 36362306a36Sopenharmony_ci if (restSize > (size_t)(op - lowPrefix)) { 36462306a36Sopenharmony_ci /* overlap copy */ 36562306a36Sopenharmony_ci BYTE * const endOfMatch = op + restSize; 36662306a36Sopenharmony_ci const BYTE *copyFrom = lowPrefix; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci while (op < endOfMatch) 36962306a36Sopenharmony_ci *op++ = *copyFrom++; 37062306a36Sopenharmony_ci } else { 37162306a36Sopenharmony_ci LZ4_memcpy(op, lowPrefix, restSize); 37262306a36Sopenharmony_ci op += restSize; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci continue; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* copy match within block */ 37962306a36Sopenharmony_ci cpy = op + length; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci /* 38262306a36Sopenharmony_ci * partialDecoding : 38362306a36Sopenharmony_ci * may not respect endBlock parsing restrictions 38462306a36Sopenharmony_ci */ 38562306a36Sopenharmony_ci assert(op <= oend); 38662306a36Sopenharmony_ci if (partialDecoding && 38762306a36Sopenharmony_ci (cpy > oend - MATCH_SAFEGUARD_DISTANCE)) { 38862306a36Sopenharmony_ci size_t const mlen = min(length, (size_t)(oend - op)); 38962306a36Sopenharmony_ci const BYTE * const matchEnd = match + mlen; 39062306a36Sopenharmony_ci BYTE * const copyEnd = op + mlen; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (matchEnd > op) { 39362306a36Sopenharmony_ci /* overlap copy */ 39462306a36Sopenharmony_ci while (op < copyEnd) 39562306a36Sopenharmony_ci *op++ = *match++; 39662306a36Sopenharmony_ci } else { 39762306a36Sopenharmony_ci LZ4_memcpy(op, match, mlen); 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci op = copyEnd; 40062306a36Sopenharmony_ci if (op == oend) 40162306a36Sopenharmony_ci break; 40262306a36Sopenharmony_ci continue; 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (unlikely(offset < 8)) { 40662306a36Sopenharmony_ci op[0] = match[0]; 40762306a36Sopenharmony_ci op[1] = match[1]; 40862306a36Sopenharmony_ci op[2] = match[2]; 40962306a36Sopenharmony_ci op[3] = match[3]; 41062306a36Sopenharmony_ci match += inc32table[offset]; 41162306a36Sopenharmony_ci LZ4_memcpy(op + 4, match, 4); 41262306a36Sopenharmony_ci match -= dec64table[offset]; 41362306a36Sopenharmony_ci } else { 41462306a36Sopenharmony_ci LZ4_copy8(op, match); 41562306a36Sopenharmony_ci match += 8; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci op += 8; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (unlikely(cpy > oend - MATCH_SAFEGUARD_DISTANCE)) { 42162306a36Sopenharmony_ci BYTE * const oCopyLimit = oend - (WILDCOPYLENGTH - 1); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci if (cpy > oend - LASTLITERALS) { 42462306a36Sopenharmony_ci /* 42562306a36Sopenharmony_ci * Error : last LASTLITERALS bytes 42662306a36Sopenharmony_ci * must be literals (uncompressed) 42762306a36Sopenharmony_ci */ 42862306a36Sopenharmony_ci goto _output_error; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (op < oCopyLimit) { 43262306a36Sopenharmony_ci LZ4_wildCopy(op, match, oCopyLimit); 43362306a36Sopenharmony_ci match += oCopyLimit - op; 43462306a36Sopenharmony_ci op = oCopyLimit; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci while (op < cpy) 43762306a36Sopenharmony_ci *op++ = *match++; 43862306a36Sopenharmony_ci } else { 43962306a36Sopenharmony_ci LZ4_copy8(op, match); 44062306a36Sopenharmony_ci if (length > 16) 44162306a36Sopenharmony_ci LZ4_wildCopy(op + 8, match + 8, cpy); 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci op = cpy; /* wildcopy correction */ 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* end of decoding */ 44762306a36Sopenharmony_ci if (endOnInput) { 44862306a36Sopenharmony_ci /* Nb of output bytes decoded */ 44962306a36Sopenharmony_ci return (int) (((char *)op) - dst); 45062306a36Sopenharmony_ci } else { 45162306a36Sopenharmony_ci /* Nb of input bytes read */ 45262306a36Sopenharmony_ci return (int) (((const char *)ip) - src); 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci /* Overflow error detected */ 45662306a36Sopenharmony_ci_output_error: 45762306a36Sopenharmony_ci return (int) (-(((const char *)ip) - src)) - 1; 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ciint LZ4_decompress_safe(const char *source, char *dest, 46162306a36Sopenharmony_ci int compressedSize, int maxDecompressedSize) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci return LZ4_decompress_generic(source, dest, 46462306a36Sopenharmony_ci compressedSize, maxDecompressedSize, 46562306a36Sopenharmony_ci endOnInputSize, decode_full_block, 46662306a36Sopenharmony_ci noDict, (BYTE *)dest, NULL, 0); 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ciint LZ4_decompress_safe_partial(const char *src, char *dst, 47062306a36Sopenharmony_ci int compressedSize, int targetOutputSize, int dstCapacity) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci dstCapacity = min(targetOutputSize, dstCapacity); 47362306a36Sopenharmony_ci return LZ4_decompress_generic(src, dst, compressedSize, dstCapacity, 47462306a36Sopenharmony_ci endOnInputSize, partial_decode, 47562306a36Sopenharmony_ci noDict, (BYTE *)dst, NULL, 0); 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ciint LZ4_decompress_fast(const char *source, char *dest, int originalSize) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci return LZ4_decompress_generic(source, dest, 0, originalSize, 48162306a36Sopenharmony_ci endOnOutputSize, decode_full_block, 48262306a36Sopenharmony_ci withPrefix64k, 48362306a36Sopenharmony_ci (BYTE *)dest - 64 * KB, NULL, 0); 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci/* ===== Instantiate a few more decoding cases, used more than once. ===== */ 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic int LZ4_decompress_safe_withPrefix64k(const char *source, char *dest, 48962306a36Sopenharmony_ci int compressedSize, int maxOutputSize) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci return LZ4_decompress_generic(source, dest, 49262306a36Sopenharmony_ci compressedSize, maxOutputSize, 49362306a36Sopenharmony_ci endOnInputSize, decode_full_block, 49462306a36Sopenharmony_ci withPrefix64k, 49562306a36Sopenharmony_ci (BYTE *)dest - 64 * KB, NULL, 0); 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistatic int LZ4_decompress_safe_withSmallPrefix(const char *source, char *dest, 49962306a36Sopenharmony_ci int compressedSize, 50062306a36Sopenharmony_ci int maxOutputSize, 50162306a36Sopenharmony_ci size_t prefixSize) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci return LZ4_decompress_generic(source, dest, 50462306a36Sopenharmony_ci compressedSize, maxOutputSize, 50562306a36Sopenharmony_ci endOnInputSize, decode_full_block, 50662306a36Sopenharmony_ci noDict, 50762306a36Sopenharmony_ci (BYTE *)dest - prefixSize, NULL, 0); 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic int LZ4_decompress_safe_forceExtDict(const char *source, char *dest, 51162306a36Sopenharmony_ci int compressedSize, int maxOutputSize, 51262306a36Sopenharmony_ci const void *dictStart, size_t dictSize) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci return LZ4_decompress_generic(source, dest, 51562306a36Sopenharmony_ci compressedSize, maxOutputSize, 51662306a36Sopenharmony_ci endOnInputSize, decode_full_block, 51762306a36Sopenharmony_ci usingExtDict, (BYTE *)dest, 51862306a36Sopenharmony_ci (const BYTE *)dictStart, dictSize); 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic int LZ4_decompress_fast_extDict(const char *source, char *dest, 52262306a36Sopenharmony_ci int originalSize, 52362306a36Sopenharmony_ci const void *dictStart, size_t dictSize) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci return LZ4_decompress_generic(source, dest, 52662306a36Sopenharmony_ci 0, originalSize, 52762306a36Sopenharmony_ci endOnOutputSize, decode_full_block, 52862306a36Sopenharmony_ci usingExtDict, (BYTE *)dest, 52962306a36Sopenharmony_ci (const BYTE *)dictStart, dictSize); 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci/* 53362306a36Sopenharmony_ci * The "double dictionary" mode, for use with e.g. ring buffers: the first part 53462306a36Sopenharmony_ci * of the dictionary is passed as prefix, and the second via dictStart + dictSize. 53562306a36Sopenharmony_ci * These routines are used only once, in LZ4_decompress_*_continue(). 53662306a36Sopenharmony_ci */ 53762306a36Sopenharmony_cistatic FORCE_INLINE 53862306a36Sopenharmony_ciint LZ4_decompress_safe_doubleDict(const char *source, char *dest, 53962306a36Sopenharmony_ci int compressedSize, int maxOutputSize, 54062306a36Sopenharmony_ci size_t prefixSize, 54162306a36Sopenharmony_ci const void *dictStart, size_t dictSize) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci return LZ4_decompress_generic(source, dest, 54462306a36Sopenharmony_ci compressedSize, maxOutputSize, 54562306a36Sopenharmony_ci endOnInputSize, decode_full_block, 54662306a36Sopenharmony_ci usingExtDict, (BYTE *)dest - prefixSize, 54762306a36Sopenharmony_ci (const BYTE *)dictStart, dictSize); 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cistatic FORCE_INLINE 55162306a36Sopenharmony_ciint LZ4_decompress_fast_doubleDict(const char *source, char *dest, 55262306a36Sopenharmony_ci int originalSize, size_t prefixSize, 55362306a36Sopenharmony_ci const void *dictStart, size_t dictSize) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci return LZ4_decompress_generic(source, dest, 55662306a36Sopenharmony_ci 0, originalSize, 55762306a36Sopenharmony_ci endOnOutputSize, decode_full_block, 55862306a36Sopenharmony_ci usingExtDict, (BYTE *)dest - prefixSize, 55962306a36Sopenharmony_ci (const BYTE *)dictStart, dictSize); 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci/* ===== streaming decompression functions ===== */ 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ciint LZ4_setStreamDecode(LZ4_streamDecode_t *LZ4_streamDecode, 56562306a36Sopenharmony_ci const char *dictionary, int dictSize) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci LZ4_streamDecode_t_internal *lz4sd = 56862306a36Sopenharmony_ci &LZ4_streamDecode->internal_donotuse; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci lz4sd->prefixSize = (size_t) dictSize; 57162306a36Sopenharmony_ci lz4sd->prefixEnd = (const BYTE *) dictionary + dictSize; 57262306a36Sopenharmony_ci lz4sd->externalDict = NULL; 57362306a36Sopenharmony_ci lz4sd->extDictSize = 0; 57462306a36Sopenharmony_ci return 1; 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci/* 57862306a36Sopenharmony_ci * *_continue() : 57962306a36Sopenharmony_ci * These decoding functions allow decompression of multiple blocks 58062306a36Sopenharmony_ci * in "streaming" mode. 58162306a36Sopenharmony_ci * Previously decoded blocks must still be available at the memory 58262306a36Sopenharmony_ci * position where they were decoded. 58362306a36Sopenharmony_ci * If it's not possible, save the relevant part of 58462306a36Sopenharmony_ci * decoded data into a safe buffer, 58562306a36Sopenharmony_ci * and indicate where it stands using LZ4_setStreamDecode() 58662306a36Sopenharmony_ci */ 58762306a36Sopenharmony_ciint LZ4_decompress_safe_continue(LZ4_streamDecode_t *LZ4_streamDecode, 58862306a36Sopenharmony_ci const char *source, char *dest, int compressedSize, int maxOutputSize) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci LZ4_streamDecode_t_internal *lz4sd = 59162306a36Sopenharmony_ci &LZ4_streamDecode->internal_donotuse; 59262306a36Sopenharmony_ci int result; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (lz4sd->prefixSize == 0) { 59562306a36Sopenharmony_ci /* The first call, no dictionary yet. */ 59662306a36Sopenharmony_ci assert(lz4sd->extDictSize == 0); 59762306a36Sopenharmony_ci result = LZ4_decompress_safe(source, dest, 59862306a36Sopenharmony_ci compressedSize, maxOutputSize); 59962306a36Sopenharmony_ci if (result <= 0) 60062306a36Sopenharmony_ci return result; 60162306a36Sopenharmony_ci lz4sd->prefixSize = result; 60262306a36Sopenharmony_ci lz4sd->prefixEnd = (BYTE *)dest + result; 60362306a36Sopenharmony_ci } else if (lz4sd->prefixEnd == (BYTE *)dest) { 60462306a36Sopenharmony_ci /* They're rolling the current segment. */ 60562306a36Sopenharmony_ci if (lz4sd->prefixSize >= 64 * KB - 1) 60662306a36Sopenharmony_ci result = LZ4_decompress_safe_withPrefix64k(source, dest, 60762306a36Sopenharmony_ci compressedSize, maxOutputSize); 60862306a36Sopenharmony_ci else if (lz4sd->extDictSize == 0) 60962306a36Sopenharmony_ci result = LZ4_decompress_safe_withSmallPrefix(source, 61062306a36Sopenharmony_ci dest, compressedSize, maxOutputSize, 61162306a36Sopenharmony_ci lz4sd->prefixSize); 61262306a36Sopenharmony_ci else 61362306a36Sopenharmony_ci result = LZ4_decompress_safe_doubleDict(source, dest, 61462306a36Sopenharmony_ci compressedSize, maxOutputSize, 61562306a36Sopenharmony_ci lz4sd->prefixSize, 61662306a36Sopenharmony_ci lz4sd->externalDict, lz4sd->extDictSize); 61762306a36Sopenharmony_ci if (result <= 0) 61862306a36Sopenharmony_ci return result; 61962306a36Sopenharmony_ci lz4sd->prefixSize += result; 62062306a36Sopenharmony_ci lz4sd->prefixEnd += result; 62162306a36Sopenharmony_ci } else { 62262306a36Sopenharmony_ci /* 62362306a36Sopenharmony_ci * The buffer wraps around, or they're 62462306a36Sopenharmony_ci * switching to another buffer. 62562306a36Sopenharmony_ci */ 62662306a36Sopenharmony_ci lz4sd->extDictSize = lz4sd->prefixSize; 62762306a36Sopenharmony_ci lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; 62862306a36Sopenharmony_ci result = LZ4_decompress_safe_forceExtDict(source, dest, 62962306a36Sopenharmony_ci compressedSize, maxOutputSize, 63062306a36Sopenharmony_ci lz4sd->externalDict, lz4sd->extDictSize); 63162306a36Sopenharmony_ci if (result <= 0) 63262306a36Sopenharmony_ci return result; 63362306a36Sopenharmony_ci lz4sd->prefixSize = result; 63462306a36Sopenharmony_ci lz4sd->prefixEnd = (BYTE *)dest + result; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci return result; 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ciint LZ4_decompress_fast_continue(LZ4_streamDecode_t *LZ4_streamDecode, 64162306a36Sopenharmony_ci const char *source, char *dest, int originalSize) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci LZ4_streamDecode_t_internal *lz4sd = &LZ4_streamDecode->internal_donotuse; 64462306a36Sopenharmony_ci int result; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci if (lz4sd->prefixSize == 0) { 64762306a36Sopenharmony_ci assert(lz4sd->extDictSize == 0); 64862306a36Sopenharmony_ci result = LZ4_decompress_fast(source, dest, originalSize); 64962306a36Sopenharmony_ci if (result <= 0) 65062306a36Sopenharmony_ci return result; 65162306a36Sopenharmony_ci lz4sd->prefixSize = originalSize; 65262306a36Sopenharmony_ci lz4sd->prefixEnd = (BYTE *)dest + originalSize; 65362306a36Sopenharmony_ci } else if (lz4sd->prefixEnd == (BYTE *)dest) { 65462306a36Sopenharmony_ci if (lz4sd->prefixSize >= 64 * KB - 1 || 65562306a36Sopenharmony_ci lz4sd->extDictSize == 0) 65662306a36Sopenharmony_ci result = LZ4_decompress_fast(source, dest, 65762306a36Sopenharmony_ci originalSize); 65862306a36Sopenharmony_ci else 65962306a36Sopenharmony_ci result = LZ4_decompress_fast_doubleDict(source, dest, 66062306a36Sopenharmony_ci originalSize, lz4sd->prefixSize, 66162306a36Sopenharmony_ci lz4sd->externalDict, lz4sd->extDictSize); 66262306a36Sopenharmony_ci if (result <= 0) 66362306a36Sopenharmony_ci return result; 66462306a36Sopenharmony_ci lz4sd->prefixSize += originalSize; 66562306a36Sopenharmony_ci lz4sd->prefixEnd += originalSize; 66662306a36Sopenharmony_ci } else { 66762306a36Sopenharmony_ci lz4sd->extDictSize = lz4sd->prefixSize; 66862306a36Sopenharmony_ci lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; 66962306a36Sopenharmony_ci result = LZ4_decompress_fast_extDict(source, dest, 67062306a36Sopenharmony_ci originalSize, lz4sd->externalDict, lz4sd->extDictSize); 67162306a36Sopenharmony_ci if (result <= 0) 67262306a36Sopenharmony_ci return result; 67362306a36Sopenharmony_ci lz4sd->prefixSize = originalSize; 67462306a36Sopenharmony_ci lz4sd->prefixEnd = (BYTE *)dest + originalSize; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci return result; 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ciint LZ4_decompress_safe_usingDict(const char *source, char *dest, 68062306a36Sopenharmony_ci int compressedSize, int maxOutputSize, 68162306a36Sopenharmony_ci const char *dictStart, int dictSize) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci if (dictSize == 0) 68462306a36Sopenharmony_ci return LZ4_decompress_safe(source, dest, 68562306a36Sopenharmony_ci compressedSize, maxOutputSize); 68662306a36Sopenharmony_ci if (dictStart+dictSize == dest) { 68762306a36Sopenharmony_ci if (dictSize >= 64 * KB - 1) 68862306a36Sopenharmony_ci return LZ4_decompress_safe_withPrefix64k(source, dest, 68962306a36Sopenharmony_ci compressedSize, maxOutputSize); 69062306a36Sopenharmony_ci return LZ4_decompress_safe_withSmallPrefix(source, dest, 69162306a36Sopenharmony_ci compressedSize, maxOutputSize, dictSize); 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci return LZ4_decompress_safe_forceExtDict(source, dest, 69462306a36Sopenharmony_ci compressedSize, maxOutputSize, dictStart, dictSize); 69562306a36Sopenharmony_ci} 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ciint LZ4_decompress_fast_usingDict(const char *source, char *dest, 69862306a36Sopenharmony_ci int originalSize, 69962306a36Sopenharmony_ci const char *dictStart, int dictSize) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci if (dictSize == 0 || dictStart + dictSize == dest) 70262306a36Sopenharmony_ci return LZ4_decompress_fast(source, dest, originalSize); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci return LZ4_decompress_fast_extDict(source, dest, originalSize, 70562306a36Sopenharmony_ci dictStart, dictSize); 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci#ifndef STATIC 70962306a36Sopenharmony_ciEXPORT_SYMBOL(LZ4_decompress_safe); 71062306a36Sopenharmony_ciEXPORT_SYMBOL(LZ4_decompress_safe_partial); 71162306a36Sopenharmony_ciEXPORT_SYMBOL(LZ4_decompress_fast); 71262306a36Sopenharmony_ciEXPORT_SYMBOL(LZ4_setStreamDecode); 71362306a36Sopenharmony_ciEXPORT_SYMBOL(LZ4_decompress_safe_continue); 71462306a36Sopenharmony_ciEXPORT_SYMBOL(LZ4_decompress_fast_continue); 71562306a36Sopenharmony_ciEXPORT_SYMBOL(LZ4_decompress_safe_usingDict); 71662306a36Sopenharmony_ciEXPORT_SYMBOL(LZ4_decompress_fast_usingDict); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 71962306a36Sopenharmony_ciMODULE_DESCRIPTION("LZ4 decompressor"); 72062306a36Sopenharmony_ci#endif 721