Merge branch 'dev' of github.com:Cyan4973/lz4 into dev

This commit is contained in:
Yann Collet 2018-03-19 16:18:25 -07:00
commit 5b67c7d185
7 changed files with 452 additions and 178 deletions

362
lib/lz4.c
View File

@ -154,7 +154,8 @@
* Memory routines
**************************************/
#include <stdlib.h> /* malloc, calloc, free */
#define ALLOCATOR(n,s) calloc(n,s)
#define ALLOC(s) malloc(s)
#define ALLOC_AND_ZERO(s) calloc(1,s)
#define FREEMEM free
#include <string.h> /* memset, memcpy */
#define MEM_INIT memset
@ -446,9 +447,32 @@ static const U32 LZ4_skipTrigger = 6; /* Increase this value ==> compression ru
* Local Structures and types
**************************************/
typedef enum { notLimited = 0, limitedOutput = 1 } limitedOutput_directive;
typedef enum { byPtr, byU32, byU16 } tableType_t;
typedef enum { clearedTable = 0, byPtr, byU32, byU16 } tableType_t;
typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive;
/**
* This enum distinguishes several different modes of accessing previous
* content in the stream.
*
* - noDict : There is no preceding content.
* - withPrefix64k : Table entries up to ctx->dictSize before the current blob
* blob being compressed are valid and refer to the preceding
* content (of length ctx->dictSize), which is available
* contiguously preceding in memory the content currently
* being compressed.
* - usingExtDict : Like withPrefix64k, but the preceding content is somewhere
* else in memory, starting at ctx->dictionary with length
* ctx->dictSize.
* - usingDictCtx : Like usingExtDict, but everything concerning the preceding
* content is in a separate context, pointed to by
* ctx->dictCtx. ctx->dictionary, ctx->dictSize, and table
* entries in the current context that refer to positions
* preceding the beginning of the current compression are
* ignored. Instead, ctx->dictCtx->dictionary and ctx->dictCtx
* ->dictSize describe the location and size of the preceding
* content, and matches are found by looking in the ctx
* ->dictCtx->hashTable.
*/
typedef enum { noDict = 0, withPrefix64k, usingExtDict, usingDictCtx } dict_directive;
typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive;
typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive;
@ -496,6 +520,7 @@ static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableTy
{
switch (tableType)
{
case clearedTable: { /* illegal! */ assert(0); return; }
case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; }
case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; }
case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; }
@ -508,20 +533,55 @@ LZ4_FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_
LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase);
}
static const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase)
static const BYTE* LZ4_getPositionOnHash(U32 h, const void* tableBase, tableType_t tableType, const BYTE* srcBase)
{
if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; }
if (tableType == byU32) { const U32* const hashTable = (U32*) tableBase; return hashTable[h] + srcBase; }
{ const U16* const hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */
if (tableType == byPtr) { const BYTE* const* hashTable = (const BYTE* const*) tableBase; return hashTable[h]; }
if (tableType == byU32) { const U32* const hashTable = (const U32*) tableBase; return hashTable[h] + srcBase; }
{ const U16* const hashTable = (const U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */
}
LZ4_FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)
LZ4_FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, const void* tableBase, tableType_t tableType, const BYTE* srcBase)
{
U32 const h = LZ4_hashPosition(p, tableType);
return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase);
}
LZ4_FORCE_INLINE void LZ4_prepareTable(
LZ4_stream_t_internal* const cctx,
const int inputSize,
const tableType_t tableType,
const dict_directive dictDirective) {
/* If the table hasn't been used, it's guaranteed to be zeroed out, and is
* therefore safe to use no matter what mode we're in. Otherwise, we figure
* out if it's safe to leave as is or whether it needs to be reset.
*/
if (cctx->tableType != clearedTable) {
if (cctx->tableType != tableType
|| (tableType == byU16 && cctx->currentOffset + inputSize >= 0xFFFFU)
|| (tableType == byU32 && cctx->currentOffset > 1 GB)
|| tableType == byPtr
|| inputSize >= 4 KB)
{
DEBUGLOG(4, "Resetting table in %p", cctx);
MEM_INIT(cctx->hashTable, 0, LZ4_HASHTABLESIZE);
cctx->currentOffset = 0;
cctx->tableType = clearedTable;
}
}
/* If the current offset is zero, we will never look in the external
* dictionary context, since there is no value a table entry can take that
* indicates a miss. In that case, we need to bump the offset to something
* non-zero.
*/
if (dictDirective == usingDictCtx &&
tableType != byPtr &&
cctx->currentOffset == 0)
{
cctx->currentOffset = 1;
}
}
/** LZ4_compress_generic() :
inlined, to ensure branches are decided at compilation time */
LZ4_FORCE_INLINE int LZ4_compress_generic(
@ -532,45 +592,50 @@ LZ4_FORCE_INLINE int LZ4_compress_generic(
const int maxOutputSize,
const limitedOutput_directive outputLimited,
const tableType_t tableType,
const dict_directive dict,
const dict_directive dictDirective,
const dictIssue_directive dictIssue,
const U32 acceleration)
{
const BYTE* ip = (const BYTE*) source;
const BYTE* base;
size_t currentOffset = cctx->currentOffset;
const BYTE* base = (const BYTE*) source - currentOffset;
const BYTE* lowLimit;
const BYTE* const lowRefLimit = ip - cctx->dictSize;
const BYTE* const dictionary = cctx->dictionary;
const BYTE* const dictEnd = dictionary + cctx->dictSize;
const ptrdiff_t dictDelta = dictEnd - (const BYTE*)source;
const LZ4_stream_t_internal* dictCtx = (const LZ4_stream_t_internal*) cctx->dictCtx;
const BYTE* const dictionary =
dictDirective == usingDictCtx ? dictCtx->dictionary : cctx->dictionary;
const U32 dictSize =
dictDirective == usingDictCtx ? dictCtx->dictSize : cctx->dictSize;
const BYTE* const lowRefLimit = (const BYTE*) source - dictSize;
const BYTE* const dictEnd = dictionary + dictSize;
const BYTE* anchor = (const BYTE*) source;
const BYTE* const iend = ip + inputSize;
const BYTE* const mflimitPlusOne = iend - MFLIMIT + 1;
const BYTE* const matchlimit = iend - LASTLITERALS;
/* the dictCtx currentOffset is indexed on the start of the dictionary,
* while a dictionary in the current context precedes the currentOffset */
const BYTE* dictBase = dictDirective == usingDictCtx ?
(const BYTE*) source - dictCtx->currentOffset :
(const BYTE*) source - dictSize - currentOffset;
const ptrdiff_t dictDelta = dictionary ? dictEnd - (const BYTE*) source : 0;
const BYTE* dictLowLimit;
BYTE* op = (BYTE*) dest;
BYTE* const olimit = op + maxOutputSize;
ptrdiff_t retval = 0;
U32 forwardH;
/* Init conditions */
if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported inputSize, too large (or negative) */
switch(dict)
{
case noDict:
default:
base = (const BYTE*)source;
lowLimit = (const BYTE*)source;
break;
case withPrefix64k:
base = (const BYTE*)source - cctx->currentOffset;
lowLimit = (const BYTE*)source - cctx->dictSize;
break;
case usingExtDict:
base = (const BYTE*)source - cctx->currentOffset;
lowLimit = (const BYTE*)source;
break;
}
lowLimit = (const BYTE*)source - (dictDirective == withPrefix64k ? dictSize : 0);
dictLowLimit = dictionary ? dictionary : lowLimit;
if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */
if (inputSize<LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
@ -598,10 +663,20 @@ LZ4_FORCE_INLINE int LZ4_compress_generic(
assert(ip < mflimitPlusOne);
match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base);
if (dict==usingExtDict) {
if (dictDirective == usingDictCtx) {
if (match < (const BYTE*)source) {
/* there was no match, try the dictionary */
match = LZ4_getPosition(ip, dictCtx->hashTable, byU32, dictBase);
refDelta = dictDelta;
lowLimit = dictLowLimit;
} else {
refDelta = 0;
lowLimit = (const BYTE*)source;
}
} else if (dictDirective==usingExtDict) {
if (match < (const BYTE*)source) {
refDelta = dictDelta;
lowLimit = dictionary;
lowLimit = dictLowLimit;
} else {
refDelta = 0;
lowLimit = (const BYTE*)source;
@ -622,7 +697,7 @@ LZ4_FORCE_INLINE int LZ4_compress_generic(
token = op++;
if ((outputLimited) && /* Check output buffer overflow */
(unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)))
return 0;
goto _clean_up;
if (litLength >= RUN_MASK) {
int len = (int)litLength-RUN_MASK;
*token = (RUN_MASK<<ML_BITS);
@ -643,7 +718,7 @@ _next_match:
/* Encode MatchLength */
{ unsigned matchCode;
if ((dict==usingExtDict) && (lowLimit==dictionary)) {
if ((dictDirective==usingExtDict || dictDirective==usingDictCtx) && lowLimit==dictionary) {
const BYTE* limit;
match += refDelta;
limit = ip + (dictEnd-match);
@ -662,7 +737,7 @@ _next_match:
if ( outputLimited && /* Check output buffer overflow */
(unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) )
return 0;
goto _clean_up;
if (matchCode >= ML_MASK) {
*token += ML_MASK;
matchCode -= ML_MASK;
@ -688,10 +763,20 @@ _next_match:
/* Test next position */
match = LZ4_getPosition(ip, cctx->hashTable, tableType, base);
if (dict==usingExtDict) {
if (dictDirective == usingDictCtx) {
if (match < (const BYTE*)source) {
/* there was no match, try the dictionary */
match = LZ4_getPosition(ip, dictCtx->hashTable, byU32, dictBase);
refDelta = dictDelta;
lowLimit = dictLowLimit;
} else {
refDelta = 0;
lowLimit = (const BYTE*)source;
}
} else if (dictDirective==usingExtDict) {
if (match < (const BYTE*)source) {
refDelta = dictDelta;
lowLimit = dictionary;
lowLimit = dictLowLimit;
} else {
refDelta = 0;
lowLimit = (const BYTE*)source;
@ -711,7 +796,7 @@ _last_literals:
{ size_t const lastRun = (size_t)(iend - anchor);
if ( (outputLimited) && /* Check output buffer overflow */
((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) )
return 0;
goto _clean_up;
if (lastRun >= RUN_MASK) {
size_t accumulator = lastRun - RUN_MASK;
*op++ = RUN_MASK << ML_BITS;
@ -724,41 +809,112 @@ _last_literals:
op += lastRun;
}
retval = (((char*)op)-dest);
_clean_up:
if (dictDirective == usingDictCtx) {
/* Subsequent linked blocks can't use the dictionary. */
/* Instead, they use the block we just compressed. */
cctx->dictCtx = NULL;
cctx->dictSize = (U32)inputSize;
} else {
cctx->dictSize += (U32)inputSize;
}
cctx->currentOffset += (U32)inputSize;
cctx->tableType = tableType;
/* End */
return (int) (((char*)op)-dest);
return (int)retval;
}
int LZ4_compress_fast_extState(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
{
LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)state)->internal_donotuse;
LZ4_resetStream((LZ4_stream_t*)state);
if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;
LZ4_resetStream((LZ4_stream_t*)state);
if (maxOutputSize >= LZ4_compressBound(inputSize)) {
if (inputSize < LZ4_64Klimit) {
return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration);
} else {
const tableType_t tableType = (sizeof(void*)==8) ? byU32 : byPtr;
return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, tableType, noDict, noDictIssue, acceleration);
}
} else {
if (inputSize < LZ4_64Klimit) {;
return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);
} else {
const tableType_t tableType = (sizeof(void*)==8) ? byU32 : byPtr;
return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, noDict, noDictIssue, acceleration);
}
}
}
/**
* LZ4_compress_fast_extState_noReset is a variant of LZ4_compress_fast_extState
* that can be used when the state is known to have already been initialized
* (via LZ4_resetStream or an earlier call to LZ4_compress_fast_extState /
* LZ4_compress_fast_extState_noReset). This can provide significantly better
* performance when the context reset would otherwise be a significant part of
* the cost of the compression, e.g., when the data to be compressed is small.
*/
int LZ4_compress_fast_extState_noReset(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
{
LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)state)->internal_donotuse;
if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;
ctx->dictionary = NULL;
ctx->dictSize = 0;
ctx->dictCtx = NULL;
if (maxOutputSize >= LZ4_compressBound(inputSize)) {
if (inputSize < LZ4_64Klimit)
return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration);
else
return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration);
if (inputSize < LZ4_64Klimit) {
const tableType_t tableType = byU16;
LZ4_prepareTable(ctx, inputSize, tableType, noDict);
if (ctx->currentOffset) {
return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, tableType, noDict, dictSmall, acceleration);
} else {
return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, tableType, noDict, noDictIssue, acceleration);
}
} else {
const tableType_t tableType = (sizeof(void*)==8) ? byU32 : byPtr;
LZ4_prepareTable(ctx, inputSize, tableType, noDict);
if (ctx->currentOffset) {
ctx->currentOffset += 64 KB;
}
return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, tableType, noDict, noDictIssue, acceleration);
}
} else {
if (inputSize < LZ4_64Klimit)
return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);
else
return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration);
if (inputSize < LZ4_64Klimit) {
const tableType_t tableType = byU16;
LZ4_prepareTable(ctx, inputSize, tableType, noDict);
if (ctx->currentOffset) {
return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, noDict, dictSmall, acceleration);
} else {
return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, noDict, noDictIssue, acceleration);
}
} else {
const tableType_t tableType = (sizeof(void*)==8) ? byU32 : byPtr;
LZ4_prepareTable(ctx, inputSize, tableType, noDict);
if (ctx->currentOffset) {
ctx->currentOffset += 64 KB;
}
return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, noDict, noDictIssue, acceleration);
}
}
}
int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
{
int result;
#if (LZ4_HEAPMODE)
void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */
LZ4_stream_t* ctxPtr = ALLOC(sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */
if (ctxPtr == NULL) return 0;
#else
LZ4_stream_t ctx;
void* const ctxPtr = &ctx;
LZ4_stream_t* const ctxPtr = &ctx;
#endif
int const result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration);
result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration);
#if (LZ4_HEAPMODE)
FREEMEM(ctxPtr);
@ -965,7 +1121,8 @@ static int LZ4_compress_destSize_extState (LZ4_stream_t* state, const char* src,
int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize)
{
#if (LZ4_HEAPMODE)
LZ4_stream_t* ctx = (LZ4_stream_t*)ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */
LZ4_stream_t* ctx = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */
if (ctx == NULL) return 0;
#else
LZ4_stream_t ctxBody;
LZ4_stream_t* ctx = &ctxBody;
@ -987,21 +1144,25 @@ int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targe
LZ4_stream_t* LZ4_createStream(void)
{
LZ4_stream_t* lz4s = (LZ4_stream_t*)ALLOCATOR(8, LZ4_STREAMSIZE_U64);
LZ4_stream_t* lz4s = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));
LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */
DEBUGLOG(4, "LZ4_createStream %p", lz4s);
if (lz4s == NULL) return NULL;
LZ4_resetStream(lz4s);
return lz4s;
}
void LZ4_resetStream (LZ4_stream_t* LZ4_stream)
{
DEBUGLOG(4, "LZ4_resetStream");
DEBUGLOG(5, "LZ4_resetStream %p", LZ4_stream);
MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t));
LZ4_stream->internal_donotuse.tableType = clearedTable;
}
int LZ4_freeStream (LZ4_stream_t* LZ4_stream)
{
if (!LZ4_stream) return 0; /* support free on NULL */
DEBUGLOG(5, "LZ4_freeStream %p", LZ4_stream);
FREEMEM(LZ4_stream);
return (0);
}
@ -1015,14 +1176,12 @@ int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize)
const BYTE* const dictEnd = p + dictSize;
const BYTE* base;
if ((dict->initCheck) || (dict->currentOffset > 1 GB)) /* Uninitialized structure, or reuse overflow */
LZ4_resetStream(LZ4_dict);
DEBUGLOG(4, "LZ4_loadDict %p", LZ4_dict);
if (dictSize < (int)HASH_UNIT) {
dict->dictionary = NULL;
dict->dictSize = 0;
return 0;
}
if ((dict->initCheck)
|| (dict->tableType != byU32 && dict->tableType != clearedTable)
|| (dict->currentOffset > 1 GB)) /* Uninitialized structure, or reuse overflow */
LZ4_resetStream(LZ4_dict);
if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB;
dict->currentOffset += 64 KB;
@ -1030,6 +1189,11 @@ int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize)
dict->dictionary = p;
dict->dictSize = (U32)(dictEnd - p);
dict->currentOffset += dict->dictSize;
dict->tableType = byU32;
if (dictSize < (int)HASH_UNIT) {
return 0;
}
while (p <= dictEnd-HASH_UNIT) {
LZ4_putPosition(p, dict->hashTable, byU32, base);
@ -1048,6 +1212,7 @@ static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src)
U32 const delta = LZ4_dict->currentOffset - 64 KB;
const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize;
int i;
DEBUGLOG(4, "LZ4_renormDictT %p", LZ4_dict);
for (i=0; i<LZ4_HASH_SIZE_U32; i++) {
if (LZ4_dict->hashTable[i] < delta) LZ4_dict->hashTable[i]=0;
else LZ4_dict->hashTable[i] -= delta;
@ -1061,6 +1226,7 @@ static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src)
int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
{
const tableType_t tableType = byU32;
LZ4_stream_t_internal* streamPtr = &LZ4_stream->internal_donotuse;
const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize;
@ -1082,25 +1248,43 @@ int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, ch
/* prefix mode : source data follows dictionary */
if (dictEnd == (const BYTE*)source) {
int result;
LZ4_prepareTable(streamPtr, inputSize, tableType, withPrefix64k);
if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset))
result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, dictSmall, acceleration);
return LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, withPrefix64k, dictSmall, acceleration);
else
result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, noDictIssue, acceleration);
streamPtr->dictSize += (U32)inputSize;
streamPtr->currentOffset += (U32)inputSize;
return result;
return LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, withPrefix64k, noDictIssue, acceleration);
}
/* external dictionary mode */
{ int result;
if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset))
result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, dictSmall, acceleration);
else
result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, noDictIssue, acceleration);
if (streamPtr->dictCtx) {
/* We depend here on the fact that dictCtx'es (produced by
* LZ4_loadDict) guarantee that their tables contain no references
* to offsets between dictCtx->currentOffset - 64 KB and
* dictCtx->currentOffset - dictCtx->dictSize. This makes it safe
* to use noDictIssue even when the dict isn't a full 64 KB.
*/
if (inputSize > 4 KB) {
/* For compressing large blobs, it is faster to pay the setup
* cost to copy the dictionary's tables into the active context,
* so that the compression loop is only looking in one table.
*/
memcpy(streamPtr, streamPtr->dictCtx, sizeof(LZ4_stream_t));
result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration);
} else {
LZ4_prepareTable(streamPtr, inputSize, tableType, usingDictCtx);
result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, usingDictCtx, noDictIssue, acceleration);
}
} else {
LZ4_prepareTable(streamPtr, inputSize, tableType, usingExtDict);
if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) {
result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, usingExtDict, dictSmall, acceleration);
} else {
result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration);
}
}
streamPtr->dictionary = (const BYTE*)source;
streamPtr->dictSize = (U32)inputSize;
streamPtr->currentOffset += (U32)inputSize;
return result;
}
}
@ -1117,11 +1301,14 @@ int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char*
if (smallest > (const BYTE*) source) smallest = (const BYTE*) source;
LZ4_renormDictT(streamPtr, smallest);
result = LZ4_compress_generic(streamPtr, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1);
if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) {
result = LZ4_compress_generic(streamPtr, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, dictSmall, 1);
} else {
result = LZ4_compress_generic(streamPtr, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1);
}
streamPtr->dictionary = (const BYTE*)source;
streamPtr->dictSize = (U32)inputSize;
streamPtr->currentOffset += (U32)inputSize;
return result;
}
@ -1366,7 +1553,7 @@ int LZ4_decompress_fast(const char* source, char* dest, int originalSize)
LZ4_streamDecode_t* LZ4_createStreamDecode(void)
{
LZ4_streamDecode_t* lz4s = (LZ4_streamDecode_t*) ALLOCATOR(1, sizeof(LZ4_streamDecode_t));
LZ4_streamDecode_t* lz4s = (LZ4_streamDecode_t*) ALLOC_AND_ZERO(sizeof(LZ4_streamDecode_t));
return lz4s;
}
@ -1516,36 +1703,27 @@ They are only provided here for compatibility with older user programs.
int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); }
int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); }
/* Obsolete Streaming functions */
int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; }
static void LZ4_init(LZ4_stream_t* lz4ds, BYTE* base)
{
MEM_INIT(lz4ds, 0, sizeof(LZ4_stream_t));
lz4ds->internal_donotuse.bufferStart = base;
}
int LZ4_resetStreamState(void* state, char* inputBuffer)
{
if ((((uptrval)state) & 3) != 0) return 1; /* Error : pointer is not aligned on 4-bytes boundary */
LZ4_init((LZ4_stream_t*)state, (BYTE*)inputBuffer);
(void)inputBuffer;
LZ4_resetStream((LZ4_stream_t*)state);
return 0;
}
void* LZ4_create (char* inputBuffer)
{
LZ4_stream_t* lz4ds = (LZ4_stream_t*)ALLOCATOR(8, sizeof(LZ4_stream_t));
LZ4_init (lz4ds, (BYTE*)inputBuffer);
return lz4ds;
(void)inputBuffer;
return LZ4_createStream();
}
char* LZ4_slideInputBuffer (void* LZ4_Data)
char* LZ4_slideInputBuffer (void* state)
{
LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)LZ4_Data)->internal_donotuse;
int dictSize = LZ4_saveDict((LZ4_stream_t*)LZ4_Data, (char*)ctx->bufferStart, 64 KB);
return (char*)(ctx->bufferStart + dictSize);
// avoid const char * -> char * conversion warning
return (char *)(uptrval)((LZ4_stream_t*)state)->internal_donotuse.dictionary;
}
/* Obsolete streaming decompression functions */

