From 42eb47d42f041054140b8e08ffc6ba85e9f092f2 Mon Sep 17 00:00:00 2001 From: Alexander Mohr Date: Tue, 5 Jul 2022 11:35:58 +0200 Subject: uncompressed-api: allow uncompressed_update only for independent blocks Signed-off-by: Alexander Mohr --- doc/lz4_manual.html | 12 ---- lib/lz4.c | 24 ++------ lib/lz4.h | 11 ---- lib/lz4frame.c | 172 ++++++++++++++++++++++------------------------------ lib/lz4frame.h | 1 + lib/lz4hc.c | 27 ++------- 6 files changed, 84 insertions(+), 163 deletions(-) diff --git a/doc/lz4_manual.html b/doc/lz4_manual.html index 700cb84..037cfc0 100644 --- a/doc/lz4_manual.html +++ b/doc/lz4_manual.html @@ -391,18 +391,6 @@ int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream);


-
LZ4LIB_STATIC_API int LZ4_getDictSize (const LZ4_stream_t* LZ4_dict, int dictSize);
-

Get the size of the dictionary. This can be used for adding data without - compression to the LZ4 archive. If linked blocked mode is used the memory - of the dictionary is kept free. - This way uncompressed data does not influence the effectiveness of the - dictionary. - @param LZ4_dict Pointer to the dictionary to get the size of. - @param dictSize The maximum dictionary size. (Normally 64 KB). - @return The size of the dictionary. - -


-

