From b03f8f0e6f40d17740685e50332b8eedb5117cec Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 4 Sep 2014 22:56:51 +0100 Subject: fixed : LZ4F_decompress() more decompress tests --- lz4frame.c | 101 +++++++++++++++++++++++++++++++-------------------- lz4frame.h | 14 ++++--- programs/frametest.c | 22 ++++++++++- 3 files changed, 91 insertions(+), 46 deletions(-) diff --git a/lz4frame.c b/lz4frame.c index 80e744e..f8facdb 100644 --- a/lz4frame.c +++ b/lz4frame.c @@ -683,7 +683,7 @@ static LZ4F_errorCode_t LZ4F_checkBuffer(LZ4F_dctx_internal_t* dctxPtr) } -typedef enum { dstage_header=0, +typedef enum { dstage_getHeader=0, dstage_storeHeader, dstage_decodeHeader, dstage_getCBlockSize, dstage_storeCBlockSize, dstage_decodeCBlockSize, dstage_copyDirect, dstage_getCBlock, dstage_storeCBlock, dstage_decodeCBlock, dstage_flushOut, @@ -744,78 +744,101 @@ LZ4F_errorCode_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContex BYTE* const dstEnd = dstStart + *dstSize; BYTE* dstPtr = dstStart; size_t nextCBlockSize=0; - const BYTE* cBlockSizePtr=NULL; - const BYTE* cBlockPtr=NULL; + const BYTE* selectedIn=NULL; LZ4F_errorCode_t goodResult = OK_NoError; if (decompressOptionsPtr==NULL) decompressOptionsPtr = &optionsNull; *srcSize = 0; *dstSize = 0; - /* expect same src buffer as previous function call */ + /* expect to continue decoding src buffer where it left previously */ if (dctxPtr->srcExpect != NULL) { if (srcStart != dctxPtr->srcExpect) return -ERROR_GENERIC; - srcPtr = srcStart + dctxPtr->srcConsumed; } while (srcPtr < srcEnd) { - //printf("src : %7i \n", (int)(srcPtr-srcStart)); switch(dctxPtr->dStage) { - case dstage_header: + case dstage_getHeader: { - LZ4F_errorCode_t errorCode = LZ4F_decodeHeader(&(dctxPtr->frameInfo), srcBuffer, (srcEnd - srcPtr)); + if ((srcEnd-srcPtr)>7) + { + selectedIn = srcPtr; + srcPtr += 7; + dctxPtr->dStage = dstage_decodeHeader; + goto goto_decodeHeader; /* break would risk leaving the while loop */ + } + dctxPtr->tmpInSize = 0; + dctxPtr->dStage = dstage_storeHeader; + /* break; break is useles, since storeHeader follows */ + } + case dstage_storeHeader: + { + size_t sizeToCopy = 7 - dctxPtr->tmpInSize; + if (sizeToCopy > (size_t)(srcEnd - srcPtr)) sizeToCopy = srcEnd - srcPtr; + memcpy(dctxPtr->tmpIn + dctxPtr->tmpInSize, srcPtr, sizeToCopy); + dctxPtr->tmpInSize += sizeToCopy; + srcPtr += sizeToCopy; + if (dctxPtr->tmpInSize < 7) break; /* src completed; come back later for more */ + selectedIn = dctxPtr->tmpIn; + dctxPtr->dStage = dstage_decodeHeader; + /* break; useless because it follows */ + } + case dstage_decodeHeader: +goto_decodeHeader: + { + LZ4F_errorCode_t errorCode = LZ4F_decodeHeader(&(dctxPtr->frameInfo), selectedIn, 7); if (LZ4F_isError(errorCode)) return errorCode; - srcPtr += errorCode; errorCode = LZ4F_checkBuffer(dctxPtr); if (LZ4F_isError(errorCode)) return errorCode; - dctxPtr->dStage = dstage_getCBlockSize; - /* break; no need to break : dstage_getCBlockSize is next stage */ + /* dctxPtr->dStage = dstage_getCBlockSize; break; no need to change stage nor break : dstage_getCBlockSize is next stage, and stage will be modified */ } case dstage_getCBlockSize: { - if ((srcEnd - srcPtr) < 4) /* not enough input to read cBlockSize */ + if ((srcEnd - srcPtr) >= 4) { - dctxPtr->tmpInSize = 0; - dctxPtr->dStage = dstage_storeCBlockSize; - break; + selectedIn = srcPtr; + srcPtr += 4; + dctxPtr->dStage = dstage_decodeCBlockSize; + goto goto_decodeCBlockSize; /* required : a break could leave while loop */ } - cBlockSizePtr = srcPtr; - srcPtr += 4; - dctxPtr->dStage = dstage_decodeCBlockSize; - break; + /* not enough input to read cBlockSize */ + dctxPtr->tmpInSize = 0; + dctxPtr->dStage = dstage_storeCBlockSize; + /* break; No need to break : dstage_storeCBlockSize is next block */ } case dstage_storeCBlockSize: { size_t sizeToCopy = 4 - dctxPtr->tmpInSize; - if (sizeToCopy < (size_t)(srcEnd - srcPtr)) sizeToCopy = srcEnd - srcPtr; + if (sizeToCopy > (size_t)(srcEnd - srcPtr)) sizeToCopy = srcEnd - srcPtr; memcpy(dctxPtr->tmpIn + dctxPtr->tmpInSize, srcPtr, sizeToCopy); srcPtr += sizeToCopy; dctxPtr->tmpInSize += sizeToCopy; if (dctxPtr->tmpInSize < 4) break; /* not enough input to read CBlockSize */ - cBlockSizePtr = dctxPtr->tmpIn; + selectedIn = dctxPtr->tmpIn; dctxPtr->dStage = dstage_decodeCBlockSize; - break; + /* break; No need to break : dstage_decodeCBlockSize is next block */ } case dstage_decodeCBlockSize: +goto_decodeCBlockSize: { - nextCBlockSize = LZ4F_readLE32(cBlockSizePtr) & 0x7FFFFFFFU; + nextCBlockSize = LZ4F_readLE32(selectedIn) & 0x7FFFFFFFU; if (nextCBlockSize==0) /* no more CBlock */ { dctxPtr->dStage = dstage_getSuffix; - break; + goto goto_getSuffix; /* required : a break could leave the while loop */ } if (nextCBlockSize > dctxPtr->maxBlockSize) return -ERROR_GENERIC; dctxPtr->sizeToDecode = nextCBlockSize; - if (LZ4F_readLE32(cBlockSizePtr) & 0x80000000U) /* uncompressed flag */ + if (LZ4F_readLE32(selectedIn) & 0x80000000U) /* uncompressed flag */ { dctxPtr->dStage = dstage_copyDirect; break; } dctxPtr->dStage = dstage_getCBlock; - break; + goto goto_getCBlock; /* break risk leaving while loop */ } case dstage_copyDirect: { @@ -834,6 +857,7 @@ LZ4F_errorCode_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContex goto _end; /* either In or Out have reached end */ } case dstage_getCBlock: +goto_getCBlock: { if ((size_t)(srcEnd-srcPtr) < nextCBlockSize) { @@ -842,7 +866,7 @@ LZ4F_errorCode_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContex dctxPtr->dStage = dstage_storeCBlock; break; } - cBlockPtr = srcPtr; + selectedIn = srcPtr; srcPtr += nextCBlockSize; dctxPtr->dStage = dstage_decodeCBlock; break; @@ -855,23 +879,23 @@ LZ4F_errorCode_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContex dctxPtr->tmpInSize += sizeToCopy; srcPtr += sizeToCopy; if (dctxPtr->tmpInSize < dctxPtr->tmpInTarget) break; /* need to read more */ - cBlockPtr = dctxPtr->tmpIn; + selectedIn = dctxPtr->tmpIn; dctxPtr->dStage = dstage_decodeCBlock; - break; + /* break; break unnecessary because it follows */ } case dstage_decodeCBlock: { int decodedSize; if ((size_t)(dstEnd-dstPtr) < dctxPtr->maxBlockSize) /* not enough room : decode into tmpOut */ { - decodedSize = LZ4_decompress_safe((const char*)cBlockPtr, (char*)dctxPtr->tmpOut, (int)dctxPtr->sizeToDecode, (int)dctxPtr->maxBlockSize); + decodedSize = LZ4_decompress_safe((const char*)selectedIn, (char*)dctxPtr->tmpOut, (int)dctxPtr->sizeToDecode, (int)dctxPtr->maxBlockSize); if (decodedSize < 0) return -ERROR_GENERIC; /* decompression failed */ dctxPtr->tmpOutSize = decodedSize; dctxPtr->tmpOutStart = 0; dctxPtr->dStage = dstage_flushOut; break; } - decodedSize = LZ4_decompress_safe((const char*)cBlockPtr, (char*)dstPtr, (int)dctxPtr->sizeToDecode, (int)dctxPtr->maxBlockSize); + decodedSize = LZ4_decompress_safe((const char*)selectedIn, (char*)dstPtr, (int)dctxPtr->sizeToDecode, (int)dctxPtr->maxBlockSize); if (decodedSize < 0) return -ERROR_GENERIC; /* decompression failed */ dstPtr += decodedSize; dctxPtr->dStage = dstage_getCBlockSize; @@ -889,17 +913,18 @@ LZ4F_errorCode_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContex break; } case dstage_getSuffix: +goto_getSuffix: { size_t suffixSize = dctxPtr->frameInfo.contentChecksumFlag * 4; if (suffixSize == 0) /* frame completed */ { goodResult = OK_FrameEnd; - dctxPtr->dStage = dstage_header; + dctxPtr->dStage = dstage_getHeader; goto _end; } if ((srcEnd - srcPtr) >= 4) /* CRC present */ { - cBlockPtr = srcPtr; + selectedIn = srcPtr; srcPtr += 4; dctxPtr->dStage = dstage_checkSuffix; break; @@ -916,7 +941,7 @@ LZ4F_errorCode_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContex srcPtr += sizeToCopy; dctxPtr->tmpInSize += sizeToCopy; if (dctxPtr->tmpInSize < 4) break; /* not enough input to read suffix */ - cBlockPtr = dctxPtr->tmpIn; + selectedIn = dctxPtr->tmpIn; dctxPtr->dStage = dstage_checkSuffix; break; } @@ -924,7 +949,7 @@ LZ4F_errorCode_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContex { /* To do */ goodResult = OK_FrameEnd; - dctxPtr->dStage = dstage_header; + dctxPtr->dStage = dstage_getHeader; goto _end; } } @@ -934,15 +959,13 @@ LZ4F_errorCode_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContex _end: - if (srcPtrsrcExpect = srcStart; - dctxPtr->srcConsumed = srcPtr - srcStart; + dctxPtr->srcExpect = srcPtr; } else { dctxPtr->srcExpect = NULL; - dctxPtr->srcConsumed = 0; } *srcSize = (srcPtr - srcStart); *dstSize = (dstPtr - dstStart); diff --git a/lz4frame.h b/lz4frame.h index 1b4ab41..ee2290b 100644 --- a/lz4frame.h +++ b/lz4frame.h @@ -74,7 +74,7 @@ int LZ4F_isError(LZ4F_errorCode_t code); /* Basically : code > -ERROR_maxCode typedef enum { LZ4F_default=0, max64KB=4, max256KB=5, max1MB=6, max4MB=7} blockSizeID_t; typedef enum { blockLinked=0, blockIndependent} blockMode_t; -typedef enum { contentChecksumEnabled, noContentChecksum} contentChecksum_t; +typedef enum { noContentChecksum=0, contentChecksumEnabled } contentChecksum_t; typedef struct { blockSizeID_t blockSizeID; /* max64KB, max256KB, max1MB, max4MB ; 0 == default */ @@ -220,18 +220,20 @@ LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_decompressionContext_t decompressionCont * The function result is an error code which can be tested using LZ4F_isError(). */ -LZ4F_errorCode_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext, void* dstBuffer, size_t* dstSize, const void* srcBuffer, size_t* srcSize, const LZ4F_decompressOptions_t* decompressOptionsPtr); +LZ4F_errorCode_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext, void* dstBuffer, size_t* dstSizePtr, const void* srcBuffer, size_t* srcSizePtr, const LZ4F_decompressOptions_t* decompressOptionsPtr); /* LZ4F_decompress() * Call this function repetitively to regenerate data compressed within srcBuffer. - * The function will attempt to decode *srcSize from srcBuffer, into dstBuffer of maximum size *dstSize. + * The function will attempt to decode *srcSizePtr bytes from srcBuffer, into dstBuffer of maximum size *dstSizePtr. * - * The number of bytes generated into dstBuffer will be provided within *dstSize (necessarily <= original value). + * The number of bytes generated into dstBuffer will be provided within *dstSizePtr (necessarily <= original value). * - * The number of bytes effectively used from srcBuffer will be provided within *srcSize (necessarily <= original value). + * The number of bytes effectively used from srcBuffer will be provided within *srcSizePtr (necessarily <= original value). * If the number of bytes read is < number of bytes provided, then the decompression operation is not complete. * This typically happens when dstBuffer is not large enough to contain all decoded data. - * LZ4F_decompress() will have to be called again, using the same src arguments (but eventually different dst arguments). + * LZ4F_decompress() will have to be called again, starting from where it stopped (srcBuffer + *srcSizePtr) + * The function will check this condition, and refuse to continue if it is not respected. * dstBuffer is supposed to be flushed between calls to the function, since its content will be rewritten. + * Different dst arguments can be used. * * The function result is an error code which can be tested using LZ4F_isError(). * When a frame is fully decoded, the function result will be OK_FrameEnd(=1). diff --git a/programs/frametest.c b/programs/frametest.c index 2b52190..7742110 100644 --- a/programs/frametest.c +++ b/programs/frametest.c @@ -205,13 +205,33 @@ int frameTest(U32 seed, int nbCycles, int startCycle, double compressibility) DISPLAY("Decompression test : \n"); { - LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx); size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH; size_t compressedBufferSize = cSize; + BYTE* op = (BYTE*)decodedBuffer; + BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH; + BYTE* ip = (BYTE*)compressedBuffer; + BYTE* const iend = (BYTE*)compressedBuffer + cSize; + LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx); if (LZ4F_isError(errorCode)) goto _output_error; + + DISPLAY("Single Block : \n"); errorCode = LZ4F_decompress(dCtx, decodedBuffer, &decodedBufferSize, compressedBuffer, &compressedBufferSize, NULL); if (LZ4F_isError(errorCode)) goto _output_error; DISPLAY("Regenerated %i bytes \n", (int)decodedBufferSize); + + DISPLAY("Byte after byte : \n"); + while (ip < iend) + { + size_t oSize = oend-op; + size_t iSize = 1; + //DISPLAY("%7i \n", (int)(ip-(BYTE*)compressedBuffer)); + errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL); + if (LZ4F_isError(errorCode)) goto _output_error; + op += oSize; + ip += iSize; + } + DISPLAY("Regenerated %i bytes \n", (int)decodedBufferSize); + errorCode = LZ4F_freeDecompressionContext(dCtx); if (LZ4F_isError(errorCode)) goto _output_error; } -- cgit v0.12