View File

@ -343,6 +343,29 @@ LZ4LIB_API int LZ4_decompress_fast_usingDict (const char* src, char* dst, int or
/*^**********************************************
* !!!!!! STATIC LINKING ONLY !!!!!!
***********************************************/
/*-************************************
* Unstable declarations
**************************************
* Declarations in this section should be considered unstable.
* Use at your own peril, etc., etc.
* They may be removed in the future.
* Their signatures may change.
**************************************/
/*!
LZ4_compress_fast_extState_noReset() :
A variant of LZ4_compress_fast_extState().
Use the _noReset variant if LZ4_resetStream() was called on the state
buffer before being used for the first time (calls to both extState
functions leave the state in a safe state, so zeroing is not required
between calls). Otherwise, using the plain _extState requires LZ4 to
reinitialize the state internally for every call.
*/
LZ4LIB_API int LZ4_compress_fast_extState_noReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);
/*-************************************
* Private definitions
**************************************
@ -357,14 +380,16 @@ LZ4LIB_API int LZ4_decompress_fast_usingDict (const char* src, char* dst, int or
#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
#include <stdint.h>
typedef struct {
typedef struct LZ4_stream_t_internal LZ4_stream_t_internal;
struct LZ4_stream_t_internal {
uint32_t hashTable[LZ4_HASH_SIZE_U32];
uint32_t currentOffset;
uint32_t initCheck;
uint16_t initCheck;
uint16_t tableType;
const uint8_t* dictionary;
uint8_t* bufferStart; /* obsolete, used for slideInputBuffer */
const LZ4_stream_t_internal* dictCtx;
uint32_t dictSize;
} LZ4_stream_t_internal;
};
typedef struct {
const uint8_t* externalDict;
@ -375,14 +400,16 @@ typedef struct {
#else
typedef struct {
typedef struct LZ4_stream_t_internal LZ4_stream_t_internal;
struct LZ4_stream_t_internal {
unsigned int hashTable[LZ4_HASH_SIZE_U32];
unsigned int currentOffset;
unsigned int initCheck;
unsigned short initCheck;
unsigned short tableType;
const unsigned char* dictionary;
unsigned char* bufferStart; /* obsolete, used for slideInputBuffer */
const LZ4_stream_t_internal* dictCtx;
unsigned int dictSize;
} LZ4_stream_t_internal;
};
typedef struct {
const unsigned char* externalDict;
@ -465,11 +492,15 @@ LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") LZ4LIB_API int LZ4_co
LZ4_DEPRECATED("use LZ4_decompress_fast() instead") LZ4LIB_API int LZ4_uncompress (const char* source, char* dest, int outputSize);
LZ4_DEPRECATED("use LZ4_decompress_safe() instead") LZ4LIB_API int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize);
/* Obsolete streaming functions; use new streaming interface whenever possible */
LZ4_DEPRECATED("use LZ4_createStream() instead") LZ4LIB_API void* LZ4_create (char* inputBuffer);
LZ4_DEPRECATED("use LZ4_createStream() instead") LZ4LIB_API int LZ4_sizeofStreamState(void);
LZ4_DEPRECATED("use LZ4_resetStream() instead") LZ4LIB_API int LZ4_resetStreamState(void* state, char* inputBuffer);
LZ4_DEPRECATED("use LZ4_saveDict() instead") LZ4LIB_API char* LZ4_slideInputBuffer (void* state);
/* Broken, obsolete streaming functions; do not use!
*
* These functions depended on data that is no longer tracked in the state. They
* are therefore broken--they don't retain any history across compressions.
*/
LZ4_DEPRECATED("Broken!!! Use LZ4_createStream() instead") LZ4LIB_API void* LZ4_create (char* inputBuffer);
LZ4_DEPRECATED("Use LZ4_createStream() instead") LZ4LIB_API int LZ4_sizeofStreamState(void);
LZ4_DEPRECATED("Broken!!! Use LZ4_resetStream() instead") LZ4LIB_API int LZ4_resetStreamState(void* state, char* inputBuffer);
LZ4_DEPRECATED("Broken!!! Use LZ4_saveDict() instead") LZ4LIB_API char* LZ4_slideInputBuffer (void* state);
/* Obsolete streaming decoding functions */
LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") LZ4LIB_API int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize);

View File

@ -46,11 +46,25 @@ You can contact the author at :
#endif
/*-************************************
* Tuning parameters
**************************************/
/*
* LZ4F_HEAPMODE :
* Select how default compression functions will allocate memory for their hash table,
* in memory stack (0:default, fastest), or in memory heap (1:requires malloc()).
*/
#ifndef LZ4F_HEAPMODE
# define LZ4F_HEAPMODE 0
#endif
/*-************************************
* Memory routines
**************************************/
#include <stdlib.h> /* malloc, calloc, free */
#define ALLOCATOR(s) calloc(1,s)
#define ALLOC(s) malloc(s)
#define ALLOC_AND_ZERO(s) calloc(1,s)
#define FREEMEM free
#include <string.h> /* memset, memcpy, memmove */
#define MEM_INIT memset
@ -188,7 +202,8 @@ typedef struct LZ4F_cctx_s
U64 totalInSize;
XXH32_state_t xxh;
void* lz4CtxPtr;
U32 lz4CtxLevel; /* 0: unallocated; 1: LZ4_stream_t; 3: LZ4_streamHC_t */
U16 lz4CtxAlloc; // sized for: 0 = none, 1 = lz4 ctx, 2 = lz4hc ctx
U16 lz4CtxState; // in use as: 0 = none, 1 = lz4 ctx, 2 = lz4hc ctx
} LZ4F_cctx_t;
@ -279,7 +294,7 @@ static size_t LZ4F_compressBound_internal(size_t srcSize,
size_t alreadyBuffered)
{
LZ4F_preferences_t prefsNull;
memset(&prefsNull, 0, sizeof(prefsNull));
MEM_INIT(&prefsNull, 0, sizeof(prefsNull));
prefsNull.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled; /* worst case */
{ const LZ4F_preferences_t* const prefsPtr = (preferencesPtr==NULL) ? &prefsNull : preferencesPtr;
U32 const flush = prefsPtr->autoFlush | (srcSize==0);
@ -308,7 +323,7 @@ size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* prefere
size_t const headerSize = maxFHSize; /* max header size, including optional fields */
if (preferencesPtr!=NULL) prefs = *preferencesPtr;
else memset(&prefs, 0, sizeof(prefs));
else MEM_INIT(&prefs, 0, sizeof(prefs));
prefs.autoFlush = 1;
return headerSize + LZ4F_compressBound_internal(srcSize, &prefs, 0);;
@ -324,27 +339,22 @@ size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* prefere
* @return : number of bytes written into dstBuffer,
* or an error code if it fails (can be tested using LZ4F_isError())
*/
size_t LZ4F_compressFrame_usingCDict(void* dstBuffer, size_t dstCapacity,
size_t LZ4F_compressFrame_usingCDict(LZ4F_cctx* cctx,
void* dstBuffer, size_t dstCapacity,
const void* srcBuffer, size_t srcSize,
const LZ4F_CDict* cdict,
const LZ4F_preferences_t* preferencesPtr)
{
LZ4F_cctx_t cctxI;
LZ4_stream_t lz4ctx; /* pretty large on stack */
LZ4F_preferences_t prefs;
LZ4F_compressOptions_t options;
BYTE* const dstStart = (BYTE*) dstBuffer;
BYTE* dstPtr = dstStart;
BYTE* const dstEnd = dstStart + dstCapacity;
memset(&cctxI, 0, sizeof(cctxI));
cctxI.version = LZ4F_VERSION;
cctxI.maxBufferSize = 5 MB; /* mess with real buffer size to prevent dynamic allocation; works only because autoflush==1 & stableSrc==1 */
if (preferencesPtr!=NULL)
prefs = *preferencesPtr;
else
memset(&prefs, 0, sizeof(prefs));
MEM_INIT(&prefs, 0, sizeof(prefs));
if (prefs.frameInfo.contentSize != 0)
prefs.frameInfo.contentSize = (U64)srcSize; /* auto-correct content size if selected (!=0) */
@ -353,32 +363,24 @@ size_t LZ4F_compressFrame_usingCDict(void* dstBuffer, size_t dstCapacity,
if (srcSize <= LZ4F_getBlockSize(prefs.frameInfo.blockSizeID))
prefs.frameInfo.blockMode = LZ4F_blockIndependent; /* only one block => no need for inter-block link */
if (prefs.compressionLevel < LZ4HC_CLEVEL_MIN) {
cctxI.lz4CtxPtr = &lz4ctx;
cctxI.lz4CtxLevel = 1;
} /* fast compression context pre-created on stack */
memset(&options, 0, sizeof(options));
MEM_INIT(&options, 0, sizeof(options));
options.stableSrc = 1;
if (dstCapacity < LZ4F_compressFrameBound(srcSize, &prefs)) /* condition to guarantee success */
return err0r(LZ4F_ERROR_dstMaxSize_tooSmall);
{ size_t const headerSize = LZ4F_compressBegin_usingCDict(&cctxI, dstBuffer, dstCapacity, cdict, &prefs); /* write header */
{ size_t const headerSize = LZ4F_compressBegin_usingCDict(cctx, dstBuffer, dstCapacity, cdict, &prefs); /* write header */
if (LZ4F_isError(headerSize)) return headerSize;
dstPtr += headerSize; /* header size */ }
{ size_t const cSize = LZ4F_compressUpdate(&cctxI, dstPtr, dstEnd-dstPtr, srcBuffer, srcSize, &options);
{ size_t const cSize = LZ4F_compressUpdate(cctx, dstPtr, dstEnd-dstPtr, srcBuffer, srcSize, &options);
if (LZ4F_isError(cSize)) return cSize;
dstPtr += cSize; }
{ size_t const tailSize = LZ4F_compressEnd(&cctxI, dstPtr, dstEnd-dstPtr, &options); /* flush last block, and generate suffix */
{ size_t const tailSize = LZ4F_compressEnd(cctx, dstPtr, dstEnd-dstPtr, &options); /* flush last block, and generate suffix */
if (LZ4F_isError(tailSize)) return tailSize;
dstPtr += tailSize; }
if (prefs.compressionLevel >= LZ4HC_CLEVEL_MIN) /* Ctx allocation only for lz4hc */
FREEMEM(cctxI.lz4CtxPtr);
return (dstPtr - dstStart);
}
@ -394,9 +396,43 @@ size_t LZ4F_compressFrame(void* dstBuffer, size_t dstCapacity,
const void* srcBuffer, size_t srcSize,
const LZ4F_preferences_t* preferencesPtr)
{
return LZ4F_compressFrame_usingCDict(dstBuffer, dstCapacity,
srcBuffer, srcSize,
NULL, preferencesPtr);
size_t result;
#if (LZ4F_HEAPMODE)
LZ4F_cctx_t *cctxPtr;
result = LZ4F_createCompressionContext(&cctxPtr, LZ4F_VERSION);
if (LZ4F_isError(result)) return result;
#else
LZ4F_cctx_t cctx;
LZ4_stream_t lz4ctx;
LZ4F_cctx_t *cctxPtr = &cctx;
MEM_INIT(&cctx, 0, sizeof(cctx));
cctx.version = LZ4F_VERSION;
cctx.maxBufferSize = 5 MB; /* mess with real buffer size to prevent dynamic allocation; works only because autoflush==1 & stableSrc==1 */
if (preferencesPtr == NULL ||
preferencesPtr->compressionLevel < LZ4HC_CLEVEL_MIN)
{
LZ4_resetStream(&lz4ctx);
cctxPtr->lz4CtxPtr = &lz4ctx;
cctxPtr->lz4CtxAlloc = 1;
cctxPtr->lz4CtxState = 1;
}
#endif
result = LZ4F_compressFrame_usingCDict(cctxPtr, dstBuffer, dstCapacity,
srcBuffer, srcSize,
NULL, preferencesPtr);
#if (LZ4F_HEAPMODE)
LZ4F_freeCompressionContext(cctxPtr);
#else
if (preferencesPtr != NULL &&
preferencesPtr->compressionLevel >= LZ4HC_CLEVEL_MIN)
{
FREEMEM(cctxPtr->lz4CtxPtr);
}
#endif
return result;
}
@ -425,7 +461,7 @@ LZ4F_CDict* LZ4F_createCDict(const void* dictBuffer, size_t dictSize)
dictStart += dictSize - 64 KB;
dictSize = 64 KB;
}
cdict->dictContent = ALLOCATOR(dictSize);
cdict->dictContent = ALLOC(dictSize);
cdict->fastCtx = LZ4_createStream();
cdict->HCCtx = LZ4_createStreamHC();
if (!cdict->dictContent || !cdict->fastCtx || !cdict->HCCtx) {
@ -464,7 +500,7 @@ void LZ4F_freeCDict(LZ4F_CDict* cdict)
*/
LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_compressionContext_t* LZ4F_compressionContextPtr, unsigned version)
{
LZ4F_cctx_t* const cctxPtr = (LZ4F_cctx_t*)ALLOCATOR(sizeof(LZ4F_cctx_t));
LZ4F_cctx_t* const cctxPtr = (LZ4F_cctx_t*)ALLOC_AND_ZERO(sizeof(LZ4F_cctx_t));
if (cctxPtr==NULL) return err0r(LZ4F_ERROR_allocation_failed);
cctxPtr->version = version;
@ -490,6 +526,28 @@ LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_compressionContext_t LZ4F_comp
}
static void LZ4F_applyCDict(void* ctx,
const LZ4F_CDict* cdict,
int level) {
if (level < LZ4HC_CLEVEL_MIN) {
LZ4_stream_t_internal* internal_ctx = &((LZ4_stream_t *)ctx)->internal_donotuse;
assert(!internal_ctx->initCheck);
/* Clear any local dictionary */
internal_ctx->dictionary = NULL;
internal_ctx->dictSize = 0;
/* Point to the dictionary context */
internal_ctx->dictCtx = cdict ? &(cdict->fastCtx->internal_donotuse) : NULL;
} else {
if (cdict) {
memcpy(ctx, cdict->HCCtx, sizeof(*cdict->HCCtx));
LZ4_setCompressionLevel((LZ4_streamHC_t*)ctx, level);
} else {
LZ4_resetStreamHC((LZ4_streamHC_t*)(ctx), level);
}
}
}
/*! LZ4F_compressBegin_usingCDict() :
* init streaming compression and writes frame header into dstBuffer.
* dstBuffer must be >= LZ4F_HEADER_SIZE_MAX bytes.
@ -507,21 +565,33 @@ size_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctxPtr,
BYTE* headerStart;
if (dstCapacity < maxFHSize) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall);
memset(&prefNull, 0, sizeof(prefNull));
MEM_INIT(&prefNull, 0, sizeof(prefNull));
if (preferencesPtr == NULL) preferencesPtr = &prefNull;
cctxPtr->prefs = *preferencesPtr;
/* Ctx Management */
{ U32 const ctxTypeID = (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) ? 1 : 2; /* 0:nothing ; 1:LZ4 table ; 2:HC tables */
if (cctxPtr->lz4CtxLevel < ctxTypeID) {
{ U16 const ctxTypeID = (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) ? 1 : 2;
if (cctxPtr->lz4CtxAlloc < ctxTypeID) {
FREEMEM(cctxPtr->lz4CtxPtr);
if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN)
if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) {
cctxPtr->lz4CtxPtr = (void*)LZ4_createStream();
else
} else {
cctxPtr->lz4CtxPtr = (void*)LZ4_createStreamHC();
}
if (cctxPtr->lz4CtxPtr == NULL) return err0r(LZ4F_ERROR_allocation_failed);
cctxPtr->lz4CtxLevel = ctxTypeID;
} }
cctxPtr->lz4CtxAlloc = ctxTypeID;
cctxPtr->lz4CtxState = ctxTypeID;
} else if (cctxPtr->lz4CtxState != ctxTypeID) {
/* otherwise, a sufficient buffer is allocated, but we need to
* reset it to the correct context type */
if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) {
LZ4_resetStream((LZ4_stream_t *) cctxPtr->lz4CtxPtr);
} else {
LZ4_resetStreamHC((LZ4_streamHC_t *) cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel);
}
cctxPtr->lz4CtxState = ctxTypeID;
}
}
/* Buffer Management */
if (cctxPtr->prefs.frameInfo.blockSizeID == 0)
@ -535,7 +605,7 @@ size_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctxPtr,
if (cctxPtr->maxBufferSize < requiredBuffSize) {
cctxPtr->maxBufferSize = 0;
FREEMEM(cctxPtr->tmpBuff);
cctxPtr->tmpBuff = (BYTE*)ALLOCATOR(requiredBuffSize);
cctxPtr->tmpBuff = (BYTE*)ALLOC_AND_ZERO(requiredBuffSize);
if (cctxPtr->tmpBuff == NULL) return err0r(LZ4F_ERROR_allocation_failed);
cctxPtr->maxBufferSize = requiredBuffSize;
} }
@ -547,19 +617,7 @@ size_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctxPtr,
cctxPtr->cdict = cdict;
if (cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) {
/* frame init only for blockLinked : blockIndependent will be init at each block */
if (cdict) {
if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) {
memcpy(cctxPtr->lz4CtxPtr, cdict->fastCtx, sizeof(*cdict->fastCtx));
} else {
memcpy(cctxPtr->lz4CtxPtr, cdict->HCCtx, sizeof(*cdict->HCCtx));
LZ4_setCompressionLevel((LZ4_streamHC_t*)cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel);
}
} else {
if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN)
LZ4_resetStream((LZ4_stream_t*)(cctxPtr->lz4CtxPtr));
else
LZ4_resetStreamHC((LZ4_streamHC_t*)(cctxPtr->lz4CtxPtr), cctxPtr->prefs.compressionLevel);
}
LZ4F_applyCDict(cctxPtr->lz4CtxPtr, cdict, cctxPtr->prefs.compressionLevel);
}
/* Magic Number */
@ -654,11 +712,12 @@ static size_t LZ4F_makeBlock(void* dst, const void* src, size_t srcSize,
static int LZ4F_compressBlock(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict)
{
int const acceleration = (level < -1) ? -level : 1;
LZ4F_applyCDict(ctx, cdict, level);
if (cdict) {
memcpy(ctx, cdict->fastCtx, sizeof(*cdict->fastCtx));
return LZ4_compress_fast_continue((LZ4_stream_t*)ctx, src, dst, srcSize, dstCapacity, acceleration);
} else {
return LZ4_compress_fast_extState_noReset(ctx, src, dst, srcSize, dstCapacity, acceleration);
}
return LZ4_compress_fast_extState(ctx, src, dst, srcSize, dstCapacity, acceleration);
}
static int LZ4F_compressBlock_continue(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict)
@ -671,8 +730,7 @@ static int LZ4F_compressBlock_continue(void* ctx, const char* src, char* dst, in
static int LZ4F_compressBlockHC(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict)
{
if (cdict) {
memcpy(ctx, cdict->HCCtx, sizeof(*cdict->HCCtx));
LZ4_setCompressionLevel((LZ4_streamHC_t*)ctx, level);
LZ4F_applyCDict(ctx, cdict, level);
return LZ4_compress_HC_continue((LZ4_streamHC_t*)ctx, src, dst, srcSize, dstCapacity);
}
return LZ4_compress_HC_extStateHC(ctx, src, dst, srcSize, dstCapacity, level);
@ -728,7 +786,7 @@ size_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr,
if (cctxPtr->cStage != 1) return err0r(LZ4F_ERROR_GENERIC);
if (dstCapacity < LZ4F_compressBound_internal(srcSize, &(cctxPtr->prefs), cctxPtr->tmpInSize))
return err0r(LZ4F_ERROR_dstMaxSize_tooSmall);
memset(&cOptionsNull, 0, sizeof(cOptionsNull));
MEM_INIT(&cOptionsNull, 0, sizeof(cOptionsNull));
if (compressOptionsPtr == NULL) compressOptionsPtr = &cOptionsNull;
/* complete tmp buffer */
@ -932,7 +990,7 @@ struct LZ4F_dctx_s {
*/
LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_dctx** LZ4F_decompressionContextPtr, unsigned versionNumber)
{
LZ4F_dctx* const dctx = (LZ4F_dctx*)ALLOCATOR(sizeof(LZ4F_dctx));
LZ4F_dctx* const dctx = (LZ4F_dctx*)ALLOC_AND_ZERO(sizeof(LZ4F_dctx));
if (dctx==NULL) return err0r(LZ4F_ERROR_GENERIC);
dctx->version = versionNumber;
@ -1004,7 +1062,7 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize
/* need to decode header to get frameInfo */
if (srcSize < minFHSize) return err0r(LZ4F_ERROR_frameHeader_incomplete); /* minimal frame header size */
memset(&(dctx->frameInfo), 0, sizeof(dctx->frameInfo));
MEM_INIT(&(dctx->frameInfo), 0, sizeof(dctx->frameInfo));
/* special case : skippable frames */
if ((LZ4F_readLE32(srcPtr) & 0xFFFFFFF0U) == LZ4F_MAGIC_SKIPPABLE_START) {
@ -1231,7 +1289,7 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
size_t nextSrcSizeHint = 1;
memset(&optionsNull, 0, sizeof(optionsNull));
MEM_INIT(&optionsNull, 0, sizeof(optionsNull));
if (decompressOptionsPtr==NULL) decompressOptionsPtr = &optionsNull;
*srcSizePtr = 0;
*dstSizePtr = 0;
@ -1280,11 +1338,11 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
if (bufferNeeded > dctx->maxBufferSize) { /* tmp buffers too small */
dctx->maxBufferSize = 0; /* ensure allocation will be re-attempted on next entry*/
FREEMEM(dctx->tmpIn);
dctx->tmpIn = (BYTE*)ALLOCATOR(dctx->maxBlockSize + 4 /* block checksum */);
dctx->tmpIn = (BYTE*)ALLOC(dctx->maxBlockSize + 4 /* block checksum */);
if (dctx->tmpIn == NULL)
return err0r(LZ4F_ERROR_allocation_failed);
FREEMEM(dctx->tmpOutBuffer);
dctx->tmpOutBuffer= (BYTE*)ALLOCATOR(bufferNeeded);
dctx->tmpOutBuffer= (BYTE*)ALLOC(bufferNeeded);
if (dctx->tmpOutBuffer== NULL)
return err0r(LZ4F_ERROR_allocation_failed);
dctx->maxBufferSize = bufferNeeded;

View File

@ -107,6 +107,7 @@ LZ4FLIB_STATIC_API void LZ4F_freeCDict(LZ4F_CDict* CDict);
/*! LZ4_compressFrame_usingCDict() :
* Compress an entire srcBuffer into a valid LZ4 frame using a digested Dictionary.
* cctx must point to a context created by LZ4F_createCompressionContext().
* If cdict==NULL, compress without a dictionary.
* dstBuffer MUST be >= LZ4F_compressFrameBound(srcSize, preferencesPtr).
* If this condition is not respected, function will fail (@return an errorCode).
@ -115,6 +116,7 @@ LZ4FLIB_STATIC_API void LZ4F_freeCDict(LZ4F_CDict* CDict);
* @return : number of bytes written into dstBuffer.
* or an error code if it fails (can be tested using LZ4F_isError()) */
LZ4FLIB_STATIC_API size_t LZ4F_compressFrame_usingCDict(
LZ4F_cctx* cctx,
void* dst, size_t dstCapacity,
const void* src, size_t srcSize,
const LZ4F_CDict* cdict,

View File

@ -858,7 +858,7 @@ int LZ4_resetStreamStateHC(void* state, char* inputBuffer)
void* LZ4_createHC (char* inputBuffer)
{
LZ4_streamHC_t* hc4 = (LZ4_streamHC_t*)ALLOCATOR(1, sizeof(LZ4_streamHC_t));
LZ4_streamHC_t* hc4 = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));
if (hc4 == NULL) return NULL; /* not enough memory */
LZ4HC_init (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
hc4->internal_donotuse.inputBuffer = (BYTE*)inputBuffer;

View File

@ -560,7 +560,7 @@ static int LZ4IO_compressFilename_extRess(cRess_t ress, const char* srcFileName,
/* single-block file */
if (readSize < blockSize) {
/* Compress in single pass */
size_t cSize = LZ4F_compressFrame_usingCDict(dstBuffer, dstBufferSize, srcBuffer, readSize, ress.cdict, &prefs);
size_t cSize = LZ4F_compressFrame_usingCDict(ctx, dstBuffer, dstBufferSize, srcBuffer, readSize, ress.cdict, &prefs);
if (LZ4F_isError(cSize)) EXM_THROW(31, "Compression failed : %s", LZ4F_getErrorName(cSize));
compressedfilesize = cSize;
DISPLAYUPDATE(2, "\rRead : %u MB ==> %.2f%% ",

View File

@ -164,7 +164,7 @@ static unsigned FUZ_highbit(U32 v32)
/*-*******************************************************
* Tests
*********************************************************/
#define CHECK_V(v,f) v = f; if (LZ4F_isError(v)) goto _output_error
#define CHECK_V(v,f) v = f; if (LZ4F_isError(v)) { fprintf(stderr, "%s\n", LZ4F_getErrorName(v)); goto _output_error; }
#define CHECK(f) { LZ4F_errorCode_t const CHECK_V(err_ , f); }
int basicTests(U32 seed, double compressibility)
@ -509,23 +509,25 @@ int basicTests(U32 seed, double compressibility)
CHECK( LZ4F_freeCompressionContext(cctx) ); cctx = NULL;
}
/* Dictionary compression test */
{ size_t const dictSize = 63 KB;
size_t const dstCapacity = LZ4F_compressFrameBound(dictSize, NULL);
size_t cSizeNoDict, cSizeWithDict;
LZ4F_CDict* const cdict = LZ4F_createCDict(CNBuffer, dictSize);
if (cdict == NULL) goto _output_error;
CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with NULL dict : ");
CHECK_V(cSizeNoDict,
LZ4F_compressFrame_usingCDict(compressedBuffer, dstCapacity,
LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
CNBuffer, dictSize,
NULL, NULL) );
DISPLAYLEVEL(3, "%u bytes \n", (unsigned)cSizeNoDict);
CHECK( LZ4F_freeCompressionContext(cctx) );
CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with dict : ");
CHECK_V(cSizeWithDict,
LZ4F_compressFrame_usingCDict(compressedBuffer, dstCapacity,
LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
CNBuffer, dictSize,
cdict, NULL) );
DISPLAYLEVEL(3, "compressed %u bytes into %u bytes \n",
@ -557,7 +559,7 @@ int basicTests(U32 seed, double compressibility)
memset(&cParams, 0, sizeof(cParams));
cParams.compressionLevel = -3;
CHECK_V(cSizeLevelMax,
LZ4F_compressFrame_usingCDict(compressedBuffer, dstCapacity,
LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
CNBuffer, dictSize,
cdict, &cParams) );
DISPLAYLEVEL(3, "%u bytes \n", (unsigned)cSizeLevelMax);
@ -569,7 +571,7 @@ int basicTests(U32 seed, double compressibility)
memset(&cParams, 0, sizeof(cParams));
cParams.compressionLevel = LZ4F_compressionLevel_max();
CHECK_V(cSizeLevelMax,
LZ4F_compressFrame_usingCDict(compressedBuffer, dstCapacity,
LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
CNBuffer, dictSize,
cdict, &cParams) );
DISPLAYLEVEL(3, "%u bytes \n", (unsigned)cSizeLevelMax);
@ -584,7 +586,7 @@ int basicTests(U32 seed, double compressibility)
cParams.frameInfo.blockMode = LZ4F_blockLinked;
cParams.frameInfo.blockSizeID = LZ4F_max64KB;
CHECK_V(cSizeContiguous,
LZ4F_compressFrame_usingCDict(compressedBuffer, outCapacity,
LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, outCapacity,
CNBuffer, inSize,
cdict, &cParams) );
DISPLAYLEVEL(3, "compressed %u bytes into %u bytes \n",
@ -620,7 +622,7 @@ int basicTests(U32 seed, double compressibility)
cParams.frameInfo.blockMode = LZ4F_blockIndependent;
cParams.frameInfo.blockSizeID = LZ4F_max64KB;
CHECK_V(cSizeIndep,
LZ4F_compressFrame_usingCDict(compressedBuffer, outCapacity,
LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, outCapacity,
CNBuffer, inSize,
cdict, &cParams) );
DISPLAYLEVEL(3, "compressed %u bytes into %u bytes \n",
@ -647,6 +649,7 @@ int basicTests(U32 seed, double compressibility)
}
LZ4F_freeCDict(cdict);
CHECK( LZ4F_freeCompressionContext(cctx) ); cctx = NULL;
}
@ -730,15 +733,17 @@ _output_error:
static void locateBuffDiff(const void* buff1, const void* buff2, size_t size, unsigned nonContiguous)
{
int p=0;
size_t p=0;
const BYTE* b1=(const BYTE*)buff1;
const BYTE* b2=(const BYTE*)buff2;
if (nonContiguous) {
DISPLAY("Non-contiguous output test (%i bytes)\n", (int)size);
return;
}
while (b1[p]==b2[p]) p++;
DISPLAY("Error at pos %i/%i : %02X != %02X \n", p, (int)size, b1[p], b2[p]);
while (p < size && b1[p]==b2[p]) p++;
if (p != size) {
DISPLAY("Error at pos %i/%i : %02X != %02X \n", (int)p, (int)size, b1[p], b2[p]);
}
}