It's possible to have input and output sharing the same buffer, for highly constrained memory environments. diff --git a/lib/lz4.c b/lib/lz4.c index 289162d..a2272cf 100644 --- a/lib/lz4.c +++ b/lib/lz4.c @@ -1679,25 +1679,6 @@ int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* return result; } -/*! LZ4_getDictSize(): - * Get the size of the dictionary. This can be used for adding data without - * compression to the LZ4 archive. If linked blocked mode is used the memory - * of the dictionary is kept free. - * This way uncompressed data does not influence the effectiveness of the - * dictionary. - * @param LZ4_dict Pointer to the dictionary to get the size of. - * @param dictSize The maximum dictionary size. (Normally 64 KB). - * @return The size of the dictionary. - */ -int LZ4_getDictSize (const LZ4_stream_t* LZ4_dict, int dictSize) -{ - const LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse; - - if ((U32)dictSize > 64 KB) { dictSize = 64 KB; } /* useless to define a dictionary > 64 KB */ - if ((U32)dictSize > dict->dictSize) { dictSize = (int)dict->dictSize; } - - return dictSize; -} /*! LZ4_saveDict() : * If previously compressed data block is not guaranteed to remain available at its memory location, @@ -1709,9 +1690,12 @@ int LZ4_getDictSize (const LZ4_stream_t* LZ4_dict, int dictSize) int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize) { LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse; - dictSize = LZ4_getDictSize(LZ4_dict, dictSize); + DEBUGLOG(5, "LZ4_saveDict : dictSize=%i, safeBuffer=%p", dictSize, safeBuffer); + if ((U32)dictSize > 64 KB) { dictSize = 64 KB; } /* useless to define a dictionary > 64 KB */ + if ((U32)dictSize > dict->dictSize) { dictSize = (int)dict->dictSize; } + if (safeBuffer == NULL) assert(dictSize == 0); if (dictSize > 0) { const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize; diff --git a/lib/lz4.h b/lib/lz4.h index ce2288e..6c068c6 100644 --- a/lib/lz4.h +++ b/lib/lz4.h @@ -509,17 +509,6 @@ LZ4LIB_STATIC_API int LZ4_compress_fast_extState_fastReset (void* state, const c */ LZ4LIB_STATIC_API void LZ4_attach_dictionary(LZ4_stream_t* workingStream, const LZ4_stream_t* dictionaryStream); -/*! LZ4_getDictSize(): - * Get the size of the dictionary. This can be used for adding data without - * compression to the LZ4 archive. If linked blocked mode is used the memory - * of the dictionary is kept free. - * This way uncompressed data does not influence the effectiveness of the - * dictionary. - * @param LZ4_dict Pointer to the dictionary to get the size of. - * @param dictSize The maximum dictionary size. (Normally 64 KB). - * @return The size of the dictionary. - */ -LZ4LIB_STATIC_API int LZ4_getDictSize (const LZ4_stream_t* LZ4_dict, int dictSize); /*! In-place compression and decompression * diff --git a/lib/lz4frame.c b/lib/lz4frame.c index f32ed1d..3042d6f 100644 --- a/lib/lz4frame.c +++ b/lib/lz4frame.c @@ -841,23 +841,12 @@ static compressFunc_t LZ4F_selectCompression(LZ4F_blockMode_t blockMode, int lev return LZ4F_compressBlockHC_continue; } -static int LZ4F_maxDictSize(void) { - return 64 KB; -} - /* Save history (up to 64KB) into @tmpBuff */ static int LZ4F_localSaveDict(LZ4F_cctx_t* cctxPtr) { if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) - return LZ4_saveDict ((LZ4_stream_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), LZ4F_maxDictSize()); - return LZ4_saveDictHC ((LZ4_streamHC_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), LZ4F_maxDictSize()); -} - -static int LZ4F_localDictSize(LZ4F_cctx_t* cctxPtr) -{ - if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) - return LZ4_getDictSize ((LZ4_stream_t*)(cctxPtr->lz4CtxPtr), LZ4F_maxDictSize()); - return LZ4_getDictHCSize ((LZ4_streamHC_t*)(cctxPtr->lz4CtxPtr), LZ4F_maxDictSize()); + return LZ4_saveDict ((LZ4_stream_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), 64 KB); + return LZ4_saveDictHC ((LZ4_streamHC_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), 64 KB); } typedef enum { notDone, fromTmpBuffer, fromSrcBuffer } LZ4F_lastBlockStatus; @@ -886,69 +875,64 @@ static size_t LZ4F_compressUpdateImpl(LZ4F_cctx* cctxPtr, size_t const blockSize = cctxPtr->maxBlockSize; const BYTE* srcPtr = (const BYTE*)srcBuffer; const BYTE* const srcEnd = srcPtr + srcSize; - BYTE* dstStart = (BYTE*)dstBuffer; + BYTE* const dstStart = (BYTE*)dstBuffer; BYTE* dstPtr = dstStart; LZ4F_lastBlockStatus lastBlockCompressed = notDone; compressFunc_t const compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel); - size_t bytesWritten = 0; + size_t bytesWritten; DEBUGLOG(4, "LZ4F_compressUpdate (srcSize=%zu)", srcSize); - /* flush currently written block, to continue with new block compression */ - if (cctxPtr->blockCompression != blockCompression) { - bytesWritten = LZ4F_flush(cctxPtr, dstBuffer, dstCapacity, compressOptionsPtr); - dstStart = (BYTE*)dstBuffer + bytesWritten; - dstPtr = dstStart; - dstCapacity -= bytesWritten; - cctxPtr->blockCompression = blockCompression; - } - RETURN_ERROR_IF(cctxPtr->cStage != 1, compressionState_uninitialized); /* state must be initialized and waiting for next block */ - - if (blockCompression == LZ4B_COMPRESSED && - dstCapacity < LZ4F_compressBound_internal(srcSize, &(cctxPtr->prefs), cctxPtr->tmpInSize)) - RETURN_ERROR(dstMaxSize_tooSmall); + if (dstCapacity < LZ4F_compressBound_internal(srcSize, &(cctxPtr->prefs), cctxPtr->tmpInSize)) + RETURN_ERROR(dstMaxSize_tooSmall); if (blockCompression == LZ4B_UNCOMPRESSED && dstCapacity < srcSize) - RETURN_ERROR(dstMaxSize_tooSmall); + RETURN_ERROR(dstMaxSize_tooSmall); + + /* flush currently written block, to continue with new block compression */ + if (cctxPtr->blockCompression != blockCompression) { + bytesWritten = LZ4F_flush(cctxPtr, dstBuffer, dstCapacity, compressOptionsPtr); + dstPtr += bytesWritten; + cctxPtr->blockCompression = blockCompression; + } if (compressOptionsPtr == NULL) compressOptionsPtr = &k_cOptionsNull; /* complete tmp buffer */ if (cctxPtr->tmpInSize > 0) { /* some data already within tmp buffer */ - size_t const sizeToCopy = blockSize - cctxPtr->tmpInSize; - assert(blockSize > cctxPtr->tmpInSize); - if (sizeToCopy > srcSize) { - /* add src to tmpIn buffer */ - memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, srcSize); - srcPtr = srcEnd; - cctxPtr->tmpInSize += srcSize; - /* still needs some CRC */ - } else { - /* complete tmpIn block and then compress it */ - lastBlockCompressed = fromTmpBuffer; - memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, sizeToCopy); - srcPtr += sizeToCopy; + size_t const sizeToCopy = blockSize - cctxPtr->tmpInSize; + assert(blockSize > cctxPtr->tmpInSize); + if (sizeToCopy > srcSize) { + /* add src to tmpIn buffer */ + memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, srcSize); + srcPtr = srcEnd; + cctxPtr->tmpInSize += srcSize; + /* still needs some CRC */ + } else { + /* complete tmpIn block and then compress it */ + lastBlockCompressed = fromTmpBuffer; + memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, sizeToCopy); + srcPtr += sizeToCopy; + + dstPtr += LZ4F_makeBlock(dstPtr, + cctxPtr->tmpIn, blockSize, + compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel, + cctxPtr->cdict, + cctxPtr->prefs.frameInfo.blockChecksumFlag, blockCompression); + if (cctxPtr->prefs.frameInfo.blockMode==LZ4F_blockLinked) cctxPtr->tmpIn += blockSize; + cctxPtr->tmpInSize = 0; + } } + while ((size_t)(srcEnd - srcPtr) >= blockSize) { + /* compress full blocks */ + lastBlockCompressed = fromSrcBuffer; dstPtr += LZ4F_makeBlock(dstPtr, - cctxPtr->tmpIn, blockSize, + srcPtr, blockSize, compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel, cctxPtr->cdict, - cctxPtr->prefs.frameInfo.blockChecksumFlag, blockCompression); - - if (cctxPtr->prefs.frameInfo.blockMode==LZ4F_blockLinked) cctxPtr->tmpIn += blockSize; - cctxPtr->tmpInSize = 0; - } - } - - while ((size_t)(srcEnd - srcPtr) >= blockSize) { - /* compress full blocks */ - lastBlockCompressed = fromSrcBuffer; - dstPtr += LZ4F_makeBlock(dstPtr, - srcPtr, blockSize, - compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel, - cctxPtr->cdict, - cctxPtr->prefs.frameInfo.blockChecksumFlag, blockCompression); - srcPtr += blockSize; + cctxPtr->prefs.frameInfo.blockChecksumFlag, + blockCompression); + srcPtr += blockSize; } if ((cctxPtr->prefs.autoFlush) && (srcPtr < srcEnd)) { @@ -960,27 +944,20 @@ static size_t LZ4F_compressUpdateImpl(LZ4F_cctx* cctxPtr, cctxPtr->cdict, cctxPtr->prefs.frameInfo.blockChecksumFlag, blockCompression); - srcPtr = srcEnd; + srcPtr = srcEnd; } /* preserve dictionary within @tmpBuff whenever necessary */ if ((cctxPtr->prefs.frameInfo.blockMode==LZ4F_blockLinked) && (lastBlockCompressed==fromSrcBuffer)) { - if (compressOptionsPtr->stableSrc) { - cctxPtr->tmpIn = cctxPtr->tmpBuff; /* src is stable : dictionary remains in src across invocations */ - } else { - int realDictSize; - if (blockCompression == LZ4B_COMPRESSED) { - realDictSize = LZ4F_localSaveDict(cctxPtr); + /* linked blocks are only supported in compressed mode, see LZ4F_uncompressedUpdate */ + assert(blockCompression == LZ4B_COMPRESSED); + if (compressOptionsPtr->stableSrc) { + cctxPtr->tmpIn = cctxPtr->tmpBuff; /* src is stable : dictionary remains in src across invocations */ } else { - /* only keep the space of the dictionary, so dict data is kept for the next compressedUpdate - * this is only relevant if linked block mode - * */ - realDictSize = LZ4F_localDictSize(cctxPtr); + int const realDictSize = LZ4F_localSaveDict(cctxPtr); + assert(0 <= realDictSize && realDictSize <= 64 KB); + cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize; } - - assert(0 <= realDictSize && realDictSize <= 64 KB); - cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize; - } } /* keep tmpIn within limits */ @@ -989,30 +966,24 @@ static size_t LZ4F_compressUpdateImpl(LZ4F_cctx* cctxPtr, { /* only preserve 64KB within internal buffer. Ensures there is enough room for next block. * note: this situation necessarily implies lastBlockCompressed==fromTmpBuffer */ - int realDictSize; - if (blockCompression == LZ4B_COMPRESSED) { - realDictSize = LZ4F_localSaveDict(cctxPtr); - } else { - /* only keep the space of the dictionary, so dict data is kept for the next compressedUpdate*/ - realDictSize = LZ4F_maxDictSize(); - } + int const realDictSize = LZ4F_localSaveDict(cctxPtr); cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize; assert((cctxPtr->tmpIn + blockSize) <= (cctxPtr->tmpBuff + cctxPtr->maxBufferSize)); } /* some input data left, necessarily < blockSize */ if (srcPtr < srcEnd) { - /* fill tmp buffer */ - size_t const sizeToCopy = (size_t)(srcEnd - srcPtr); - memcpy(cctxPtr->tmpIn, srcPtr, sizeToCopy); - cctxPtr->tmpInSize = sizeToCopy; + /* fill tmp buffer */ + size_t const sizeToCopy = (size_t)(srcEnd - srcPtr); + memcpy(cctxPtr->tmpIn, srcPtr, sizeToCopy); + cctxPtr->tmpInSize = sizeToCopy; } if (cctxPtr->prefs.frameInfo.contentChecksumFlag == LZ4F_contentChecksumEnabled) - (void)XXH32_update(&(cctxPtr->xxh), srcBuffer, srcSize); + (void)XXH32_update(&(cctxPtr->xxh), srcBuffer, srcSize); cctxPtr->totalInSize += srcSize; - return bytesWritten + (size_t)(dstPtr - dstStart); + return (size_t)(dstPtr - dstStart); } /*! LZ4F_compressUpdate() : @@ -1032,10 +1003,10 @@ size_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr, const void* srcBuffer, size_t srcSize, const LZ4F_compressOptions_t* compressOptionsPtr) { - return LZ4F_compressUpdateImpl(cctxPtr, - dstBuffer, dstCapacity, - srcBuffer, srcSize, - compressOptionsPtr, LZ4B_COMPRESSED); + return LZ4F_compressUpdateImpl(cctxPtr, + dstBuffer, dstCapacity, + srcBuffer, srcSize, + compressOptionsPtr, LZ4B_COMPRESSED); } /*! LZ4F_compressUpdate() : @@ -1044,6 +1015,7 @@ size_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr, * src data is either buffered or compressed into @dstBuffer. * If previously an uncompressed block was written, buffered data is flushed * before appending compressed data is continued. + * This is only supported when LZ4F_blockIndependent is used * @dstCapacity MUST be >= LZ4F_compressBound(srcSize, preferencesPtr). * @compressOptionsPtr is optional : provide NULL to mean "default". * @return : the number of bytes written into dstBuffer. It can be zero, meaning input data was just buffered. @@ -1051,13 +1023,14 @@ size_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr, * After an error, the state is left in a UB state, and must be re-initialized. */ size_t LZ4F_uncompressedUpdate(LZ4F_cctx* cctxPtr, - void* dstBuffer, size_t dstCapacity, - const void* srcBuffer, size_t srcSize, - const LZ4F_compressOptions_t* compressOptionsPtr) { - return LZ4F_compressUpdateImpl(cctxPtr, - dstBuffer, dstCapacity, - srcBuffer, srcSize, - compressOptionsPtr, LZ4B_UNCOMPRESSED); + void* dstBuffer, size_t dstCapacity, + const void* srcBuffer, size_t srcSize, + const LZ4F_compressOptions_t* compressOptionsPtr) { + assert(cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockIndependent); + return LZ4F_compressUpdateImpl(cctxPtr, + dstBuffer, dstCapacity, + srcBuffer, srcSize, + compressOptionsPtr, LZ4B_UNCOMPRESSED); } @@ -1090,7 +1063,8 @@ size_t LZ4F_flush(LZ4F_cctx* cctxPtr, cctxPtr->tmpIn, cctxPtr->tmpInSize, compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel, cctxPtr->cdict, - cctxPtr->prefs.frameInfo.blockChecksumFlag, cctxPtr->blockCompression); + cctxPtr->prefs.frameInfo.blockChecksumFlag, + cctxPtr->blockCompression); assert(((void)"flush overflows dstBuffer!", (size_t)(dstPtr - dstStart) <= dstCapacity)); if (cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) diff --git a/lib/lz4frame.h b/lib/lz4frame.h index 7d81fa0..691ad50 100644 --- a/lib/lz4frame.h +++ b/lib/lz4frame.h @@ -552,6 +552,7 @@ LZ4FLIB_STATIC_API size_t LZ4F_getBlockSize(unsigned); * After an error, the state is left in a UB state, and must be re-initialized or freed. * If previously a compressed block was written, buffered data is flushed * before appending uncompressed data is continued. + * This is only supported when LZ4F_blockIndependent is used * `cOptPtr` is optional : NULL can be provided, in which case all options are set to default. * @return : number of bytes written into `dstBuffer` (it can be zero, meaning input data was just buffered). * or an error code if it fails (which can be tested using LZ4F_isError()) diff --git a/lib/lz4hc.c b/lib/lz4hc.c index b5bc880..99650a6 100644 --- a/lib/lz4hc.c +++ b/lib/lz4hc.c @@ -1154,26 +1154,6 @@ int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const ch return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, fillOutput); } -/*! LZ4_getDictHCSize(): - * Get the size of the dictionary. This can be used for adding data without - * compression to the LZ4 archive. If linked blocked mode is used the memory - * of the dictionary is kept free. - * This way uncompressed data does not influence the effectiveness of the - * dictionary. - * @param LZ4_dict Pointer to the dictionary to get the size of. - * @param dictSize The maximum dictionary size. (Normally 64 KB). - * @return The size of the dictionary. - */ -int LZ4_getDictHCSize(const LZ4_streamHC_t* LZ4_streamHCPtr, int dictSize) { - const LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse; - int const prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit)); - DEBUGLOG(5, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize); - assert(prefixSize >= 0); - if (dictSize > 64 KB) dictSize = 64 KB; - if (dictSize < 4) dictSize = 0; - if (dictSize > prefixSize) dictSize = prefixSize; - return dictSize; -} /* LZ4_saveDictHC : @@ -1184,7 +1164,12 @@ int LZ4_getDictHCSize(const LZ4_streamHC_t* LZ4_streamHCPtr, int dictSize) { int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize) { LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse; - dictSize = LZ4_getDictHCSize(LZ4_streamHCPtr, dictSize); + int const prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit)); + DEBUGLOG(5, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize); + assert(prefixSize >= 0); + if (dictSize > 64 KB) dictSize = 64 KB; + if (dictSize < 4) dictSize = 0; + if (dictSize > prefixSize) dictSize = prefixSize; if (safeBuffer == NULL) assert(dictSize == 0); if (dictSize > 0) memmove(safeBuffer, streamPtr->end - dictSize, dictSize); -- cgit v0.12