2015-10-22 14:31:46 +00:00
/*
ZSTD HC - High Compression Mode of Zstandard
2016-01-28 16:56:33 +00:00
Copyright ( C ) 2015 - 2016 , Yann Collet .
2015-10-22 14:31:46 +00:00
BSD 2 - Clause License ( http : //www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions are
met :
* 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
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 :
- Zstd source repository : https : //www.zstd.net
*/
2015-10-30 14:49:48 +00:00
/* *******************************************************
* Compiler specifics
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef _MSC_VER /* Visual Studio */
# define FORCE_INLINE static __forceinline
# include <intrin.h> /* For Visual 2005 */
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
# else
# ifdef __GNUC__
# define FORCE_INLINE static inline __attribute__((always_inline))
# else
# define FORCE_INLINE static inline
# endif
# endif
2016-02-11 23:07:30 +00:00
/*-*************************************
2016-02-03 01:46:46 +00:00
* Dependencies
2015-10-22 14:31:46 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <stdlib.h> /* malloc */
# include <string.h> /* memset */
2015-11-11 20:38:21 +00:00
# include "mem.h"
# include "fse_static.h"
2016-01-25 03:10:46 +00:00
# include "huff0_static.h"
2015-10-29 16:15:14 +00:00
# include "zstd_internal.h"
2015-10-22 14:31:46 +00:00
2016-02-11 23:07:30 +00:00
/*-*************************************
2015-11-11 20:38:21 +00:00
* Constants
2015-10-22 14:31:46 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-03-19 14:18:42 +00:00
static const U32 g_searchStrength = 8 ; /* control skip over incompressible data */
2015-10-22 14:31:46 +00:00
2016-02-11 23:07:30 +00:00
/*-*************************************
2016-01-23 18:28:41 +00:00
* Helper functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
size_t ZSTD_compressBound ( size_t srcSize ) { return FSE_compressBound ( srcSize ) + 12 ; }
2016-02-11 23:07:30 +00:00
/*-*************************************
2015-11-11 20:38:21 +00:00
* Sequence storage
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void ZSTD_resetSeqStore ( seqStore_t * ssPtr )
{
ssPtr - > offset = ssPtr - > offsetStart ;
ssPtr - > lit = ssPtr - > litStart ;
ssPtr - > litLength = ssPtr - > litLengthStart ;
ssPtr - > matchLength = ssPtr - > matchLengthStart ;
2016-04-07 15:19:00 +00:00
ssPtr - > longLengthID = 0 ;
2015-11-11 20:38:21 +00:00
}
2016-02-11 23:07:30 +00:00
/*-*************************************
2015-11-11 20:38:21 +00:00
* Context memory management
2015-10-22 14:31:46 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-11-11 12:43:58 +00:00
struct ZSTD_CCtx_s
2015-10-22 14:31:46 +00:00
{
2015-11-13 10:27:46 +00:00
const BYTE * nextSrc ; /* next block here to continue on current prefix */
2015-10-22 15:55:40 +00:00
const BYTE * base ; /* All regular indexes relative to this position */
const BYTE * dictBase ; /* extDict indexes relative to this position */
2015-10-22 14:31:46 +00:00
U32 dictLimit ; /* below that point, need extDict */
2015-10-22 15:55:40 +00:00
U32 lowLimit ; /* below that point, no more data */
2015-10-22 14:31:46 +00:00
U32 nextToUpdate ; /* index from which to continue dictionary update */
2016-02-19 09:09:35 +00:00
U32 nextToUpdate3 ; /* index from which to continue dictionary update */
2016-03-23 14:53:38 +00:00
U32 hashLog3 ; /* dispatch table : larger == faster, more memory */
2016-02-02 13:36:49 +00:00
U32 loadedDictEnd ;
2016-01-07 14:35:18 +00:00
U32 stage ;
2015-11-11 12:43:58 +00:00
ZSTD_parameters params ;
2015-10-29 17:41:45 +00:00
void * workSpace ;
size_t workSpaceSize ;
2015-12-02 13:00:45 +00:00
size_t blockSize ;
2016-01-07 14:35:18 +00:00
size_t hbSize ;
2016-03-11 20:58:04 +00:00
char headerBuffer [ ZSTD_FRAMEHEADERSIZE_MAX ] ;
2016-01-07 14:35:18 +00:00
2015-10-29 17:41:45 +00:00
seqStore_t seqStore ; /* sequences storage ptrs */
2015-10-25 13:06:35 +00:00
U32 * hashTable ;
2016-02-19 09:09:35 +00:00
U32 * hashTable3 ;
2016-04-04 11:49:18 +00:00
U32 * chainTable ;
2016-01-26 02:14:20 +00:00
HUF_CElt * hufTable ;
2016-01-27 23:18:06 +00:00
U32 flagStaticTables ;
FSE_CTable offcodeCTable [ FSE_CTABLE_SIZE_U32 ( OffFSELog , MaxOff ) ] ;
FSE_CTable matchlengthCTable [ FSE_CTABLE_SIZE_U32 ( MLFSELog , MaxML ) ] ;
FSE_CTable litlengthCTable [ FSE_CTABLE_SIZE_U32 ( LLFSELog , MaxLL ) ] ;
2015-10-22 14:31:46 +00:00
} ;
2015-11-11 12:43:58 +00:00
ZSTD_CCtx * ZSTD_createCCtx ( void )
2015-10-22 14:31:46 +00:00
{
2015-11-11 12:43:58 +00:00
return ( ZSTD_CCtx * ) calloc ( 1 , sizeof ( ZSTD_CCtx ) ) ;
2015-10-22 14:31:46 +00:00
}
2015-11-11 12:43:58 +00:00
size_t ZSTD_freeCCtx ( ZSTD_CCtx * cctx )
2015-10-25 13:06:35 +00:00
{
2015-10-29 17:41:45 +00:00
free ( cctx - > workSpace ) ;
2015-10-25 13:06:35 +00:00
free ( cctx ) ;
2016-02-05 01:33:10 +00:00
return 0 ; /* reserved as a potential error code in the future */
2015-10-25 13:06:35 +00:00
}
2015-10-22 14:31:46 +00:00
2016-03-26 19:52:14 +00:00
const seqStore_t * ZSTD_getSeqStore ( const ZSTD_CCtx * ctx ) /* hidden interface */
2016-02-11 23:07:30 +00:00
{
2016-03-26 19:52:14 +00:00
return & ( ctx - > seqStore ) ;
2016-02-11 23:07:30 +00:00
}
2015-11-04 11:05:27 +00:00
2016-02-10 12:37:52 +00:00
# define CLAMP(val,min,max) { if (val<min) val=min; else if (val>max) val=max; }
2016-03-30 14:50:44 +00:00
# define CLAMPCHECK(val,min,max) { if ((val<min) || (val>max)) return ERROR(compressionParameter_unsupported); }
/** ZSTD_checkParams() :
ensure param values remain within authorized range .
@ return : 0 , or an error code if one value is beyond authorized range */
2016-03-30 17:48:05 +00:00
size_t ZSTD_checkCParams ( ZSTD_compressionParameters cParams )
2016-03-30 14:50:44 +00:00
{
2016-04-04 02:22:53 +00:00
CLAMPCHECK ( cParams . windowLog , ZSTD_WINDOWLOG_MIN , ZSTD_WINDOWLOG_MAX ) ;
2016-04-04 11:49:18 +00:00
CLAMPCHECK ( cParams . chainLog , ZSTD_CHAINLOG_MIN , ZSTD_CHAINLOG_MAX ) ;
2016-03-30 17:48:05 +00:00
CLAMPCHECK ( cParams . hashLog , ZSTD_HASHLOG_MIN , ZSTD_HASHLOG_MAX ) ;
CLAMPCHECK ( cParams . searchLog , ZSTD_SEARCHLOG_MIN , ZSTD_SEARCHLOG_MAX ) ;
2016-04-06 10:34:42 +00:00
{ U32 const searchLengthMin = ( cParams . strategy = = ZSTD_fast | | cParams . strategy = = ZSTD_greedy ) ? ZSTD_SEARCHLENGTH_MIN + 1 : ZSTD_SEARCHLENGTH_MIN ;
2016-03-30 17:48:05 +00:00
U32 const searchLengthMax = ( cParams . strategy = = ZSTD_fast ) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX - 1 ;
CLAMPCHECK ( cParams . searchLength , searchLengthMin , searchLengthMax ) ; }
CLAMPCHECK ( cParams . targetLength , ZSTD_TARGETLENGTH_MIN , ZSTD_TARGETLENGTH_MAX ) ;
2016-03-30 19:28:15 +00:00
if ( ( U32 ) ( cParams . strategy ) > ( U32 ) ZSTD_btopt ) return ERROR ( compressionParameter_unsupported ) ;
2016-03-30 14:50:44 +00:00
return 0 ;
}
2016-02-10 12:37:52 +00:00
2016-03-30 14:50:44 +00:00
static unsigned ZSTD_highbit ( U32 val ) ;
2016-03-30 17:48:05 +00:00
/** ZSTD_checkCParams_advanced() :
temporary work - around , while the compressor compatibility remains limited regarding windowLog < 18 */
size_t ZSTD_checkCParams_advanced ( ZSTD_compressionParameters cParams , U64 srcSize )
{
2016-04-01 16:54:13 +00:00
if ( srcSize > ( 1ULL < < ZSTD_WINDOWLOG_MIN ) ) return ZSTD_checkCParams ( cParams ) ;
2016-03-30 17:48:05 +00:00
if ( cParams . windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN ) return ERROR ( compressionParameter_unsupported ) ;
2016-04-04 11:49:18 +00:00
if ( srcSize < = ( 1ULL < < cParams . windowLog ) ) cParams . windowLog = ZSTD_WINDOWLOG_MIN ; /* fake value - temporary work around */
if ( srcSize < = ( 1ULL < < cParams . chainLog ) ) cParams . chainLog = ZSTD_CHAINLOG_MIN ; /* fake value - temporary work around */
2016-04-01 22:46:40 +00:00
if ( ( srcSize < = ( 1ULL < < cParams . hashLog ) ) & & ( ( U32 ) cParams . strategy < ( U32 ) ZSTD_btlazy2 ) ) cParams . hashLog = ZSTD_HASHLOG_MIN ; /* fake value - temporary work around */
2016-03-30 17:48:05 +00:00
return ZSTD_checkCParams ( cParams ) ;
}
2016-03-30 14:50:44 +00:00
/** ZSTD_adjustParams() :
optimize params for q given input ( ` srcSize ` and ` dictSize ` ) .
mostly downsizing to reduce memory consumption and initialization .
Both ` srcSize ` and ` dictSize ` are optional ( use 0 if unknown ) ,
but if both are 0 , no optimization can be done .
Note : params is considered validated at this stage . Use ZSTD_checkParams ( ) to ensure that . */
2016-03-30 18:06:26 +00:00
void ZSTD_adjustCParams ( ZSTD_compressionParameters * params , U64 srcSize , size_t dictSize )
2016-03-30 14:50:44 +00:00
{
if ( srcSize + dictSize = = 0 ) return ; /* no size information available : no adjustment */
2015-11-04 11:05:27 +00:00
2016-03-19 17:08:32 +00:00
/* resize params, to use less memory when necessary */
2016-03-30 18:06:26 +00:00
{ U32 const minSrcSize = ( srcSize = = 0 ) ? 500 : 0 ;
U64 const rSize = srcSize + dictSize + minSrcSize ;
2016-04-04 12:53:16 +00:00
if ( rSize < ( ( U64 ) 1 < < ZSTD_WINDOWLOG_MAX ) ) {
2016-03-30 14:50:44 +00:00
U32 const srcLog = ZSTD_highbit ( ( U32 ) ( rSize ) - 1 ) + 1 ;
if ( params - > windowLog > srcLog ) params - > windowLog = srcLog ;
} }
2016-03-19 16:18:00 +00:00
if ( params - > hashLog > params - > windowLog ) params - > hashLog = params - > windowLog ;
2016-03-30 14:50:44 +00:00
{ U32 const btPlus = ( params - > strategy = = ZSTD_btlazy2 ) | | ( params - > strategy = = ZSTD_btopt ) ;
2016-04-04 11:49:18 +00:00
U32 const maxChainLog = params - > windowLog + btPlus ;
if ( params - > chainLog > maxChainLog ) params - > chainLog = maxChainLog ; } /* <= ZSTD_CHAINLOG_MAX */
2016-03-19 16:18:00 +00:00
if ( params - > windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN ) params - > windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN ; /* required for frame header */
2016-04-01 22:40:09 +00:00
if ( ( params - > hashLog < ZSTD_HASHLOG_MIN ) & & ( ( U32 ) params - > strategy > = ( U32 ) ZSTD_btlazy2 ) ) params - > hashLog = ZSTD_HASHLOG_MIN ; /* required to ensure collision resistance in bt */
2015-11-04 11:05:27 +00:00
}
2016-03-30 18:42:19 +00:00
size_t ZSTD_sizeofCCtx ( ZSTD_compressionParameters cParams ) /* hidden interface, for paramagrill */
2016-03-19 15:09:09 +00:00
{
ZSTD_CCtx * zc = ZSTD_createCCtx ( ) ;
2016-03-30 18:42:19 +00:00
ZSTD_parameters params ;
params . cParams = cParams ;
params . fParams . contentSizeFlag = 1 ;
2016-03-30 17:48:05 +00:00
ZSTD_compressBegin_advanced ( zc , NULL , 0 , params , 0 ) ;
2016-03-20 23:07:42 +00:00
{ size_t const ccsize = sizeof ( * zc ) + zc - > workSpaceSize ;
2016-03-19 16:18:00 +00:00
ZSTD_freeCCtx ( zc ) ;
2016-03-20 23:07:42 +00:00
return ccsize ; }
2016-03-08 11:22:11 +00:00
}
2016-04-01 13:48:48 +00:00
/*! ZSTD_resetCCtx_advanced() :
note : ' params ' is expected to be validated */
2015-11-11 12:43:58 +00:00
static size_t ZSTD_resetCCtx_advanced ( ZSTD_CCtx * zc ,
2015-11-25 13:42:45 +00:00
ZSTD_parameters params )
2016-01-28 16:56:33 +00:00
{ /* note : params considered validated here */
2016-03-30 17:48:05 +00:00
const size_t blockSize = MIN ( ZSTD_BLOCKSIZE_MAX , ( size_t ) 1 < < params . cParams . windowLog ) ;
const U32 divider = ( params . cParams . searchLength = = 3 ) ? 3 : 4 ;
2016-03-08 01:35:34 +00:00
const size_t maxNbSeq = blockSize / divider ;
2016-03-22 22:19:28 +00:00
const size_t tokenSpace = blockSize + 11 * maxNbSeq ;
2016-04-04 11:49:18 +00:00
const size_t chainSize = ( params . cParams . strategy = = ZSTD_fast ) ? 0 : ( 1 < < params . cParams . chainLog ) ;
2016-03-30 17:48:05 +00:00
const size_t hSize = 1 < < params . cParams . hashLog ;
2016-03-23 14:53:38 +00:00
const size_t h3Size = ( zc - > hashLog3 ) ? 1 < < zc - > hashLog3 : 0 ;
2016-04-04 11:49:18 +00:00
const size_t tableSpace = ( chainSize + hSize + h3Size ) * sizeof ( U32 ) ;
2016-03-02 14:56:24 +00:00
2016-03-19 15:09:09 +00:00
/* Check if workSpace is large enough, alloc a new one if needed */
2016-04-07 13:24:29 +00:00
{ size_t const optSpace = ( ( MaxML + 1 ) + ( MaxLL + 1 ) + ( MaxOff + 1 ) + ( 1 < < Litbits ) ) * sizeof ( U32 )
2016-03-19 15:09:09 +00:00
+ ( ZSTD_OPT_NUM + 1 ) * ( sizeof ( ZSTD_match_t ) + sizeof ( ZSTD_optimal_t ) ) ;
size_t const neededSpace = tableSpace + ( 256 * sizeof ( U32 ) ) /* huffTable */ + tokenSpace
2016-04-04 11:28:28 +00:00
+ ( ( params . cParams . strategy = = ZSTD_btopt ) ? optSpace : 0 ) ;
2016-03-19 15:09:09 +00:00
if ( zc - > workSpaceSize < neededSpace ) {
free ( zc - > workSpace ) ;
zc - > workSpace = malloc ( neededSpace ) ;
if ( zc - > workSpace = = NULL ) return ERROR ( memory_allocation ) ;
zc - > workSpaceSize = neededSpace ;
2016-03-19 16:18:00 +00:00
} }
2016-03-19 15:09:09 +00:00
2016-01-28 16:56:33 +00:00
memset ( zc - > workSpace , 0 , tableSpace ) ; /* reset only tables */
2016-02-19 09:09:35 +00:00
zc - > hashTable3 = ( U32 * ) ( zc - > workSpace ) ;
2016-03-19 15:09:09 +00:00
zc - > hashTable = zc - > hashTable3 + h3Size ;
2016-04-04 11:49:18 +00:00
zc - > chainTable = zc - > hashTable + hSize ;
zc - > seqStore . buffer = zc - > chainTable + chainSize ;
2016-01-28 16:56:33 +00:00
zc - > hufTable = ( HUF_CElt * ) zc - > seqStore . buffer ;
zc - > flagStaticTables = 0 ;
2016-03-20 18:14:22 +00:00
zc - > seqStore . buffer = ( ( U32 * ) ( zc - > seqStore . buffer ) ) + 256 ;
2015-10-25 13:06:35 +00:00
2015-11-07 00:13:31 +00:00
zc - > nextToUpdate = 1 ;
2015-11-13 10:27:46 +00:00
zc - > nextSrc = NULL ;
2015-10-29 15:49:43 +00:00
zc - > base = NULL ;
zc - > dictBase = NULL ;
zc - > dictLimit = 0 ;
zc - > lowLimit = 0 ;
2015-10-25 13:06:35 +00:00
zc - > params = params ;
2015-12-02 13:00:45 +00:00
zc - > blockSize = blockSize ;
2016-02-10 12:37:52 +00:00
2016-03-30 17:48:05 +00:00
if ( params . cParams . strategy = = ZSTD_btopt ) {
2016-03-23 19:44:12 +00:00
zc - > seqStore . litFreq = ( U32 * ) ( zc - > seqStore . buffer ) ;
2016-03-04 18:17:31 +00:00
zc - > seqStore . litLengthFreq = zc - > seqStore . litFreq + ( 1 < < Litbits ) ;
2016-03-21 12:24:16 +00:00
zc - > seqStore . matchLengthFreq = zc - > seqStore . litLengthFreq + ( MaxLL + 1 ) ;
2016-03-22 22:19:28 +00:00
zc - > seqStore . offCodeFreq = zc - > seqStore . matchLengthFreq + ( MaxML + 1 ) ;
2016-04-07 13:24:29 +00:00
zc - > seqStore . matchTable = ( ZSTD_match_t * ) ( ( void * ) ( zc - > seqStore . offCodeFreq + ( MaxOff + 1 ) ) ) ;
2016-03-04 18:17:31 +00:00
zc - > seqStore . priceTable = ( ZSTD_optimal_t * ) ( ( void * ) ( zc - > seqStore . matchTable + ZSTD_OPT_NUM + 1 ) ) ;
2016-03-23 19:44:12 +00:00
zc - > seqStore . buffer = zc - > seqStore . priceTable + ZSTD_OPT_NUM + 1 ;
2016-03-04 18:17:31 +00:00
zc - > seqStore . litLengthSum = 0 ;
}
2016-03-23 19:44:12 +00:00
zc - > seqStore . offsetStart = ( U32 * ) ( zc - > seqStore . buffer ) ;
zc - > seqStore . litLengthStart = ( U16 * ) ( void * ) ( zc - > seqStore . offsetStart + maxNbSeq ) ;
zc - > seqStore . matchLengthStart = ( U16 * ) ( void * ) ( zc - > seqStore . litLengthStart + maxNbSeq ) ;
zc - > seqStore . llCodeStart = ( BYTE * ) ( zc - > seqStore . matchLengthStart + maxNbSeq ) ;
zc - > seqStore . mlCodeStart = zc - > seqStore . llCodeStart + maxNbSeq ;
zc - > seqStore . offCodeStart = zc - > seqStore . mlCodeStart + maxNbSeq ;
zc - > seqStore . litStart = zc - > seqStore . offCodeStart + maxNbSeq ;
2016-03-02 19:37:49 +00:00
2016-01-07 14:35:18 +00:00
zc - > hbSize = 0 ;
2016-01-08 16:27:50 +00:00
zc - > stage = 0 ;
2016-02-02 13:36:49 +00:00
zc - > loadedDictEnd = 0 ;
2015-10-29 15:49:43 +00:00
2015-10-30 05:40:22 +00:00
return 0 ;
2015-10-22 14:31:46 +00:00
}
2015-10-25 13:06:35 +00:00
2016-03-07 23:03:59 +00:00
/*! ZSTD_copyCCtx() :
* Duplicate an existing context ` srcCCtx ` into another one ` dstCCtx ` .
* Only works during stage 0 ( i . e . before first call to ZSTD_compressContinue ( ) ) .
2016-01-26 14:58:49 +00:00
* @ return : 0 , or an error code */
size_t ZSTD_copyCCtx ( ZSTD_CCtx * dstCCtx , const ZSTD_CCtx * srcCCtx )
{
if ( srcCCtx - > stage ! = 0 ) return ERROR ( stage_wrong ) ;
2016-03-23 14:53:38 +00:00
dstCCtx - > hashLog3 = srcCCtx - > hashLog3 ; /* must be before ZSTD_resetCCtx_advanced */
2016-01-26 14:58:49 +00:00
ZSTD_resetCCtx_advanced ( dstCCtx , srcCCtx - > params ) ;
/* copy tables */
2016-04-04 12:54:53 +00:00
{ const size_t chainSize = ( srcCCtx - > params . cParams . strategy = = ZSTD_fast ) ? 0 : ( 1 < < srcCCtx - > params . cParams . chainLog ) ;
2016-03-30 17:48:05 +00:00
const size_t hSize = 1 < < srcCCtx - > params . cParams . hashLog ;
2016-03-23 14:53:38 +00:00
const size_t h3Size = ( srcCCtx - > hashLog3 ) ? 1 < < srcCCtx - > hashLog3 : 0 ;
2016-04-04 12:54:53 +00:00
const size_t tableSpace = ( chainSize + hSize + h3Size ) * sizeof ( U32 ) ;
2016-03-19 16:18:00 +00:00
memcpy ( dstCCtx - > workSpace , srcCCtx - > workSpace , tableSpace ) ;
}
2016-01-26 14:58:49 +00:00
/* copy frame header */
dstCCtx - > hbSize = srcCCtx - > hbSize ;
memcpy ( dstCCtx - > headerBuffer , srcCCtx - > headerBuffer , srcCCtx - > hbSize ) ;
/* copy dictionary pointers */
2016-03-19 16:18:00 +00:00
dstCCtx - > nextToUpdate = srcCCtx - > nextToUpdate ;
dstCCtx - > nextToUpdate3 = srcCCtx - > nextToUpdate3 ;
dstCCtx - > nextSrc = srcCCtx - > nextSrc ;
dstCCtx - > base = srcCCtx - > base ;
dstCCtx - > dictBase = srcCCtx - > dictBase ;
dstCCtx - > dictLimit = srcCCtx - > dictLimit ;
dstCCtx - > lowLimit = srcCCtx - > lowLimit ;
dstCCtx - > loadedDictEnd = srcCCtx - > loadedDictEnd ;
2016-01-26 14:58:49 +00:00
2016-01-27 23:18:06 +00:00
/* copy entropy tables */
dstCCtx - > flagStaticTables = srcCCtx - > flagStaticTables ;
2016-01-28 16:56:33 +00:00
if ( srcCCtx - > flagStaticTables ) {
2016-01-26 14:58:49 +00:00
memcpy ( dstCCtx - > hufTable , srcCCtx - > hufTable , 256 * 4 ) ;
2016-01-27 23:18:06 +00:00
memcpy ( dstCCtx - > litlengthCTable , srcCCtx - > litlengthCTable , sizeof ( dstCCtx - > litlengthCTable ) ) ;
memcpy ( dstCCtx - > matchlengthCTable , srcCCtx - > matchlengthCTable , sizeof ( dstCCtx - > matchlengthCTable ) ) ;
memcpy ( dstCCtx - > offcodeCTable , srcCCtx - > offcodeCTable , sizeof ( dstCCtx - > offcodeCTable ) ) ;
}
2016-01-26 14:58:49 +00:00
return 0 ;
}
2016-03-20 15:20:06 +00:00
/*! ZSTD_reduceTable() :
2016-03-20 23:07:42 +00:00
* reduce table indexes by ` reducerValue ` */
2016-03-20 15:20:06 +00:00
static void ZSTD_reduceTable ( U32 * const table , U32 const size , U32 const reducerValue )
2015-11-13 10:27:46 +00:00
{
2016-03-20 15:20:06 +00:00
U32 u ;
for ( u = 0 ; u < size ; u + + ) {
if ( table [ u ] < reducerValue ) table [ u ] = 0 ;
else table [ u ] - = reducerValue ;
2015-11-13 10:27:46 +00:00
}
}
2016-03-20 15:20:06 +00:00
/*! ZSTD_reduceIndex() :
* rescale all indexes to avoid future overflow ( indexes are U32 ) */
static void ZSTD_reduceIndex ( ZSTD_CCtx * zc , const U32 reducerValue )
{
2016-03-30 17:48:05 +00:00
{ const U32 hSize = 1 < < zc - > params . cParams . hashLog ;
2016-03-20 15:20:06 +00:00
ZSTD_reduceTable ( zc - > hashTable , hSize , reducerValue ) ; }
2016-04-04 11:49:18 +00:00
{ const U32 chainSize = ( zc - > params . cParams . strategy = = ZSTD_fast ) ? 0 : ( 1 < < zc - > params . cParams . chainLog ) ;
ZSTD_reduceTable ( zc - > chainTable , chainSize , reducerValue ) ; }
2016-03-20 15:20:06 +00:00
2016-03-23 14:53:38 +00:00
{ const U32 h3Size = ( zc - > hashLog3 ) ? 1 < < zc - > hashLog3 : 0 ;
2016-03-20 15:20:06 +00:00
ZSTD_reduceTable ( zc - > hashTable3 , h3Size , reducerValue ) ; }
}
2015-11-13 10:27:46 +00:00
2016-01-28 16:56:33 +00:00
/*-*******************************************************
2015-11-11 20:38:21 +00:00
* Block entropic compression
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-03-13 10:08:40 +00:00
/* Frame format description
Frame Header - [ Block Header - Block ] - Frame End
1 ) Frame Header
- 4 bytes - Magic Number : ZSTD_MAGICNUMBER ( defined within zstd_static . h )
- 1 byte - Frame Descriptor
2 ) Block Header
- 3 bytes , starting with a 2 - bits descriptor
Uncompressed , Compressed , Frame End , unused
3 ) Block
See Block Format Description
4 ) Frame End
- 3 bytes , compatible with Block Header
*/
/* Frame descriptor
1 byte , using :
bit 0 - 3 : windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN ( see zstd_internal . h )
bit 4 : minmatch 4 ( 0 ) or 3 ( 1 )
bit 5 : reserved ( must be zero )
bit 6 - 7 : Frame content size : unknown , 1 byte , 2 bytes , 8 bytes
Optional : content size ( 0 , 1 , 2 or 8 bytes )
0 : unknown
1 : 0 - 255 bytes
2 : 256 - 65535 + 256
8 : up to 16 exa
*/
2016-01-23 18:28:41 +00:00
/* Block format description
Block = Literal Section - Sequences Section
Prerequisite : size of ( compressed ) block , maximum size of regenerated data
1 ) Literal Section
1.1 ) Header : 1 - 5 bytes
flags : 2 bits
00 compressed by Huff0
01 unused
10 is Raw ( uncompressed )
11 is Rle
Note : using 01 = > Huff0 with precomputed table ?
Note : delta map ? = > compressed ?
1.1 .1 ) Huff0 - compressed literal block : 3 - 5 bytes
2016-01-25 03:10:46 +00:00
srcSize < 1 KB = > 3 bytes ( 2 - 2 - 10 - 10 ) = > single stream
2016-01-23 18:28:41 +00:00
srcSize < 1 KB = > 3 bytes ( 2 - 2 - 10 - 10 )
2016-01-25 03:22:03 +00:00
srcSize < 16 KB = > 4 bytes ( 2 - 2 - 14 - 14 )
2016-01-23 18:28:41 +00:00
else = > 5 bytes ( 2 - 2 - 18 - 18 )
big endian convention
1.1 .2 ) Raw ( uncompressed ) literal block header : 1 - 3 bytes
size : 5 bits : ( IS_RAW < < 6 ) + ( 0 < < 4 ) + size
12 bits : ( IS_RAW < < 6 ) + ( 2 < < 4 ) + ( size > > 8 )
size & 255
20 bits : ( IS_RAW < < 6 ) + ( 3 < < 4 ) + ( size > > 16 )
size > > 8 & 255
size & 255
1.1 .3 ) Rle ( repeated single byte ) literal block header : 1 - 3 bytes
size : 5 bits : ( IS_RLE < < 6 ) + ( 0 < < 4 ) + size
12 bits : ( IS_RLE < < 6 ) + ( 2 < < 4 ) + ( size > > 8 )
size & 255
20 bits : ( IS_RLE < < 6 ) + ( 3 < < 4 ) + ( size > > 16 )
size > > 8 & 255
size & 255
2016-01-25 03:22:03 +00:00
1.1 .4 ) Huff0 - compressed literal block , using precomputed CTables : 3 - 5 bytes
srcSize < 1 KB = > 3 bytes ( 2 - 2 - 10 - 10 ) = > single stream
srcSize < 1 KB = > 3 bytes ( 2 - 2 - 10 - 10 )
srcSize < 16 KB = > 4 bytes ( 2 - 2 - 14 - 14 )
else = > 5 bytes ( 2 - 2 - 18 - 18 )
big endian convention
1 - CTable available ( stored into workspace ? )
2016-01-26 02:14:20 +00:00
2 - Small input ( fast heuristic ? Full comparison ? depend on clevel ? )
2016-01-25 03:22:03 +00:00
2016-01-23 18:28:41 +00:00
1.2 ) Literal block content
1.2 .1 ) Huff0 block , using sizes from header
See Huff0 format
2016-01-27 23:18:06 +00:00
1.2 .2 ) Huff0 block , using prepared table
2016-01-23 18:28:41 +00:00
2016-01-27 23:18:06 +00:00
1.2 .3 ) Raw content
2016-01-23 18:28:41 +00:00
2016-01-27 23:18:06 +00:00
1.2 .4 ) single byte
2016-01-23 18:28:41 +00:00
2 ) Sequences section
2016-01-27 23:18:06 +00:00
- Nb Sequences : 2 bytes , little endian
- Control Token : 1 byte ( see below )
- Dumps Length : 1 or 2 bytes ( depending on control token )
- Dumps : as stated by dumps length
- Literal Lengths FSE table ( as needed depending on encoding method )
- Offset Codes FSE table ( as needed depending on encoding method )
- Match Lengths FSE table ( as needed depending on encoding method )
2.1 ) Control Token
8 bits , divided as :
0 - 1 : dumpsLength
2 - 3 : MatchLength , FSE encoding method
4 - 5 : Offset Codes , FSE encoding method
6 - 7 : Literal Lengths , FSE encoding method
FSE encoding method :
FSE_ENCODING_RAW : uncompressed ; no header
FSE_ENCODING_RLE : single repeated value ; header 1 byte
FSE_ENCODING_STATIC : use prepared table ; no header
FSE_ENCODING_DYNAMIC : read NCount
2016-01-23 18:28:41 +00:00
*/
2015-11-11 20:38:21 +00:00
2016-03-15 00:24:33 +00:00
size_t ZSTD_noCompressBlock ( void * dst , size_t dstCapacity , const void * src , size_t srcSize )
2015-11-11 20:38:21 +00:00
{
BYTE * const ostart = ( BYTE * const ) dst ;
2016-03-15 00:24:33 +00:00
if ( srcSize + ZSTD_blockHeaderSize > dstCapacity ) return ERROR ( dstSize_tooSmall ) ;
2015-11-11 20:38:21 +00:00
memcpy ( ostart + ZSTD_blockHeaderSize , src , srcSize ) ;
/* Build header */
ostart [ 0 ] = ( BYTE ) ( srcSize > > 16 ) ;
ostart [ 1 ] = ( BYTE ) ( srcSize > > 8 ) ;
ostart [ 2 ] = ( BYTE ) srcSize ;
ostart [ 0 ] + = ( BYTE ) ( bt_raw < < 6 ) ; /* is a raw (uncompressed) block */
return ZSTD_blockHeaderSize + srcSize ;
}
2016-03-15 00:24:33 +00:00
static size_t ZSTD_noCompressLiterals ( void * dst , size_t dstCapacity , const void * src , size_t srcSize )
2015-11-11 20:38:21 +00:00
{
BYTE * const ostart = ( BYTE * const ) dst ;
2016-03-18 11:37:45 +00:00
U32 const flSize = 1 + ( srcSize > 31 ) + ( srcSize > 4095 ) ;
2015-11-11 20:38:21 +00:00
2016-03-15 00:24:33 +00:00
if ( srcSize + flSize > dstCapacity ) return ERROR ( dstSize_tooSmall ) ;
2015-11-11 20:38:21 +00:00
2016-01-23 18:28:41 +00:00
switch ( flSize )
{
case 1 : /* 2 - 1 - 5 */
ostart [ 0 ] = ( BYTE ) ( ( IS_RAW < < 6 ) + ( 0 < < 5 ) + srcSize ) ;
break ;
case 2 : /* 2 - 2 - 12 */
ostart [ 0 ] = ( BYTE ) ( ( IS_RAW < < 6 ) + ( 2 < < 4 ) + ( srcSize > > 8 ) ) ;
ostart [ 1 ] = ( BYTE ) srcSize ;
break ;
default : /*note : should not be necessary : flSize is within {1,2,3} */
case 3 : /* 2 - 2 - 20 */
ostart [ 0 ] = ( BYTE ) ( ( IS_RAW < < 6 ) + ( 3 < < 4 ) + ( srcSize > > 16 ) ) ;
ostart [ 1 ] = ( BYTE ) ( srcSize > > 8 ) ;
ostart [ 2 ] = ( BYTE ) srcSize ;
break ;
}
memcpy ( ostart + flSize , src , srcSize ) ;
return srcSize + flSize ;
2015-11-11 20:38:21 +00:00
}
2016-03-15 00:24:33 +00:00
static size_t ZSTD_compressRleLiteralsBlock ( void * dst , size_t dstCapacity , const void * src , size_t srcSize )
2015-11-11 20:38:21 +00:00
{
BYTE * const ostart = ( BYTE * const ) dst ;
2016-03-18 11:37:45 +00:00
U32 const flSize = 1 + ( srcSize > 31 ) + ( srcSize > 4095 ) ;
2016-01-23 18:28:41 +00:00
2016-03-15 00:24:33 +00:00
( void ) dstCapacity ; /* dstCapacity guaranteed to be >=4, hence large enough */
2016-01-23 18:28:41 +00:00
switch ( flSize )
{
case 1 : /* 2 - 1 - 5 */
ostart [ 0 ] = ( BYTE ) ( ( IS_RLE < < 6 ) + ( 0 < < 5 ) + srcSize ) ;
break ;
case 2 : /* 2 - 2 - 12 */
ostart [ 0 ] = ( BYTE ) ( ( IS_RLE < < 6 ) + ( 2 < < 4 ) + ( srcSize > > 8 ) ) ;
ostart [ 1 ] = ( BYTE ) srcSize ;
break ;
2016-03-18 11:37:45 +00:00
default : /*note : should not be necessary : flSize is necessarily within {1,2,3} */
2016-01-23 18:28:41 +00:00
case 3 : /* 2 - 2 - 20 */
ostart [ 0 ] = ( BYTE ) ( ( IS_RLE < < 6 ) + ( 3 < < 4 ) + ( srcSize > > 16 ) ) ;
ostart [ 1 ] = ( BYTE ) ( srcSize > > 8 ) ;
ostart [ 2 ] = ( BYTE ) srcSize ;
break ;
}
2015-11-11 20:38:21 +00:00
2016-01-23 18:28:41 +00:00
ostart [ flSize ] = * ( const BYTE * ) src ;
return flSize + 1 ;
2015-11-11 20:38:21 +00:00
}
2016-01-23 18:28:41 +00:00
2016-03-20 00:09:18 +00:00
static size_t ZSTD_minGain ( size_t srcSize ) { return ( srcSize > > 6 ) + 2 ; }
2015-11-11 20:38:21 +00:00
2016-01-26 02:14:20 +00:00
static size_t ZSTD_compressLiterals ( ZSTD_CCtx * zc ,
2016-03-15 00:24:33 +00:00
void * dst , size_t dstCapacity ,
2015-11-11 20:38:21 +00:00
const void * src , size_t srcSize )
{
2016-03-18 11:37:45 +00:00
size_t const minGain = ZSTD_minGain ( srcSize ) ;
size_t const lhSize = 3 + ( srcSize > = 1 KB ) + ( srcSize > = 16 KB ) ;
2015-11-11 20:38:21 +00:00
BYTE * const ostart = ( BYTE * ) dst ;
2016-01-25 03:10:46 +00:00
U32 singleStream = srcSize < 256 ;
2016-01-26 02:14:20 +00:00
U32 hType = IS_HUF ;
2016-03-18 11:37:45 +00:00
size_t cLitSize ;
2015-11-11 20:38:21 +00:00
2016-03-20 00:09:18 +00:00
/* small ? don't even attempt compression (speed opt) */
# define LITERAL_NOENTROPY 63
{ size_t const minLitSize = zc - > flagStaticTables ? 6 : LITERAL_NOENTROPY ;
if ( srcSize < = minLitSize ) return ZSTD_noCompressLiterals ( dst , dstCapacity , src , srcSize ) ;
}
if ( dstCapacity < lhSize + 1 ) return ERROR ( dstSize_tooSmall ) ; /* not enough space for compression */
2016-01-27 23:18:06 +00:00
if ( zc - > flagStaticTables & & ( lhSize = = 3 ) ) {
2016-01-26 02:14:20 +00:00
hType = IS_PCH ;
singleStream = 1 ;
2016-03-18 11:37:45 +00:00
cLitSize = HUF_compress1X_usingCTable ( ostart + lhSize , dstCapacity - lhSize , src , srcSize , zc - > hufTable ) ;
2016-01-27 23:18:06 +00:00
} else {
2016-03-18 11:37:45 +00:00
cLitSize = singleStream ? HUF_compress1X ( ostart + lhSize , dstCapacity - lhSize , src , srcSize , 255 , 12 )
2016-03-15 00:24:33 +00:00
: HUF_compress2 ( ostart + lhSize , dstCapacity - lhSize , src , srcSize , 255 , 12 ) ;
2016-01-26 02:14:20 +00:00
}
2015-11-11 20:38:21 +00:00
2016-03-18 11:37:45 +00:00
if ( ( cLitSize = = 0 ) | | ( cLitSize > = srcSize - minGain ) )
return ZSTD_noCompressLiterals ( dst , dstCapacity , src , srcSize ) ;
if ( cLitSize = = 1 )
return ZSTD_compressRleLiteralsBlock ( dst , dstCapacity , src , srcSize ) ;
2015-11-11 20:38:21 +00:00
/* Build header */
2016-01-23 18:28:41 +00:00
switch ( lhSize )
2015-11-11 20:38:21 +00:00
{
2016-01-23 18:28:41 +00:00
case 3 : /* 2 - 2 - 10 - 10 */
2016-01-26 02:14:20 +00:00
ostart [ 0 ] = ( BYTE ) ( ( srcSize > > 6 ) + ( singleStream < < 4 ) + ( hType < < 6 ) ) ;
2016-03-18 11:37:45 +00:00
ostart [ 1 ] = ( BYTE ) ( ( srcSize < < 2 ) + ( cLitSize > > 8 ) ) ;
ostart [ 2 ] = ( BYTE ) ( cLitSize ) ;
2016-01-23 18:28:41 +00:00
break ;
case 4 : /* 2 - 2 - 14 - 14 */
2016-01-26 02:14:20 +00:00
ostart [ 0 ] = ( BYTE ) ( ( srcSize > > 10 ) + ( 2 < < 4 ) + ( hType < < 6 ) ) ;
2016-01-23 18:28:41 +00:00
ostart [ 1 ] = ( BYTE ) ( srcSize > > 2 ) ;
2016-03-18 11:37:45 +00:00
ostart [ 2 ] = ( BYTE ) ( ( srcSize < < 6 ) + ( cLitSize > > 8 ) ) ;
ostart [ 3 ] = ( BYTE ) ( cLitSize ) ;
2016-01-23 18:28:41 +00:00
break ;
2016-03-18 11:37:45 +00:00
default : /* should not be necessary, lhSize is only {3,4,5} */
2016-01-23 18:28:41 +00:00
case 5 : /* 2 - 2 - 18 - 18 */
2016-01-26 02:14:20 +00:00
ostart [ 0 ] = ( BYTE ) ( ( srcSize > > 14 ) + ( 3 < < 4 ) + ( hType < < 6 ) ) ;
2016-01-23 18:28:41 +00:00
ostart [ 1 ] = ( BYTE ) ( srcSize > > 6 ) ;
2016-03-18 11:37:45 +00:00
ostart [ 2 ] = ( BYTE ) ( ( srcSize < < 2 ) + ( cLitSize > > 16 ) ) ;
ostart [ 3 ] = ( BYTE ) ( cLitSize > > 8 ) ;
ostart [ 4 ] = ( BYTE ) ( cLitSize ) ;
2016-01-23 18:28:41 +00:00
break ;
2015-11-11 20:38:21 +00:00
}
2016-03-18 11:37:45 +00:00
return lhSize + cLitSize ;
2015-11-11 20:38:21 +00:00
}
2016-03-26 19:52:14 +00:00
void ZSTD_seqToCodes ( const seqStore_t * seqStorePtr , size_t const nbSeq )
{
/* LL codes */
{ static const BYTE LL_Code [ 64 ] = { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ,
8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 ,
16 , 16 , 17 , 17 , 18 , 18 , 19 , 19 ,
20 , 20 , 20 , 20 , 21 , 21 , 21 , 21 ,
22 , 22 , 22 , 22 , 22 , 22 , 22 , 22 ,
23 , 23 , 23 , 23 , 23 , 23 , 23 , 23 ,
24 , 24 , 24 , 24 , 24 , 24 , 24 , 24 ,
24 , 24 , 24 , 24 , 24 , 24 , 24 , 24 } ;
const BYTE LL_deltaCode = 19 ;
2016-04-07 15:19:00 +00:00
const U16 * const llTable = seqStorePtr - > litLengthStart ;
2016-03-26 19:52:14 +00:00
BYTE * const llCodeTable = seqStorePtr - > llCodeStart ;
size_t u ;
for ( u = 0 ; u < nbSeq ; u + + ) {
2016-04-07 15:19:00 +00:00
U32 const ll = llTable [ u ] ;
2016-03-26 19:52:14 +00:00
llCodeTable [ u ] = ( ll > 63 ) ? ( BYTE ) ZSTD_highbit ( ll ) + LL_deltaCode : LL_Code [ ll ] ;
2016-04-07 15:19:00 +00:00
}
if ( seqStorePtr - > longLengthID = = 1 )
llCodeTable [ seqStorePtr - > longLengthPos ] = MaxLL ;
}
2016-03-26 19:52:14 +00:00
/* Offset codes */
{ const U32 * const offsetTable = seqStorePtr - > offsetStart ;
BYTE * const ofCodeTable = seqStorePtr - > offCodeStart ;
size_t u ;
for ( u = 0 ; u < nbSeq ; u + + ) ofCodeTable [ u ] = ( BYTE ) ZSTD_highbit ( offsetTable [ u ] ) ;
}
/* ML codes */
{ static const BYTE ML_Code [ 128 ] = { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 ,
16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 ,
32 , 32 , 33 , 33 , 34 , 34 , 35 , 35 , 36 , 36 , 36 , 36 , 37 , 37 , 37 , 37 ,
38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 ,
40 , 40 , 40 , 40 , 40 , 40 , 40 , 40 , 40 , 40 , 40 , 40 , 40 , 40 , 40 , 40 ,
41 , 41 , 41 , 41 , 41 , 41 , 41 , 41 , 41 , 41 , 41 , 41 , 41 , 41 , 41 , 41 ,
42 , 42 , 42 , 42 , 42 , 42 , 42 , 42 , 42 , 42 , 42 , 42 , 42 , 42 , 42 , 42 ,
42 , 42 , 42 , 42 , 42 , 42 , 42 , 42 , 42 , 42 , 42 , 42 , 42 , 42 , 42 , 42 } ;
const BYTE ML_deltaCode = 36 ;
2016-04-07 15:19:00 +00:00
const U16 * const mlTable = seqStorePtr - > matchLengthStart ;
2016-03-26 19:52:14 +00:00
BYTE * const mlCodeTable = seqStorePtr - > mlCodeStart ;
size_t u ;
for ( u = 0 ; u < nbSeq ; u + + ) {
2016-04-07 15:19:00 +00:00
U32 const ml = mlTable [ u ] ;
2016-03-26 19:52:14 +00:00
mlCodeTable [ u ] = ( ml > 127 ) ? ( BYTE ) ZSTD_highbit ( ml ) + ML_deltaCode : ML_Code [ ml ] ;
2016-04-07 15:19:00 +00:00
}
if ( seqStorePtr - > longLengthID = = 2 )
mlCodeTable [ seqStorePtr - > longLengthPos ] = MaxML ;
}
2016-03-26 19:52:14 +00:00
}
2016-01-26 02:14:20 +00:00
size_t ZSTD_compressSequences ( ZSTD_CCtx * zc ,
2016-03-15 00:24:33 +00:00
void * dst , size_t dstCapacity ,
2015-11-11 20:38:21 +00:00
size_t srcSize )
{
2016-01-26 02:14:20 +00:00
const seqStore_t * seqStorePtr = & ( zc - > seqStore ) ;
2015-11-11 20:38:21 +00:00
U32 count [ MaxSeq + 1 ] ;
S16 norm [ MaxSeq + 1 ] ;
2016-01-27 23:18:06 +00:00
FSE_CTable * CTable_LitLength = zc - > litlengthCTable ;
FSE_CTable * CTable_OffsetBits = zc - > offcodeCTable ;
FSE_CTable * CTable_MatchLength = zc - > matchlengthCTable ;
2015-11-11 20:38:21 +00:00
U32 LLtype , Offtype , MLtype ; /* compressed, raw or rle */
2016-03-21 12:24:16 +00:00
U16 * const llTable = seqStorePtr - > litLengthStart ;
2016-03-22 11:14:26 +00:00
U16 * const mlTable = seqStorePtr - > matchLengthStart ;
2015-11-11 20:38:21 +00:00
const U32 * const offsetTable = seqStorePtr - > offsetStart ;
2016-03-20 23:07:42 +00:00
const U32 * const offsetTableEnd = seqStorePtr - > offset ;
2016-03-23 21:31:57 +00:00
BYTE * const ofCodeTable = seqStorePtr - > offCodeStart ;
2016-03-20 18:14:22 +00:00
BYTE * const llCodeTable = seqStorePtr - > llCodeStart ;
2016-03-22 11:14:26 +00:00
BYTE * const mlCodeTable = seqStorePtr - > mlCodeStart ;
2015-11-23 12:34:21 +00:00
BYTE * const ostart = ( BYTE * ) dst ;
2016-03-15 00:24:33 +00:00
BYTE * const oend = ostart + dstCapacity ;
2016-03-18 11:37:45 +00:00
BYTE * op = ostart ;
2016-03-20 23:07:42 +00:00
size_t const nbSeq = offsetTableEnd - offsetTable ;
2015-11-11 20:38:21 +00:00
BYTE * seqHead ;
/* Compress literals */
2016-03-20 00:09:18 +00:00
{ const BYTE * const literals = seqStorePtr - > litStart ;
2016-03-18 11:37:45 +00:00
size_t const litSize = seqStorePtr - > lit - literals ;
2016-03-20 00:09:18 +00:00
size_t const cSize = ZSTD_compressLiterals ( zc , op , dstCapacity , literals , litSize ) ;
2015-11-11 20:38:21 +00:00
if ( ZSTD_isError ( cSize ) ) return cSize ;
op + = cSize ;
}
/* Sequences Header */
2016-03-23 21:31:57 +00:00
if ( ( oend - op ) < 3 /*max nbSeq Size*/ + 1 /*seqHead */ ) return ERROR ( dstSize_tooSmall ) ;
2016-03-04 13:45:31 +00:00
if ( nbSeq < 0x7F ) * op + + = ( BYTE ) nbSeq ;
else if ( nbSeq < LONGNBSEQ ) op [ 0 ] = ( BYTE ) ( ( nbSeq > > 8 ) + 0x80 ) , op [ 1 ] = ( BYTE ) nbSeq , op + = 2 ;
else op [ 0 ] = 0xFF , MEM_writeLE16 ( op + 1 , ( U16 ) ( nbSeq - LONGNBSEQ ) ) , op + = 3 ;
2016-01-30 23:58:06 +00:00
if ( nbSeq = = 0 ) goto _check_compressibility ;
2015-11-11 20:38:21 +00:00
2016-03-22 22:19:28 +00:00
/* seqHead : flags for FSE encoding type */
seqHead = op + + ;
2015-11-11 20:38:21 +00:00
2016-01-27 23:18:06 +00:00
# define MIN_SEQ_FOR_DYNAMIC_FSE 64
# define MAX_SEQ_FOR_STATIC_FSE 1000
2016-03-26 19:52:14 +00:00
/* convert length/distances into codes */
ZSTD_seqToCodes ( seqStorePtr , nbSeq ) ;
2016-03-20 18:14:22 +00:00
2015-11-11 20:38:21 +00:00
/* CTable for Literal Lengths */
2016-03-22 11:14:26 +00:00
{ U32 max = MaxLL ;
size_t const mostFrequent = FSE_countFast ( count , & max , llCodeTable , nbSeq ) ;
if ( ( mostFrequent = = nbSeq ) & & ( nbSeq > 2 ) ) {
* op + + = llCodeTable [ 0 ] ;
FSE_buildCTable_rle ( CTable_LitLength , ( BYTE ) max ) ;
LLtype = FSE_ENCODING_RLE ;
} else if ( ( zc - > flagStaticTables ) & & ( nbSeq < MAX_SEQ_FOR_STATIC_FSE ) ) {
LLtype = FSE_ENCODING_STATIC ;
} else if ( ( nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE ) | | ( mostFrequent < ( nbSeq > > ( LL_defaultNormLog - 1 ) ) ) ) {
FSE_buildCTable ( CTable_LitLength , LL_defaultNorm , MaxLL , LL_defaultNormLog ) ;
LLtype = FSE_ENCODING_RAW ;
} else {
size_t nbSeq_1 = nbSeq ;
const U32 tableLog = FSE_optimalTableLog ( LLFSELog , nbSeq , max ) ;
if ( count [ llCodeTable [ nbSeq - 1 ] ] > 1 ) { count [ llCodeTable [ nbSeq - 1 ] ] - - ; nbSeq_1 - - ; }
FSE_normalizeCount ( norm , tableLog , count , nbSeq_1 , max ) ;
2016-03-23 00:32:41 +00:00
{ size_t const NCountSize = FSE_writeNCount ( op , oend - op , norm , max , tableLog ) ; /* overflow protected */
if ( FSE_isError ( NCountSize ) ) return ERROR ( GENERIC ) ;
op + = NCountSize ; }
2016-03-22 11:14:26 +00:00
FSE_buildCTable ( CTable_LitLength , norm , max , tableLog ) ;
LLtype = FSE_ENCODING_DYNAMIC ;
} }
2015-11-11 20:38:21 +00:00
2016-03-26 19:52:14 +00:00
/* CTable for Offsets */
2016-03-22 11:14:26 +00:00
{ U32 max = MaxOff ;
2016-03-23 21:31:57 +00:00
size_t const mostFrequent = FSE_countFast ( count , & max , ofCodeTable , nbSeq ) ;
2016-03-22 11:14:26 +00:00
if ( ( mostFrequent = = nbSeq ) & & ( nbSeq > 2 ) ) {
2016-03-23 21:31:57 +00:00
* op + + = ofCodeTable [ 0 ] ;
2016-03-22 11:14:26 +00:00
FSE_buildCTable_rle ( CTable_OffsetBits , ( BYTE ) max ) ;
Offtype = FSE_ENCODING_RLE ;
} else if ( ( zc - > flagStaticTables ) & & ( nbSeq < MAX_SEQ_FOR_STATIC_FSE ) ) {
Offtype = FSE_ENCODING_STATIC ;
2016-04-07 13:24:29 +00:00
} else if ( ( nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE ) | | ( mostFrequent < ( nbSeq > > ( OF_defaultNormLog - 1 ) ) ) ) {
FSE_buildCTable ( CTable_OffsetBits , OF_defaultNorm , MaxOff , OF_defaultNormLog ) ;
2016-03-22 11:14:26 +00:00
Offtype = FSE_ENCODING_RAW ;
} else {
size_t nbSeq_1 = nbSeq ;
const U32 tableLog = FSE_optimalTableLog ( OffFSELog , nbSeq , max ) ;
2016-03-23 21:31:57 +00:00
if ( count [ ofCodeTable [ nbSeq - 1 ] ] > 1 ) { count [ ofCodeTable [ nbSeq - 1 ] ] - - ; nbSeq_1 - - ; }
2016-03-22 11:14:26 +00:00
FSE_normalizeCount ( norm , tableLog , count , nbSeq_1 , max ) ;
2016-03-23 00:32:41 +00:00
{ size_t const NCountSize = FSE_writeNCount ( op , oend - op , norm , max , tableLog ) ; /* overflow protected */
if ( FSE_isError ( NCountSize ) ) return ERROR ( GENERIC ) ;
op + = NCountSize ; }
2016-03-22 11:14:26 +00:00
FSE_buildCTable ( CTable_OffsetBits , norm , max , tableLog ) ;
Offtype = FSE_ENCODING_DYNAMIC ;
} }
2015-11-11 20:38:21 +00:00
/* CTable for MatchLengths */
2016-03-22 11:14:26 +00:00
{ U32 max = MaxML ;
size_t const mostFrequent = FSE_countFast ( count , & max , mlCodeTable , nbSeq ) ;
if ( ( mostFrequent = = nbSeq ) & & ( nbSeq > 2 ) ) {
2016-03-23 19:44:12 +00:00
* op + + = * mlCodeTable ;
2016-03-22 11:14:26 +00:00
FSE_buildCTable_rle ( CTable_MatchLength , ( BYTE ) max ) ;
MLtype = FSE_ENCODING_RLE ;
} else if ( ( zc - > flagStaticTables ) & & ( nbSeq < MAX_SEQ_FOR_STATIC_FSE ) ) {
MLtype = FSE_ENCODING_STATIC ;
} else if ( ( nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE ) | | ( mostFrequent < ( nbSeq > > ( ML_defaultNormLog - 1 ) ) ) ) {
FSE_buildCTable ( CTable_MatchLength , ML_defaultNorm , MaxML , ML_defaultNormLog ) ;
MLtype = FSE_ENCODING_RAW ;
} else {
size_t nbSeq_1 = nbSeq ;
const U32 tableLog = FSE_optimalTableLog ( MLFSELog , nbSeq , max ) ;
if ( count [ mlCodeTable [ nbSeq - 1 ] ] > 1 ) { count [ mlCodeTable [ nbSeq - 1 ] ] - - ; nbSeq_1 - - ; }
FSE_normalizeCount ( norm , tableLog , count , nbSeq_1 , max ) ;
{ size_t const NCountSize = FSE_writeNCount ( op , oend - op , norm , max , tableLog ) ; /* overflow protected */
if ( FSE_isError ( NCountSize ) ) return ERROR ( GENERIC ) ;
op + = NCountSize ; }
FSE_buildCTable ( CTable_MatchLength , norm , max , tableLog ) ;
MLtype = FSE_ENCODING_DYNAMIC ;
} }
2015-11-11 20:38:21 +00:00
2016-03-22 22:19:28 +00:00
* seqHead = ( BYTE ) ( ( LLtype < < 6 ) + ( Offtype < < 4 ) + ( MLtype < < 2 ) ) ;
2016-01-27 23:18:06 +00:00
zc - > flagStaticTables = 0 ;
2015-11-11 20:38:21 +00:00
/* Encoding Sequences */
2016-03-19 17:08:32 +00:00
{ BIT_CStream_t blockStream ;
2016-03-18 11:37:45 +00:00
FSE_CState_t stateMatchLength ;
FSE_CState_t stateOffsetBits ;
FSE_CState_t stateLitLength ;
2015-11-11 20:38:21 +00:00
2016-03-18 11:37:45 +00:00
{ size_t const errorCode = BIT_initCStream ( & blockStream , op , oend - op ) ;
2016-03-20 18:14:22 +00:00
if ( ERR_isError ( errorCode ) ) return ERROR ( dstSize_tooSmall ) ; } /* not enough space remaining */
/* first symbols */
2016-03-22 11:14:26 +00:00
FSE_initCState2 ( & stateMatchLength , CTable_MatchLength , mlCodeTable [ nbSeq - 1 ] ) ;
2016-03-23 21:31:57 +00:00
FSE_initCState2 ( & stateOffsetBits , CTable_OffsetBits , ofCodeTable [ nbSeq - 1 ] ) ;
2016-03-20 18:14:22 +00:00
FSE_initCState2 ( & stateLitLength , CTable_LitLength , llCodeTable [ nbSeq - 1 ] ) ;
2016-03-21 12:24:16 +00:00
BIT_addBits ( & blockStream , llTable [ nbSeq - 1 ] , LL_bits [ llCodeTable [ nbSeq - 1 ] ] ) ;
2016-03-26 16:18:11 +00:00
if ( MEM_32bits ( ) ) BIT_flushBits ( & blockStream ) ;
2016-03-23 13:00:09 +00:00
BIT_addBits ( & blockStream , mlTable [ nbSeq - 1 ] , ML_bits [ mlCodeTable [ nbSeq - 1 ] ] ) ;
2016-03-26 16:18:11 +00:00
if ( MEM_32bits ( ) ) BIT_flushBits ( & blockStream ) ;
2016-03-24 01:31:27 +00:00
BIT_addBits ( & blockStream , offsetTable [ nbSeq - 1 ] , ofCodeTable [ nbSeq - 1 ] ) ;
2016-03-20 18:14:22 +00:00
BIT_flushBits ( & blockStream ) ;
2015-11-11 20:38:21 +00:00
2016-03-22 11:14:26 +00:00
{ size_t n ;
for ( n = nbSeq - 2 ; n < nbSeq ; n - - ) { /* intentional underflow */
2016-03-26 16:18:11 +00:00
const BYTE ofCode = ofCodeTable [ n ] ;
2016-03-23 21:31:57 +00:00
const BYTE mlCode = mlCodeTable [ n ] ;
const BYTE llCode = llCodeTable [ n ] ;
const U32 llBits = LL_bits [ llCode ] ;
const U32 mlBits = ML_bits [ mlCode ] ;
2016-03-26 16:18:11 +00:00
const U32 ofBits = ofCode ; /* 32b*/ /* 64b*/
2016-03-22 11:14:26 +00:00
/* (7)*/ /* (7)*/
2016-03-26 16:18:11 +00:00
FSE_encodeSymbol ( & blockStream , & stateOffsetBits , ofCode ) ; /* 15 */ /* 15 */
FSE_encodeSymbol ( & blockStream , & stateMatchLength , mlCode ) ; /* 24 */ /* 24 */
if ( MEM_32bits ( ) ) BIT_flushBits ( & blockStream ) ; /* (7)*/
FSE_encodeSymbol ( & blockStream , & stateLitLength , llCode ) ; /* 16 */ /* 33 */
if ( MEM_32bits ( ) | | ( ofBits + mlBits + llBits > 64 - 7 - ( LLFSELog + MLFSELog + OffFSELog ) ) )
BIT_flushBits ( & blockStream ) ; /* (7)*/
2016-03-23 21:31:57 +00:00
BIT_addBits ( & blockStream , llTable [ n ] , llBits ) ;
2016-03-26 16:18:11 +00:00
if ( MEM_32bits ( ) & & ( ( llBits + mlBits ) > 24 ) ) BIT_flushBits ( & blockStream ) ;
2016-03-23 21:31:57 +00:00
BIT_addBits ( & blockStream , mlTable [ n ] , mlBits ) ;
2016-03-26 16:18:11 +00:00
if ( MEM_32bits ( ) ) BIT_flushBits ( & blockStream ) ; /* (7)*/
BIT_addBits ( & blockStream , offsetTable [ n ] , ofBits ) ; /* 31 */
BIT_flushBits ( & blockStream ) ; /* (7)*/
2016-03-22 11:14:26 +00:00
} }
2015-11-11 20:38:21 +00:00
FSE_flushCState ( & blockStream , & stateMatchLength ) ;
FSE_flushCState ( & blockStream , & stateOffsetBits ) ;
FSE_flushCState ( & blockStream , & stateLitLength ) ;
2016-03-26 16:18:11 +00:00
{ size_t const streamSize = BIT_closeCStream ( & blockStream ) ;
if ( streamSize = = 0 ) return ERROR ( dstSize_tooSmall ) ; /* not enough space */
op + = streamSize ;
} }
2015-11-11 20:38:21 +00:00
/* check compressibility */
2016-01-30 23:58:06 +00:00
_check_compressibility :
2016-03-22 11:14:26 +00:00
{ size_t const minGain = ZSTD_minGain ( srcSize ) ;
size_t const maxCSize = srcSize - minGain ;
if ( ( size_t ) ( op - ostart ) > = maxCSize ) return 0 ; }
2015-11-11 20:38:21 +00:00
2015-11-23 12:34:21 +00:00
return op - ostart ;
2015-11-11 20:38:21 +00:00
}
2016-03-08 17:24:21 +00:00
/*! ZSTD_storeSeq() :
Store a sequence ( literal length , literals , offset code and match length code ) into seqStore_t .
` offsetCode ` : distance to match , or 0 = = repCode .
` matchCode ` : matchLength - MINMATCH
2015-11-11 20:38:21 +00:00
*/
MEM_STATIC void ZSTD_storeSeq ( seqStore_t * seqStorePtr , size_t litLength , const BYTE * literals , size_t offsetCode , size_t matchCode )
{
2016-02-02 16:30:37 +00:00
#if 0 /* for debug */
2015-11-11 20:38:21 +00:00
static const BYTE * g_start = NULL ;
2016-03-21 12:24:16 +00:00
const U32 pos = ( U32 ) ( literals - g_start ) ;
2015-11-11 20:38:21 +00:00
if ( g_start = = NULL ) g_start = literals ;
2016-03-26 16:18:11 +00:00
if ( ( pos > 200000000 ) & & ( pos < 200900000 ) )
printf ( " Cpos %6u :%5u literals & match %3u bytes at distance %6u \n " ,
2016-03-25 10:43:48 +00:00
pos , ( U32 ) litLength , ( U32 ) matchCode + MINMATCH , ( U32 ) offsetCode ) ;
2015-11-11 20:38:21 +00:00
# endif
2016-03-25 09:52:25 +00:00
ZSTD_statsUpdatePrices ( & seqStorePtr - > stats , litLength , literals , offsetCode , matchCode ) ;
2015-11-11 20:38:21 +00:00
/* copy Literals */
ZSTD_wildcopy ( seqStorePtr - > lit , literals , litLength ) ;
seqStorePtr - > lit + = litLength ;
/* literal Length */
2016-04-07 15:19:00 +00:00
if ( litLength > 0xFFFF ) { seqStorePtr - > longLengthID = 1 ; seqStorePtr - > longLengthPos = ( U32 ) ( seqStorePtr - > litLength - seqStorePtr - > litLengthStart ) ; }
* seqStorePtr - > litLength + + = ( U16 ) litLength ;
2015-11-11 20:38:21 +00:00
/* match offset */
2016-03-24 01:31:27 +00:00
* ( seqStorePtr - > offset + + ) = ( U32 ) offsetCode + 1 ;
2015-11-11 20:38:21 +00:00
/* match Length */
2016-04-07 15:19:00 +00:00
if ( matchCode > 0xFFFF ) { seqStorePtr - > longLengthID = 2 ; seqStorePtr - > longLengthPos = ( U32 ) ( seqStorePtr - > matchLength - seqStorePtr - > matchLengthStart ) ; }
* seqStorePtr - > matchLength + + = ( U16 ) matchCode ;
2015-11-11 20:38:21 +00:00
}
2016-02-11 23:07:30 +00:00
/*-*************************************
2015-11-11 20:38:21 +00:00
* Match length counter
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-11-23 12:34:21 +00:00
static unsigned ZSTD_NbCommonBytes ( register size_t val )
2015-11-11 20:38:21 +00:00
{
2016-01-28 16:56:33 +00:00
if ( MEM_isLittleEndian ( ) ) {
if ( MEM_64bits ( ) ) {
2015-11-11 20:38:21 +00:00
# if defined(_MSC_VER) && defined(_WIN64)
unsigned long r = 0 ;
_BitScanForward64 ( & r , ( U64 ) val ) ;
2015-12-09 08:05:22 +00:00
return ( unsigned ) ( r > > 3 ) ;
2015-11-11 20:38:21 +00:00
# elif defined(__GNUC__) && (__GNUC__ >= 3)
return ( __builtin_ctzll ( ( U64 ) val ) > > 3 ) ;
# else
static const int DeBruijnBytePos [ 64 ] = { 0 , 0 , 0 , 0 , 0 , 1 , 1 , 2 , 0 , 3 , 1 , 3 , 1 , 4 , 2 , 7 , 0 , 2 , 3 , 6 , 1 , 5 , 3 , 5 , 1 , 3 , 4 , 4 , 2 , 5 , 6 , 7 , 7 , 0 , 1 , 2 , 3 , 3 , 4 , 6 , 2 , 6 , 5 , 5 , 3 , 4 , 5 , 6 , 7 , 1 , 2 , 4 , 6 , 4 , 4 , 5 , 7 , 2 , 6 , 5 , 7 , 6 , 7 , 7 } ;
return DeBruijnBytePos [ ( ( U64 ) ( ( val & - ( long long ) val ) * 0x0218A392CDABBD3FULL ) ) > > 58 ] ;
# endif
2016-01-28 16:56:33 +00:00
} else { /* 32 bits */
2015-11-11 20:38:21 +00:00
# if defined(_MSC_VER)
unsigned long r = 0 ;
_BitScanForward ( & r , ( U32 ) val ) ;
2015-12-09 08:05:22 +00:00
return ( unsigned ) ( r > > 3 ) ;
2015-11-11 20:38:21 +00:00
# elif defined(__GNUC__) && (__GNUC__ >= 3)
return ( __builtin_ctz ( ( U32 ) val ) > > 3 ) ;
# else
static const int DeBruijnBytePos [ 32 ] = { 0 , 0 , 3 , 0 , 3 , 1 , 3 , 0 , 3 , 2 , 2 , 1 , 3 , 2 , 0 , 1 , 3 , 3 , 1 , 2 , 2 , 2 , 2 , 0 , 3 , 1 , 2 , 0 , 1 , 0 , 1 , 1 } ;
return DeBruijnBytePos [ ( ( U32 ) ( ( val & - ( S32 ) val ) * 0x077CB531U ) ) > > 27 ] ;
# endif
}
2016-01-28 16:56:33 +00:00
} else { /* Big Endian CPU */
if ( MEM_64bits ( ) ) {
2015-11-11 20:38:21 +00:00
# if defined(_MSC_VER) && defined(_WIN64)
unsigned long r = 0 ;
_BitScanReverse64 ( & r , val ) ;
return ( unsigned ) ( r > > 3 ) ;
# elif defined(__GNUC__) && (__GNUC__ >= 3)
return ( __builtin_clzll ( val ) > > 3 ) ;
# else
unsigned r ;
const unsigned n32 = sizeof ( size_t ) * 4 ; /* calculate this way due to compiler complaining in 32-bits mode */
if ( ! ( val > > n32 ) ) { r = 4 ; } else { r = 0 ; val > > = n32 ; }
if ( ! ( val > > 16 ) ) { r + = 2 ; val > > = 8 ; } else { val > > = 24 ; }
r + = ( ! val ) ;
return r ;
# endif
2016-01-28 16:56:33 +00:00
} else { /* 32 bits */
2015-11-11 20:38:21 +00:00
# if defined(_MSC_VER)
unsigned long r = 0 ;
_BitScanReverse ( & r , ( unsigned long ) val ) ;
return ( unsigned ) ( r > > 3 ) ;
# elif defined(__GNUC__) && (__GNUC__ >= 3)
return ( __builtin_clz ( ( U32 ) val ) > > 3 ) ;
# else
unsigned r ;
if ( ! ( val > > 16 ) ) { r = 2 ; val > > = 8 ; } else { r = 0 ; val > > = 24 ; }
r + = ( ! val ) ;
return r ;
# endif
2016-01-28 16:56:33 +00:00
} }
2015-11-11 20:38:21 +00:00
}
2015-11-23 12:34:21 +00:00
static size_t ZSTD_count ( const BYTE * pIn , const BYTE * pMatch , const BYTE * pInLimit )
2015-11-11 20:38:21 +00:00
{
const BYTE * const pStart = pIn ;
2016-01-27 23:18:06 +00:00
while ( ( pIn < pInLimit - ( sizeof ( size_t ) - 1 ) ) ) {
2016-02-11 23:07:30 +00:00
size_t diff = MEM_readST ( pMatch ) ^ MEM_readST ( pIn ) ;
2015-11-11 20:38:21 +00:00
if ( ! diff ) { pIn + = sizeof ( size_t ) ; pMatch + = sizeof ( size_t ) ; continue ; }
pIn + = ZSTD_NbCommonBytes ( diff ) ;
return ( size_t ) ( pIn - pStart ) ;
}
if ( MEM_64bits ( ) ) if ( ( pIn < ( pInLimit - 3 ) ) & & ( MEM_read32 ( pMatch ) = = MEM_read32 ( pIn ) ) ) { pIn + = 4 ; pMatch + = 4 ; }
if ( ( pIn < ( pInLimit - 1 ) ) & & ( MEM_read16 ( pMatch ) = = MEM_read16 ( pIn ) ) ) { pIn + = 2 ; pMatch + = 2 ; }
if ( ( pIn < pInLimit ) & & ( * pMatch = = * pIn ) ) pIn + + ;
return ( size_t ) ( pIn - pStart ) ;
}
2016-02-11 05:23:24 +00:00
/** ZSTD_count_2segments() :
2016-02-11 23:07:30 +00:00
* can count match length with ` ip ` & ` match ` in 2 different segments .
2015-11-23 12:34:21 +00:00
* convention : on reaching mEnd , match count continue starting from iStart
*/
static size_t ZSTD_count_2segments ( const BYTE * ip , const BYTE * match , const BYTE * iEnd , const BYTE * mEnd , const BYTE * iStart )
{
size_t matchLength ;
const BYTE * vEnd = ip + ( mEnd - match ) ;
if ( vEnd > iEnd ) vEnd = iEnd ;
matchLength = ZSTD_count ( ip , match , vEnd ) ;
if ( match + matchLength = = mEnd )
matchLength + = ZSTD_count ( ip + matchLength , iStart , iEnd ) ;
return matchLength ;
}
2015-11-11 20:38:21 +00:00
2016-01-28 16:56:33 +00:00
/*-*************************************
2015-11-11 20:38:21 +00:00
* Hashes
2015-10-22 14:31:46 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-02-19 09:09:35 +00:00
static const U32 prime3bytes = 506832829U ;
static U32 ZSTD_hash3 ( U32 u , U32 h ) { return ( ( u < < ( 32 - 24 ) ) * prime3bytes ) > > ( 32 - h ) ; }
2016-03-07 09:07:08 +00:00
static size_t ZSTD_hash3Ptr ( const void * ptr , U32 h ) { return ZSTD_hash3 ( MEM_readLE32 ( ptr ) , h ) ; }
2016-02-19 09:09:35 +00:00
2015-10-30 14:49:48 +00:00
static const U32 prime4bytes = 2654435761U ;
2016-01-28 16:56:33 +00:00
static U32 ZSTD_hash4 ( U32 u , U32 h ) { return ( u * prime4bytes ) > > ( 32 - h ) ; }
2015-11-11 12:43:58 +00:00
static size_t ZSTD_hash4Ptr ( const void * ptr , U32 h ) { return ZSTD_hash4 ( MEM_read32 ( ptr ) , h ) ; }
2015-10-29 15:49:43 +00:00
2015-10-30 14:49:48 +00:00
static const U64 prime5bytes = 889523592379ULL ;
2016-01-28 16:56:33 +00:00
static size_t ZSTD_hash5 ( U64 u , U32 h ) { return ( size_t ) ( ( ( u < < ( 64 - 40 ) ) * prime5bytes ) > > ( 64 - h ) ) ; }
2016-02-07 03:00:27 +00:00
static size_t ZSTD_hash5Ptr ( const void * p , U32 h ) { return ZSTD_hash5 ( MEM_readLE64 ( p ) , h ) ; }
2015-10-29 15:49:43 +00:00
2015-10-30 14:49:48 +00:00
static const U64 prime6bytes = 227718039650203ULL ;
2016-01-28 16:56:33 +00:00
static size_t ZSTD_hash6 ( U64 u , U32 h ) { return ( size_t ) ( ( ( u < < ( 64 - 48 ) ) * prime6bytes ) > > ( 64 - h ) ) ; }
2016-02-07 03:00:27 +00:00
static size_t ZSTD_hash6Ptr ( const void * p , U32 h ) { return ZSTD_hash6 ( MEM_readLE64 ( p ) , h ) ; }
2015-10-22 14:31:46 +00:00
2015-11-11 20:38:21 +00:00
static const U64 prime7bytes = 58295818150454627ULL ;
2016-01-28 16:56:33 +00:00
static size_t ZSTD_hash7 ( U64 u , U32 h ) { return ( size_t ) ( ( ( u < < ( 64 - 56 ) ) * prime7bytes ) > > ( 64 - h ) ) ; }
2016-02-07 03:00:27 +00:00
static size_t ZSTD_hash7Ptr ( const void * p , U32 h ) { return ZSTD_hash7 ( MEM_readLE64 ( p ) , h ) ; }
2015-11-05 16:32:18 +00:00
2015-11-11 12:43:58 +00:00
static size_t ZSTD_hashPtr ( const void * p , U32 hBits , U32 mls )
2015-10-30 14:49:48 +00:00
{
switch ( mls )
{
default :
2015-11-11 12:43:58 +00:00
case 4 : return ZSTD_hash4Ptr ( p , hBits ) ;
case 5 : return ZSTD_hash5Ptr ( p , hBits ) ;
case 6 : return ZSTD_hash6Ptr ( p , hBits ) ;
case 7 : return ZSTD_hash7Ptr ( p , hBits ) ;
2015-10-30 14:49:48 +00:00
}
}
2016-01-28 16:56:33 +00:00
2016-02-02 13:36:49 +00:00
/*-*************************************
2015-11-05 16:32:18 +00:00
* Fast Scan
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-12-04 16:16:37 +00:00
static void ZSTD_fillHashTable ( ZSTD_CCtx * zc , const void * end , const U32 mls )
{
U32 * const hashTable = zc - > hashTable ;
2016-03-30 17:48:05 +00:00
const U32 hBits = zc - > params . cParams . hashLog ;
2015-12-04 16:16:37 +00:00
const BYTE * const base = zc - > base ;
const BYTE * ip = base + zc - > nextToUpdate ;
2016-02-02 13:36:49 +00:00
const BYTE * const iend = ( ( const BYTE * ) end ) - 8 ;
2016-03-19 14:11:42 +00:00
const size_t fastHashFillStep = 3 ;
2015-12-04 16:16:37 +00:00
2016-01-27 23:18:06 +00:00
while ( ip < = iend ) {
2015-12-04 16:16:37 +00:00
hashTable [ ZSTD_hashPtr ( ip , hBits , mls ) ] = ( U32 ) ( ip - base ) ;
2016-03-19 14:11:42 +00:00
ip + = fastHashFillStep ;
2015-12-04 16:16:37 +00:00
}
}
2015-11-05 16:32:18 +00:00
FORCE_INLINE
2016-01-23 18:28:41 +00:00
void ZSTD_compressBlock_fast_generic ( ZSTD_CCtx * zc ,
2015-11-13 10:27:46 +00:00
const void * src , size_t srcSize ,
const U32 mls )
2015-11-05 16:32:18 +00:00
{
2015-12-04 16:16:37 +00:00
U32 * const hashTable = zc - > hashTable ;
2016-03-30 17:48:05 +00:00
const U32 hBits = zc - > params . cParams . hashLog ;
2015-11-24 13:06:07 +00:00
seqStore_t * seqStorePtr = & ( zc - > seqStore ) ;
const BYTE * const base = zc - > base ;
2015-11-05 16:32:18 +00:00
const BYTE * const istart = ( const BYTE * ) src ;
2015-11-06 09:52:17 +00:00
const BYTE * ip = istart ;
2015-11-05 16:32:18 +00:00
const BYTE * anchor = istart ;
2015-12-29 13:29:08 +00:00
const U32 lowIndex = zc - > dictLimit ;
const BYTE * const lowest = base + lowIndex ;
2015-11-05 16:32:18 +00:00
const BYTE * const iend = istart + srcSize ;
const BYTE * const ilimit = iend - 8 ;
2015-11-13 10:27:46 +00:00
size_t offset_2 = REPCODE_STARTVALUE , offset_1 = REPCODE_STARTVALUE ;
2015-11-05 16:32:18 +00:00
/* init */
2015-11-20 11:03:53 +00:00
ZSTD_resetSeqStore ( seqStorePtr ) ;
2016-01-31 01:04:15 +00:00
if ( ip < lowest + REPCODE_STARTVALUE ) ip = lowest + REPCODE_STARTVALUE ;
2015-11-05 16:32:18 +00:00
/* Main Search Loop */
2016-01-27 23:18:06 +00:00
while ( ip < ilimit ) { /* < instead of <=, because repcode check at (ip+1) */
2015-11-23 12:34:21 +00:00
size_t mlCode ;
2015-11-20 11:03:53 +00:00
size_t offset ;
2015-11-11 12:43:58 +00:00
const size_t h = ZSTD_hashPtr ( ip , hBits , mls ) ;
2015-12-29 13:29:08 +00:00
const U32 matchIndex = hashTable [ h ] ;
const BYTE * match = base + matchIndex ;
2016-01-02 00:16:28 +00:00
const U32 current = ( U32 ) ( ip - base ) ;
hashTable [ h ] = current ; /* update hash table */
2015-11-05 16:32:18 +00:00
2016-01-27 23:18:06 +00:00
if ( MEM_read32 ( ip + 1 - offset_1 ) = = MEM_read32 ( ip + 1 ) ) { /* note : by construction, offset_1 <= current */
2016-04-06 07:46:01 +00:00
mlCode = ZSTD_count ( ip + 1 + EQUAL_READ32 , ip + 1 + EQUAL_READ32 - offset_1 , iend ) + EQUAL_READ32 ;
2015-11-20 11:46:08 +00:00
ip + + ;
2016-04-06 07:46:01 +00:00
ZSTD_storeSeq ( seqStorePtr , ip - anchor , anchor , 0 , mlCode - MINMATCH ) ;
2016-03-16 14:35:14 +00:00
} else {
2015-12-29 13:29:08 +00:00
if ( ( matchIndex < = lowIndex ) | |
2016-01-27 23:18:06 +00:00
( MEM_read32 ( match ) ! = MEM_read32 ( ip ) ) ) {
2015-11-20 11:46:08 +00:00
ip + = ( ( ip - anchor ) > > g_searchStrength ) + 1 ;
continue ;
}
2016-04-06 07:46:01 +00:00
mlCode = ZSTD_count ( ip + EQUAL_READ32 , match + EQUAL_READ32 , iend ) + EQUAL_READ32 ;
2015-11-20 11:46:08 +00:00
offset = ip - match ;
2015-11-23 12:34:21 +00:00
while ( ( ip > anchor ) & & ( match > lowest ) & & ( ip [ - 1 ] = = match [ - 1 ] ) ) { ip - - ; match - - ; mlCode + + ; } /* catch up */
2015-11-20 11:46:08 +00:00
offset_2 = offset_1 ;
offset_1 = offset ;
2016-03-16 14:35:14 +00:00
2016-04-06 07:46:01 +00:00
ZSTD_storeSeq ( seqStorePtr , ip - anchor , anchor , offset + ZSTD_REP_MOVE , mlCode - MINMATCH ) ;
2015-11-20 11:46:08 +00:00
}
/* match found */
2016-04-06 07:46:01 +00:00
ip + = mlCode ;
2015-11-20 11:46:08 +00:00
anchor = ip ;
2016-01-27 23:18:06 +00:00
if ( ip < = ilimit ) {
2015-11-20 11:46:08 +00:00
/* Fill Table */
2016-01-07 14:35:18 +00:00
hashTable [ ZSTD_hashPtr ( base + current + 2 , hBits , mls ) ] = current + 2 ; /* here because current+2 could be > iend-8 */
2015-11-20 11:46:08 +00:00
hashTable [ ZSTD_hashPtr ( ip - 2 , hBits , mls ) ] = ( U32 ) ( ip - 2 - base ) ;
/* check immediate repcode */
while ( ( ip < = ilimit )
2016-01-27 23:18:06 +00:00
& & ( MEM_read32 ( ip ) = = MEM_read32 ( ip - offset_2 ) ) ) {
2015-11-20 11:46:08 +00:00
/* store sequence */
2016-04-06 07:46:01 +00:00
size_t const rlCode = ZSTD_count ( ip + EQUAL_READ32 , ip + EQUAL_READ32 - offset_2 , iend ) + EQUAL_READ32 ;
2016-03-19 17:08:32 +00:00
{ size_t const tmpOff = offset_2 ; offset_2 = offset_1 ; offset_1 = tmpOff ; } /* swap offset_2 <=> offset_1 */
2015-11-20 11:46:08 +00:00
hashTable [ ZSTD_hashPtr ( ip , hBits , mls ) ] = ( U32 ) ( ip - base ) ;
2016-04-06 07:46:01 +00:00
ZSTD_storeSeq ( seqStorePtr , 0 , anchor , 0 , rlCode - MINMATCH ) ;
ip + = rlCode ;
2015-11-20 11:46:08 +00:00
anchor = ip ;
continue ; /* faster when present ... (?) */
2016-01-27 23:18:06 +00:00
} } }
2015-11-05 16:32:18 +00:00
2016-03-19 17:08:32 +00:00
/* Last Literals */
{ size_t const lastLLSize = iend - anchor ;
2015-11-05 16:32:18 +00:00
memcpy ( seqStorePtr - > lit , anchor , lastLLSize ) ;
seqStorePtr - > lit + = lastLLSize ;
}
}
2016-02-11 06:14:25 +00:00
static void ZSTD_compressBlock_fast ( ZSTD_CCtx * ctx ,
2016-01-23 18:28:41 +00:00
const void * src , size_t srcSize )
2015-11-05 16:32:18 +00:00
{
2016-03-30 17:48:05 +00:00
const U32 mls = ctx - > params . cParams . searchLength ;
2015-11-05 16:32:18 +00:00
switch ( mls )
{
default :
case 4 :
2016-01-23 18:28:41 +00:00
ZSTD_compressBlock_fast_generic ( ctx , src , srcSize , 4 ) ; return ;
2015-11-05 16:32:18 +00:00
case 5 :
2016-01-23 18:28:41 +00:00
ZSTD_compressBlock_fast_generic ( ctx , src , srcSize , 5 ) ; return ;
2015-11-05 16:32:18 +00:00
case 6 :
2016-01-23 18:28:41 +00:00
ZSTD_compressBlock_fast_generic ( ctx , src , srcSize , 6 ) ; return ;
2015-11-05 16:32:18 +00:00
case 7 :
2016-01-23 18:28:41 +00:00
ZSTD_compressBlock_fast_generic ( ctx , src , srcSize , 7 ) ; return ;
2015-11-05 16:32:18 +00:00
}
}
2015-10-22 14:31:46 +00:00
2016-02-11 06:14:25 +00:00
static void ZSTD_compressBlock_fast_extDict_generic ( ZSTD_CCtx * ctx ,
2016-01-23 18:28:41 +00:00
const void * src , size_t srcSize ,
const U32 mls )
2015-11-13 10:27:46 +00:00
{
U32 * hashTable = ctx - > hashTable ;
2016-03-30 17:48:05 +00:00
const U32 hBits = ctx - > params . cParams . hashLog ;
2015-11-13 10:27:46 +00:00
seqStore_t * seqStorePtr = & ( ctx - > seqStore ) ;
const BYTE * const base = ctx - > base ;
const BYTE * const dictBase = ctx - > dictBase ;
const BYTE * const istart = ( const BYTE * ) src ;
const BYTE * ip = istart ;
const BYTE * anchor = istart ;
const U32 lowLimit = ctx - > lowLimit ;
2015-11-23 12:34:21 +00:00
const BYTE * const dictStart = dictBase + lowLimit ;
2015-11-13 10:27:46 +00:00
const U32 dictLimit = ctx - > dictLimit ;
2015-11-20 11:03:53 +00:00
const BYTE * const lowPrefixPtr = base + dictLimit ;
const BYTE * const dictEnd = dictBase + dictLimit ;
2015-11-13 10:27:46 +00:00
const BYTE * const iend = istart + srcSize ;
const BYTE * const ilimit = iend - 8 ;
2015-11-17 13:26:54 +00:00
U32 offset_2 = REPCODE_STARTVALUE , offset_1 = REPCODE_STARTVALUE ;
2015-11-13 10:27:46 +00:00
/* init */
ZSTD_resetSeqStore ( seqStorePtr ) ;
2016-01-31 01:04:15 +00:00
/* skip first position to avoid read overflow during repcode match check */
2016-01-27 23:18:06 +00:00
hashTable [ ZSTD_hashPtr ( ip + 0 , hBits , mls ) ] = ( U32 ) ( ip - base + 0 ) ;
2016-01-31 01:04:15 +00:00
ip + = REPCODE_STARTVALUE ;
2015-11-13 10:27:46 +00:00
/* Main Search Loop */
2016-01-27 23:18:06 +00:00
while ( ip < ilimit ) { /* < instead of <=, because (ip+1) */
2015-11-13 10:27:46 +00:00
const size_t h = ZSTD_hashPtr ( ip , hBits , mls ) ;
2015-11-20 11:03:53 +00:00
const U32 matchIndex = hashTable [ h ] ;
2015-11-13 10:27:46 +00:00
const BYTE * matchBase = matchIndex < dictLimit ? dictBase : base ;
2015-11-26 10:43:00 +00:00
const BYTE * match = matchBase + matchIndex ;
2015-11-13 10:27:46 +00:00
const U32 current = ( U32 ) ( ip - base ) ;
2015-11-20 11:03:53 +00:00
const U32 repIndex = current + 1 - offset_1 ;
2015-11-20 11:46:08 +00:00
const BYTE * repBase = repIndex < dictLimit ? dictBase : base ;
2015-11-13 10:27:46 +00:00
const BYTE * repMatch = repBase + repIndex ;
2015-11-23 12:34:21 +00:00
size_t mlCode ;
2015-11-20 11:03:53 +00:00
U32 offset ;
2015-11-13 10:27:46 +00:00
hashTable [ h ] = current ; /* update hash table */
2016-03-20 15:00:00 +00:00
if ( ( ( repIndex > = dictLimit ) | | ( repIndex < = dictLimit - 4 ) )
2016-01-27 23:18:06 +00:00
& & ( MEM_read32 ( repMatch ) = = MEM_read32 ( ip + 1 ) ) ) {
2015-11-20 11:46:08 +00:00
const BYTE * repMatchEnd = repIndex < dictLimit ? dictEnd : iend ;
2016-04-06 07:46:01 +00:00
mlCode = ZSTD_count_2segments ( ip + 1 + EQUAL_READ32 , repMatch + EQUAL_READ32 , iend , repMatchEnd , lowPrefixPtr ) + EQUAL_READ32 ;
2015-11-20 11:03:53 +00:00
ip + + ;
2016-04-06 07:46:01 +00:00
ZSTD_storeSeq ( seqStorePtr , ip - anchor , anchor , 0 , mlCode - MINMATCH ) ;
2016-01-27 23:18:06 +00:00
} else {
2015-11-20 11:46:08 +00:00
if ( ( matchIndex < lowLimit ) | |
2016-03-20 15:00:00 +00:00
( MEM_read32 ( match ) ! = MEM_read32 ( ip ) ) ) {
ip + = ( ( ip - anchor ) > > g_searchStrength ) + 1 ;
continue ;
}
{ const BYTE * matchEnd = matchIndex < dictLimit ? dictEnd : iend ;
2015-11-23 12:34:21 +00:00
const BYTE * lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr ;
2016-04-06 07:46:01 +00:00
mlCode = ZSTD_count_2segments ( ip + EQUAL_READ32 , match + EQUAL_READ32 , iend , matchEnd , lowPrefixPtr ) + EQUAL_READ32 ;
2016-01-27 23:18:06 +00:00
while ( ( ip > anchor ) & & ( match > lowMatchPtr ) & & ( ip [ - 1 ] = = match [ - 1 ] ) ) { ip - - ; match - - ; mlCode + + ; } /* catch up */
2015-11-20 11:46:08 +00:00
offset = current - matchIndex ;
offset_2 = offset_1 ;
offset_1 = offset ;
2016-04-06 07:46:01 +00:00
ZSTD_storeSeq ( seqStorePtr , ip - anchor , anchor , offset + ZSTD_REP_MOVE , mlCode - MINMATCH ) ;
2016-01-27 23:18:06 +00:00
} }
2015-11-20 11:46:08 +00:00
2015-11-23 12:34:21 +00:00
/* found a match : store it */
2016-04-06 07:46:01 +00:00
ip + = mlCode ;
2015-11-20 11:46:08 +00:00
anchor = ip ;
2016-01-27 23:18:06 +00:00
if ( ip < = ilimit ) {
2015-11-26 10:43:00 +00:00
/* Fill Table */
2015-11-23 15:17:21 +00:00
hashTable [ ZSTD_hashPtr ( base + current + 2 , hBits , mls ) ] = current + 2 ;
2015-11-20 11:46:08 +00:00
hashTable [ ZSTD_hashPtr ( ip - 2 , hBits , mls ) ] = ( U32 ) ( ip - 2 - base ) ;
/* check immediate repcode */
2016-01-27 23:18:06 +00:00
while ( ip < = ilimit ) {
2016-04-01 13:48:48 +00:00
U32 const current2 = ( U32 ) ( ip - base ) ;
U32 const repIndex2 = current2 - offset_2 ;
2015-11-20 11:46:08 +00:00
const BYTE * repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2 ;
2015-11-20 11:03:53 +00:00
if ( ( ( repIndex2 < = dictLimit - 4 ) | | ( repIndex2 > = dictLimit ) )
2016-01-27 23:18:06 +00:00
& & ( MEM_read32 ( repMatch2 ) = = MEM_read32 ( ip ) ) ) {
2015-11-23 12:34:21 +00:00
const BYTE * const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend ;
2016-04-06 07:46:01 +00:00
size_t repLength2 = ZSTD_count_2segments ( ip + EQUAL_READ32 , repMatch2 + EQUAL_READ32 , iend , repEnd2 , lowPrefixPtr ) + EQUAL_READ32 ;
2015-11-23 12:34:21 +00:00
U32 tmpOffset = offset_2 ; offset_2 = offset_1 ; offset_1 = tmpOffset ; /* swap offset_2 <=> offset_1 */
2016-04-06 07:46:01 +00:00
ZSTD_storeSeq ( seqStorePtr , 0 , anchor , 0 , repLength2 - MINMATCH ) ;
2015-11-23 12:34:21 +00:00
hashTable [ ZSTD_hashPtr ( ip , hBits , mls ) ] = current2 ;
2016-04-06 07:46:01 +00:00
ip + = repLength2 ;
2015-11-20 11:46:08 +00:00
anchor = ip ;
continue ;
}
2015-11-20 11:03:53 +00:00
break ;
2016-01-27 23:18:06 +00:00
} } }
2015-11-13 10:27:46 +00:00
/* Last Literals */
2016-03-19 17:08:32 +00:00
{ size_t const lastLLSize = iend - anchor ;
2015-11-13 10:27:46 +00:00
memcpy ( seqStorePtr - > lit , anchor , lastLLSize ) ;
seqStorePtr - > lit + = lastLLSize ;
}
}
2016-02-11 06:14:25 +00:00
static void ZSTD_compressBlock_fast_extDict ( ZSTD_CCtx * ctx ,
2015-11-13 10:27:46 +00:00
const void * src , size_t srcSize )
{
2016-03-30 17:48:05 +00:00
const U32 mls = ctx - > params . cParams . searchLength ;
2015-11-13 10:27:46 +00:00
switch ( mls )
{
default :
case 4 :
2016-01-25 03:22:03 +00:00
ZSTD_compressBlock_fast_extDict_generic ( ctx , src , srcSize , 4 ) ; return ;
2015-11-13 10:27:46 +00:00
case 5 :
2016-01-25 03:22:03 +00:00
ZSTD_compressBlock_fast_extDict_generic ( ctx , src , srcSize , 5 ) ; return ;
2015-11-13 10:27:46 +00:00
case 6 :
2016-01-25 03:22:03 +00:00
ZSTD_compressBlock_fast_extDict_generic ( ctx , src , srcSize , 6 ) ; return ;
2015-11-13 10:27:46 +00:00
case 7 :
2016-01-25 03:22:03 +00:00
ZSTD_compressBlock_fast_extDict_generic ( ctx , src , srcSize , 7 ) ; return ;
2015-11-13 10:27:46 +00:00
}
}
2016-04-06 10:34:42 +00:00
2016-04-06 15:14:19 +00:00
/* ***********************
* Hash Chain
* * * * * * * * * * * * * * * * * * * * * * * * */
# define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
/* Update chains up to ip (excluded)
Assumption : always within prefix ( ie . not within extDict ) */
FORCE_INLINE
U32 ZSTD_insertAndFindFirstIndex ( ZSTD_CCtx * zc , const BYTE * ip , U32 mls )
{
U32 * const hashTable = zc - > hashTable ;
const U32 hashLog = zc - > params . cParams . hashLog ;
U32 * const chainTable = zc - > chainTable ;
const U32 chainMask = ( 1 < < zc - > params . cParams . chainLog ) - 1 ;
const BYTE * const base = zc - > base ;
const U32 target = ( U32 ) ( ip - base ) ;
U32 idx = zc - > nextToUpdate ;
while ( idx < target ) {
size_t const h = ZSTD_hashPtr ( base + idx , hashLog , mls ) ;
NEXT_IN_CHAIN ( idx , chainMask ) = hashTable [ h ] ;
hashTable [ h ] = idx ;
idx + + ;
}
zc - > nextToUpdate = target ;
return hashTable [ ZSTD_hashPtr ( ip , hashLog , mls ) ] ;
}
2016-04-06 18:58:00 +00:00
/* Update hashTable3 up to ip (excluded)
Assumption : always within prefix ( ie . not within extDict ) */
FORCE_INLINE
U32 ZSTD_insertAndFindFirstIndexHash3 ( ZSTD_CCtx * zc , const BYTE * ip )
{
U32 * const hashTable3 = zc - > hashTable3 ;
U32 const hashLog3 = zc - > hashLog3 ;
const BYTE * const base = zc - > base ;
U32 idx = zc - > nextToUpdate3 ;
const U32 target = zc - > nextToUpdate3 = ( U32 ) ( ip - base ) ;
const size_t hash3 = ZSTD_hash3Ptr ( ip , hashLog3 ) ;
2016-04-07 13:24:29 +00:00
2016-04-06 18:58:00 +00:00
while ( idx < target ) {
hashTable3 [ ZSTD_hash3Ptr ( base + idx , hashLog3 ) ] = idx ;
idx + + ;
}
return hashTable3 [ hash3 ] ;
}
2016-04-06 15:14:19 +00:00
FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
size_t ZSTD_HcFindBestMatch_generic (
ZSTD_CCtx * zc , /* Index table will be updated */
const BYTE * const ip , const BYTE * const iLimit ,
size_t * offsetPtr ,
const U32 maxNbAttempts , const U32 mls , const U32 extDict )
{
U32 * const chainTable = zc - > chainTable ;
const U32 chainSize = ( 1 < < zc - > params . cParams . chainLog ) ;
const U32 chainMask = chainSize - 1 ;
const BYTE * const base = zc - > base ;
const BYTE * const dictBase = zc - > dictBase ;
const U32 dictLimit = zc - > dictLimit ;
const BYTE * const prefixStart = base + dictLimit ;
const BYTE * const dictEnd = dictBase + dictLimit ;
const U32 lowLimit = zc - > lowLimit ;
const U32 current = ( U32 ) ( ip - base ) ;
const U32 minChain = current > chainSize ? current - chainSize : 0 ;
int nbAttempts = maxNbAttempts ;
const U32 minMatch = ( mls = = 3 ) ? 3 : 4 ;
size_t ml = minMatch - 1 ;
2016-04-07 09:35:17 +00:00
#if 0
2016-04-06 15:14:19 +00:00
if ( minMatch = = 3 ) { /* HC3 match finder */
2016-04-06 18:58:00 +00:00
U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3 ( zc , ip ) ;
if ( matchIndex3 > lowLimit & & current - matchIndex3 < ( 1 < < 18 ) ) {
2016-04-06 15:14:19 +00:00
const BYTE * match ;
size_t currentMl = 0 ;
2016-04-06 18:58:00 +00:00
if ( ( ! extDict ) | | matchIndex3 > = dictLimit ) {
match = base + matchIndex3 ;
2016-04-07 09:35:17 +00:00
if ( match [ ml ] = = ip [ ml ] ) currentMl = ZSTD_count ( ip , match , iLimit ) ; /* potentially better */
2016-04-06 15:14:19 +00:00
} else {
2016-04-06 18:58:00 +00:00
match = dictBase + matchIndex3 ;
if ( MEM_readMINMATCH ( match , MINMATCH ) = = MEM_readMINMATCH ( ip , MINMATCH ) ) /* assumption : matchIndex3 <= dictLimit-4 (by table construction) */
2016-04-06 15:14:19 +00:00
currentMl = ZSTD_count_2segments ( ip + MINMATCH , match + MINMATCH , iLimit , dictEnd , prefixStart ) + MINMATCH ;
}
/* save best solution */
2016-04-07 13:24:29 +00:00
if ( currentMl > ml ) {
ml = currentMl ; * offsetPtr = ZSTD_REP_MOVE + current - matchIndex3 ;
if ( ip + currentMl = = iLimit ) return ( ml > = MINMATCH ) ? ml : 0 ; /* best possible, and avoid read overflow*/
2016-04-07 09:35:17 +00:00
} }
2016-04-06 15:14:19 +00:00
}
2016-04-07 09:35:17 +00:00
# endif
2016-04-06 15:14:19 +00:00
/* HC4 match finder */
U32 matchIndex = ZSTD_insertAndFindFirstIndex ( zc , ip , mls ) ;
for ( ; ( matchIndex > lowLimit ) & & ( nbAttempts ) ; nbAttempts - - ) {
const BYTE * match ;
size_t currentMl = 0 ;
if ( ( ! extDict ) | | matchIndex > = dictLimit ) {
match = base + matchIndex ;
if ( match [ ml ] = = ip [ ml ] ) /* potentially better */
currentMl = ZSTD_count ( ip , match , iLimit ) ;
} else {
match = dictBase + matchIndex ;
if ( MEM_readMINMATCH ( match , minMatch ) = = MEM_readMINMATCH ( ip , minMatch ) ) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
currentMl = ZSTD_count_2segments ( ip + minMatch , match + minMatch , iLimit , dictEnd , prefixStart ) + minMatch ;
}
/* save best solution */
if ( currentMl > ml ) { ml = currentMl ; * offsetPtr = ZSTD_REP_MOVE + current - matchIndex ; if ( ip + currentMl = = iLimit ) break ; /* best possible, and avoid read overflow*/ }
if ( matchIndex < = minChain ) break ;
matchIndex = NEXT_IN_CHAIN ( matchIndex , chainMask ) ;
}
return ( ml > = minMatch ) ? ml : 0 ;
}
FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
ZSTD_CCtx * zc ,
const BYTE * ip , const BYTE * const iLimit ,
size_t * offsetPtr ,
const U32 maxNbAttempts , const U32 matchLengthSearch )
{
switch ( matchLengthSearch )
{
case 3 : return ZSTD_HcFindBestMatch_generic ( zc , ip , iLimit , offsetPtr , maxNbAttempts , 3 , 0 ) ;
default :
case 4 : return ZSTD_HcFindBestMatch_generic ( zc , ip , iLimit , offsetPtr , maxNbAttempts , 4 , 0 ) ;
case 5 : return ZSTD_HcFindBestMatch_generic ( zc , ip , iLimit , offsetPtr , maxNbAttempts , 5 , 0 ) ;
case 6 : return ZSTD_HcFindBestMatch_generic ( zc , ip , iLimit , offsetPtr , maxNbAttempts , 6 , 0 ) ;
}
}
FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
ZSTD_CCtx * zc ,
const BYTE * ip , const BYTE * const iLimit ,
size_t * offsetPtr ,
const U32 maxNbAttempts , const U32 matchLengthSearch )
{
switch ( matchLengthSearch )
{
case 3 : return ZSTD_HcFindBestMatch_generic ( zc , ip , iLimit , offsetPtr , maxNbAttempts , 3 , 1 ) ;
default :
case 4 : return ZSTD_HcFindBestMatch_generic ( zc , ip , iLimit , offsetPtr , maxNbAttempts , 4 , 1 ) ;
case 5 : return ZSTD_HcFindBestMatch_generic ( zc , ip , iLimit , offsetPtr , maxNbAttempts , 5 , 1 ) ;
case 6 : return ZSTD_HcFindBestMatch_generic ( zc , ip , iLimit , offsetPtr , maxNbAttempts , 6 , 1 ) ;
}
}
2016-04-06 10:34:42 +00:00
2016-02-11 05:23:24 +00:00
/*-*************************************
2015-11-04 02:52:54 +00:00
* Binary Tree search
2015-10-22 14:31:46 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-02-11 05:23:24 +00:00
/** ZSTD_insertBt1() : add one or multiple positions to tree.
* ip : assumed < = iend - 8 .
2015-11-23 13:23:47 +00:00
* @ return : nb of positions added */
2016-01-01 06:29:39 +00:00
static U32 ZSTD_insertBt1 ( ZSTD_CCtx * zc , const BYTE * const ip , const U32 mls , const BYTE * const iend , U32 nbCompares ,
U32 extDict )
2015-11-04 02:52:54 +00:00
{
U32 * const hashTable = zc - > hashTable ;
2016-03-30 17:48:05 +00:00
const U32 hashLog = zc - > params . cParams . hashLog ;
2015-11-11 12:43:58 +00:00
const size_t h = ZSTD_hashPtr ( ip , hashLog , mls ) ;
2016-04-04 11:49:18 +00:00
U32 * const bt = zc - > chainTable ;
const U32 btLog = zc - > params . cParams . chainLog - 1 ;
2015-11-04 02:52:54 +00:00
const U32 btMask = ( 1 < < btLog ) - 1 ;
U32 matchIndex = hashTable [ h ] ;
size_t commonLengthSmaller = 0 , commonLengthLarger = 0 ;
const BYTE * const base = zc - > base ;
2016-01-01 06:29:39 +00:00
const BYTE * const dictBase = zc - > dictBase ;
const U32 dictLimit = zc - > dictLimit ;
const BYTE * const dictEnd = dictBase + dictLimit ;
const BYTE * const prefixStart = base + dictLimit ;
2015-11-07 00:13:31 +00:00
const BYTE * match = base + matchIndex ;
2015-12-11 09:44:07 +00:00
const U32 current = ( U32 ) ( ip - base ) ;
2015-11-08 14:08:03 +00:00
const U32 btLow = btMask > = current ? 0 : current - btMask ;
2015-11-04 02:52:54 +00:00
U32 * smallerPtr = bt + 2 * ( current & btMask ) ;
2016-01-16 23:12:55 +00:00
U32 * largerPtr = smallerPtr + 1 ;
2015-11-04 11:05:27 +00:00
U32 dummy32 ; /* to be nullified at the end */
2015-11-23 14:29:15 +00:00
const U32 windowLow = zc - > lowLimit ;
2015-12-31 18:08:44 +00:00
U32 matchEndIdx = current + 8 ;
2016-02-15 16:06:29 +00:00
size_t bestLength = 8 ;
2016-01-21 10:57:45 +00:00
U32 predictedSmall = * ( bt + 2 * ( ( current - 1 ) & btMask ) + 0 ) ;
U32 predictedLarge = * ( bt + 2 * ( ( current - 1 ) & btMask ) + 1 ) ;
predictedSmall + = ( predictedSmall > 0 ) ;
predictedLarge + = ( predictedLarge > 0 ) ;
2015-11-07 00:13:31 +00:00
2015-12-11 09:44:07 +00:00
hashTable [ h ] = current ; /* Update Hash Table */
2015-11-04 02:52:54 +00:00
2016-01-27 23:18:06 +00:00
while ( nbCompares - - & & ( matchIndex > windowLow ) ) {
2015-11-04 02:52:54 +00:00
U32 * nextPtr = bt + 2 * ( matchIndex & btMask ) ;
size_t matchLength = MIN ( commonLengthSmaller , commonLengthLarger ) ; /* guaranteed minimum nb of common bytes */
2016-02-11 05:23:24 +00:00
# if 1 /* note : can create issues when hlog small <= 11 */
2016-02-10 12:37:52 +00:00
const U32 * predictPtr = bt + 2 * ( ( matchIndex - 1 ) & btMask ) ; /* written this way, as bt is a roll buffer */
2016-01-27 23:18:06 +00:00
if ( matchIndex = = predictedSmall ) {
/* no need to check length, result known */
2016-01-16 23:12:55 +00:00
* smallerPtr = matchIndex ;
if ( matchIndex < = btLow ) { smallerPtr = & dummy32 ; break ; } /* beyond tree size, stop the search */
smallerPtr = nextPtr + 1 ; /* new "smaller" => larger of match */
matchIndex = nextPtr [ 1 ] ; /* new matchIndex larger than previous (closer to current) */
2016-01-21 10:57:45 +00:00
predictedSmall = predictPtr [ 1 ] + ( predictPtr [ 1 ] > 0 ) ;
2016-01-16 23:12:55 +00:00
continue ;
}
2016-01-27 23:18:06 +00:00
if ( matchIndex = = predictedLarge ) {
2016-01-16 23:12:55 +00:00
* largerPtr = matchIndex ;
if ( matchIndex < = btLow ) { largerPtr = & dummy32 ; break ; } /* beyond tree size, stop the search */
largerPtr = nextPtr ;
matchIndex = nextPtr [ 0 ] ;
2016-01-21 10:57:45 +00:00
predictedLarge = predictPtr [ 0 ] + ( predictPtr [ 0 ] > 0 ) ;
2016-01-16 23:12:55 +00:00
continue ;
}
2016-02-11 05:23:24 +00:00
# endif
2016-01-27 23:18:06 +00:00
if ( ( ! extDict ) | | ( matchIndex + matchLength > = dictLimit ) ) {
2016-01-01 06:29:39 +00:00
match = base + matchIndex ;
if ( match [ matchLength ] = = ip [ matchLength ] )
matchLength + = ZSTD_count ( ip + matchLength + 1 , match + matchLength + 1 , iend ) + 1 ;
2016-01-27 23:18:06 +00:00
} else {
2016-01-01 06:29:39 +00:00
match = dictBase + matchIndex ;
matchLength + = ZSTD_count_2segments ( ip + matchLength , match + matchLength , iend , dictEnd , prefixStart ) ;
if ( matchIndex + matchLength > = dictLimit )
match = base + matchIndex ; /* to prepare for next usage of match[matchLength] */
}
2015-11-04 02:52:54 +00:00
2016-02-15 16:06:29 +00:00
if ( matchLength > bestLength ) {
bestLength = matchLength ;
if ( matchLength > matchEndIdx - matchIndex )
matchEndIdx = matchIndex + ( U32 ) matchLength ;
}
2015-12-29 21:26:09 +00:00
2015-11-04 11:05:27 +00:00
if ( ip + matchLength = = iend ) /* equal : no way to know if inf or sup */
2016-01-01 06:29:39 +00:00
break ; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
2015-11-04 02:52:54 +00:00
2016-01-27 23:18:06 +00:00
if ( match [ matchLength ] < ip [ matchLength ] ) { /* necessarily within correct buffer */
2015-11-04 02:52:54 +00:00
/* match is smaller than current */
* smallerPtr = matchIndex ; /* update smaller idx */
commonLengthSmaller = matchLength ; /* all smaller will now have at least this guaranteed common length */
2015-11-07 00:13:31 +00:00
if ( matchIndex < = btLow ) { smallerPtr = & dummy32 ; break ; } /* beyond tree size, stop the search */
2015-11-04 02:52:54 +00:00
smallerPtr = nextPtr + 1 ; /* new "smaller" => larger of match */
2015-11-07 00:13:31 +00:00
matchIndex = nextPtr [ 1 ] ; /* new matchIndex larger than previous (closer to current) */
2016-01-27 23:18:06 +00:00
} else {
2015-11-04 02:52:54 +00:00
/* match is larger than current */
* largerPtr = matchIndex ;
commonLengthLarger = matchLength ;
2015-11-07 00:13:31 +00:00
if ( matchIndex < = btLow ) { largerPtr = & dummy32 ; break ; } /* beyond tree size, stop the search */
2015-11-04 02:52:54 +00:00
largerPtr = nextPtr ;
2015-11-07 00:13:31 +00:00
matchIndex = nextPtr [ 0 ] ;
2016-01-27 23:18:06 +00:00
} }
2015-11-04 02:52:54 +00:00
2015-11-04 11:05:27 +00:00
* smallerPtr = * largerPtr = 0 ;
2016-02-15 16:06:29 +00:00
if ( bestLength > 384 ) return MIN ( 192 , ( U32 ) ( bestLength - 384 ) ) ;
if ( matchEndIdx > current + 8 ) return matchEndIdx - current - 8 ;
return 1 ;
2015-11-04 02:52:54 +00:00
}
2016-02-11 06:14:25 +00:00
static size_t ZSTD_insertBtAndFindBestMatch (
2015-11-11 12:43:58 +00:00
ZSTD_CCtx * zc ,
2015-11-04 02:52:54 +00:00
const BYTE * const ip , const BYTE * const iend ,
size_t * offsetPtr ,
2016-01-01 06:47:58 +00:00
U32 nbCompares , const U32 mls ,
U32 extDict )
2015-11-04 02:52:54 +00:00
{
U32 * const hashTable = zc - > hashTable ;
2016-03-30 17:48:05 +00:00
const U32 hashLog = zc - > params . cParams . hashLog ;
2015-11-11 12:43:58 +00:00
const size_t h = ZSTD_hashPtr ( ip , hashLog , mls ) ;
2016-04-04 11:49:18 +00:00
U32 * const bt = zc - > chainTable ;
const U32 btLog = zc - > params . cParams . chainLog - 1 ;
2015-11-04 02:52:54 +00:00
const U32 btMask = ( 1 < < btLog ) - 1 ;
U32 matchIndex = hashTable [ h ] ;
size_t commonLengthSmaller = 0 , commonLengthLarger = 0 ;
const BYTE * const base = zc - > base ;
2016-01-01 06:47:58 +00:00
const BYTE * const dictBase = zc - > dictBase ;
const U32 dictLimit = zc - > dictLimit ;
const BYTE * const dictEnd = dictBase + dictLimit ;
const BYTE * const prefixStart = base + dictLimit ;
2015-11-04 02:52:54 +00:00
const U32 current = ( U32 ) ( ip - base ) ;
const U32 btLow = btMask > = current ? 0 : current - btMask ;
2015-11-23 14:29:15 +00:00
const U32 windowLow = zc - > lowLimit ;
2015-11-04 02:52:54 +00:00
U32 * smallerPtr = bt + 2 * ( current & btMask ) ;
U32 * largerPtr = bt + 2 * ( current & btMask ) + 1 ;
2015-12-31 18:08:44 +00:00
U32 matchEndIdx = current + 8 ;
2015-11-04 11:05:27 +00:00
U32 dummy32 ; /* to be nullified at the end */
2016-04-06 10:34:42 +00:00
const U32 minMatch = ( mls = = 3 ) ? 3 : 4 ;
size_t bestLength = minMatch - 1 ;
if ( minMatch = = 3 ) { /* HC3 match finder */
2016-04-07 09:35:17 +00:00
U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3 ( zc , ip ) ;
2016-04-06 10:34:42 +00:00
if ( matchIndex3 > windowLow & & ( current - matchIndex3 < ( 1 < < 18 ) ) ) {
const BYTE * match ;
size_t currentMl = 0 ;
if ( ( ! extDict ) | | matchIndex3 > = dictLimit ) {
match = base + matchIndex3 ;
if ( match [ bestLength ] = = ip [ bestLength ] ) currentMl = ZSTD_count ( ip , match , iend ) ;
} else {
match = dictBase + matchIndex3 ;
2016-04-07 09:35:17 +00:00
if ( MEM_readMINMATCH ( match , MINMATCH ) = = MEM_readMINMATCH ( ip , MINMATCH ) ) /* assumption : matchIndex3 <= dictLimit-4 (by table construction) */
currentMl = ZSTD_count_2segments ( ip + MINMATCH , match + MINMATCH , iend , dictEnd , prefixStart ) + MINMATCH ;
2016-04-06 10:34:42 +00:00
}
/* save best solution */
if ( currentMl > bestLength ) {
bestLength = currentMl , * offsetPtr = ZSTD_REP_MOVE + current - matchIndex3 ;
if ( ip + currentMl = = iend ) goto update ; /* best possible, and avoid read overflow*/
}
2016-04-06 15:14:19 +00:00
} }
2015-11-04 02:52:54 +00:00
2015-12-11 09:44:07 +00:00
hashTable [ h ] = current ; /* Update Hash Table */
2015-11-04 02:52:54 +00:00
2016-01-27 23:18:06 +00:00
while ( nbCompares - - & & ( matchIndex > windowLow ) ) {
2015-11-04 02:52:54 +00:00
U32 * nextPtr = bt + 2 * ( matchIndex & btMask ) ;
size_t matchLength = MIN ( commonLengthSmaller , commonLengthLarger ) ; /* guaranteed minimum nb of common bytes */
2016-01-01 06:47:58 +00:00
const BYTE * match ;
2015-11-04 02:52:54 +00:00
2016-01-27 23:18:06 +00:00
if ( ( ! extDict ) | | ( matchIndex + matchLength > = dictLimit ) ) {
2016-01-01 06:47:58 +00:00
match = base + matchIndex ;
if ( match [ matchLength ] = = ip [ matchLength ] )
matchLength + = ZSTD_count ( ip + matchLength + 1 , match + matchLength + 1 , iend ) + 1 ;
2016-01-27 23:18:06 +00:00
} else {
2016-01-01 06:47:58 +00:00
match = dictBase + matchIndex ;
matchLength + = ZSTD_count_2segments ( ip + matchLength , match + matchLength , iend , dictEnd , prefixStart ) ;
if ( matchIndex + matchLength > = dictLimit )
match = base + matchIndex ; /* to prepare for next usage of match[matchLength] */
}
2015-11-04 02:52:54 +00:00
2016-01-27 23:18:06 +00:00
if ( matchLength > bestLength ) {
2015-12-29 21:26:09 +00:00
if ( matchLength > matchEndIdx - matchIndex )
2015-12-29 22:40:02 +00:00
matchEndIdx = matchIndex + ( U32 ) matchLength ;
2015-11-04 16:41:20 +00:00
if ( ( 4 * ( int ) ( matchLength - bestLength ) ) > ( int ) ( ZSTD_highbit ( current - matchIndex + 1 ) - ZSTD_highbit ( ( U32 ) offsetPtr [ 0 ] + 1 ) ) )
2016-04-06 10:34:42 +00:00
bestLength = matchLength , * offsetPtr = ZSTD_REP_MOVE + current - matchIndex ;
2015-11-04 11:05:27 +00:00
if ( ip + matchLength = = iend ) /* equal : no way to know if inf or sup */
2015-11-23 12:34:21 +00:00
break ; /* drop, to guarantee consistency (miss a little bit of compression) */
2015-11-04 02:52:54 +00:00
}
2016-01-27 23:18:06 +00:00
if ( match [ matchLength ] < ip [ matchLength ] ) {
2015-11-04 02:52:54 +00:00
/* match is smaller than current */
* smallerPtr = matchIndex ; /* update smaller idx */
commonLengthSmaller = matchLength ; /* all smaller will now have at least this guaranteed common length */
2015-11-23 12:34:21 +00:00
if ( matchIndex < = btLow ) { smallerPtr = & dummy32 ; break ; } /* beyond tree size, stop the search */
2015-11-04 11:05:27 +00:00
smallerPtr = nextPtr + 1 ; /* new "smaller" => larger of match */
2015-11-23 12:34:21 +00:00
matchIndex = nextPtr [ 1 ] ; /* new matchIndex larger than previous (closer to current) */
2016-01-27 23:18:06 +00:00
} else {
2015-11-04 02:52:54 +00:00
/* match is larger than current */
* largerPtr = matchIndex ;
commonLengthLarger = matchLength ;
2015-11-23 12:34:21 +00:00
if ( matchIndex < = btLow ) { largerPtr = & dummy32 ; break ; } /* beyond tree size, stop the search */
2015-11-04 02:52:54 +00:00
largerPtr = nextPtr ;
2015-11-23 12:34:21 +00:00
matchIndex = nextPtr [ 0 ] ;
2016-02-10 13:01:49 +00:00
} }
2015-11-04 02:52:54 +00:00
2015-11-04 11:05:27 +00:00
* smallerPtr = * largerPtr = 0 ;
2015-11-04 02:52:54 +00:00
2016-04-06 10:34:42 +00:00
update :
2015-12-31 18:08:44 +00:00
zc - > nextToUpdate = ( matchEndIdx > current + 8 ) ? matchEndIdx - 8 : current + 1 ;
2016-04-06 11:15:38 +00:00
return ( bestLength > = minMatch ) ? bestLength : 0 ;
2015-11-04 02:52:54 +00:00
}
2016-02-15 16:06:29 +00:00
static void ZSTD_updateTree ( ZSTD_CCtx * zc , const BYTE * const ip , const BYTE * const iend , const U32 nbCompares , const U32 mls )
2016-02-11 06:14:25 +00:00
{
const BYTE * const base = zc - > base ;
const U32 target = ( U32 ) ( ip - base ) ;
U32 idx = zc - > nextToUpdate ;
2016-02-15 16:06:29 +00:00
while ( idx < target )
idx + = ZSTD_insertBt1 ( zc , base + idx , mls , iend , nbCompares , 0 ) ;
2016-02-11 06:14:25 +00:00
}
2016-03-20 15:00:00 +00:00
/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
2016-02-11 06:14:25 +00:00
static size_t ZSTD_BtFindBestMatch (
2015-11-11 12:43:58 +00:00
ZSTD_CCtx * zc ,
2015-11-04 02:52:54 +00:00
const BYTE * const ip , const BYTE * const iLimit ,
size_t * offsetPtr ,
const U32 maxNbAttempts , const U32 mls )
{
2015-12-29 21:26:09 +00:00
if ( ip < zc - > base + zc - > nextToUpdate ) return 0 ; /* skipped area */
2016-02-15 16:06:29 +00:00
ZSTD_updateTree ( zc , ip , iLimit , maxNbAttempts , mls ) ;
2016-01-01 06:47:58 +00:00
return ZSTD_insertBtAndFindBestMatch ( zc , ip , iLimit , offsetPtr , maxNbAttempts , mls , 0 ) ;
2015-11-04 02:52:54 +00:00
}
2016-02-10 13:01:49 +00:00
static size_t ZSTD_BtFindBestMatch_selectMLS (
2015-11-11 12:43:58 +00:00
ZSTD_CCtx * zc , /* Index table will be updated */
2015-11-04 02:52:54 +00:00
const BYTE * ip , const BYTE * const iLimit ,
size_t * offsetPtr ,
const U32 maxNbAttempts , const U32 matchLengthSearch )
{
switch ( matchLengthSearch )
{
2016-04-06 10:34:42 +00:00
case 3 : return ZSTD_BtFindBestMatch ( zc , ip , iLimit , offsetPtr , maxNbAttempts , 3 ) ;
2015-11-04 02:52:54 +00:00
default :
2015-11-11 12:43:58 +00:00
case 4 : return ZSTD_BtFindBestMatch ( zc , ip , iLimit , offsetPtr , maxNbAttempts , 4 ) ;
case 5 : return ZSTD_BtFindBestMatch ( zc , ip , iLimit , offsetPtr , maxNbAttempts , 5 ) ;
case 6 : return ZSTD_BtFindBestMatch ( zc , ip , iLimit , offsetPtr , maxNbAttempts , 6 ) ;
2015-11-04 02:52:54 +00:00
}
}
2016-02-15 16:06:29 +00:00
static void ZSTD_updateTree_extDict ( ZSTD_CCtx * zc , const BYTE * const ip , const BYTE * const iend , const U32 nbCompares , const U32 mls )
{
const BYTE * const base = zc - > base ;
const U32 target = ( U32 ) ( ip - base ) ;
U32 idx = zc - > nextToUpdate ;
while ( idx < target ) idx + = ZSTD_insertBt1 ( zc , base + idx , mls , iend , nbCompares , 1 ) ;
}
2015-11-23 14:29:15 +00:00
/** Tree updater, providing best match */
2016-02-11 06:14:25 +00:00
static size_t ZSTD_BtFindBestMatch_extDict (
2015-11-23 14:29:15 +00:00
ZSTD_CCtx * zc ,
const BYTE * const ip , const BYTE * const iLimit ,
size_t * offsetPtr ,
const U32 maxNbAttempts , const U32 mls )
{
2015-12-29 21:26:09 +00:00
if ( ip < zc - > base + zc - > nextToUpdate ) return 0 ; /* skipped area */
2016-02-15 16:06:29 +00:00
ZSTD_updateTree_extDict ( zc , ip , iLimit , maxNbAttempts , mls ) ;
2016-01-01 06:47:58 +00:00
return ZSTD_insertBtAndFindBestMatch ( zc , ip , iLimit , offsetPtr , maxNbAttempts , mls , 1 ) ;
2015-11-23 14:29:15 +00:00
}
2016-02-11 06:14:25 +00:00
static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
2015-11-23 14:29:15 +00:00
ZSTD_CCtx * zc , /* Index table will be updated */
const BYTE * ip , const BYTE * const iLimit ,
size_t * offsetPtr ,
const U32 maxNbAttempts , const U32 matchLengthSearch )
{
switch ( matchLengthSearch )
{
2016-04-06 10:34:42 +00:00
case 3 : return ZSTD_BtFindBestMatch_extDict ( zc , ip , iLimit , offsetPtr , maxNbAttempts , 3 ) ;
2015-11-23 14:29:15 +00:00
default :
case 4 : return ZSTD_BtFindBestMatch_extDict ( zc , ip , iLimit , offsetPtr , maxNbAttempts , 4 ) ;
case 5 : return ZSTD_BtFindBestMatch_extDict ( zc , ip , iLimit , offsetPtr , maxNbAttempts , 5 ) ;
case 6 : return ZSTD_BtFindBestMatch_extDict ( zc , ip , iLimit , offsetPtr , maxNbAttempts , 6 ) ;
}
}
2015-11-05 16:32:18 +00:00
2016-04-05 17:01:10 +00:00
/* *******************************
2016-04-06 15:14:19 +00:00
* Greedy parser
2016-04-05 17:01:10 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-02-16 16:41:03 +00:00
FORCE_INLINE
2016-04-05 17:01:10 +00:00
void ZSTD_compressBlock_greedy_generic ( ZSTD_CCtx * ctx ,
const void * src , size_t srcSize )
2015-11-05 14:00:24 +00:00
{
2016-04-05 17:01:10 +00:00
seqStore_t * seqStorePtr = & ( ctx - > seqStore ) ;
const BYTE * const istart = ( const BYTE * ) src ;
const BYTE * ip = istart ;
const BYTE * anchor = istart ;
const BYTE * const iend = istart + srcSize ;
const BYTE * const ilimit = iend - 8 ;
const BYTE * const base = ctx - > base + ctx - > dictLimit ;
2015-11-05 14:00:24 +00:00
2016-04-05 17:01:10 +00:00
const U32 maxSearches = 1 < < ctx - > params . cParams . searchLog ;
const U32 mls = ctx - > params . cParams . searchLength ;
2015-11-05 14:00:24 +00:00
2016-04-05 17:01:10 +00:00
/* init */
U32 rep [ ZSTD_REP_INIT ] ;
for ( U32 i = 0 ; i < ZSTD_REP_INIT ; i + + )
rep [ i ] = REPCODE_STARTVALUE ;
2015-11-05 14:00:24 +00:00
2016-04-05 17:01:10 +00:00
ZSTD_resetSeqStore ( seqStorePtr ) ;
if ( ( ip - base ) < REPCODE_STARTVALUE ) ip = base + REPCODE_STARTVALUE ;
2015-11-05 14:00:24 +00:00
2016-04-05 17:01:10 +00:00
/* Match Loop */
while ( ip < ilimit ) {
size_t matchLength = 0 ;
size_t offset = 0 ;
const BYTE * start = ip + 1 ;
2015-11-05 14:00:24 +00:00
2016-04-05 17:01:10 +00:00
/* check repCode */
if ( MEM_read32 ( start ) = = MEM_read32 ( start - rep [ 0 ] ) ) {
/* repcode : we take it */
2016-04-06 07:46:01 +00:00
matchLength = ZSTD_count ( start + EQUAL_READ32 , start + EQUAL_READ32 - rep [ 0 ] , iend ) + EQUAL_READ32 ;
2016-04-05 17:01:10 +00:00
goto _storeSequence ;
2015-11-05 14:00:24 +00:00
}
2016-04-05 17:01:10 +00:00
/* first search (depth 0) */
{ size_t offsetFound = 99999999 ;
size_t const ml2 = ZSTD_HcFindBestMatch_selectMLS ( ctx , ip , iend , & offsetFound , maxSearches , mls ) ;
if ( ml2 > matchLength )
2016-04-06 10:34:42 +00:00
matchLength = ml2 , start = ip , offset = offsetFound ;
2016-04-05 17:01:10 +00:00
}
2015-11-23 12:34:21 +00:00
2016-04-06 07:46:01 +00:00
if ( matchLength < EQUAL_READ32 ) {
2016-04-05 17:01:10 +00:00
ip + = ( ( ip - anchor ) > > g_searchStrength ) + 1 ; /* jump faster over incompressible sections */
continue ;
}
2015-11-05 14:00:24 +00:00
2016-04-05 17:01:10 +00:00
/* catch up */
while ( ( start > anchor ) & & ( start > base + offset - ZSTD_REP_MOVE ) & & ( start [ - 1 ] = = start [ - 1 - offset + ZSTD_REP_MOVE ] ) ) /* only search for offset within prefix */
{ start - - ; matchLength + + ; }
2016-04-05 19:03:43 +00:00
rep [ 1 ] = rep [ 0 ] ; rep [ 0 ] = ( U32 ) ( offset - ZSTD_REP_MOVE ) ;
2015-11-05 14:00:24 +00:00
2016-04-05 17:01:10 +00:00
_storeSequence :
/* store sequence */
{ size_t const litLength = start - anchor ;
ZSTD_storeSeq ( seqStorePtr , litLength , anchor , offset , matchLength - MINMATCH ) ;
anchor = ip = start + matchLength ;
}
2016-04-07 13:24:29 +00:00
2016-04-05 17:01:10 +00:00
/* check immediate repcode */
while ( ( ip < = ilimit )
& & ( MEM_read32 ( ip ) = = MEM_read32 ( ip - rep [ 1 ] ) ) ) {
/* store sequence */
2016-04-06 07:46:01 +00:00
matchLength = ZSTD_count ( ip + EQUAL_READ32 , ip + EQUAL_READ32 - rep [ 1 ] , iend ) + EQUAL_READ32 ;
2016-04-05 19:03:43 +00:00
offset = rep [ 1 ] ; rep [ 1 ] = rep [ 0 ] ; rep [ 0 ] = ( U32 ) offset ; /* swap offset history */
2016-04-06 07:46:01 +00:00
ZSTD_storeSeq ( seqStorePtr , 0 , anchor , 0 , matchLength - MINMATCH ) ;
ip + = matchLength ;
2016-04-05 17:01:10 +00:00
anchor = ip ;
continue ; /* faster when present ... (?) */
} }
2015-11-05 14:00:24 +00:00
2016-04-05 17:01:10 +00:00
/* Last Literals */
{ size_t const lastLLSize = iend - anchor ;
memcpy ( seqStorePtr - > lit , anchor , lastLLSize ) ;
seqStorePtr - > lit + = lastLLSize ;
ZSTD_statsUpdatePrices ( & seqStorePtr - > stats , lastLLSize , anchor , 0 , 0 ) ;
2015-11-23 13:37:59 +00:00
}
}
2016-04-05 17:01:10 +00:00
FORCE_INLINE
void ZSTD_compressBlock_greedy_extDict_generic ( ZSTD_CCtx * ctx ,
const void * src , size_t srcSize )
2015-11-05 14:00:24 +00:00
{
2016-04-05 17:01:10 +00:00
seqStore_t * seqStorePtr = & ( ctx - > seqStore ) ;
const BYTE * const istart = ( const BYTE * ) src ;
const BYTE * ip = istart ;
const BYTE * anchor = istart ;
const BYTE * const iend = istart + srcSize ;
const BYTE * const ilimit = iend - 8 ;
const BYTE * const base = ctx - > base ;
const U32 dictLimit = ctx - > dictLimit ;
const BYTE * const prefixStart = base + dictLimit ;
const BYTE * const dictBase = ctx - > dictBase ;
const BYTE * const dictEnd = dictBase + dictLimit ;
const BYTE * const dictStart = dictBase + ctx - > lowLimit ;
const U32 maxSearches = 1 < < ctx - > params . cParams . searchLog ;
const U32 mls = ctx - > params . cParams . searchLength ;
/* init */
U32 rep [ ZSTD_REP_INIT ] ;
for ( U32 i = 0 ; i < ZSTD_REP_INIT ; i + + )
rep [ i ] = REPCODE_STARTVALUE ;
ZSTD_resetSeqStore ( seqStorePtr ) ;
if ( ( ip - prefixStart ) < REPCODE_STARTVALUE ) ip + = REPCODE_STARTVALUE ;
/* Match Loop */
while ( ip < ilimit ) {
size_t matchLength = 0 ;
size_t offset = 0 ;
const BYTE * start = ip + 1 ;
U32 current = ( U32 ) ( start - base ) ;
/* check repCode */
{
const U32 repIndex = ( U32 ) ( current - rep [ 0 ] ) ;
const BYTE * const repBase = repIndex < dictLimit ? dictBase : base ;
const BYTE * const repMatch = repBase + repIndex ;
if ( ( U32 ) ( ( dictLimit - 1 ) - repIndex ) > = 3 ) /* intentional overflow */
if ( MEM_read32 ( start ) = = MEM_read32 ( repMatch ) ) {
/* repcode detected we should take it */
const BYTE * const repEnd = repIndex < dictLimit ? dictEnd : iend ;
2016-04-06 07:46:01 +00:00
matchLength = ZSTD_count_2segments ( start + EQUAL_READ32 , repMatch + EQUAL_READ32 , iend , repEnd , prefixStart ) + EQUAL_READ32 ;
2016-04-05 17:01:10 +00:00
goto _storeSequence ;
} }
/* first search (depth 0) */
{ size_t offsetFound = 99999999 ;
size_t const ml2 = ZSTD_HcFindBestMatch_extDict_selectMLS ( ctx , ip , iend , & offsetFound , maxSearches , mls ) ;
if ( ml2 > matchLength )
2016-04-06 10:34:42 +00:00
matchLength = ml2 , start = ip , offset = offsetFound ;
2016-04-05 17:01:10 +00:00
}
2016-04-06 07:46:01 +00:00
if ( matchLength < EQUAL_READ32 ) {
2016-04-05 17:01:10 +00:00
ip + = ( ( ip - anchor ) > > g_searchStrength ) + 1 ; /* jump faster over incompressible sections */
continue ;
}
/* catch up */
if ( offset > = ZSTD_REP_NUM ) {
U32 matchIndex = ( U32 ) ( ( start - base ) - ( offset - ZSTD_REP_MOVE ) ) ;
const BYTE * match = ( matchIndex < dictLimit ) ? dictBase + matchIndex : base + matchIndex ;
const BYTE * const mStart = ( matchIndex < dictLimit ) ? dictStart : prefixStart ;
while ( ( start > anchor ) & & ( match > mStart ) & & ( start [ - 1 ] = = match [ - 1 ] ) ) { start - - ; match - - ; matchLength + + ; }
2016-04-05 19:03:43 +00:00
rep [ 1 ] = rep [ 0 ] ; rep [ 0 ] = ( U32 ) ( offset - ZSTD_REP_MOVE ) ;
2016-04-07 13:24:29 +00:00
}
2016-04-05 17:01:10 +00:00
_storeSequence :
/* store sequence */
{ size_t const litLength = start - anchor ;
ZSTD_storeSeq ( seqStorePtr , litLength , anchor , offset , matchLength - MINMATCH ) ;
anchor = ip = start + matchLength ;
}
/* check immediate repcode */
while ( ip < = ilimit ) {
const U32 repIndex = ( U32 ) ( ( ip - base ) - rep [ 1 ] ) ;
const BYTE * const repBase = repIndex < dictLimit ? dictBase : base ;
const BYTE * const repMatch = repBase + repIndex ;
if ( ( U32 ) ( ( dictLimit - 1 ) - repIndex ) > = 3 ) /* intentional overflow */
if ( MEM_read32 ( ip ) = = MEM_read32 ( repMatch ) ) {
/* repcode detected we should take it */
const BYTE * const repEnd = repIndex < dictLimit ? dictEnd : iend ;
2016-04-06 07:46:01 +00:00
matchLength = ZSTD_count_2segments ( ip + EQUAL_READ32 , repMatch + EQUAL_READ32 , iend , repEnd , prefixStart ) + EQUAL_READ32 ;
2016-04-05 19:03:43 +00:00
offset = rep [ 1 ] ; rep [ 1 ] = rep [ 0 ] ; rep [ 0 ] = ( U32 ) offset ; /* swap offset history */
2016-04-05 17:01:10 +00:00
ZSTD_storeSeq ( seqStorePtr , 0 , anchor , 0 , matchLength - MINMATCH ) ;
ip + = matchLength ;
anchor = ip ;
continue ; /* faster when present ... (?) */
}
break ;
} }
/* Last Literals */
{ size_t const lastLLSize = iend - anchor ;
memcpy ( seqStorePtr - > lit , anchor , lastLLSize ) ;
seqStorePtr - > lit + = lastLLSize ;
2015-11-05 14:00:24 +00:00
}
}
2016-04-05 17:01:10 +00:00
2015-11-22 12:24:05 +00:00
/* *******************************
2015-11-22 01:53:43 +00:00
* Common parser - lazy strategy
2015-11-22 12:24:05 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-11-05 14:00:24 +00:00
FORCE_INLINE
2016-01-23 18:28:41 +00:00
void ZSTD_compressBlock_lazy_generic ( ZSTD_CCtx * ctx ,
const void * src , size_t srcSize ,
2015-11-22 01:42:28 +00:00
const U32 searchMethod , const U32 depth )
2015-11-04 02:52:54 +00:00
{
seqStore_t * seqStorePtr = & ( ctx - > seqStore ) ;
const BYTE * const istart = ( const BYTE * ) src ;
const BYTE * ip = istart ;
const BYTE * anchor = istart ;
const BYTE * const iend = istart + srcSize ;
const BYTE * const ilimit = iend - 8 ;
2015-12-05 08:23:53 +00:00
const BYTE * const base = ctx - > base + ctx - > dictLimit ;
2015-11-04 02:52:54 +00:00
2016-03-30 17:48:05 +00:00
const U32 maxSearches = 1 < < ctx - > params . cParams . searchLog ;
const U32 mls = ctx - > params . cParams . searchLength ;
2016-04-06 10:34:42 +00:00
const U32 minMatch = ( mls = = 3 ) ? 3 : 4 ;
2015-11-04 02:52:54 +00:00
2015-11-11 12:43:58 +00:00
typedef size_t ( * searchMax_f ) ( ZSTD_CCtx * zc , const BYTE * ip , const BYTE * iLimit ,
2015-11-05 14:00:24 +00:00
size_t * offsetPtr ,
U32 maxNbAttempts , U32 matchLengthSearch ) ;
2015-11-11 12:43:58 +00:00
searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS ;
2015-11-05 14:00:24 +00:00
2015-11-04 02:52:54 +00:00
/* init */
2016-03-18 10:03:43 +00:00
U32 rep [ ZSTD_REP_INIT ] ;
2016-04-05 16:16:38 +00:00
for ( U32 i = 0 ; i < ZSTD_REP_INIT ; i + + )
2016-03-16 11:57:07 +00:00
rep [ i ] = REPCODE_STARTVALUE ;
2016-04-06 10:34:42 +00:00
ctx - > nextToUpdate3 = ctx - > nextToUpdate ;
2015-11-04 02:52:54 +00:00
ZSTD_resetSeqStore ( seqStorePtr ) ;
2015-12-05 08:23:53 +00:00
if ( ( ip - base ) < REPCODE_STARTVALUE ) ip = base + REPCODE_STARTVALUE ;
2015-11-04 02:52:54 +00:00
/* Match Loop */
2016-01-27 23:18:06 +00:00
while ( ip < ilimit ) {
2015-11-21 14:27:35 +00:00
size_t matchLength = 0 ;
size_t offset = 0 ;
2016-03-17 18:53:38 +00:00
const BYTE * start = ip ;
2015-11-04 02:52:54 +00:00
2015-11-20 11:03:53 +00:00
/* check repCode */
2016-04-05 17:01:10 +00:00
for ( U32 i = 0 ; i < ZSTD_REP_NUM ; i + + )
2016-04-06 10:34:42 +00:00
if ( MEM_readMINMATCH ( ip , minMatch ) = = MEM_readMINMATCH ( ip - rep [ i ] , minMatch ) ) {
2015-11-20 11:03:53 +00:00
/* repcode : we take it */
2016-03-16 14:35:14 +00:00
if ( matchLength = = 0 ) {
2016-04-06 10:34:42 +00:00
matchLength = ZSTD_count ( ip + minMatch , ip + minMatch - rep [ i ] , iend ) + minMatch ;
2016-03-16 14:35:14 +00:00
offset = i ;
2016-03-17 18:53:38 +00:00
} else {
2016-04-06 10:34:42 +00:00
size_t mlRep = ZSTD_count ( ip + minMatch , ip + minMatch - rep [ i ] , iend ) + minMatch ;
2016-03-22 10:56:22 +00:00
int gain2 = ( int ) ( mlRep * 3 /*- ZSTD_highbit((U32)i+1)*/ + ( i = = 1 ) ) ;
int gain1 = ( int ) ( matchLength * 3 - /*ZSTD_highbit((U32)offset+1)*/ + 1 + ( offset = = 1 ) ) ;
2016-03-16 14:35:14 +00:00
if ( gain2 > gain1 )
matchLength = mlRep , offset = i ;
2016-03-16 11:57:07 +00:00
}
2015-11-04 02:52:54 +00:00
}
2016-03-19 17:08:32 +00:00
/* first search (depth 0) */
{ size_t offsetFound = 99999999 ;
size_t const ml2 = searchMax ( ctx , ip , iend , & offsetFound , maxSearches , mls ) ;
2015-11-23 15:17:21 +00:00
if ( ml2 > matchLength )
matchLength = ml2 , start = ip , offset = offsetFound ;
}
2016-01-27 23:18:06 +00:00
if ( matchLength < MINMATCH ) {
2015-11-23 15:17:21 +00:00
ip + = ( ( ip - anchor ) > > g_searchStrength ) + 1 ; /* jump faster over incompressible sections */
continue ;
}
2015-11-04 02:52:54 +00:00
/* let's try to find a better solution */
2015-11-22 01:42:28 +00:00
if ( depth > = 1 )
2016-01-27 23:18:06 +00:00
while ( ip < ilimit ) {
2015-11-04 02:52:54 +00:00
ip + + ;
2016-04-05 17:01:10 +00:00
for ( U32 i = 0 ; i < ZSTD_REP_NUM ; i + + )
2016-04-06 10:34:42 +00:00
if ( MEM_readMINMATCH ( ip , minMatch ) = = MEM_readMINMATCH ( ip - rep [ i ] , minMatch ) ) {
size_t const mlRep = ZSTD_count ( ip + minMatch , ip + minMatch - rep [ i ] , iend ) + minMatch ;
2016-03-19 17:08:32 +00:00
int const gain2 = ( int ) ( mlRep * 3 ) ;
2016-04-04 14:28:40 +00:00
int const gain1 = ( int ) ( matchLength * 3 - ZSTD_highbit ( ( U32 ) offset + 1 ) + 1 + ( offset < ZSTD_REP_NUM ) ) ;
2015-11-22 01:42:28 +00:00
if ( ( mlRep > = MINMATCH ) & & ( gain2 > gain1 ) )
2016-03-16 14:35:14 +00:00
matchLength = mlRep , offset = i , start = ip ;
2015-11-04 02:52:54 +00:00
}
2016-03-19 17:08:32 +00:00
{ size_t offset2 = 99999999 ;
size_t const ml2 = searchMax ( ctx , ip , iend , & offset2 , maxSearches , mls ) ;
int const gain2 = ( int ) ( ml2 * 4 - ZSTD_highbit ( ( U32 ) offset2 + 1 ) ) ; /* raw approx */
int const gain1 = ( int ) ( matchLength * 4 - ZSTD_highbit ( ( U32 ) offset + 1 ) + 4 ) ;
2016-01-27 23:18:06 +00:00
if ( ( ml2 > = MINMATCH ) & & ( gain2 > gain1 ) ) {
2015-11-06 17:44:54 +00:00
matchLength = ml2 , offset = offset2 , start = ip ;
2015-11-04 02:52:54 +00:00
continue ; /* search a better one */
2016-01-27 23:18:06 +00:00
} }
2015-11-04 02:52:54 +00:00
/* let's find an even better one */
2016-01-27 23:18:06 +00:00
if ( ( depth = = 2 ) & & ( ip < ilimit ) ) {
2015-11-04 02:52:54 +00:00
ip + + ;
2016-04-05 17:01:10 +00:00
for ( U32 i = 0 ; i < ZSTD_REP_NUM ; i + + )
2016-04-06 10:34:42 +00:00
if ( MEM_readMINMATCH ( ip , minMatch ) = = MEM_readMINMATCH ( ip - rep [ i ] , minMatch ) ) {
size_t const ml2 = ZSTD_count ( ip + minMatch , ip + minMatch - rep [ i ] , iend ) + minMatch ;
2016-03-19 17:08:32 +00:00
int const gain2 = ( int ) ( ml2 * 4 ) ;
2016-04-04 14:28:40 +00:00
int const gain1 = ( int ) ( matchLength * 4 - ZSTD_highbit ( ( U32 ) offset + 1 ) + 1 + ( offset < ZSTD_REP_NUM ) ) ;
2015-11-09 02:19:33 +00:00
if ( ( ml2 > = MINMATCH ) & & ( gain2 > gain1 ) )
2016-03-16 14:35:14 +00:00
matchLength = ml2 , offset = i , start = ip ;
2015-11-04 02:52:54 +00:00
}
2016-03-19 17:08:32 +00:00
{ size_t offset2 = 99999999 ;
size_t const ml2 = searchMax ( ctx , ip , iend , & offset2 , maxSearches , mls ) ;
int const gain2 = ( int ) ( ml2 * 4 - ZSTD_highbit ( ( U32 ) offset2 + 1 ) ) ; /* raw approx */
int const gain1 = ( int ) ( matchLength * 4 - ZSTD_highbit ( ( U32 ) offset + 1 ) + 7 ) ;
2016-01-27 23:18:06 +00:00
if ( ( ml2 > = MINMATCH ) & & ( gain2 > gain1 ) ) {
2015-11-06 17:44:54 +00:00
matchLength = ml2 , offset = offset2 , start = ip ;
continue ;
2016-01-27 23:18:06 +00:00
} } }
2015-11-04 02:52:54 +00:00
break ; /* nothing found : store previous solution */
}
2016-02-16 16:41:03 +00:00
/* catch up */
2016-03-16 11:57:07 +00:00
if ( offset > = ZSTD_REP_NUM ) {
2016-03-18 10:03:43 +00:00
while ( ( start > anchor ) & & ( start > base + offset - ZSTD_REP_MOVE ) & & ( start [ - 1 ] = = start [ - 1 - offset + ZSTD_REP_MOVE ] ) ) /* only search for offset within prefix */
2015-11-09 02:19:33 +00:00
{ start - - ; matchLength + + ; }
}
/* store sequence */
2015-11-04 02:52:54 +00:00
{
2016-03-16 11:57:07 +00:00
if ( offset > = ZSTD_REP_NUM ) {
2016-03-16 14:35:14 +00:00
rep [ 2 ] = rep [ 1 ] ;
rep [ 1 ] = rep [ 0 ] ;
2016-04-05 19:03:43 +00:00
rep [ 0 ] = ( U32 ) ( offset - ZSTD_REP_MOVE ) ;
2016-03-16 14:35:14 +00:00
} else {
if ( offset ! = 0 ) {
2016-04-05 16:16:38 +00:00
U32 temp = rep [ offset ] ;
2016-03-18 15:10:35 +00:00
if ( offset > 1 ) rep [ 2 ] = rep [ 1 ] ;
if ( offset > 0 ) rep [ 1 ] = rep [ 0 ] ;
2016-03-16 14:35:14 +00:00
rep [ 0 ] = temp ;
}
2016-03-17 18:53:38 +00:00
if ( offset < = 1 & & start = = anchor ) offset = 1 - offset ;
2016-03-16 11:57:07 +00:00
}
2016-04-05 08:30:05 +00:00
2016-04-04 14:28:40 +00:00
size_t const litLength = start - anchor ;
2015-11-04 02:52:54 +00:00
ZSTD_storeSeq ( seqStorePtr , litLength , anchor , offset , matchLength - MINMATCH ) ;
2015-11-09 02:19:33 +00:00
anchor = ip = start + matchLength ;
2015-11-04 02:52:54 +00:00
}
2016-03-17 18:53:38 +00:00
}
2015-11-04 02:52:54 +00:00
/* Last Literals */
2016-03-19 17:08:32 +00:00
{ size_t const lastLLSize = iend - anchor ;
2015-11-04 02:52:54 +00:00
memcpy ( seqStorePtr - > lit , anchor , lastLLSize ) ;
seqStorePtr - > lit + = lastLLSize ;
2016-03-25 09:52:25 +00:00
ZSTD_statsUpdatePrices ( & seqStorePtr - > stats , lastLLSize , anchor , 0 , 0 ) ;
2015-11-04 02:52:54 +00:00
}
}
2016-01-31 10:25:48 +00:00
2016-04-06 15:14:19 +00:00
/* The optimal parser */
# include "zstd_opt.h"
2016-02-22 09:06:17 +00:00
static void ZSTD_compressBlock_btopt ( ZSTD_CCtx * ctx , const void * src , size_t srcSize )
2016-01-31 10:25:48 +00:00
{
2016-04-05 19:03:43 +00:00
ZSTD_compressBlock_opt_generic ( ctx , src , srcSize ) ;
2016-01-31 10:25:48 +00:00
}
2016-01-23 18:28:41 +00:00
static void ZSTD_compressBlock_btlazy2 ( ZSTD_CCtx * ctx , const void * src , size_t srcSize )
2015-10-22 14:31:46 +00:00
{
2016-01-25 03:22:03 +00:00
ZSTD_compressBlock_lazy_generic ( ctx , src , srcSize , 1 , 2 ) ;
2015-11-05 14:00:24 +00:00
}
2015-10-22 14:31:46 +00:00
2016-01-23 18:28:41 +00:00
static void ZSTD_compressBlock_lazy2 ( ZSTD_CCtx * ctx , const void * src , size_t srcSize )
2015-11-05 14:00:24 +00:00
{
2016-01-25 03:22:03 +00:00
ZSTD_compressBlock_lazy_generic ( ctx , src , srcSize , 0 , 2 ) ;
2015-11-05 14:00:24 +00:00
}
2015-10-22 14:31:46 +00:00
2016-01-23 18:28:41 +00:00
static void ZSTD_compressBlock_lazy ( ZSTD_CCtx * ctx , const void * src , size_t srcSize )
2015-11-05 14:00:24 +00:00
{
2016-01-25 03:22:03 +00:00
ZSTD_compressBlock_lazy_generic ( ctx , src , srcSize , 0 , 1 ) ;
2015-10-22 14:31:46 +00:00
}
2016-01-23 18:28:41 +00:00
static void ZSTD_compressBlock_greedy ( ZSTD_CCtx * ctx , const void * src , size_t srcSize )
2015-10-31 11:57:14 +00:00
{
2016-04-05 17:01:10 +00:00
ZSTD_compressBlock_greedy_generic ( ctx , src , srcSize ) ;
2015-10-31 11:57:14 +00:00
}
2015-11-22 01:53:43 +00:00
FORCE_INLINE
2016-01-23 18:28:41 +00:00
void ZSTD_compressBlock_lazy_extDict_generic ( ZSTD_CCtx * ctx ,
const void * src , size_t srcSize ,
2015-11-22 01:53:43 +00:00
const U32 searchMethod , const U32 depth )
{
seqStore_t * seqStorePtr = & ( ctx - > seqStore ) ;
const BYTE * const istart = ( const BYTE * ) src ;
const BYTE * ip = istart ;
const BYTE * anchor = istart ;
const BYTE * const iend = istart + srcSize ;
const BYTE * const ilimit = iend - 8 ;
const BYTE * const base = ctx - > base ;
const U32 dictLimit = ctx - > dictLimit ;
const BYTE * const prefixStart = base + dictLimit ;
const BYTE * const dictBase = ctx - > dictBase ;
const BYTE * const dictEnd = dictBase + dictLimit ;
2015-11-24 13:06:07 +00:00
const BYTE * const dictStart = dictBase + ctx - > lowLimit ;
2015-11-22 01:53:43 +00:00
2016-03-30 17:48:05 +00:00
const U32 maxSearches = 1 < < ctx - > params . cParams . searchLog ;
const U32 mls = ctx - > params . cParams . searchLength ;
2016-04-06 10:34:42 +00:00
const U32 minMatch = ( mls = = 3 ) ? 3 : 4 ;
2015-11-22 01:53:43 +00:00
typedef size_t ( * searchMax_f ) ( ZSTD_CCtx * zc , const BYTE * ip , const BYTE * iLimit ,
size_t * offsetPtr ,
U32 maxNbAttempts , U32 matchLengthSearch ) ;
2015-11-23 14:29:15 +00:00
searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS ;
2015-11-22 01:53:43 +00:00
/* init */
2016-03-18 10:03:43 +00:00
U32 rep [ ZSTD_REP_INIT ] ;
2016-04-05 16:16:38 +00:00
for ( U32 i = 0 ; i < ZSTD_REP_INIT ; i + + )
2016-03-16 11:57:07 +00:00
rep [ i ] = REPCODE_STARTVALUE ;
2016-04-05 16:16:38 +00:00
2016-04-06 10:34:42 +00:00
ctx - > nextToUpdate3 = ctx - > nextToUpdate ;
2015-11-22 01:53:43 +00:00
ZSTD_resetSeqStore ( seqStorePtr ) ;
2015-12-11 09:44:07 +00:00
if ( ( ip - prefixStart ) < REPCODE_STARTVALUE ) ip + = REPCODE_STARTVALUE ;
2015-11-22 01:53:43 +00:00
/* Match Loop */
2016-01-27 23:18:06 +00:00
while ( ip < ilimit ) {
2015-11-22 01:53:43 +00:00
size_t matchLength = 0 ;
size_t offset = 0 ;
2016-04-05 16:16:38 +00:00
const BYTE * start = ip ;
2015-11-22 01:53:43 +00:00
U32 current = ( U32 ) ( ip - base ) ;
/* check repCode */
2016-04-05 17:01:10 +00:00
for ( U32 i = 0 ; i < ZSTD_REP_NUM ; i + + ) {
2016-04-05 16:16:38 +00:00
const U32 repIndex = ( U32 ) ( current - rep [ i ] ) ;
2015-11-22 01:53:43 +00:00
const BYTE * const repBase = repIndex < dictLimit ? dictBase : base ;
const BYTE * const repMatch = repBase + repIndex ;
2015-11-23 12:34:21 +00:00
if ( ( U32 ) ( ( dictLimit - 1 ) - repIndex ) > = 3 ) /* intentional overflow */
2016-04-06 10:34:42 +00:00
if ( MEM_readMINMATCH ( ip , minMatch ) = = MEM_readMINMATCH ( repMatch , minMatch ) ) {
2015-11-22 01:53:43 +00:00
/* repcode detected we should take it */
const BYTE * const repEnd = repIndex < dictLimit ? dictEnd : iend ;
2016-04-05 16:16:38 +00:00
if ( matchLength = = 0 ) {
offset = i ;
2016-04-06 10:34:42 +00:00
matchLength = ZSTD_count_2segments ( ip + minMatch , repMatch + minMatch , iend , repEnd , prefixStart ) + minMatch ;
2016-04-05 16:16:38 +00:00
} else {
2016-04-06 10:34:42 +00:00
size_t mlRep = ZSTD_count_2segments ( ip + minMatch , repMatch + minMatch , iend , repEnd , prefixStart ) + minMatch ;
2016-04-05 16:16:38 +00:00
int gain2 = ( int ) ( mlRep * 3 /*- ZSTD_highbit((U32)i+1)*/ + ( i = = 1 ) ) ;
int gain1 = ( int ) ( matchLength * 3 - /*ZSTD_highbit((U32)offset+1)*/ + 1 + ( offset = = 1 ) ) ;
if ( gain2 > gain1 )
matchLength = mlRep , offset = i ;
}
2016-01-27 23:18:06 +00:00
} }
2015-11-22 01:53:43 +00:00
2016-03-19 17:08:32 +00:00
/* first search (depth 0) */
{ size_t offsetFound = 99999999 ;
size_t const ml2 = searchMax ( ctx , ip , iend , & offsetFound , maxSearches , mls ) ;
2015-11-23 15:17:21 +00:00
if ( ml2 > matchLength )
matchLength = ml2 , start = ip , offset = offsetFound ;
}
2016-01-27 23:18:06 +00:00
if ( matchLength < MINMATCH ) {
2015-11-23 15:17:21 +00:00
ip + = ( ( ip - anchor ) > > g_searchStrength ) + 1 ; /* jump faster over incompressible sections */
continue ;
}
2015-11-22 01:53:43 +00:00
/* let's try to find a better solution */
if ( depth > = 1 )
2016-01-27 23:18:06 +00:00
while ( ip < ilimit ) {
2015-11-22 01:53:43 +00:00
ip + + ;
current + + ;
/* check repCode */
2016-04-05 17:01:10 +00:00
for ( U32 i = 0 ; i < ZSTD_REP_NUM ; i + + ) {
2016-04-05 16:16:38 +00:00
const U32 repIndex = ( U32 ) ( current - rep [ i ] ) ;
2015-11-22 01:53:43 +00:00
const BYTE * const repBase = repIndex < dictLimit ? dictBase : base ;
const BYTE * const repMatch = repBase + repIndex ;
2015-11-23 12:34:21 +00:00
if ( ( U32 ) ( ( dictLimit - 1 ) - repIndex ) > = 3 ) /* intentional overflow */
2016-04-06 10:34:42 +00:00
if ( MEM_readMINMATCH ( ip , minMatch ) = = MEM_readMINMATCH ( repMatch , minMatch ) ) {
2015-11-22 01:53:43 +00:00
/* repcode detected */
const BYTE * const repEnd = repIndex < dictLimit ? dictEnd : iend ;
2016-04-06 10:34:42 +00:00
size_t const repLength = ZSTD_count_2segments ( ip + minMatch , repMatch + minMatch , iend , repEnd , prefixStart ) + minMatch ;
2016-03-19 17:08:32 +00:00
int const gain2 = ( int ) ( repLength * 3 ) ;
2016-04-05 16:16:38 +00:00
int const gain1 = ( int ) ( matchLength * 3 - ZSTD_highbit ( ( U32 ) offset + 1 ) + 1 + ( offset < ZSTD_REP_NUM ) ) ;
2015-11-23 12:34:21 +00:00
if ( ( repLength > = MINMATCH ) & & ( gain2 > gain1 ) )
2016-04-05 16:16:38 +00:00
matchLength = repLength , offset = i , start = ip ;
2016-01-27 23:18:06 +00:00
} }
2015-11-22 01:53:43 +00:00
/* search match, depth 1 */
2016-03-19 17:08:32 +00:00
{ size_t offset2 = 99999999 ;
size_t const ml2 = searchMax ( ctx , ip , iend , & offset2 , maxSearches , mls ) ;
int const gain2 = ( int ) ( ml2 * 4 - ZSTD_highbit ( ( U32 ) offset2 + 1 ) ) ; /* raw approx */
int const gain1 = ( int ) ( matchLength * 4 - ZSTD_highbit ( ( U32 ) offset + 1 ) + 4 ) ;
2016-01-27 23:18:06 +00:00
if ( ( ml2 > = MINMATCH ) & & ( gain2 > gain1 ) ) {
2015-11-22 01:53:43 +00:00
matchLength = ml2 , offset = offset2 , start = ip ;
continue ; /* search a better one */
2016-01-27 23:18:06 +00:00
} }
2015-11-22 01:53:43 +00:00
/* let's find an even better one */
2016-01-27 23:18:06 +00:00
if ( ( depth = = 2 ) & & ( ip < ilimit ) ) {
2015-11-22 01:53:43 +00:00
ip + + ;
current + + ;
/* check repCode */
2016-04-05 17:01:10 +00:00
for ( U32 i = 0 ; i < ZSTD_REP_NUM ; i + + ) {
2016-04-05 16:16:38 +00:00
const U32 repIndex = ( U32 ) ( current - rep [ i ] ) ;
2015-11-22 01:53:43 +00:00
const BYTE * const repBase = repIndex < dictLimit ? dictBase : base ;
const BYTE * const repMatch = repBase + repIndex ;
2015-11-23 12:34:21 +00:00
if ( ( U32 ) ( ( dictLimit - 1 ) - repIndex ) > = 3 ) /* intentional overflow */
2016-04-06 10:34:42 +00:00
if ( MEM_readMINMATCH ( ip , minMatch ) = = MEM_readMINMATCH ( repMatch , minMatch ) ) {
2015-11-22 01:53:43 +00:00
/* repcode detected */
const BYTE * const repEnd = repIndex < dictLimit ? dictEnd : iend ;
2016-04-06 10:34:42 +00:00
size_t const repLength = ZSTD_count_2segments ( ip + minMatch , repMatch + minMatch , iend , repEnd , prefixStart ) + minMatch ;
2016-04-05 16:16:38 +00:00
int const gain2 = ( int ) ( repLength * 4 ) ;
int const gain1 = ( int ) ( matchLength * 4 - ZSTD_highbit ( ( U32 ) offset + 1 ) + 1 + ( offset < ZSTD_REP_NUM ) ) ;
2015-11-23 12:34:21 +00:00
if ( ( repLength > = MINMATCH ) & & ( gain2 > gain1 ) )
2016-04-05 16:16:38 +00:00
matchLength = repLength , offset = i , start = ip ;
2016-01-27 23:18:06 +00:00
} }
2015-11-22 01:53:43 +00:00
/* search match, depth 2 */
2016-03-19 17:08:32 +00:00
{ size_t offset2 = 99999999 ;
size_t const ml2 = searchMax ( ctx , ip , iend , & offset2 , maxSearches , mls ) ;
int const gain2 = ( int ) ( ml2 * 4 - ZSTD_highbit ( ( U32 ) offset2 + 1 ) ) ; /* raw approx */
int const gain1 = ( int ) ( matchLength * 4 - ZSTD_highbit ( ( U32 ) offset + 1 ) + 7 ) ;
2016-01-27 23:18:06 +00:00
if ( ( ml2 > = MINMATCH ) & & ( gain2 > gain1 ) ) {
2015-11-22 01:53:43 +00:00
matchLength = ml2 , offset = offset2 , start = ip ;
continue ;
2016-01-27 23:18:06 +00:00
} } }
2015-11-22 01:53:43 +00:00
break ; /* nothing found : store previous solution */
}
/* catch up */
2016-03-16 11:57:07 +00:00
if ( offset > = ZSTD_REP_NUM ) {
2016-03-18 10:03:43 +00:00
U32 matchIndex = ( U32 ) ( ( start - base ) - ( offset - ZSTD_REP_MOVE ) ) ;
2015-11-24 13:06:07 +00:00
const BYTE * match = ( matchIndex < dictLimit ) ? dictBase + matchIndex : base + matchIndex ;
const BYTE * const mStart = ( matchIndex < dictLimit ) ? dictStart : prefixStart ;
while ( ( start > anchor ) & & ( match > mStart ) & & ( start [ - 1 ] = = match [ - 1 ] ) ) { start - - ; match - - ; matchLength + + ; } /* catch up */
2015-11-22 01:53:43 +00:00
}
/* store sequence */
2016-04-07 13:24:29 +00:00
{
2016-04-05 16:16:38 +00:00
if ( offset > = ZSTD_REP_NUM ) {
rep [ 2 ] = rep [ 1 ] ;
rep [ 1 ] = rep [ 0 ] ;
2016-04-05 19:03:43 +00:00
rep [ 0 ] = ( U32 ) ( offset - ZSTD_REP_MOVE ) ;
2016-04-05 16:16:38 +00:00
} else {
if ( offset ! = 0 ) {
U32 temp = rep [ offset ] ;
if ( offset > 1 ) rep [ 2 ] = rep [ 1 ] ;
if ( offset > 0 ) rep [ 1 ] = rep [ 0 ] ;
rep [ 0 ] = temp ;
}
2015-11-22 01:53:43 +00:00
2016-04-05 16:16:38 +00:00
if ( offset < = 1 & & start = = anchor ) offset = 1 - offset ;
2015-11-22 01:53:43 +00:00
}
2016-04-05 16:16:38 +00:00
size_t const litLength = start - anchor ;
ZSTD_storeSeq ( seqStorePtr , litLength , anchor , offset , matchLength - MINMATCH ) ;
anchor = ip = start + matchLength ;
2016-01-27 23:18:06 +00:00
} }
2015-11-22 01:53:43 +00:00
/* Last Literals */
2016-03-20 15:00:00 +00:00
{ size_t const lastLLSize = iend - anchor ;
2015-11-22 01:53:43 +00:00
memcpy ( seqStorePtr - > lit , anchor , lastLLSize ) ;
seqStorePtr - > lit + = lastLLSize ;
}
}
2016-01-23 18:28:41 +00:00
void ZSTD_compressBlock_greedy_extDict ( ZSTD_CCtx * ctx , const void * src , size_t srcSize )
2015-11-22 01:53:43 +00:00
{
2016-04-05 17:01:10 +00:00
ZSTD_compressBlock_greedy_extDict_generic ( ctx , src , srcSize ) ;
2015-11-22 01:53:43 +00:00
}
2016-01-23 18:28:41 +00:00
static void ZSTD_compressBlock_lazy_extDict ( ZSTD_CCtx * ctx , const void * src , size_t srcSize )
2015-11-22 02:12:28 +00:00
{
2016-01-25 03:22:03 +00:00
ZSTD_compressBlock_lazy_extDict_generic ( ctx , src , srcSize , 0 , 1 ) ;
2015-11-22 02:12:28 +00:00
}
2015-11-22 01:53:43 +00:00
2016-01-23 18:28:41 +00:00
static void ZSTD_compressBlock_lazy2_extDict ( ZSTD_CCtx * ctx , const void * src , size_t srcSize )
2015-11-22 11:22:04 +00:00
{
2016-01-25 03:22:03 +00:00
ZSTD_compressBlock_lazy_extDict_generic ( ctx , src , srcSize , 0 , 2 ) ;
2015-11-22 11:22:04 +00:00
}
2016-01-23 18:28:41 +00:00
static void ZSTD_compressBlock_btlazy2_extDict ( ZSTD_CCtx * ctx , const void * src , size_t srcSize )
2015-11-23 12:34:21 +00:00
{
2016-01-25 03:22:03 +00:00
ZSTD_compressBlock_lazy_extDict_generic ( ctx , src , srcSize , 1 , 2 ) ;
2015-11-23 12:34:21 +00:00
}
2016-02-22 09:06:17 +00:00
static void ZSTD_compressBlock_btopt_extDict ( ZSTD_CCtx * ctx , const void * src , size_t srcSize )
2016-01-31 10:25:48 +00:00
{
2016-04-05 19:03:43 +00:00
ZSTD_compressBlock_opt_extDict_generic ( ctx , src , srcSize ) ;
2016-01-31 10:25:48 +00:00
}
2015-11-21 14:27:35 +00:00
2016-01-23 18:28:41 +00:00
typedef void ( * ZSTD_blockCompressor ) ( ZSTD_CCtx * ctx , const void * src , size_t srcSize ) ;
2015-11-04 11:05:27 +00:00
2016-01-26 02:14:20 +00:00
static ZSTD_blockCompressor ZSTD_selectBlockCompressor ( ZSTD_strategy strat , int extDict )
2015-10-31 11:57:14 +00:00
{
2016-02-22 09:06:17 +00:00
static const ZSTD_blockCompressor blockCompressor [ 2 ] [ 6 ] = {
2016-04-05 21:58:51 +00:00
# if 1
2016-02-22 09:06:17 +00:00
{ ZSTD_compressBlock_fast , ZSTD_compressBlock_greedy , ZSTD_compressBlock_lazy , ZSTD_compressBlock_lazy2 , ZSTD_compressBlock_btlazy2 , ZSTD_compressBlock_btopt } ,
2016-04-05 16:16:38 +00:00
# else
{ ZSTD_compressBlock_fast_extDict , ZSTD_compressBlock_greedy_extDict , ZSTD_compressBlock_lazy_extDict , ZSTD_compressBlock_lazy2_extDict , ZSTD_compressBlock_btlazy2_extDict , ZSTD_compressBlock_btopt_extDict } ,
# endif
2016-02-22 09:06:17 +00:00
{ ZSTD_compressBlock_fast_extDict , ZSTD_compressBlock_greedy_extDict , ZSTD_compressBlock_lazy_extDict , ZSTD_compressBlock_lazy2_extDict , ZSTD_compressBlock_btlazy2_extDict , ZSTD_compressBlock_btopt_extDict }
2015-11-29 01:38:09 +00:00
} ;
return blockCompressor [ extDict ] [ ( U32 ) strat ] ;
2015-10-31 11:57:14 +00:00
}
2016-03-15 00:24:33 +00:00
static size_t ZSTD_compressBlock_internal ( ZSTD_CCtx * zc , void * dst , size_t dstCapacity , const void * src , size_t srcSize )
2015-11-04 11:05:27 +00:00
{
2016-03-30 17:48:05 +00:00
ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor ( zc - > params . cParams . strategy , zc - > lowLimit < zc - > dictLimit ) ;
2016-02-02 13:36:49 +00:00
if ( srcSize < MIN_CBLOCK_SIZE + ZSTD_blockHeaderSize + 1 ) return 0 ; /* don't even attempt compression below a certain srcSize */
2016-01-23 18:28:41 +00:00
blockCompressor ( zc , src , srcSize ) ;
2016-03-15 00:24:33 +00:00
return ZSTD_compressSequences ( zc , dst , dstCapacity , srcSize ) ;
2015-11-04 11:05:27 +00:00
}
2016-03-25 09:52:25 +00:00
2016-02-02 13:36:49 +00:00
static size_t ZSTD_compress_generic ( ZSTD_CCtx * zc ,
2016-03-15 00:24:33 +00:00
void * dst , size_t dstCapacity ,
2015-10-22 14:31:46 +00:00
const void * src , size_t srcSize )
{
2016-02-02 13:36:49 +00:00
size_t blockSize = zc - > blockSize ;
2015-10-22 14:31:46 +00:00
size_t remaining = srcSize ;
const BYTE * ip = ( const BYTE * ) src ;
BYTE * const ostart = ( BYTE * ) dst ;
BYTE * op = ostart ;
2016-03-30 17:48:05 +00:00
const U32 maxDist = 1 < < zc - > params . cParams . windowLog ;
2016-03-25 09:52:25 +00:00
ZSTD_stats_t * stats = & zc - > seqStore . stats ;
ZSTD_statsInit ( stats ) ;
2015-11-01 11:40:22 +00:00
2016-02-02 13:36:49 +00:00
while ( remaining ) {
2015-11-04 17:19:39 +00:00
size_t cSize ;
2016-03-25 09:52:25 +00:00
ZSTD_statsResetFreqs ( stats ) ;
2015-10-22 14:31:46 +00:00
2016-03-15 00:24:33 +00:00
if ( dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE ) return ERROR ( dstSize_tooSmall ) ; /* not enough space to store compressed block */
2015-11-04 17:19:39 +00:00
if ( remaining < blockSize ) blockSize = remaining ;
2015-11-13 10:27:46 +00:00
2016-03-19 17:08:32 +00:00
if ( ( U32 ) ( ip + blockSize - zc - > base ) > zc - > loadedDictEnd + maxDist ) {
/* enforce maxDist */
U32 const newLowLimit = ( U32 ) ( ip + blockSize - zc - > base ) - maxDist ;
2016-02-02 15:00:50 +00:00
if ( zc - > lowLimit < newLowLimit ) zc - > lowLimit = newLowLimit ;
2016-02-02 13:36:49 +00:00
if ( zc - > dictLimit < zc - > lowLimit ) zc - > dictLimit = zc - > lowLimit ;
2015-11-24 13:06:07 +00:00
}
2015-11-13 10:27:46 +00:00
2016-03-15 00:24:33 +00:00
cSize = ZSTD_compressBlock_internal ( zc , op + ZSTD_blockHeaderSize , dstCapacity - ZSTD_blockHeaderSize , ip , blockSize ) ;
2015-10-22 14:31:46 +00:00
if ( ZSTD_isError ( cSize ) ) return cSize ;
2016-02-02 13:36:49 +00:00
if ( cSize = = 0 ) { /* block is not compressible */
2016-03-15 00:24:33 +00:00
cSize = ZSTD_noCompressBlock ( op , dstCapacity , ip , blockSize ) ;
2016-01-09 01:10:40 +00:00
if ( ZSTD_isError ( cSize ) ) return cSize ;
2016-02-02 13:36:49 +00:00
} else {
2015-10-22 14:31:46 +00:00
op [ 0 ] = ( BYTE ) ( cSize > > 16 ) ;
op [ 1 ] = ( BYTE ) ( cSize > > 8 ) ;
op [ 2 ] = ( BYTE ) cSize ;
2015-11-19 16:28:35 +00:00
op [ 0 ] + = ( BYTE ) ( bt_compressed < < 6 ) ; /* is a compressed block */
2015-10-22 14:31:46 +00:00
cSize + = 3 ;
}
2015-11-04 17:19:39 +00:00
remaining - = blockSize ;
2016-03-15 00:24:33 +00:00
dstCapacity - = cSize ;
2015-11-04 17:19:39 +00:00
ip + = blockSize ;
2015-10-22 14:31:46 +00:00
op + = cSize ;
}
2016-04-04 10:10:00 +00:00
ZSTD_statsPrint ( stats , zc - > params . cParams . searchLength ) ;
2015-10-22 14:31:46 +00:00
return op - ostart ;
}
2016-01-09 00:08:23 +00:00
static size_t ZSTD_compressContinue_internal ( ZSTD_CCtx * zc ,
2016-03-23 21:31:57 +00:00
void * dst , size_t dstCapacity ,
2016-01-09 00:08:23 +00:00
const void * src , size_t srcSize ,
U32 frame )
2015-10-22 14:31:46 +00:00
{
2015-10-29 15:49:43 +00:00
const BYTE * const ip = ( const BYTE * ) src ;
2016-01-07 14:35:18 +00:00
size_t hbSize = 0 ;
2016-02-02 13:36:49 +00:00
if ( frame & & ( zc - > stage = = 0 ) ) {
2016-01-07 14:35:18 +00:00
hbSize = zc - > hbSize ;
2016-03-23 21:31:57 +00:00
if ( dstCapacity < = hbSize ) return ERROR ( dstSize_tooSmall ) ;
2016-01-07 14:35:18 +00:00
zc - > stage = 1 ;
memcpy ( dst , zc - > headerBuffer , hbSize ) ;
2016-03-23 21:31:57 +00:00
dstCapacity - = hbSize ;
2016-01-07 14:35:18 +00:00
dst = ( char * ) dst + hbSize ;
}
2015-10-22 14:31:46 +00:00
2015-12-04 16:16:37 +00:00
/* Check if blocks follow each other */
2016-02-02 13:36:49 +00:00
if ( src ! = zc - > nextSrc ) {
2015-12-04 16:16:37 +00:00
/* not contiguous */
2016-03-19 17:08:32 +00:00
size_t const delta = zc - > nextSrc - ip ;
2015-12-04 16:16:37 +00:00
zc - > lowLimit = zc - > dictLimit ;
zc - > dictLimit = ( U32 ) ( zc - > nextSrc - zc - > base ) ;
zc - > dictBase = zc - > base ;
zc - > base - = delta ;
zc - > nextToUpdate = zc - > dictLimit ;
2015-12-05 08:23:53 +00:00
if ( zc - > dictLimit - zc - > lowLimit < 8 ) zc - > lowLimit = zc - > dictLimit ; /* too small extDict */
2015-12-04 16:16:37 +00:00
}
2015-11-13 10:27:46 +00:00
/* preemptive overflow correction */
2016-02-02 13:36:49 +00:00
if ( zc - > lowLimit > ( 1 < < 30 ) ) {
2016-03-30 17:48:05 +00:00
U32 const btplus = ( zc - > params . cParams . strategy = = ZSTD_btlazy2 ) | | ( zc - > params . cParams . strategy = = ZSTD_btopt ) ;
2016-04-04 11:49:18 +00:00
U32 const chainMask = ( 1 < < ( zc - > params . cParams . chainLog - btplus ) ) - 1 ;
U32 const newLowLimit = zc - > lowLimit & chainMask ; /* preserve position % chainSize */
2016-03-19 17:08:32 +00:00
U32 const correction = zc - > lowLimit - newLowLimit ;
2015-11-24 13:06:07 +00:00
ZSTD_reduceIndex ( zc , correction ) ;
zc - > base + = correction ;
zc - > dictBase + = correction ;
2015-12-11 09:44:07 +00:00
zc - > lowLimit = newLowLimit ;
2015-11-24 13:06:07 +00:00
zc - > dictLimit - = correction ;
if ( zc - > nextToUpdate < correction ) zc - > nextToUpdate = 0 ;
else zc - > nextToUpdate - = correction ;
2015-11-13 10:27:46 +00:00
}
2016-01-09 00:08:23 +00:00
/* if input and dictionary overlap : reduce dictionary (presumed modified by input) */
2016-02-02 13:36:49 +00:00
if ( ( ip + srcSize > zc - > dictBase + zc - > lowLimit ) & & ( ip < zc - > dictBase + zc - > dictLimit ) ) {
2015-11-24 13:06:07 +00:00
zc - > lowLimit = ( U32 ) ( ip + srcSize - zc - > dictBase ) ;
if ( zc - > lowLimit > zc - > dictLimit ) zc - > lowLimit = zc - > dictLimit ;
2015-10-22 14:31:46 +00:00
}
2015-11-24 13:06:07 +00:00
zc - > nextSrc = ip + srcSize ;
2016-03-19 17:08:32 +00:00
{ size_t const cSize = frame ?
2016-03-23 21:31:57 +00:00
ZSTD_compress_generic ( zc , dst , dstCapacity , src , srcSize ) :
ZSTD_compressBlock_internal ( zc , dst , dstCapacity , src , srcSize ) ;
2016-01-07 14:35:18 +00:00
if ( ZSTD_isError ( cSize ) ) return cSize ;
return cSize + hbSize ;
}
2015-10-22 14:31:46 +00:00
}
2016-01-09 00:08:23 +00:00
size_t ZSTD_compressContinue ( ZSTD_CCtx * zc ,
2016-03-23 21:31:57 +00:00
void * dst , size_t dstCapacity ,
2016-01-09 00:08:23 +00:00
const void * src , size_t srcSize )
{
2016-03-23 21:31:57 +00:00
return ZSTD_compressContinue_internal ( zc , dst , dstCapacity , src , srcSize , 1 ) ;
2016-01-09 00:08:23 +00:00
}
2016-03-15 00:24:33 +00:00
size_t ZSTD_compressBlock ( ZSTD_CCtx * zc , void * dst , size_t dstCapacity , const void * src , size_t srcSize )
2016-01-09 00:08:23 +00:00
{
2016-03-16 14:26:51 +00:00
if ( srcSize > ZSTD_BLOCKSIZE_MAX ) return ERROR ( srcSize_wrong ) ;
2016-04-04 19:15:23 +00:00
ZSTD_LOG_BLOCK ( " %p: ZSTD_compressBlock searchLength=%d \n " , zc - > base , zc - > params . cParams . searchLength ) ;
2016-03-15 00:24:33 +00:00
return ZSTD_compressContinue_internal ( zc , dst , dstCapacity , src , srcSize , 0 ) ;
2016-01-09 00:08:23 +00:00
}
2016-01-26 02:14:20 +00:00
static size_t ZSTD_loadDictionaryContent ( ZSTD_CCtx * zc , const void * src , size_t srcSize )
2015-12-04 16:16:37 +00:00
{
const BYTE * const ip = ( const BYTE * ) src ;
const BYTE * const iend = ip + srcSize ;
/* input becomes current prefix */
zc - > lowLimit = zc - > dictLimit ;
zc - > dictLimit = ( U32 ) ( zc - > nextSrc - zc - > base ) ;
zc - > dictBase = zc - > base ;
zc - > base + = ip - zc - > nextSrc ;
zc - > nextToUpdate = zc - > dictLimit ;
2016-02-02 13:36:49 +00:00
zc - > loadedDictEnd = ( U32 ) ( iend - zc - > base ) ;
2015-12-04 16:16:37 +00:00
zc - > nextSrc = iend ;
if ( srcSize < = 8 ) return 0 ;
2016-03-30 17:48:05 +00:00
switch ( zc - > params . cParams . strategy )
2015-12-04 16:16:37 +00:00
{
case ZSTD_fast :
2016-03-30 17:48:05 +00:00
ZSTD_fillHashTable ( zc , iend , zc - > params . cParams . searchLength ) ;
2015-12-04 16:16:37 +00:00
break ;
case ZSTD_greedy :
case ZSTD_lazy :
case ZSTD_lazy2 :
2016-03-30 17:48:05 +00:00
ZSTD_insertAndFindFirstIndex ( zc , iend - 8 , zc - > params . cParams . searchLength ) ;
2015-12-04 16:16:37 +00:00
break ;
case ZSTD_btlazy2 :
2016-02-15 06:21:54 +00:00
case ZSTD_btopt :
2016-03-30 17:48:05 +00:00
ZSTD_updateTree ( zc , iend - 8 , iend , 1 < < zc - > params . cParams . searchLog , zc - > params . cParams . searchLength ) ;
2015-12-04 16:16:37 +00:00
break ;
default :
return ERROR ( GENERIC ) ; /* strategy doesn't exist; impossible */
}
2016-02-02 13:36:49 +00:00
zc - > nextToUpdate = zc - > loadedDictEnd ;
2015-12-04 16:16:37 +00:00
return 0 ;
}
2015-10-22 14:31:46 +00:00
2016-01-26 02:14:20 +00:00
/* Dictionary format :
Magic = = ZSTD_DICT_MAGIC ( 4 bytes )
2016-03-13 10:08:40 +00:00
HUF_writeCTable ( 256 )
2016-01-26 02:14:20 +00:00
Dictionary content
*/
2016-03-13 10:08:40 +00:00
/*! ZSTD_loadDictEntropyStats() :
2016-01-26 02:14:20 +00:00
@ return : size read from dictionary */
static size_t ZSTD_loadDictEntropyStats ( ZSTD_CCtx * zc , const void * dict , size_t dictSize )
{
/* note : magic number already checked */
2016-01-27 23:18:06 +00:00
size_t offcodeHeaderSize , matchlengthHeaderSize , litlengthHeaderSize , errorCode ;
short offcodeNCount [ MaxOff + 1 ] ;
unsigned offcodeMaxValue = MaxOff , offcodeLog = OffFSELog ;
short matchlengthNCount [ MaxML + 1 ] ;
unsigned matchlengthMaxValue = MaxML , matchlengthLog = MLFSELog ;
short litlengthNCount [ MaxLL + 1 ] ;
unsigned litlengthMaxValue = MaxLL , litlengthLog = LLFSELog ;
2016-03-19 17:08:32 +00:00
size_t const hufHeaderSize = HUF_readCTable ( zc - > hufTable , 255 , dict , dictSize ) ;
2016-01-26 02:14:20 +00:00
if ( HUF_isError ( hufHeaderSize ) ) return ERROR ( dictionary_corrupted ) ;
2016-01-27 23:18:06 +00:00
zc - > flagStaticTables = 1 ;
dict = ( const char * ) dict + hufHeaderSize ;
dictSize - = hufHeaderSize ;
offcodeHeaderSize = FSE_readNCount ( offcodeNCount , & offcodeMaxValue , & offcodeLog , dict , dictSize ) ;
if ( FSE_isError ( offcodeHeaderSize ) ) return ERROR ( dictionary_corrupted ) ;
errorCode = FSE_buildCTable ( zc - > offcodeCTable , offcodeNCount , offcodeMaxValue , offcodeLog ) ;
if ( FSE_isError ( errorCode ) ) return ERROR ( dictionary_corrupted ) ;
dict = ( const char * ) dict + offcodeHeaderSize ;
dictSize - = offcodeHeaderSize ;
matchlengthHeaderSize = FSE_readNCount ( matchlengthNCount , & matchlengthMaxValue , & matchlengthLog , dict , dictSize ) ;
if ( FSE_isError ( matchlengthHeaderSize ) ) return ERROR ( dictionary_corrupted ) ;
errorCode = FSE_buildCTable ( zc - > matchlengthCTable , matchlengthNCount , matchlengthMaxValue , matchlengthLog ) ;
if ( FSE_isError ( errorCode ) ) return ERROR ( dictionary_corrupted ) ;
dict = ( const char * ) dict + matchlengthHeaderSize ;
dictSize - = matchlengthHeaderSize ;
litlengthHeaderSize = FSE_readNCount ( litlengthNCount , & litlengthMaxValue , & litlengthLog , dict , dictSize ) ;
if ( FSE_isError ( litlengthHeaderSize ) ) return ERROR ( dictionary_corrupted ) ;
errorCode = FSE_buildCTable ( zc - > litlengthCTable , litlengthNCount , litlengthMaxValue , litlengthLog ) ;
if ( FSE_isError ( errorCode ) ) return ERROR ( dictionary_corrupted ) ;
return hufHeaderSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize ;
2016-01-26 02:14:20 +00:00
}
2016-03-15 00:24:33 +00:00
/** ZSTD_compress_insertDictionary() :
* @ return : 0 , or an error code */
2016-01-26 15:31:22 +00:00
static size_t ZSTD_compress_insertDictionary ( ZSTD_CCtx * zc , const void * dict , size_t dictSize )
2016-01-26 02:14:20 +00:00
{
2016-03-15 00:24:33 +00:00
if ( ( dict = = NULL ) | | ( dictSize < = 4 ) ) return 0 ;
2016-01-26 14:58:49 +00:00
2016-03-15 00:24:33 +00:00
/* default : dict is pure content */
if ( MEM_readLE32 ( dict ) ! = ZSTD_DICT_MAGIC ) return ZSTD_loadDictionaryContent ( zc , dict , dictSize ) ;
/* known magic number : dict is parsed for entropy stats and content */
2016-03-30 14:50:44 +00:00
{ size_t const eSize = ZSTD_loadDictEntropyStats ( zc , ( const char * ) dict + 4 /* skip magic */ , dictSize - 4 ) + 4 ;
if ( ZSTD_isError ( eSize ) ) return eSize ;
return ZSTD_loadDictionaryContent ( zc , ( const char * ) dict + eSize , dictSize - eSize ) ;
2016-01-26 14:58:49 +00:00
}
2016-01-07 14:35:18 +00:00
}
2016-04-01 13:48:48 +00:00
/*! ZSTD_compressBegin_internal() :
2016-01-07 14:35:18 +00:00
* @ return : 0 , or an error code */
2016-04-01 13:48:48 +00:00
static size_t ZSTD_compressBegin_internal ( ZSTD_CCtx * zc ,
2016-01-26 15:31:22 +00:00
const void * dict , size_t dictSize ,
2016-03-30 17:48:05 +00:00
ZSTD_parameters params , U64 pledgedSrcSize )
2015-10-22 14:31:46 +00:00
{
2016-04-07 13:24:29 +00:00
U32 hashLog3 = ( pledgedSrcSize | | pledgedSrcSize > = 8192 ) ? ZSTD_HASHLOG3_MAX : ( ( pledgedSrcSize > = 2048 ) ? ZSTD_HASHLOG3_MIN + 1 : ZSTD_HASHLOG3_MIN ) ;
2016-04-04 10:10:00 +00:00
zc - > hashLog3 = ( params . cParams . searchLength = = 3 ) ? hashLog3 : 0 ;
2016-03-23 14:53:38 +00:00
// printf("windowLog=%d hashLog=%d hashLog3=%d \n", params.windowLog, params.hashLog, zc->hashLog3);
2015-11-25 13:42:45 +00:00
2016-03-15 00:24:33 +00:00
{ size_t const errorCode = ZSTD_resetCCtx_advanced ( zc , params ) ;
2016-03-21 12:24:16 +00:00
if ( ZSTD_isError ( errorCode ) ) return errorCode ; }
2015-11-13 10:27:46 +00:00
2016-03-15 00:24:33 +00:00
/* Write Frame Header into ctx headerBuffer */
MEM_writeLE32 ( zc - > headerBuffer , ZSTD_MAGICNUMBER ) ;
2016-03-19 14:11:42 +00:00
{ BYTE * const op = ( BYTE * ) zc - > headerBuffer ;
2016-03-30 17:48:05 +00:00
U32 const fcsId = ( pledgedSrcSize > 0 ) + ( pledgedSrcSize > = 256 ) + ( pledgedSrcSize > = 65536 + 256 ) ; /* 0-3 */
BYTE fdescriptor = ( BYTE ) ( params . cParams . windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN ) ; /* windowLog : 4 KB - 128 MB */
2016-03-15 00:24:33 +00:00
fdescriptor | = ( BYTE ) ( fcsId < < 6 ) ;
2016-03-15 00:33:36 +00:00
op [ 4 ] = fdescriptor ;
2016-03-15 00:24:33 +00:00
switch ( fcsId )
{
default : /* impossible */
case 0 : break ;
2016-03-30 17:48:05 +00:00
case 1 : op [ 5 ] = ( BYTE ) ( pledgedSrcSize ) ; break ;
case 2 : MEM_writeLE16 ( op + 5 , ( U16 ) ( pledgedSrcSize - 256 ) ) ; break ;
case 3 : MEM_writeLE64 ( op + 5 , ( U64 ) ( pledgedSrcSize ) ) ; break ;
2016-03-15 00:24:33 +00:00
}
2016-03-19 14:11:42 +00:00
zc - > hbSize = ZSTD_frameHeaderSize_min + ZSTD_fcs_fieldSize [ fcsId ] ;
2016-03-15 00:24:33 +00:00
}
2016-01-07 14:35:18 +00:00
2016-03-15 00:24:33 +00:00
zc - > stage = 0 ;
2016-01-26 15:31:22 +00:00
return ZSTD_compress_insertDictionary ( zc , dict , dictSize ) ;
2015-10-22 14:31:46 +00:00
}
2015-10-25 13:06:35 +00:00
2016-04-01 13:48:48 +00:00
/*! ZSTD_compressBegin_advanced() :
* @ return : 0 , or an error code */
size_t ZSTD_compressBegin_advanced ( ZSTD_CCtx * zc ,
const void * dict , size_t dictSize ,
ZSTD_parameters params , U64 pledgedSrcSize )
{
/* compression parameters verification and optimization */
{ size_t const errorCode = ZSTD_checkCParams_advanced ( params . cParams , pledgedSrcSize ) ;
if ( ZSTD_isError ( errorCode ) ) return errorCode ; }
return ZSTD_compressBegin_internal ( zc , dict , dictSize , params , pledgedSrcSize ) ;
}
2016-01-26 15:31:22 +00:00
size_t ZSTD_compressBegin_usingDict ( ZSTD_CCtx * zc , const void * dict , size_t dictSize , int compressionLevel )
2016-01-26 02:14:20 +00:00
{
2016-03-30 17:48:05 +00:00
ZSTD_parameters params ;
params . cParams = ZSTD_getCParams ( compressionLevel , 0 , dictSize ) ;
params . fParams . contentSizeFlag = 0 ;
2016-04-01 13:48:48 +00:00
ZSTD_adjustCParams ( & params . cParams , 0 , dictSize ) ;
2016-03-01 13:14:35 +00:00
ZSTD_LOG_BLOCK ( " %p: ZSTD_compressBegin_usingDict compressionLevel=%d \n " , zc - > base , compressionLevel ) ;
2016-04-01 13:48:48 +00:00
return ZSTD_compressBegin_internal ( zc , dict , dictSize , params , 0 ) ;
2016-01-26 15:31:22 +00:00
}
2015-11-25 13:42:45 +00:00
2016-04-04 10:10:00 +00:00
size_t ZSTD_compressBegin_targetSrcSize ( ZSTD_CCtx * zc , const void * dict , size_t dictSize , size_t targetSrcSize , int compressionLevel )
{
ZSTD_parameters params ;
params . cParams = ZSTD_getCParams ( compressionLevel , targetSrcSize , dictSize ) ;
params . fParams . contentSizeFlag = 1 ;
ZSTD_adjustCParams ( & params . cParams , targetSrcSize , dictSize ) ;
ZSTD_LOG_BLOCK ( " %p: ZSTD_compressBegin_targetSrcSize compressionLevel=%d \n " , zc - > base , compressionLevel ) ;
return ZSTD_compressBegin_internal ( zc , dict , dictSize , params , targetSrcSize ) ;
}
2016-01-26 15:31:22 +00:00
size_t ZSTD_compressBegin ( ZSTD_CCtx * zc , int compressionLevel )
2015-11-25 13:42:45 +00:00
{
2016-03-01 13:14:35 +00:00
ZSTD_LOG_BLOCK ( " %p: ZSTD_compressBegin compressionLevel=%d \n " , zc - > base , compressionLevel ) ;
2016-03-30 17:48:05 +00:00
return ZSTD_compressBegin_usingDict ( zc , NULL , 0 , compressionLevel ) ;
2015-10-25 13:06:35 +00:00
}
2016-03-13 10:08:40 +00:00
/*! ZSTD_compressEnd() :
* Write frame epilogue .
2015-11-25 13:42:45 +00:00
* @ return : nb of bytes written into dst ( or an error code ) */
2016-03-15 00:24:33 +00:00
size_t ZSTD_compressEnd ( ZSTD_CCtx * zc , void * dst , size_t dstCapacity )
2015-10-29 15:49:43 +00:00
{
BYTE * op = ( BYTE * ) dst ;
2016-01-07 14:35:18 +00:00
size_t hbSize = 0 ;
2015-10-29 15:49:43 +00:00
2016-03-19 17:08:32 +00:00
/* special case : empty frame : header still within internal buffer */
2016-01-27 23:18:06 +00:00
if ( zc - > stage = = 0 ) {
2016-01-07 14:35:18 +00:00
hbSize = zc - > hbSize ;
2016-03-15 00:24:33 +00:00
if ( dstCapacity < = hbSize ) return ERROR ( dstSize_tooSmall ) ;
2016-01-07 14:35:18 +00:00
zc - > stage = 1 ;
memcpy ( dst , zc - > headerBuffer , hbSize ) ;
2016-03-15 00:24:33 +00:00
dstCapacity - = hbSize ;
2016-01-07 14:35:18 +00:00
op + = hbSize ;
}
2015-10-29 15:49:43 +00:00
2016-01-07 14:35:18 +00:00
/* frame epilogue */
2016-03-15 00:24:33 +00:00
if ( dstCapacity < 3 ) return ERROR ( dstSize_tooSmall ) ;
2015-10-29 15:49:43 +00:00
op [ 0 ] = ( BYTE ) ( bt_end < < 6 ) ;
op [ 1 ] = 0 ;
op [ 2 ] = 0 ;
2016-01-07 14:35:18 +00:00
return 3 + hbSize ;
2015-10-29 15:49:43 +00:00
}
2016-01-30 02:14:15 +00:00
size_t ZSTD_compress_usingPreparedCCtx ( ZSTD_CCtx * cctx , const ZSTD_CCtx * preparedCCtx ,
2016-03-15 00:24:33 +00:00
void * dst , size_t dstCapacity ,
2016-01-30 02:14:15 +00:00
const void * src , size_t srcSize )
{
2016-03-19 17:08:32 +00:00
{ size_t const errorCode = ZSTD_copyCCtx ( cctx , preparedCCtx ) ;
if ( ZSTD_isError ( errorCode ) ) return errorCode ;
}
{ size_t const cSize = ZSTD_compressContinue ( cctx , dst , dstCapacity , src , srcSize ) ;
if ( ZSTD_isError ( cSize ) ) return cSize ;
{ size_t const endSize = ZSTD_compressEnd ( cctx , ( char * ) dst + cSize , dstCapacity - cSize ) ;
if ( ZSTD_isError ( endSize ) ) return endSize ;
return cSize + endSize ;
} }
2016-01-30 02:14:15 +00:00
}
2016-03-30 14:50:44 +00:00
static size_t ZSTD_compress_internal ( ZSTD_CCtx * ctx ,
2016-03-15 00:24:33 +00:00
void * dst , size_t dstCapacity ,
2015-11-25 13:42:45 +00:00
const void * src , size_t srcSize ,
2015-12-18 00:26:48 +00:00
const void * dict , size_t dictSize ,
2015-11-25 13:42:45 +00:00
ZSTD_parameters params )
2015-10-22 14:31:46 +00:00
{
BYTE * const ostart = ( BYTE * ) dst ;
BYTE * op = ostart ;
2016-01-26 15:31:22 +00:00
/* Init */
2016-04-01 13:48:48 +00:00
{ size_t const errorCode = ZSTD_compressBegin_internal ( ctx , dict , dictSize , params , srcSize ) ;
2016-03-23 21:31:57 +00:00
if ( ZSTD_isError ( errorCode ) ) return errorCode ; }
2015-10-22 14:31:46 +00:00
/* body (compression) */
2016-03-15 00:24:33 +00:00
{ size_t const oSize = ZSTD_compressContinue ( ctx , op , dstCapacity , src , srcSize ) ;
2016-03-23 21:31:57 +00:00
if ( ZSTD_isError ( oSize ) ) return oSize ;
op + = oSize ;
dstCapacity - = oSize ; }
2015-10-22 14:31:46 +00:00
/* Close frame */
2016-03-15 00:24:33 +00:00
{ size_t const oSize = ZSTD_compressEnd ( ctx , op , dstCapacity ) ;
2016-03-23 21:31:57 +00:00
if ( ZSTD_isError ( oSize ) ) return oSize ;
op + = oSize ; }
2015-10-22 14:31:46 +00:00
return ( op - ostart ) ;
}
2016-03-30 14:50:44 +00:00
size_t ZSTD_compress_advanced ( ZSTD_CCtx * ctx ,
void * dst , size_t dstCapacity ,
const void * src , size_t srcSize ,
const void * dict , size_t dictSize ,
ZSTD_parameters params )
{
2016-03-30 17:48:05 +00:00
size_t const errorCode = ZSTD_checkCParams_advanced ( params . cParams , srcSize ) ;
2016-03-30 14:50:44 +00:00
if ( ZSTD_isError ( errorCode ) ) return errorCode ;
return ZSTD_compress_internal ( ctx , dst , dstCapacity , src , srcSize , dict , dictSize , params ) ;
}
2016-03-15 00:24:33 +00:00
size_t ZSTD_compress_usingDict ( ZSTD_CCtx * ctx , void * dst , size_t dstCapacity , const void * src , size_t srcSize , const void * dict , size_t dictSize , int compressionLevel )
2015-12-18 00:26:48 +00:00
{
2016-03-30 17:48:05 +00:00
ZSTD_parameters params ;
2016-03-01 13:14:35 +00:00
ZSTD_LOG_BLOCK ( " %p: ZSTD_compress_usingDict srcSize=%d dictSize=%d compressionLevel=%d \n " , ctx - > base , ( int ) srcSize , ( int ) dictSize , compressionLevel ) ;
2016-03-30 17:48:05 +00:00
params . cParams = ZSTD_getCParams ( compressionLevel , srcSize , dictSize ) ;
params . fParams . contentSizeFlag = 1 ;
ZSTD_adjustCParams ( & params . cParams , srcSize , dictSize ) ;
2016-03-30 14:50:44 +00:00
return ZSTD_compress_internal ( ctx , dst , dstCapacity , src , srcSize , dict , dictSize , params ) ;
2015-12-18 00:26:48 +00:00
}
2016-03-15 00:24:33 +00:00
size_t ZSTD_compressCCtx ( ZSTD_CCtx * ctx , void * dst , size_t dstCapacity , const void * src , size_t srcSize , int compressionLevel )
2015-10-25 13:06:35 +00:00
{
2016-03-01 13:14:35 +00:00
ZSTD_LOG_BLOCK ( " %p: ZSTD_compressCCtx srcSize=%d compressionLevel=%d \n " , ctx - > base , ( int ) srcSize , compressionLevel ) ;
2016-03-30 14:50:44 +00:00
return ZSTD_compress_usingDict ( ctx , dst , dstCapacity , src , srcSize , NULL , 0 , compressionLevel ) ;
2015-10-25 13:06:35 +00:00
}
2016-03-15 00:24:33 +00:00
size_t ZSTD_compress ( void * dst , size_t dstCapacity , const void * src , size_t srcSize , int compressionLevel )
2015-10-22 14:31:46 +00:00
{
2015-10-29 21:02:40 +00:00
size_t result ;
2015-11-11 12:43:58 +00:00
ZSTD_CCtx ctxBody ;
2015-10-29 17:41:45 +00:00
memset ( & ctxBody , 0 , sizeof ( ctxBody ) ) ;
2016-03-15 00:24:33 +00:00
result = ZSTD_compressCCtx ( & ctxBody , dst , dstCapacity , src , srcSize , compressionLevel ) ;
2016-01-07 14:35:18 +00:00
free ( ctxBody . workSpace ) ; /* can't free ctxBody, since it's on stack; just free heap content */
2015-10-29 21:02:40 +00:00
return result ;
2015-10-22 14:31:46 +00:00
}
2015-12-17 22:50:15 +00:00
2016-01-30 02:14:15 +00:00
2016-02-10 12:37:52 +00:00
/*-===== Pre-defined compression levels =====-*/
2016-01-30 02:14:15 +00:00
2016-03-09 15:57:09 +00:00
# define ZSTD_MAX_CLEVEL 22
2016-02-03 01:11:32 +00:00
unsigned ZSTD_maxCLevel ( void ) { return ZSTD_MAX_CLEVEL ; }
2016-03-30 17:48:05 +00:00
static const ZSTD_compressionParameters ZSTD_defaultCParameters [ 4 ] [ ZSTD_MAX_CLEVEL + 1 ] = {
2016-01-30 02:14:15 +00:00
{ /* "default" */
2016-03-30 17:48:05 +00:00
/* W, C, H, S, L, SL, strat */
{ 0 , 0 , 0 , 0 , 0 , 0 , ZSTD_fast } , /* level 0 - never used */
{ 19 , 13 , 14 , 1 , 7 , 4 , ZSTD_fast } , /* level 1 */
{ 19 , 15 , 16 , 1 , 6 , 4 , ZSTD_fast } , /* level 2 */
{ 20 , 18 , 20 , 1 , 6 , 4 , ZSTD_fast } , /* level 3 */
{ 20 , 13 , 17 , 2 , 5 , 4 , ZSTD_greedy } , /* level 4.*/
{ 20 , 15 , 18 , 3 , 5 , 4 , ZSTD_greedy } , /* level 5 */
{ 21 , 16 , 19 , 2 , 5 , 4 , ZSTD_lazy } , /* level 6 */
{ 21 , 17 , 20 , 3 , 5 , 4 , ZSTD_lazy } , /* level 7 */
{ 21 , 18 , 20 , 3 , 5 , 4 , ZSTD_lazy2 } , /* level 8.*/
{ 21 , 20 , 20 , 3 , 5 , 4 , ZSTD_lazy2 } , /* level 9 */
{ 21 , 19 , 21 , 4 , 5 , 4 , ZSTD_lazy2 } , /* level 10 */
{ 22 , 20 , 22 , 4 , 5 , 4 , ZSTD_lazy2 } , /* level 11 */
{ 22 , 20 , 22 , 5 , 5 , 4 , ZSTD_lazy2 } , /* level 12 */
{ 22 , 21 , 22 , 5 , 5 , 4 , ZSTD_lazy2 } , /* level 13 */
{ 22 , 21 , 22 , 6 , 5 , 4 , ZSTD_lazy2 } , /* level 14 */
{ 22 , 21 , 21 , 5 , 5 , 4 , ZSTD_btlazy2 } , /* level 15 */
{ 23 , 22 , 22 , 5 , 5 , 4 , ZSTD_btlazy2 } , /* level 16 */
{ 23 , 22 , 22 , 6 , 5 , 22 , ZSTD_btopt } , /* level 17 */
{ 22 , 22 , 22 , 5 , 3 , 44 , ZSTD_btopt } , /* level 18 */
{ 23 , 24 , 22 , 7 , 3 , 44 , ZSTD_btopt } , /* level 19 */
{ 25 , 26 , 22 , 7 , 3 , 71 , ZSTD_btopt } , /* level 20 */
{ 26 , 26 , 24 , 7 , 3 , 256 , ZSTD_btopt } , /* level 21 */
{ 27 , 28 , 26 , 9 , 3 , 256 , ZSTD_btopt } , /* level 22 */
2016-01-30 02:14:15 +00:00
} ,
{ /* for srcSize <= 256 KB */
2016-03-30 17:48:05 +00:00
/* W, C, H, S, L, T, strat */
{ 0 , 0 , 0 , 0 , 0 , 0 , ZSTD_fast } , /* level 0 */
{ 18 , 14 , 15 , 1 , 6 , 4 , ZSTD_fast } , /* level 1 */
{ 18 , 14 , 16 , 1 , 5 , 4 , ZSTD_fast } , /* level 2 */
{ 18 , 14 , 17 , 1 , 5 , 4 , ZSTD_fast } , /* level 3.*/
{ 18 , 14 , 15 , 4 , 4 , 4 , ZSTD_greedy } , /* level 4 */
{ 18 , 16 , 17 , 4 , 4 , 4 , ZSTD_greedy } , /* level 5 */
{ 18 , 17 , 17 , 3 , 4 , 4 , ZSTD_lazy } , /* level 6 */
{ 18 , 17 , 17 , 4 , 4 , 4 , ZSTD_lazy } , /* level 7 */
{ 18 , 17 , 17 , 4 , 4 , 4 , ZSTD_lazy2 } , /* level 8 */
{ 18 , 17 , 17 , 5 , 4 , 4 , ZSTD_lazy2 } , /* level 9 */
{ 18 , 17 , 17 , 6 , 4 , 4 , ZSTD_lazy2 } , /* level 10 */
{ 18 , 17 , 17 , 7 , 4 , 4 , ZSTD_lazy2 } , /* level 11 */
{ 18 , 18 , 17 , 4 , 4 , 4 , ZSTD_btlazy2 } , /* level 12 */
{ 18 , 19 , 17 , 7 , 4 , 4 , ZSTD_btlazy2 } , /* level 13.*/
{ 18 , 17 , 19 , 8 , 4 , 24 , ZSTD_btopt } , /* level 14.*/
{ 18 , 19 , 19 , 8 , 4 , 48 , ZSTD_btopt } , /* level 15.*/
{ 18 , 19 , 18 , 9 , 4 , 128 , ZSTD_btopt } , /* level 16.*/
{ 18 , 19 , 18 , 9 , 4 , 192 , ZSTD_btopt } , /* level 17.*/
{ 18 , 19 , 18 , 9 , 4 , 256 , ZSTD_btopt } , /* level 18.*/
{ 18 , 19 , 18 , 10 , 4 , 256 , ZSTD_btopt } , /* level 19.*/
{ 18 , 19 , 18 , 11 , 4 , 256 , ZSTD_btopt } , /* level 20.*/
{ 18 , 19 , 18 , 12 , 4 , 256 , ZSTD_btopt } , /* level 21.*/
{ 18 , 19 , 18 , 12 , 4 , 256 , ZSTD_btopt } , /* level 22*/
2016-01-30 02:14:15 +00:00
} ,
{ /* for srcSize <= 128 KB */
2016-03-30 17:48:05 +00:00
/* W, C, H, S, L, T, strat */
{ 0 , 0 , 0 , 0 , 0 , 0 , ZSTD_fast } , /* level 0 - never used */
{ 17 , 12 , 13 , 1 , 6 , 4 , ZSTD_fast } , /* level 1 */
{ 17 , 13 , 16 , 1 , 5 , 4 , ZSTD_fast } , /* level 2 */
{ 17 , 13 , 14 , 2 , 5 , 4 , ZSTD_greedy } , /* level 3 */
{ 17 , 13 , 15 , 3 , 4 , 4 , ZSTD_greedy } , /* level 4 */
{ 17 , 15 , 17 , 4 , 4 , 4 , ZSTD_greedy } , /* level 5 */
{ 17 , 16 , 17 , 3 , 4 , 4 , ZSTD_lazy } , /* level 6 */
{ 17 , 15 , 17 , 4 , 4 , 4 , ZSTD_lazy2 } , /* level 7 */
{ 17 , 17 , 17 , 4 , 4 , 4 , ZSTD_lazy2 } , /* level 8 */
{ 17 , 17 , 17 , 5 , 4 , 4 , ZSTD_lazy2 } , /* level 9 */
{ 17 , 17 , 17 , 6 , 4 , 4 , ZSTD_lazy2 } , /* level 10 */
{ 17 , 17 , 17 , 7 , 4 , 4 , ZSTD_lazy2 } , /* level 11 */
{ 17 , 17 , 17 , 8 , 4 , 4 , ZSTD_lazy2 } , /* level 12 */
{ 17 , 18 , 17 , 6 , 4 , 4 , ZSTD_btlazy2 } , /* level 13.*/
{ 17 , 17 , 17 , 7 , 3 , 8 , ZSTD_btopt } , /* level 14.*/
{ 17 , 17 , 17 , 7 , 3 , 16 , ZSTD_btopt } , /* level 15.*/
{ 17 , 18 , 17 , 7 , 3 , 32 , ZSTD_btopt } , /* level 16.*/
{ 17 , 18 , 17 , 7 , 3 , 64 , ZSTD_btopt } , /* level 17.*/
{ 17 , 18 , 17 , 7 , 3 , 256 , ZSTD_btopt } , /* level 18.*/
{ 17 , 18 , 17 , 8 , 3 , 256 , ZSTD_btopt } , /* level 19.*/
{ 17 , 18 , 17 , 9 , 3 , 256 , ZSTD_btopt } , /* level 20.*/
{ 17 , 18 , 17 , 10 , 3 , 256 , ZSTD_btopt } , /* level 21.*/
{ 17 , 18 , 17 , 11 , 3 , 256 , ZSTD_btopt } , /* level 22.*/
2016-01-30 02:14:15 +00:00
} ,
{ /* for srcSize <= 16 KB */
2016-03-30 17:48:05 +00:00
/* W, C, H, S, L, T, strat */
{ 0 , 0 , 0 , 0 , 0 , 0 , ZSTD_fast } , /* level 0 -- never used */
{ 14 , 14 , 14 , 1 , 4 , 4 , ZSTD_fast } , /* level 1 */
{ 14 , 14 , 15 , 1 , 4 , 4 , ZSTD_fast } , /* level 2 */
{ 14 , 14 , 14 , 4 , 4 , 4 , ZSTD_greedy } , /* level 3.*/
2016-04-06 11:15:38 +00:00
#if 0
2016-04-06 10:34:42 +00:00
{ 14 , 14 , 14 , 3 , 3 , 4 , ZSTD_lazy } , /* level 4.*/
{ 14 , 14 , 14 , 4 , 3 , 4 , ZSTD_lazy2 } , /* level 5 */
{ 14 , 14 , 14 , 5 , 3 , 4 , ZSTD_lazy2 } , /* level 6 */
{ 14 , 14 , 14 , 6 , 3 , 4 , ZSTD_lazy2 } , /* level 7.*/
{ 14 , 14 , 14 , 7 , 3 , 4 , ZSTD_lazy2 } , /* level 8.*/
{ 14 , 15 , 14 , 6 , 3 , 4 , ZSTD_btlazy2 } , /* level 9.*/
# else
2016-03-30 17:48:05 +00:00
{ 14 , 14 , 14 , 3 , 4 , 4 , ZSTD_lazy } , /* level 4.*/
{ 14 , 14 , 14 , 4 , 4 , 4 , ZSTD_lazy2 } , /* level 5 */
{ 14 , 14 , 14 , 5 , 4 , 4 , ZSTD_lazy2 } , /* level 6 */
{ 14 , 14 , 14 , 6 , 4 , 4 , ZSTD_lazy2 } , /* level 7.*/
{ 14 , 14 , 14 , 7 , 4 , 4 , ZSTD_lazy2 } , /* level 8.*/
{ 14 , 15 , 14 , 6 , 4 , 4 , ZSTD_btlazy2 } , /* level 9.*/
2016-04-06 10:34:42 +00:00
# endif
2016-03-30 17:48:05 +00:00
{ 14 , 15 , 14 , 3 , 3 , 6 , ZSTD_btopt } , /* level 10.*/
{ 14 , 15 , 14 , 6 , 3 , 8 , ZSTD_btopt } , /* level 11.*/
{ 14 , 15 , 14 , 6 , 3 , 16 , ZSTD_btopt } , /* level 12.*/
{ 14 , 15 , 14 , 6 , 3 , 24 , ZSTD_btopt } , /* level 13.*/
{ 14 , 15 , 15 , 6 , 3 , 48 , ZSTD_btopt } , /* level 14.*/
{ 14 , 15 , 15 , 6 , 3 , 64 , ZSTD_btopt } , /* level 15.*/
{ 14 , 15 , 15 , 6 , 3 , 96 , ZSTD_btopt } , /* level 16.*/
{ 14 , 15 , 15 , 6 , 3 , 128 , ZSTD_btopt } , /* level 17.*/
{ 14 , 15 , 15 , 6 , 3 , 256 , ZSTD_btopt } , /* level 18.*/
{ 14 , 15 , 15 , 7 , 3 , 256 , ZSTD_btopt } , /* level 19.*/
{ 14 , 15 , 15 , 8 , 3 , 256 , ZSTD_btopt } , /* level 20.*/
{ 14 , 15 , 15 , 9 , 3 , 256 , ZSTD_btopt } , /* level 21.*/
{ 14 , 15 , 15 , 10 , 3 , 256 , ZSTD_btopt } , /* level 22.*/
2016-01-30 02:14:15 +00:00
} ,
} ;
2016-03-05 17:43:21 +00:00
/*! ZSTD_getParams() :
2016-01-30 02:14:15 +00:00
* @ return ZSTD_parameters structure for a selected compression level and srcSize .
2016-03-20 14:46:10 +00:00
* ` srcSize ` value is optional , select 0 if not known */
2016-03-30 17:48:05 +00:00
ZSTD_compressionParameters ZSTD_getCParams ( int compressionLevel , U64 srcSize , size_t dictSize )
2016-01-30 02:14:15 +00:00
{
2016-04-04 02:22:53 +00:00
ZSTD_compressionParameters cp ;
2016-04-04 11:28:28 +00:00
size_t const addedSize = srcSize ? 0 : 500 ;
2016-04-04 02:22:53 +00:00
U64 const rSize = srcSize + dictSize ? srcSize + dictSize + addedSize : ( U64 ) - 1 ;
2016-03-30 17:48:05 +00:00
U32 const tableID = ( rSize < = 256 KB ) + ( rSize < = 128 KB ) + ( rSize < = 16 KB ) ; /* intentional underflow for srcSizeHint == 0 */
2016-01-30 02:14:15 +00:00
if ( compressionLevel < = 0 ) compressionLevel = 1 ;
if ( compressionLevel > ZSTD_MAX_CLEVEL ) compressionLevel = ZSTD_MAX_CLEVEL ;
2016-04-04 02:22:53 +00:00
cp = ZSTD_defaultCParameters [ tableID ] [ compressionLevel ] ;
2016-04-04 11:28:28 +00:00
if ( MEM_32bits ( ) ) { /* auto-correction, for 32-bits mode */
if ( cp . windowLog > ZSTD_WINDOWLOG_MAX ) cp . windowLog = ZSTD_WINDOWLOG_MAX ;
2016-04-04 11:49:18 +00:00
if ( cp . chainLog > ZSTD_CHAINLOG_MAX ) cp . chainLog = ZSTD_CHAINLOG_MAX ;
2016-04-04 11:28:28 +00:00
if ( cp . hashLog > ZSTD_HASHLOG_MAX ) cp . hashLog = ZSTD_HASHLOG_MAX ;
}
2016-04-04 02:22:53 +00:00
return cp ;
2016-01-30 02:14:15 +00:00
}