2013-07-09 03:01:49 +04:00
/*
* LZ4 HC - High Compression Mode of LZ4
2017-02-25 02:01:12 +03:00
* Copyright ( C ) 2011 - 2015 , Yann Collet .
2013-07-09 03:01:49 +04:00
*
2017-02-25 02:01:12 +03:00
* BSD 2 - Clause License ( http : //www.opensource.org/licenses/bsd - license.php)
2013-07-09 03:01:49 +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:49 +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 .
* You can contact the author at :
2017-02-25 02:01:12 +03:00
* - LZ4 homepage : http : //www.lz4.org
* - LZ4 source repository : https : //github.com/lz4/lz4
2013-07-09 03:01:49 +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:49 +04:00
*/
2017-02-25 02:01:12 +03:00
/*-************************************
* Dependencies
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-07-09 03:01:49 +04:00
# include <linux/lz4.h>
# include "lz4defs.h"
2017-02-25 02:01:12 +03:00
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/string.h> /* memset */
/* *************************************
* Local Constants and types
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-07-09 03:01:49 +04:00
2017-02-25 02:01:12 +03:00
# define OPTIMAL_ML (int)((ML_MASK - 1) + MINMATCH)
2013-07-09 03:01:49 +04:00
2017-02-25 02:01:12 +03:00
# define HASH_FUNCTION(i) (((i) * 2654435761U) \
> > ( ( MINMATCH * 8 ) - LZ4HC_HASH_LOG ) )
# define DELTANEXTU16(p) chainTable[(U16)(p)] /* faster */
static U32 LZ4HC_hashPtr ( const void * ptr )
{
return HASH_FUNCTION ( LZ4_read32 ( ptr ) ) ;
}
/**************************************
* HC Compression
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void LZ4HC_init ( LZ4HC_CCtx_internal * hc4 , const BYTE * start )
2013-07-09 03:01:49 +04:00
{
2017-02-25 02:01:12 +03:00
memset ( ( void * ) hc4 - > hashTable , 0 , sizeof ( hc4 - > hashTable ) ) ;
memset ( hc4 - > chainTable , 0xFF , sizeof ( hc4 - > chainTable ) ) ;
hc4 - > nextToUpdate = 64 * KB ;
hc4 - > base = start - 64 * KB ;
hc4 - > end = start ;
hc4 - > dictBase = start - 64 * KB ;
hc4 - > dictLimit = 64 * KB ;
hc4 - > lowLimit = 64 * KB ;
2013-07-09 03:01:49 +04:00
}
/* Update chains up to ip (excluded) */
2017-02-25 02:01:12 +03:00
static FORCE_INLINE void LZ4HC_Insert ( LZ4HC_CCtx_internal * hc4 ,
const BYTE * ip )
2013-07-09 03:01:49 +04:00
{
2017-02-25 02:01:12 +03:00
U16 * const chainTable = hc4 - > chainTable ;
U32 * const hashTable = hc4 - > hashTable ;
2013-07-09 03:01:49 +04:00
const BYTE * const base = hc4 - > base ;
2017-02-25 02:01:12 +03:00
U32 const target = ( U32 ) ( ip - base ) ;
U32 idx = hc4 - > nextToUpdate ;
while ( idx < target ) {
U32 const h = LZ4HC_hashPtr ( base + idx ) ;
size_t delta = idx - hashTable [ h ] ;
2013-07-09 03:01:49 +04:00
if ( delta > MAX_DISTANCE )
delta = MAX_DISTANCE ;
2017-02-25 02:01:12 +03:00
DELTANEXTU16 ( idx ) = ( U16 ) delta ;
2013-07-09 03:01:49 +04:00
2017-02-25 02:01:12 +03:00
hashTable [ h ] = idx ;
idx + + ;
2013-07-09 03:01:49 +04:00
}
2017-02-25 02:01:12 +03:00
hc4 - > nextToUpdate = target ;
2013-07-09 03:01:49 +04:00
}
2017-02-25 02:01:12 +03:00
static FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (
LZ4HC_CCtx_internal * hc4 , /* Index table will be updated */
const BYTE * ip ,
const BYTE * const iLimit ,
const BYTE * * matchpos ,
const int maxNbAttempts )
2013-07-09 03:01:49 +04:00
{
2017-02-25 02:01:12 +03:00
U16 * const chainTable = hc4 - > chainTable ;
U32 * const HashTable = hc4 - > hashTable ;
2013-07-09 03:01:49 +04:00
const BYTE * const base = hc4 - > base ;
2017-02-25 02:01:12 +03:00
const BYTE * const dictBase = hc4 - > dictBase ;
const U32 dictLimit = hc4 - > dictLimit ;
const U32 lowLimit = ( hc4 - > lowLimit + 64 * KB > ( U32 ) ( ip - base ) )
? hc4 - > lowLimit
: ( U32 ) ( ip - base ) - ( 64 * KB - 1 ) ;
U32 matchIndex ;
int nbAttempts = maxNbAttempts ;
size_t ml = 0 ;
2013-07-09 03:01:49 +04:00
/* HC4 match finder */
2017-02-25 02:01:12 +03:00
LZ4HC_Insert ( hc4 , ip ) ;
matchIndex = HashTable [ LZ4HC_hashPtr ( ip ) ] ;
while ( ( matchIndex > = lowLimit )
& & ( nbAttempts ) ) {
nbAttempts - - ;
if ( matchIndex > = dictLimit ) {
const BYTE * const match = base + matchIndex ;
if ( * ( match + ml ) = = * ( ip + ml )
& & ( LZ4_read32 ( match ) = = LZ4_read32 ( ip ) ) ) {
size_t const mlt = LZ4_count ( ip + MINMATCH ,
match + MINMATCH , iLimit ) + MINMATCH ;
2013-07-09 03:01:49 +04:00
if ( mlt > ml ) {
ml = mlt ;
2017-02-25 02:01:12 +03:00
* matchpos = match ;
}
}
} else {
const BYTE * const match = dictBase + matchIndex ;
if ( LZ4_read32 ( match ) = = LZ4_read32 ( ip ) ) {
size_t mlt ;
const BYTE * vLimit = ip
+ ( dictLimit - matchIndex ) ;
if ( vLimit > iLimit )
vLimit = iLimit ;
mlt = LZ4_count ( ip + MINMATCH ,
match + MINMATCH , vLimit ) + MINMATCH ;
if ( ( ip + mlt = = vLimit )
& & ( vLimit < iLimit ) )
mlt + = LZ4_count ( ip + mlt ,
base + dictLimit ,
iLimit ) ;
if ( mlt > ml ) {
/* virtual matchpos */
ml = mlt ;
* matchpos = base + matchIndex ;
2013-07-09 03:01:49 +04:00
}
}
}
2017-02-25 02:01:12 +03:00
matchIndex - = DELTANEXTU16 ( matchIndex ) ;
2013-07-09 03:01:49 +04:00
}
return ( int ) ml ;
}
2017-02-25 02:01:12 +03:00
static FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch (
LZ4HC_CCtx_internal * hc4 ,
const BYTE * const ip ,
const BYTE * const iLowLimit ,
const BYTE * const iHighLimit ,
int longest ,
const BYTE * * matchpos ,
const BYTE * * startpos ,
const int maxNbAttempts )
2013-07-09 03:01:49 +04:00
{
2017-02-25 02:01:12 +03:00
U16 * const chainTable = hc4 - > chainTable ;
U32 * const HashTable = hc4 - > hashTable ;
2013-07-09 03:01:49 +04:00
const BYTE * const base = hc4 - > base ;
2017-02-25 02:01:12 +03:00
const U32 dictLimit = hc4 - > dictLimit ;
const BYTE * const lowPrefixPtr = base + dictLimit ;
const U32 lowLimit = ( hc4 - > lowLimit + 64 * KB > ( U32 ) ( ip - base ) )
? hc4 - > lowLimit
: ( U32 ) ( ip - base ) - ( 64 * KB - 1 ) ;
const BYTE * const dictBase = hc4 - > dictBase ;
U32 matchIndex ;
int nbAttempts = maxNbAttempts ;
int delta = ( int ) ( ip - iLowLimit ) ;
2013-07-09 03:01:49 +04:00
/* First Match */
2017-02-25 02:01:12 +03:00
LZ4HC_Insert ( hc4 , ip ) ;
matchIndex = HashTable [ LZ4HC_hashPtr ( ip ) ] ;
while ( ( matchIndex > = lowLimit )
& & ( nbAttempts ) ) {
nbAttempts - - ;
if ( matchIndex > = dictLimit ) {
const BYTE * matchPtr = base + matchIndex ;
if ( * ( iLowLimit + longest )
= = * ( matchPtr - delta + longest ) ) {
if ( LZ4_read32 ( matchPtr ) = = LZ4_read32 ( ip ) ) {
int mlt = MINMATCH + LZ4_count (
ip + MINMATCH ,
matchPtr + MINMATCH ,
iHighLimit ) ;
int back = 0 ;
while ( ( ip + back > iLowLimit )
& & ( matchPtr + back > lowPrefixPtr )
& & ( ip [ back - 1 ] = = matchPtr [ back - 1 ] ) )
back - - ;
mlt - = back ;
if ( mlt > longest ) {
longest = ( int ) mlt ;
* matchpos = matchPtr + back ;
* startpos = ip + back ;
2013-07-09 03:01:49 +04:00
}
}
2017-02-25 02:01:12 +03:00
}
} else {
const BYTE * const matchPtr = dictBase + matchIndex ;
if ( LZ4_read32 ( matchPtr ) = = LZ4_read32 ( ip ) ) {
size_t mlt ;
int back = 0 ;
const BYTE * vLimit = ip + ( dictLimit - matchIndex ) ;
if ( vLimit > iHighLimit )
vLimit = iHighLimit ;
mlt = LZ4_count ( ip + MINMATCH ,
matchPtr + MINMATCH , vLimit ) + MINMATCH ;
if ( ( ip + mlt = = vLimit ) & & ( vLimit < iHighLimit ) )
mlt + = LZ4_count ( ip + mlt , base + dictLimit ,
iHighLimit ) ;
while ( ( ip + back > iLowLimit )
& & ( matchIndex + back > lowLimit )
& & ( ip [ back - 1 ] = = matchPtr [ back - 1 ] ) )
back - - ;
mlt - = back ;
if ( ( int ) mlt > longest ) {
longest = ( int ) mlt ;
* matchpos = base + matchIndex + back ;
* startpos = ip + back ;
2013-07-09 03:01:49 +04:00
}
}
}
2017-02-25 02:01:12 +03:00
matchIndex - = DELTANEXTU16 ( matchIndex ) ;
2013-07-09 03:01:49 +04:00
}
2017-02-25 02:01:12 +03:00
2013-07-09 03:01:49 +04:00
return longest ;
}
2017-02-25 02:01:12 +03:00
static FORCE_INLINE int LZ4HC_encodeSequence (
const BYTE * * ip ,
BYTE * * op ,
const BYTE * * anchor ,
int matchLength ,
const BYTE * const match ,
limitedOutput_directive limitedOutputBuffer ,
BYTE * oend )
2013-07-09 03:01:49 +04:00
{
2017-02-25 02:01:12 +03:00
int length ;
BYTE * token ;
2013-07-09 03:01:49 +04:00
/* Encode Literal length */
length = ( int ) ( * ip - * anchor ) ;
token = ( * op ) + + ;
2017-02-25 02:01:12 +03:00
if ( ( limitedOutputBuffer )
& & ( ( * op + ( length > > 8 )
+ length + ( 2 + 1 + LASTLITERALS ) ) > oend ) ) {
/* Check output limit */
return 1 ;
}
2013-07-09 03:01:49 +04:00
if ( length > = ( int ) RUN_MASK ) {
2017-02-25 02:01:12 +03:00
int len ;
* token = ( RUN_MASK < < ML_BITS ) ;
2013-07-09 03:01:49 +04:00
len = length - RUN_MASK ;
for ( ; len > 254 ; len - = 255 )
* ( * op ) + + = 255 ;
2017-02-25 02:01:12 +03:00
* ( * op ) + + = ( BYTE ) len ;
2013-07-09 03:01:49 +04:00
} else
2017-02-25 02:01:12 +03:00
* token = ( BYTE ) ( length < < ML_BITS ) ;
2013-07-09 03:01:49 +04:00
/* Copy Literals */
2017-02-25 02:01:12 +03:00
LZ4_wildCopy ( * op , * anchor , ( * op ) + length ) ;
* op + = length ;
2013-07-09 03:01:49 +04:00
/* Encode Offset */
2017-02-25 02:01:12 +03:00
LZ4_writeLE16 ( * op , ( U16 ) ( * ip - match ) ) ;
* op + = 2 ;
2013-07-09 03:01:49 +04:00
/* Encode MatchLength */
2017-02-25 02:01:12 +03:00
length = ( int ) ( matchLength - MINMATCH ) ;
if ( ( limitedOutputBuffer )
& & ( * op + ( length > > 8 )
+ ( 1 + LASTLITERALS ) > oend ) ) {
/* Check output limit */
return 1 ;
}
if ( length > = ( int ) ML_MASK ) {
2013-07-09 03:01:49 +04:00
* token + = ML_MASK ;
2017-02-25 02:01:12 +03:00
length - = ML_MASK ;
for ( ; length > 509 ; length - = 510 ) {
2013-07-09 03:01:49 +04:00
* ( * op ) + + = 255 ;
* ( * op ) + + = 255 ;
}
2017-02-25 02:01:12 +03:00
if ( length > 254 ) {
length - = 255 ;
2013-07-09 03:01:49 +04:00
* ( * op ) + + = 255 ;
}
2017-02-25 02:01:12 +03:00
* ( * op ) + + = ( BYTE ) length ;
2013-07-09 03:01:49 +04:00
} else
2017-02-25 02:01:12 +03:00
* token + = ( BYTE ) ( length ) ;
2013-07-09 03:01:49 +04:00
/* Prepare next loop */
2017-02-25 02:01:12 +03:00
* ip + = matchLength ;
2013-07-09 03:01:49 +04:00
* anchor = * ip ;
return 0 ;
}
2017-02-25 02:01:12 +03:00
static int LZ4HC_compress_generic (
LZ4HC_CCtx_internal * const ctx ,
const char * const source ,
char * const dest ,
int const inputSize ,
int const maxOutputSize ,
int compressionLevel ,
limitedOutput_directive limit
)
2013-07-09 03:01:49 +04:00
{
2017-02-25 02:01:12 +03:00
const BYTE * ip = ( const BYTE * ) source ;
const BYTE * anchor = ip ;
const BYTE * const iend = ip + inputSize ;
const BYTE * const mflimit = iend - MFLIMIT ;
const BYTE * const matchlimit = ( iend - LASTLITERALS ) ;
2013-07-09 03:01:49 +04:00
2017-02-25 02:01:12 +03:00
BYTE * op = ( BYTE * ) dest ;
BYTE * const oend = op + maxOutputSize ;
2013-07-09 03:01:49 +04:00
2017-02-25 02:01:12 +03:00
unsigned int maxNbAttempts ;
2013-07-09 03:01:49 +04:00
int ml , ml2 , ml3 , ml0 ;
2017-02-25 02:01:12 +03:00
const BYTE * ref = NULL ;
const BYTE * start2 = NULL ;
const BYTE * ref2 = NULL ;
const BYTE * start3 = NULL ;
const BYTE * ref3 = NULL ;
const BYTE * start0 ;
const BYTE * ref0 ;
/* init */
if ( compressionLevel > LZ4HC_MAX_CLEVEL )
compressionLevel = LZ4HC_MAX_CLEVEL ;
if ( compressionLevel < 1 )
compressionLevel = LZ4HC_DEFAULT_CLEVEL ;
maxNbAttempts = 1 < < ( compressionLevel - 1 ) ;
ctx - > end + = inputSize ;
2013-07-09 03:01:49 +04:00
ip + + ;
/* Main Loop */
while ( ip < mflimit ) {
2017-02-25 02:01:12 +03:00
ml = LZ4HC_InsertAndFindBestMatch ( ctx , ip ,
matchlimit , ( & ref ) , maxNbAttempts ) ;
2013-07-09 03:01:49 +04:00
if ( ! ml ) {
ip + + ;
continue ;
}
/* saved, in case we would skip too much */
start0 = ip ;
ref0 = ref ;
ml0 = ml ;
2017-02-25 02:01:12 +03:00
_Search2 :
if ( ip + ml < mflimit )
ml2 = LZ4HC_InsertAndGetWiderMatch ( ctx ,
ip + ml - 2 , ip + 0 ,
matchlimit , ml , & ref2 ,
& start2 , maxNbAttempts ) ;
2013-07-09 03:01:49 +04:00
else
ml2 = ml ;
2017-02-25 02:01:12 +03:00
2013-07-09 03:01:49 +04:00
if ( ml2 = = ml ) {
2017-02-25 02:01:12 +03:00
/* No better match */
if ( LZ4HC_encodeSequence ( & ip , & op ,
& anchor , ml , ref , limit , oend ) )
return 0 ;
2013-07-09 03:01:49 +04:00
continue ;
}
if ( start0 < ip ) {
if ( start2 < ip + ml0 ) {
2017-02-25 02:01:12 +03:00
/* empirical */
2013-07-09 03:01:49 +04:00
ip = start0 ;
ref = ref0 ;
ml = ml0 ;
}
}
2017-02-25 02:01:12 +03:00
/* Here, start0 == ip */
2013-07-09 03:01:49 +04:00
if ( ( start2 - ip ) < 3 ) {
2017-02-25 02:01:12 +03:00
/* First Match too small : removed */
2013-07-09 03:01:49 +04:00
ml = ml2 ;
ip = start2 ;
ref = ref2 ;
2017-02-25 02:01:12 +03:00
goto _Search2 ;
2013-07-09 03:01:49 +04:00
}
2017-02-25 02:01:12 +03:00
_Search3 :
2013-07-09 03:01:49 +04:00
/*
2017-02-25 02:01:12 +03:00
* Currently we have :
* ml2 > ml1 , and
* ip1 + 3 < = ip2 ( usually < ip1 + ml1 )
*/
2013-07-09 03:01:49 +04:00
if ( ( start2 - ip ) < OPTIMAL_ML ) {
int correction ;
int new_ml = ml ;
2017-02-25 02:01:12 +03:00
2013-07-09 03:01:49 +04:00
if ( new_ml > OPTIMAL_ML )
new_ml = OPTIMAL_ML ;
if ( ip + new_ml > start2 + ml2 - MINMATCH )
new_ml = ( int ) ( start2 - ip ) + ml2 - MINMATCH ;
2017-02-25 02:01:12 +03:00
2013-07-09 03:01:49 +04:00
correction = new_ml - ( int ) ( start2 - ip ) ;
2017-02-25 02:01:12 +03:00
2013-07-09 03:01:49 +04:00
if ( correction > 0 ) {
start2 + = correction ;
ref2 + = correction ;
ml2 - = correction ;
}
}
/*
2017-02-25 02:01:12 +03:00
* Now , we have start2 = ip + new_ml ,
* with new_ml = min ( ml , OPTIMAL_ML = 18 )
2013-07-09 03:01:49 +04:00
*/
2017-02-25 02:01:12 +03:00
2013-07-09 03:01:49 +04:00
if ( start2 + ml2 < mflimit )
2017-02-25 02:01:12 +03:00
ml3 = LZ4HC_InsertAndGetWiderMatch ( ctx ,
start2 + ml2 - 3 , start2 ,
matchlimit , ml2 , & ref3 , & start3 ,
maxNbAttempts ) ;
2013-07-09 03:01:49 +04:00
else
ml3 = ml2 ;
if ( ml3 = = ml2 ) {
2017-02-25 02:01:12 +03:00
/* No better match : 2 sequences to encode */
2013-07-09 03:01:49 +04:00
/* ip & ref are known; Now for ml */
2017-02-25 02:01:12 +03:00
if ( start2 < ip + ml )
2013-07-09 03:01:49 +04:00
ml = ( int ) ( start2 - ip ) ;
/* Now, encode 2 sequences */
2017-02-25 02:01:12 +03:00
if ( LZ4HC_encodeSequence ( & ip , & op , & anchor ,
ml , ref , limit , oend ) )
return 0 ;
2013-07-09 03:01:49 +04:00
ip = start2 ;
2017-02-25 02:01:12 +03:00
if ( LZ4HC_encodeSequence ( & ip , & op , & anchor ,
ml2 , ref2 , limit , oend ) )
return 0 ;
2013-07-09 03:01:49 +04:00
continue ;
}
if ( start3 < ip + ml + 3 ) {
2017-02-25 02:01:12 +03:00
/* Not enough space for match 2 : remove it */
2013-07-09 03:01:49 +04:00
if ( start3 > = ( ip + ml ) ) {
2017-02-25 02:01:12 +03:00
/* can write Seq1 immediately
* = = > Seq2 is removed ,
* so Seq3 becomes Seq1
*/
2013-07-09 03:01:49 +04:00
if ( start2 < ip + ml ) {
2017-02-25 02:01:12 +03:00
int correction = ( int ) ( ip + ml - start2 ) ;
2013-07-09 03:01:49 +04:00
start2 + = correction ;
ref2 + = correction ;
ml2 - = correction ;
if ( ml2 < MINMATCH ) {
start2 = start3 ;
ref2 = ref3 ;
ml2 = ml3 ;
}
}
2017-02-25 02:01:12 +03:00
if ( LZ4HC_encodeSequence ( & ip , & op , & anchor ,
ml , ref , limit , oend ) )
return 0 ;
ip = start3 ;
2013-07-09 03:01:49 +04:00
ref = ref3 ;
2017-02-25 02:01:12 +03:00
ml = ml3 ;
2013-07-09 03:01:49 +04:00
start0 = start2 ;
ref0 = ref2 ;
ml0 = ml2 ;
2017-02-25 02:01:12 +03:00
goto _Search2 ;
2013-07-09 03:01:49 +04:00
}
start2 = start3 ;
ref2 = ref3 ;
ml2 = ml3 ;
2017-02-25 02:01:12 +03:00
goto _Search3 ;
2013-07-09 03:01:49 +04:00
}
/*
2017-02-25 02:01:12 +03:00
* OK , now we have 3 ascending matches ;
* let ' s write at least the first one
* ip & ref are known ; Now for ml
*/
2013-07-09 03:01:49 +04:00
if ( start2 < ip + ml ) {
if ( ( start2 - ip ) < ( int ) ML_MASK ) {
int correction ;
2017-02-25 02:01:12 +03:00
2013-07-09 03:01:49 +04:00
if ( ml > OPTIMAL_ML )
ml = OPTIMAL_ML ;
if ( ip + ml > start2 + ml2 - MINMATCH )
2017-02-25 02:01:12 +03:00
ml = ( int ) ( start2 - ip ) + ml2 - MINMATCH ;
2013-07-09 03:01:49 +04:00
correction = ml - ( int ) ( start2 - ip ) ;
if ( correction > 0 ) {
start2 + = correction ;
ref2 + = correction ;
ml2 - = correction ;
}
} else
ml = ( int ) ( start2 - ip ) ;
}
2017-02-25 02:01:12 +03:00
if ( LZ4HC_encodeSequence ( & ip , & op , & anchor , ml ,
ref , limit , oend ) )
return 0 ;
2013-07-09 03:01:49 +04:00
ip = start2 ;
ref = ref2 ;
ml = ml2 ;
start2 = start3 ;
ref2 = ref3 ;
ml2 = ml3 ;
2017-02-25 02:01:12 +03:00
goto _Search3 ;
2013-07-09 03:01:49 +04:00
}
/* Encode Last Literals */
2017-02-25 02:01:12 +03:00
{
int lastRun = ( int ) ( iend - anchor ) ;
if ( ( limit )
& & ( ( ( char * ) op - dest ) + lastRun + 1
+ ( ( lastRun + 255 - RUN_MASK ) / 255 )
> ( U32 ) maxOutputSize ) ) {
/* Check output limit */
return 0 ;
}
if ( lastRun > = ( int ) RUN_MASK ) {
* op + + = ( RUN_MASK < < ML_BITS ) ;
lastRun - = RUN_MASK ;
for ( ; lastRun > 254 ; lastRun - = 255 )
* op + + = 255 ;
* op + + = ( BYTE ) lastRun ;
} else
* op + + = ( BYTE ) ( lastRun < < ML_BITS ) ;
memcpy ( op , anchor , iend - anchor ) ;
op + = iend - anchor ;
}
2013-07-09 03:01:49 +04:00
/* End */
return ( int ) ( ( ( char * ) op ) - dest ) ;
}
2017-02-25 02:01:12 +03:00
static int LZ4_compress_HC_extStateHC (
void * state ,
const char * src ,
char * dst ,
int srcSize ,
int maxDstSize ,
int compressionLevel )
2013-07-09 03:01:49 +04:00
{
2017-02-25 02:01:12 +03:00
LZ4HC_CCtx_internal * ctx = & ( ( LZ4_streamHC_t * ) state ) - > internal_donotuse ;
2013-07-09 03:01:49 +04:00
2017-02-25 02:01:12 +03:00
if ( ( ( size_t ) ( state ) & ( sizeof ( void * ) - 1 ) ) ! = 0 ) {
/* Error : state is not aligned
* for pointers ( 32 or 64 bits )
*/
return 0 ;
}
2013-07-09 03:01:49 +04:00
2017-02-25 02:01:12 +03:00
LZ4HC_init ( ctx , ( const BYTE * ) src ) ;
2013-07-09 03:01:49 +04:00
2017-02-25 02:01:12 +03:00
if ( maxDstSize < LZ4_compressBound ( srcSize ) )
return LZ4HC_compress_generic ( ctx , src , dst ,
srcSize , maxDstSize , compressionLevel , limitedOutput ) ;
else
return LZ4HC_compress_generic ( ctx , src , dst ,
srcSize , maxDstSize , compressionLevel , noLimit ) ;
}
int LZ4_compress_HC ( const char * src , char * dst , int srcSize ,
int maxDstSize , int compressionLevel , void * wrkmem )
{
return LZ4_compress_HC_extStateHC ( wrkmem , src , dst ,
srcSize , maxDstSize , compressionLevel ) ;
}
EXPORT_SYMBOL ( LZ4_compress_HC ) ;
/**************************************
* Streaming Functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void LZ4_resetStreamHC ( LZ4_streamHC_t * LZ4_streamHCPtr , int compressionLevel )
{
LZ4_streamHCPtr - > internal_donotuse . base = NULL ;
LZ4_streamHCPtr - > internal_donotuse . compressionLevel = ( unsigned int ) compressionLevel ;
}
int LZ4_loadDictHC ( LZ4_streamHC_t * LZ4_streamHCPtr ,
const char * dictionary ,
int dictSize )
{
LZ4HC_CCtx_internal * ctxPtr = & LZ4_streamHCPtr - > internal_donotuse ;
if ( dictSize > 64 * KB ) {
dictionary + = dictSize - 64 * KB ;
dictSize = 64 * KB ;
}
LZ4HC_init ( ctxPtr , ( const BYTE * ) dictionary ) ;
if ( dictSize > = 4 )
LZ4HC_Insert ( ctxPtr , ( const BYTE * ) dictionary + ( dictSize - 3 ) ) ;
ctxPtr - > end = ( const BYTE * ) dictionary + dictSize ;
return dictSize ;
}
EXPORT_SYMBOL ( LZ4_loadDictHC ) ;
/* compression */
static void LZ4HC_setExternalDict (
LZ4HC_CCtx_internal * ctxPtr ,
const BYTE * newBlock )
{
if ( ctxPtr - > end > = ctxPtr - > base + 4 ) {
/* Referencing remaining dictionary content */
LZ4HC_Insert ( ctxPtr , ctxPtr - > end - 3 ) ;
}
/*
* Only one memory segment for extDict ,
* so any previous extDict is lost at this stage
*/
ctxPtr - > lowLimit = ctxPtr - > dictLimit ;
ctxPtr - > dictLimit = ( U32 ) ( ctxPtr - > end - ctxPtr - > base ) ;
ctxPtr - > dictBase = ctxPtr - > base ;
ctxPtr - > base = newBlock - ctxPtr - > dictLimit ;
ctxPtr - > end = newBlock ;
/* match referencing will resume from there */
ctxPtr - > nextToUpdate = ctxPtr - > dictLimit ;
}
static int LZ4_compressHC_continue_generic (
LZ4_streamHC_t * LZ4_streamHCPtr ,
const char * source ,
char * dest ,
int inputSize ,
int maxOutputSize ,
limitedOutput_directive limit )
{
LZ4HC_CCtx_internal * ctxPtr = & LZ4_streamHCPtr - > internal_donotuse ;
/* auto - init if forgotten */
if ( ctxPtr - > base = = NULL )
LZ4HC_init ( ctxPtr , ( const BYTE * ) source ) ;
/* Check overflow */
if ( ( size_t ) ( ctxPtr - > end - ctxPtr - > base ) > 2 * GB ) {
size_t dictSize = ( size_t ) ( ctxPtr - > end - ctxPtr - > base )
- ctxPtr - > dictLimit ;
if ( dictSize > 64 * KB )
dictSize = 64 * KB ;
LZ4_loadDictHC ( LZ4_streamHCPtr ,
( const char * ) ( ctxPtr - > end ) - dictSize , ( int ) dictSize ) ;
}
/* Check if blocks follow each other */
if ( ( const BYTE * ) source ! = ctxPtr - > end )
LZ4HC_setExternalDict ( ctxPtr , ( const BYTE * ) source ) ;
/* Check overlapping input/dictionary space */
{
const BYTE * sourceEnd = ( const BYTE * ) source + inputSize ;
const BYTE * const dictBegin = ctxPtr - > dictBase + ctxPtr - > lowLimit ;
const BYTE * const dictEnd = ctxPtr - > dictBase + ctxPtr - > dictLimit ;
if ( ( sourceEnd > dictBegin )
& & ( ( const BYTE * ) source < dictEnd ) ) {
if ( sourceEnd > dictEnd )
sourceEnd = dictEnd ;
ctxPtr - > lowLimit = ( U32 ) ( sourceEnd - ctxPtr - > dictBase ) ;
if ( ctxPtr - > dictLimit - ctxPtr - > lowLimit < 4 )
ctxPtr - > lowLimit = ctxPtr - > dictLimit ;
}
}
return LZ4HC_compress_generic ( ctxPtr , source , dest ,
inputSize , maxOutputSize , ctxPtr - > compressionLevel , limit ) ;
}
int LZ4_compress_HC_continue (
LZ4_streamHC_t * LZ4_streamHCPtr ,
const char * source ,
char * dest ,
int inputSize ,
int maxOutputSize )
{
if ( maxOutputSize < LZ4_compressBound ( inputSize ) )
return LZ4_compressHC_continue_generic ( LZ4_streamHCPtr ,
source , dest , inputSize , maxOutputSize , limitedOutput ) ;
else
return LZ4_compressHC_continue_generic ( LZ4_streamHCPtr ,
source , dest , inputSize , maxOutputSize , noLimit ) ;
}
EXPORT_SYMBOL ( LZ4_compress_HC_continue ) ;
/* dictionary saving */
int LZ4_saveDictHC (
LZ4_streamHC_t * LZ4_streamHCPtr ,
char * safeBuffer ,
int dictSize )
{
LZ4HC_CCtx_internal * const streamPtr = & LZ4_streamHCPtr - > internal_donotuse ;
int const prefixSize = ( int ) ( streamPtr - > end
- ( streamPtr - > base + streamPtr - > dictLimit ) ) ;
if ( dictSize > 64 * KB )
dictSize = 64 * KB ;
if ( dictSize < 4 )
dictSize = 0 ;
if ( dictSize > prefixSize )
dictSize = prefixSize ;
memmove ( safeBuffer , streamPtr - > end - dictSize , dictSize ) ;
2013-07-09 03:01:49 +04:00
2017-02-25 02:01:12 +03:00
{
U32 const endIndex = ( U32 ) ( streamPtr - > end - streamPtr - > base ) ;
streamPtr - > end = ( const BYTE * ) safeBuffer + dictSize ;
streamPtr - > base = streamPtr - > end - endIndex ;
streamPtr - > dictLimit = endIndex - dictSize ;
streamPtr - > lowLimit = endIndex - dictSize ;
if ( streamPtr - > nextToUpdate < streamPtr - > dictLimit )
streamPtr - > nextToUpdate = streamPtr - > dictLimit ;
}
return dictSize ;
}
EXPORT_SYMBOL ( LZ4_saveDictHC ) ;
2013-08-23 03:35:47 +04:00
MODULE_LICENSE ( " Dual BSD/GPL " ) ;
2017-02-25 02:01:12 +03:00
MODULE_DESCRIPTION ( " LZ4 HC compressor " ) ;