2013-07-09 03:01:45 +04:00
/*
* LZ4 - Fast LZ compression algorithm
2017-02-25 02:01:12 +03:00
* Copyright ( C ) 2011 - 2016 , Yann Collet .
* BSD 2 - Clause License ( http : //www.opensource.org/licenses/bsd - license.php)
2013-07-09 03:01:45 +04:00
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are
* met :
2017-02-25 02:01:12 +03:00
* * Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* * Redistributions in binary form must reproduce the above
2013-07-09 03:01:45 +04:00
* copyright notice , this list of conditions and the following disclaimer
* in the documentation and / or other materials provided with the
* distribution .
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
* SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT
* LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
2017-02-25 02:01:12 +03:00
* You can contact the author at :
* - LZ4 homepage : http : //www.lz4.org
* - LZ4 source repository : https : //github.com/lz4/lz4
2013-07-09 03:01:45 +04:00
*
2017-02-25 02:01:12 +03:00
* Changed for kernel usage by :
* Sven Schmidt < 4 sschmid @ informatik . uni - hamburg . de >
2013-07-09 03:01:45 +04:00
*/
2017-02-25 02:01:12 +03:00
/*-************************************
* Dependencies
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/lz4.h>
# include "lz4defs.h"
# include <linux/init.h>
2013-07-09 03:01:45 +04:00
# include <linux/module.h>
# include <linux/kernel.h>
# include <asm/unaligned.h>
2017-02-25 02:01:12 +03:00
/*-*****************************
* Decompression functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2018-10-31 01:07:28 +03:00
# define DEBUGLOG(l, ...) {} /* disabled */
# ifndef assert
# define assert(condition) ((void)0)
# endif
/*
* LZ4_decompress_generic ( ) :
* This generic decompression function covers all use cases .
* It shall be instantiated several times , using different sets of directives .
* Note that it is important for performance that this function really get inlined ,
2017-02-25 02:01:12 +03:00
* in order to remove useless branches during compilation optimization .
*/
static FORCE_INLINE int LZ4_decompress_generic (
2018-10-31 01:07:28 +03:00
const char * const src ,
char * const dst ,
int srcSize ,
2017-02-25 02:01:12 +03:00
/*
* If endOnInput = = endOnInputSize ,
2018-10-31 01:07:28 +03:00
* this value is ` dstCapacity `
2017-02-25 02:01:12 +03:00
*/
int outputSize ,
/* endOnOutputSize, endOnInputSize */
2018-10-31 01:07:28 +03:00
endCondition_directive endOnInput ,
2017-02-25 02:01:12 +03:00
/* full, partial */
2018-10-31 01:07:28 +03:00
earlyEnd_directive partialDecoding ,
2017-02-25 02:01:12 +03:00
/* noDict, withPrefix64k, usingExtDict */
2018-10-31 01:07:28 +03:00
dict_directive dict ,
/* always <= dst, == dst when no prefix */
2017-02-25 02:01:12 +03:00
const BYTE * const lowPrefix ,
/* only if dict == usingExtDict */
const BYTE * const dictStart ,
/* note : = 0 if noDict */
const size_t dictSize
)
2013-07-09 03:01:45 +04:00
{
2018-10-31 01:07:28 +03:00
const BYTE * ip = ( const BYTE * ) src ;
const BYTE * const iend = ip + srcSize ;
2017-02-25 02:01:12 +03:00
2018-10-31 01:07:28 +03:00
BYTE * op = ( BYTE * ) dst ;
2017-02-25 02:01:12 +03:00
BYTE * const oend = op + outputSize ;
2013-07-09 03:01:45 +04:00
BYTE * cpy ;
2017-02-25 02:01:12 +03:00
const BYTE * const dictEnd = ( const BYTE * ) dictStart + dictSize ;
2018-10-31 01:07:28 +03:00
static const unsigned int inc32table [ 8 ] = { 0 , 1 , 2 , 1 , 0 , 4 , 4 , 4 } ;
static const int dec64table [ 8 ] = { 0 , 0 , 0 , - 1 , - 4 , 1 , 2 , 3 } ;
2013-07-09 03:01:45 +04:00
2017-02-25 02:01:12 +03:00
const int safeDecode = ( endOnInput = = endOnInputSize ) ;
const int checkOffset = ( ( safeDecode ) & & ( dictSize < ( int ) ( 64 * KB ) ) ) ;
2018-10-31 01:07:28 +03:00
/* Set up the "end" pointers for the shortcut. */
const BYTE * const shortiend = iend -
( endOnInput ? 14 : 8 ) /*maxLL*/ - 2 /*offset*/ ;
const BYTE * const shortoend = oend -
( endOnInput ? 14 : 8 ) /*maxLL*/ - 18 /*maxML*/ ;
DEBUGLOG ( 5 , " %s (srcSize:%i, dstSize:%i) " , __func__ ,
srcSize , outputSize ) ;
2017-02-25 02:01:12 +03:00
/* Special cases */
2018-10-31 01:07:28 +03:00
assert ( lowPrefix < = op ) ;
assert ( src ! = NULL ) ;
2017-02-25 02:01:12 +03:00
/* Empty output buffer */
if ( ( endOnInput ) & & ( unlikely ( outputSize = = 0 ) ) )
2018-10-31 01:07:28 +03:00
return ( ( srcSize = = 1 ) & & ( * ip = = 0 ) ) ? 0 : - 1 ;
2017-02-25 02:01:12 +03:00
if ( ( ! endOnInput ) & & ( unlikely ( outputSize = = 0 ) ) )
return ( * ip = = 0 ? 1 : - 1 ) ;
2018-10-31 01:07:28 +03:00
if ( ( endOnInput ) & & unlikely ( srcSize = = 0 ) )
return - 1 ;
2017-02-25 02:01:12 +03:00
/* Main Loop : decode sequences */
2013-07-09 03:01:45 +04:00
while ( 1 ) {
2017-02-25 02:01:12 +03:00
size_t length ;
const BYTE * match ;
size_t offset ;
/* get literal length */
unsigned int const token = * ip + + ;
length = token > > ML_BITS ;
2013-07-09 03:01:45 +04:00
2018-10-31 01:07:28 +03:00
/* ip < iend before the increment */
assert ( ! endOnInput | | ip < = iend ) ;
/*
* A two - stage shortcut for the most common case :
* 1 ) If the literal length is 0. .14 , and there is enough
* space , enter the shortcut and copy 16 bytes on behalf
* of the literals ( in the fast mode , only 8 bytes can be
* safely copied this way ) .
* 2 ) Further if the match length is 4. .18 , copy 18 bytes
* in a similar manner ; but we ensure that there ' s enough
* space in the output for those 18 bytes earlier , upon
* entering the shortcut ( in other words , there is a
* combined check for both stages ) .
*/
if ( ( endOnInput ? length ! = RUN_MASK : length < = 8 )
/*
* strictly " less than " on input , to re - enter
* the loop with at least one byte
*/
& & likely ( ( endOnInput ? ip < shortiend : 1 ) &
( op < = shortoend ) ) ) {
/* Copy the literals */
memcpy ( op , ip , endOnInput ? 16 : 8 ) ;
op + = length ; ip + = length ;
/*
* The second stage :
* prepare for match copying , decode full info .
* If it doesn ' t work out , the info won ' t be wasted .
*/
length = token & ML_MASK ; /* match length */
offset = LZ4_readLE16 ( ip ) ;
ip + = 2 ;
match = op - offset ;
assert ( match < = op ) ; /* check overflow */
/* Do not deal with overlapping matches. */
if ( ( length ! = ML_MASK ) & &
( offset > = 8 ) & &
( dict = = withPrefix64k | | match > = lowPrefix ) ) {
/* Copy the match. */
memcpy ( op + 0 , match + 0 , 8 ) ;
memcpy ( op + 8 , match + 8 , 8 ) ;
memcpy ( op + 16 , match + 16 , 2 ) ;
op + = length + MINMATCH ;
/* Both stages worked, load the next token. */
continue ;
}
/*
* The second stage didn ' t work out , but the info
* is ready . Propel it right to the point of match
* copying .
*/
goto _copy_match ;
}
/* decode literal length */
2013-07-09 03:01:45 +04:00
if ( length = = RUN_MASK ) {
2017-02-25 02:01:12 +03:00
unsigned int s ;
2013-07-09 03:01:45 +04:00
2018-10-31 01:07:28 +03:00
if ( unlikely ( endOnInput ? ip > = iend - RUN_MASK : 0 ) ) {
/* overflow detection */
goto _output_error ;
}
2017-02-25 02:01:12 +03:00
do {
s = * ip + + ;
length + = s ;
} while ( likely ( endOnInput
? ip < iend - RUN_MASK
: 1 ) & ( s = = 255 ) ) ;
if ( ( safeDecode )
2018-10-31 01:07:28 +03:00
& & unlikely ( ( uptrval ) ( op ) +
length < ( uptrval ) ( op ) ) ) {
2017-02-25 02:01:12 +03:00
/* overflow detection */
2014-06-21 09:01:41 +04:00
goto _output_error ;
2017-02-25 02:01:12 +03:00
}
if ( ( safeDecode )
2018-10-31 01:07:28 +03:00
& & unlikely ( ( uptrval ) ( ip ) +
length < ( uptrval ) ( ip ) ) ) {
2017-02-25 02:01:12 +03:00
/* overflow detection */
goto _output_error ;
}
2013-07-09 03:01:45 +04:00
}
/* copy literals */
cpy = op + length ;
2018-10-31 01:07:28 +03:00
LZ4_STATIC_ASSERT ( MFLIMIT > = WILDCOPYLENGTH ) ;
if ( ( ( endOnInput ) & & ( ( cpy > oend - MFLIMIT )
2017-02-25 02:01:12 +03:00
| | ( ip + length > iend - ( 2 + 1 + LASTLITERALS ) ) ) )
| | ( ( ! endOnInput ) & & ( cpy > oend - WILDCOPYLENGTH ) ) ) {
if ( partialDecoding ) {
if ( cpy > oend ) {
/*
2018-10-31 01:07:28 +03:00
* Partial decoding :
* stop in the middle of literal segment
2017-02-25 02:01:12 +03:00
*/
2018-10-31 01:07:28 +03:00
cpy = oend ;
length = oend - op ;
2017-02-25 02:01:12 +03:00
}
if ( ( endOnInput )
& & ( ip + length > iend ) ) {
/*
* Error :
* read attempt beyond
* end of input buffer
*/
goto _output_error ;
}
} else {
if ( ( ! endOnInput )
& & ( cpy ! = oend ) ) {
/*
* Error :
* block decoding must
* stop exactly there
*/
goto _output_error ;
}
if ( ( endOnInput )
& & ( ( ip + length ! = iend )
| | ( cpy > oend ) ) ) {
/*
* Error :
* input must be consumed
*/
goto _output_error ;
}
}
2013-07-09 03:01:45 +04:00
memcpy ( op , ip , length ) ;
ip + = length ;
2017-02-25 02:01:12 +03:00
op + = length ;
2018-10-31 01:07:28 +03:00
2017-02-25 02:01:12 +03:00
/* Necessarily EOF, due to parsing restrictions */
2018-10-31 01:07:28 +03:00
if ( ! partialDecoding | | ( cpy = = oend ) )
break ;
} else {
/* may overwrite up to WILDCOPYLENGTH beyond cpy */
LZ4_wildCopy ( op , ip , cpy ) ;
ip + = length ;
op = cpy ;
2013-07-09 03:01:45 +04:00
}
2017-02-25 02:01:12 +03:00
2013-07-09 03:01:45 +04:00
/* get offset */
2017-02-25 02:01:12 +03:00
offset = LZ4_readLE16 ( ip ) ;
2013-07-09 03:01:45 +04:00
ip + = 2 ;
2017-02-25 02:01:12 +03:00
match = op - offset ;
2013-07-09 03:01:45 +04:00
2018-10-31 01:07:28 +03:00
/* get matchlength */
length = token & ML_MASK ;
_copy_match :
if ( ( checkOffset ) & & ( unlikely ( match + dictSize < lowPrefix ) ) ) {
2017-02-25 02:01:12 +03:00
/* Error : offset outside buffers */
2013-07-09 03:01:45 +04:00
goto _output_error ;
2017-02-25 02:01:12 +03:00
}
/* costs ~1%; silence an msan warning when offset == 0 */
2018-10-31 01:07:28 +03:00
/*
* note : when partialDecoding , there is no guarantee that
* at least 4 bytes remain available in output buffer
*/
if ( ! partialDecoding ) {
assert ( oend > op ) ;
assert ( oend - op > = 4 ) ;
LZ4_write32 ( op , ( U32 ) offset ) ;
}
2013-07-09 03:01:45 +04:00
if ( length = = ML_MASK ) {
2017-02-25 02:01:12 +03:00
unsigned int s ;
do {
s = * ip + + ;
if ( ( endOnInput ) & & ( ip > iend - LASTLITERALS ) )
goto _output_error ;
length + = s ;
} while ( s = = 255 ) ;
if ( ( safeDecode )
& & unlikely (
2018-10-31 01:07:28 +03:00
( uptrval ) ( op ) + length < ( uptrval ) op ) ) {
2017-02-25 02:01:12 +03:00
/* overflow detection */
2014-06-25 00:59:01 +04:00
goto _output_error ;
2017-02-25 02:01:12 +03:00
}
2013-07-09 03:01:45 +04:00
}
2017-02-25 02:01:12 +03:00
length + = MINMATCH ;
2018-10-31 01:07:28 +03:00
/* match starting within external dictionary */
2017-02-25 02:01:12 +03:00
if ( ( dict = = usingExtDict ) & & ( match < lowPrefix ) ) {
if ( unlikely ( op + length > oend - LASTLITERALS ) ) {
/* doesn't respect parsing restriction */
2018-10-31 01:07:28 +03:00
if ( ! partialDecoding )
goto _output_error ;
length = min ( length , ( size_t ) ( oend - op ) ) ;
2017-02-25 02:01:12 +03:00
}
if ( length < = ( size_t ) ( lowPrefix - match ) ) {
/*
2018-10-31 01:07:28 +03:00
* match fits entirely within external
* dictionary : just copy
2017-02-25 02:01:12 +03:00
*/
memmove ( op , dictEnd - ( lowPrefix - match ) ,
length ) ;
op + = length ;
} else {
/*
2018-10-31 01:07:28 +03:00
* match stretches into both external
2017-02-25 02:01:12 +03:00
* dictionary and current block
*/
size_t const copySize = ( size_t ) ( lowPrefix - match ) ;
size_t const restSize = length - copySize ;
memcpy ( op , dictEnd - copySize , copySize ) ;
op + = copySize ;
if ( restSize > ( size_t ) ( op - lowPrefix ) ) {
/* overlap copy */
BYTE * const endOfMatch = op + restSize ;
const BYTE * copyFrom = lowPrefix ;
while ( op < endOfMatch )
* op + + = * copyFrom + + ;
} else {
memcpy ( op , lowPrefix , restSize ) ;
op + = restSize ;
}
}
continue ;
}
/* copy match within block */
cpy = op + length ;
2018-10-31 01:07:28 +03:00
/*
* partialDecoding :
* may not respect endBlock parsing restrictions
*/
assert ( op < = oend ) ;
if ( partialDecoding & &
( cpy > oend - MATCH_SAFEGUARD_DISTANCE ) ) {
size_t const mlen = min ( length , ( size_t ) ( oend - op ) ) ;
const BYTE * const matchEnd = match + mlen ;
BYTE * const copyEnd = op + mlen ;
if ( matchEnd > op ) {
/* overlap copy */
while ( op < copyEnd )
* op + + = * match + + ;
} else {
memcpy ( op , match , mlen ) ;
}
op = copyEnd ;
if ( op = = oend )
break ;
continue ;
}
2017-02-25 02:01:12 +03:00
2018-10-31 01:07:28 +03:00
if ( unlikely ( offset < 8 ) ) {
2017-02-25 02:01:12 +03:00
op [ 0 ] = match [ 0 ] ;
op [ 1 ] = match [ 1 ] ;
op [ 2 ] = match [ 2 ] ;
op [ 3 ] = match [ 3 ] ;
2018-10-31 01:07:28 +03:00
match + = inc32table [ offset ] ;
2017-02-25 02:01:12 +03:00
memcpy ( op + 4 , match , 4 ) ;
2018-10-31 01:07:28 +03:00
match - = dec64table [ offset ] ;
2013-07-09 03:01:45 +04:00
} else {
2017-02-25 02:01:12 +03:00
LZ4_copy8 ( op , match ) ;
match + = 8 ;
2013-07-09 03:01:45 +04:00
}
2017-02-25 02:01:12 +03:00
op + = 8 ;
2018-10-31 01:07:28 +03:00
if ( unlikely ( cpy > oend - MATCH_SAFEGUARD_DISTANCE ) ) {
2017-02-25 02:01:12 +03:00
BYTE * const oCopyLimit = oend - ( WILDCOPYLENGTH - 1 ) ;
if ( cpy > oend - LASTLITERALS ) {
/*
* Error : last LASTLITERALS bytes
* must be literals ( uncompressed )
*/
2015-03-16 04:03:19 +03:00
goto _output_error ;
2017-02-25 02:01:12 +03:00
}
if ( op < oCopyLimit ) {
LZ4_wildCopy ( op , match , oCopyLimit ) ;
match + = oCopyLimit - op ;
op = oCopyLimit ;
}
2013-07-09 03:01:45 +04:00
while ( op < cpy )
2017-02-25 02:01:12 +03:00
* op + + = * match + + ;
} else {
LZ4_copy8 ( op , match ) ;
if ( length > 16 )
LZ4_wildCopy ( op + 8 , match + 8 , cpy ) ;
2013-07-09 03:01:45 +04:00
}
2018-10-31 01:07:28 +03:00
op = cpy ; /* wildcopy correction */
2013-07-09 03:01:45 +04:00
}
2017-02-25 02:01:12 +03:00
2013-07-09 03:01:45 +04:00
/* end of decoding */
2017-02-25 02:01:12 +03:00
if ( endOnInput ) {
/* Nb of output bytes decoded */
2018-10-31 01:07:28 +03:00
return ( int ) ( ( ( char * ) op ) - dst ) ;
2017-02-25 02:01:12 +03:00
} else {
/* Nb of input bytes read */
2018-10-31 01:07:28 +03:00
return ( int ) ( ( ( const char * ) ip ) - src ) ;
2017-02-25 02:01:12 +03:00
}
2013-07-09 03:01:45 +04:00
2017-02-25 02:01:12 +03:00
/* Overflow error detected */
2013-07-09 03:01:45 +04:00
_output_error :
2018-10-31 01:07:28 +03:00
return ( int ) ( - ( ( ( const char * ) ip ) - src ) ) - 1 ;
2013-07-09 03:01:45 +04:00
}
2017-02-25 02:01:12 +03:00
int LZ4_decompress_safe ( const char * source , char * dest ,
int compressedSize , int maxDecompressedSize )
2013-07-09 03:01:45 +04:00
{
2018-10-31 01:07:28 +03:00
return LZ4_decompress_generic ( source , dest ,
compressedSize , maxDecompressedSize ,
endOnInputSize , decode_full_block ,
noDict , ( BYTE * ) dest , NULL , 0 ) ;
2017-02-25 02:01:12 +03:00
}
2013-07-09 03:01:45 +04:00
2018-10-31 01:07:28 +03:00
int LZ4_decompress_safe_partial ( const char * src , char * dst ,
int compressedSize , int targetOutputSize , int dstCapacity )
2017-02-25 02:01:12 +03:00
{
2018-10-31 01:07:28 +03:00
dstCapacity = min ( targetOutputSize , dstCapacity ) ;
return LZ4_decompress_generic ( src , dst , compressedSize , dstCapacity ,
endOnInputSize , partial_decode ,
noDict , ( BYTE * ) dst , NULL , 0 ) ;
2017-02-25 02:01:12 +03:00
}
2013-07-09 03:01:45 +04:00
2017-02-25 02:01:12 +03:00
int LZ4_decompress_fast ( const char * source , char * dest , int originalSize )
{
return LZ4_decompress_generic ( source , dest , 0 , originalSize ,
2018-10-31 01:07:28 +03:00
endOnOutputSize , decode_full_block ,
withPrefix64k ,
( BYTE * ) dest - 64 * KB , NULL , 0 ) ;
}
/* ===== Instantiate a few more decoding cases, used more than once. ===== */
int LZ4_decompress_safe_withPrefix64k ( const char * source , char * dest ,
int compressedSize , int maxOutputSize )
{
return LZ4_decompress_generic ( source , dest ,
compressedSize , maxOutputSize ,
endOnInputSize , decode_full_block ,
withPrefix64k ,
( BYTE * ) dest - 64 * KB , NULL , 0 ) ;
}
static int LZ4_decompress_safe_withSmallPrefix ( const char * source , char * dest ,
int compressedSize ,
int maxOutputSize ,
size_t prefixSize )
{
return LZ4_decompress_generic ( source , dest ,
compressedSize , maxOutputSize ,
endOnInputSize , decode_full_block ,
noDict ,
( BYTE * ) dest - prefixSize , NULL , 0 ) ;
}
int LZ4_decompress_safe_forceExtDict ( const char * source , char * dest ,
int compressedSize , int maxOutputSize ,
const void * dictStart , size_t dictSize )
{
return LZ4_decompress_generic ( source , dest ,
compressedSize , maxOutputSize ,
endOnInputSize , decode_full_block ,
usingExtDict , ( BYTE * ) dest ,
( const BYTE * ) dictStart , dictSize ) ;
2017-02-25 02:01:12 +03:00
}
2013-07-09 03:01:45 +04:00
2018-10-31 01:07:28 +03:00
static int LZ4_decompress_fast_extDict ( const char * source , char * dest ,
int originalSize ,
const void * dictStart , size_t dictSize )
{
return LZ4_decompress_generic ( source , dest ,
0 , originalSize ,
endOnOutputSize , decode_full_block ,
usingExtDict , ( BYTE * ) dest ,
( const BYTE * ) dictStart , dictSize ) ;
}
/*
* The " double dictionary " mode , for use with e . g . ring buffers : the first part
* of the dictionary is passed as prefix , and the second via dictStart + dictSize .
* These routines are used only once , in LZ4_decompress_ * _continue ( ) .
*/
static FORCE_INLINE
int LZ4_decompress_safe_doubleDict ( const char * source , char * dest ,
int compressedSize , int maxOutputSize ,
size_t prefixSize ,
const void * dictStart , size_t dictSize )
{
return LZ4_decompress_generic ( source , dest ,
compressedSize , maxOutputSize ,
endOnInputSize , decode_full_block ,
usingExtDict , ( BYTE * ) dest - prefixSize ,
( const BYTE * ) dictStart , dictSize ) ;
}
static FORCE_INLINE
int LZ4_decompress_fast_doubleDict ( const char * source , char * dest ,
int originalSize , size_t prefixSize ,
const void * dictStart , size_t dictSize )
{
return LZ4_decompress_generic ( source , dest ,
0 , originalSize ,
endOnOutputSize , decode_full_block ,
usingExtDict , ( BYTE * ) dest - prefixSize ,
( const BYTE * ) dictStart , dictSize ) ;
}
/* ===== streaming decompression functions ===== */
2017-02-25 02:01:12 +03:00
int LZ4_setStreamDecode ( LZ4_streamDecode_t * LZ4_streamDecode ,
const char * dictionary , int dictSize )
{
2018-10-31 01:07:28 +03:00
LZ4_streamDecode_t_internal * lz4sd =
& LZ4_streamDecode - > internal_donotuse ;
2013-07-09 03:01:45 +04:00
2017-02-25 02:01:12 +03:00
lz4sd - > prefixSize = ( size_t ) dictSize ;
lz4sd - > prefixEnd = ( const BYTE * ) dictionary + dictSize ;
lz4sd - > externalDict = NULL ;
lz4sd - > extDictSize = 0 ;
return 1 ;
}
2013-07-09 03:01:45 +04:00
2017-02-25 02:01:12 +03:00
/*
* * _continue ( ) :
* These decoding functions allow decompression of multiple blocks
* in " streaming " mode .
* Previously decoded blocks must still be available at the memory
* position where they were decoded .
* If it ' s not possible , save the relevant part of
* decoded data into a safe buffer ,
* and indicate where it stands using LZ4_setStreamDecode ( )
*/
int LZ4_decompress_safe_continue ( LZ4_streamDecode_t * LZ4_streamDecode ,
const char * source , char * dest , int compressedSize , int maxOutputSize )
{
2018-10-31 01:07:28 +03:00
LZ4_streamDecode_t_internal * lz4sd =
& LZ4_streamDecode - > internal_donotuse ;
2017-02-25 02:01:12 +03:00
int result ;
2018-10-31 01:07:28 +03:00
if ( lz4sd - > prefixSize = = 0 ) {
/* The first call, no dictionary yet. */
assert ( lz4sd - > extDictSize = = 0 ) ;
result = LZ4_decompress_safe ( source , dest ,
compressedSize , maxOutputSize ) ;
if ( result < = 0 )
return result ;
lz4sd - > prefixSize = result ;
lz4sd - > prefixEnd = ( BYTE * ) dest + result ;
} else if ( lz4sd - > prefixEnd = = ( BYTE * ) dest ) {
/* They're rolling the current segment. */
if ( lz4sd - > prefixSize > = 64 * KB - 1 )
result = LZ4_decompress_safe_withPrefix64k ( source , dest ,
compressedSize , maxOutputSize ) ;
else if ( lz4sd - > extDictSize = = 0 )
result = LZ4_decompress_safe_withSmallPrefix ( source ,
dest , compressedSize , maxOutputSize ,
lz4sd - > prefixSize ) ;
else
result = LZ4_decompress_safe_doubleDict ( source , dest ,
compressedSize , maxOutputSize ,
lz4sd - > prefixSize ,
lz4sd - > externalDict , lz4sd - > extDictSize ) ;
2017-02-25 02:01:12 +03:00
if ( result < = 0 )
return result ;
lz4sd - > prefixSize + = result ;
2018-10-31 01:07:28 +03:00
lz4sd - > prefixEnd + = result ;
2017-02-25 02:01:12 +03:00
} else {
2018-10-31 01:07:28 +03:00
/*
* The buffer wraps around , or they ' re
* switching to another buffer .
*/
2017-02-25 02:01:12 +03:00
lz4sd - > extDictSize = lz4sd - > prefixSize ;
lz4sd - > externalDict = lz4sd - > prefixEnd - lz4sd - > extDictSize ;
2018-10-31 01:07:28 +03:00
result = LZ4_decompress_safe_forceExtDict ( source , dest ,
2017-02-25 02:01:12 +03:00
compressedSize , maxOutputSize ,
lz4sd - > externalDict , lz4sd - > extDictSize ) ;
if ( result < = 0 )
return result ;
lz4sd - > prefixSize = result ;
2018-10-31 01:07:28 +03:00
lz4sd - > prefixEnd = ( BYTE * ) dest + result ;
2017-02-25 02:01:12 +03:00
}
2013-07-09 03:01:45 +04:00
2017-02-25 02:01:12 +03:00
return result ;
}
2013-07-09 03:01:45 +04:00
2017-02-25 02:01:12 +03:00
int LZ4_decompress_fast_continue ( LZ4_streamDecode_t * LZ4_streamDecode ,
const char * source , char * dest , int originalSize )
{
LZ4_streamDecode_t_internal * lz4sd = & LZ4_streamDecode - > internal_donotuse ;
int result ;
2018-10-31 01:07:28 +03:00
if ( lz4sd - > prefixSize = = 0 ) {
assert ( lz4sd - > extDictSize = = 0 ) ;
result = LZ4_decompress_fast ( source , dest , originalSize ) ;
if ( result < = 0 )
return result ;
lz4sd - > prefixSize = originalSize ;
lz4sd - > prefixEnd = ( BYTE * ) dest + originalSize ;
} else if ( lz4sd - > prefixEnd = = ( BYTE * ) dest ) {
if ( lz4sd - > prefixSize > = 64 * KB - 1 | |
lz4sd - > extDictSize = = 0 )
result = LZ4_decompress_fast ( source , dest ,
originalSize ) ;
else
result = LZ4_decompress_fast_doubleDict ( source , dest ,
originalSize , lz4sd - > prefixSize ,
lz4sd - > externalDict , lz4sd - > extDictSize ) ;
2017-02-25 02:01:12 +03:00
if ( result < = 0 )
return result ;
lz4sd - > prefixSize + = originalSize ;
2018-10-31 01:07:28 +03:00
lz4sd - > prefixEnd + = originalSize ;
2017-02-25 02:01:12 +03:00
} else {
lz4sd - > extDictSize = lz4sd - > prefixSize ;
lz4sd - > externalDict = lz4sd - > prefixEnd - lz4sd - > extDictSize ;
2018-10-31 01:07:28 +03:00
result = LZ4_decompress_fast_extDict ( source , dest ,
originalSize , lz4sd - > externalDict , lz4sd - > extDictSize ) ;
2017-02-25 02:01:12 +03:00
if ( result < = 0 )
return result ;
lz4sd - > prefixSize = originalSize ;
2018-10-31 01:07:28 +03:00
lz4sd - > prefixEnd = ( BYTE * ) dest + originalSize ;
2013-07-09 03:01:45 +04:00
}
2017-02-25 02:01:12 +03:00
return result ;
2013-07-09 03:01:45 +04:00
}
2018-10-31 01:07:28 +03:00
int LZ4_decompress_safe_usingDict ( const char * source , char * dest ,
int compressedSize , int maxOutputSize ,
const char * dictStart , int dictSize )
2013-07-09 03:01:45 +04:00
{
2017-02-25 02:01:12 +03:00
if ( dictSize = = 0 )
2018-10-31 01:07:28 +03:00
return LZ4_decompress_safe ( source , dest ,
compressedSize , maxOutputSize ) ;
if ( dictStart + dictSize = = dest ) {
if ( dictSize > = 64 * KB - 1 )
return LZ4_decompress_safe_withPrefix64k ( source , dest ,
compressedSize , maxOutputSize ) ;
return LZ4_decompress_safe_withSmallPrefix ( source , dest ,
compressedSize , maxOutputSize , dictSize ) ;
2017-02-25 02:01:12 +03:00
}
2018-10-31 01:07:28 +03:00
return LZ4_decompress_safe_forceExtDict ( source , dest ,
compressedSize , maxOutputSize , dictStart , dictSize ) ;
2013-07-09 03:01:45 +04:00
}
2017-02-25 02:01:12 +03:00
int LZ4_decompress_fast_usingDict ( const char * source , char * dest ,
2018-10-31 01:07:28 +03:00
int originalSize ,
const char * dictStart , int dictSize )
2013-07-09 03:01:45 +04:00
{
2018-10-31 01:07:28 +03:00
if ( dictSize = = 0 | | dictStart + dictSize = = dest )
return LZ4_decompress_fast ( source , dest , originalSize ) ;
return LZ4_decompress_fast_extDict ( source , dest , originalSize ,
dictStart , dictSize ) ;
2013-07-09 03:01:45 +04:00
}
2017-02-25 02:01:12 +03:00
2013-07-09 03:01:45 +04:00
# ifndef STATIC
2017-02-25 02:01:12 +03:00
EXPORT_SYMBOL ( LZ4_decompress_safe ) ;
EXPORT_SYMBOL ( LZ4_decompress_safe_partial ) ;
EXPORT_SYMBOL ( LZ4_decompress_fast ) ;
EXPORT_SYMBOL ( LZ4_setStreamDecode ) ;
EXPORT_SYMBOL ( LZ4_decompress_safe_continue ) ;
EXPORT_SYMBOL ( LZ4_decompress_fast_continue ) ;
EXPORT_SYMBOL ( LZ4_decompress_safe_usingDict ) ;
EXPORT_SYMBOL ( LZ4_decompress_fast_usingDict ) ;
2013-07-09 03:01:45 +04:00
2013-08-23 03:35:47 +04:00
MODULE_LICENSE ( " Dual BSD/GPL " ) ;
2017-02-25 02:01:12 +03:00
MODULE_DESCRIPTION ( " LZ4 decompressor " ) ;
2013-07-09 03:01:45 +04:00
# endif