Merge pull request #663 from lz4/headerSize

made LZ4F_getHeaderSize() public
This commit is contained in:
Yann Collet 2019-04-09 21:30:14 -07:00 committed by GitHub
commit 5580f4333a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 107 additions and 60 deletions

View File

@ -211,7 +211,7 @@ static void LZ4F_writeLE64 (void* dst, U64 value64)
#define LZ4F_BLOCKUNCOMPRESSED_FLAG 0x80000000U
#define LZ4F_BLOCKSIZEID_DEFAULT LZ4F_max64KB
static const size_t minFHSize = 7;
static const size_t minFHSize = LZ4F_HEADER_SIZE_MIN; /* 7 */
static const size_t maxFHSize = LZ4F_HEADER_SIZE_MAX; /* 19 */
static const size_t BHSize = 4; /* block header : size, and compress flag */
static const size_t BFSize = 4; /* block footer : checksum (optional) */
@ -280,8 +280,9 @@ size_t LZ4F_getBlockSize(unsigned blockSizeID)
static const size_t blockSizes[4] = { 64 KB, 256 KB, 1 MB, 4 MB };
if (blockSizeID == 0) blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT;
if (blockSizeID < 4 || blockSizeID > 7) return err0r(LZ4F_ERROR_maxBlockSize_invalid);
blockSizeID -= 4;
if (blockSizeID < LZ4F_max64KB || blockSizeID > LZ4F_max4MB)
return err0r(LZ4F_ERROR_maxBlockSize_invalid);
blockSizeID -= LZ4F_max64KB;
return blockSizes[blockSizeID];
}
@ -1094,31 +1095,6 @@ void LZ4F_resetDecompressionContext(LZ4F_dctx* dctx)
}
/*! LZ4F_headerSize() :
* @return : size of frame header
* or an error code, which can be tested using LZ4F_isError()
*/
static size_t LZ4F_headerSize(const void* src, size_t srcSize)
{
/* minimal srcSize to determine header size */
if (srcSize < 5) return err0r(LZ4F_ERROR_frameHeader_incomplete);
/* special case : skippable frames */
if ((LZ4F_readLE32(src) & 0xFFFFFFF0U) == LZ4F_MAGIC_SKIPPABLE_START) return 8;
/* control magic number */
if (LZ4F_readLE32(src) != LZ4F_MAGICNUMBER)
return err0r(LZ4F_ERROR_frameType_unknown);
/* Frame Header Size */
{ BYTE const FLG = ((const BYTE*)src)[4];
U32 const contentSizeFlag = (FLG>>3) & _1BIT;
U32 const dictIDFlag = FLG & _1BIT;
return minFHSize + (contentSizeFlag*8) + (dictIDFlag*4);
}
}
/*! LZ4F_decodeHeader() :
* input : `src` points at the **beginning of the frame**
* output : set internal values of dctx, such as
@ -1191,6 +1167,7 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize
}
/* check header */
assert(frameHeaderSize > 5);
{ BYTE const HC = LZ4F_headerChecksum(srcPtr+4, frameHeaderSize-5);
if (HC != srcPtr[frameHeaderSize-1])
return err0r(LZ4F_ERROR_headerChecksum_invalid);
@ -1214,6 +1191,34 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize
}
/*! LZ4F_headerSize() :
* @return : size of frame header
* or an error code, which can be tested using LZ4F_isError()
*/
size_t LZ4F_headerSize(const void* src, size_t srcSize)
{
if (src == NULL) return err0r(LZ4F_ERROR_srcPtr_wrong);
/* minimal srcSize to determine header size */
if (srcSize < LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH)
return err0r(LZ4F_ERROR_frameHeader_incomplete);
/* special case : skippable frames */
if ((LZ4F_readLE32(src) & 0xFFFFFFF0U) == LZ4F_MAGIC_SKIPPABLE_START)
return 8;
/* control magic number */
if (LZ4F_readLE32(src) != LZ4F_MAGICNUMBER)
return err0r(LZ4F_ERROR_frameType_unknown);
/* Frame Header Size */
{ BYTE const FLG = ((const BYTE*)src)[4];
U32 const contentSizeFlag = (FLG>>3) & _1BIT;
U32 const dictIDFlag = FLG & _1BIT;
return minFHSize + (contentSizeFlag*8) + (dictIDFlag*4);
}
}
/*! LZ4F_getFrameInfo() :
* This function extracts frame parameters (max blockSize, frame checksum, etc.).
* Usage is optional. Objective is to provide relevant information for allocation purposes.
@ -1229,10 +1234,12 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize
* note 1 : in case of error, dctx is not modified. Decoding operations can resume from where they stopped.
* note 2 : frame parameters are *copied into* an already allocated LZ4F_frameInfo_t structure.
*/
LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctx, LZ4F_frameInfo_t* frameInfoPtr,
const void* srcBuffer, size_t* srcSizePtr)
LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctx,
LZ4F_frameInfo_t* frameInfoPtr,
const void* srcBuffer, size_t* srcSizePtr)
{
if (dctx->dStage > dstage_storeFrameHeader) { /* assumption : dstage_* header enum at beginning of range */
LZ4F_STATIC_ASSERT(dstage_getFrameHeader < dstage_storeFrameHeader);
if (dctx->dStage > dstage_storeFrameHeader) {
/* frameInfo already decoded */
size_t o=0, i=0;
*srcSizePtr = 0;
@ -1245,7 +1252,6 @@ LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctx, LZ4F_frameInfo_t* frameInfoP
*srcSizePtr = 0;
return err0r(LZ4F_ERROR_frameDecoding_alreadyStarted);
} else {
size_t decodeResult;
size_t const hSize = LZ4F_headerSize(srcBuffer, *srcSizePtr);
if (LZ4F_isError(hSize)) { *srcSizePtr=0; return hSize; }
if (*srcSizePtr < hSize) {
@ -1253,16 +1259,16 @@ LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctx, LZ4F_frameInfo_t* frameInfoP
return err0r(LZ4F_ERROR_frameHeader_incomplete);
}
decodeResult = LZ4F_decodeHeader(dctx, srcBuffer, hSize);
if (LZ4F_isError(decodeResult)) {
*srcSizePtr = 0;
} else {
*srcSizePtr = decodeResult;
decodeResult = BHSize; /* block header size */
}
*frameInfoPtr = dctx->frameInfo;
return decodeResult;
} }
{ size_t decodeResult = LZ4F_decodeHeader(dctx, srcBuffer, hSize);
if (LZ4F_isError(decodeResult)) {
*srcSizePtr = 0;
} else {
*srcSizePtr = decodeResult;
decodeResult = BHSize; /* block header size */
}
*frameInfoPtr = dctx->frameInfo;
return decodeResult;
} } }
}

View File

@ -247,7 +247,8 @@ LZ4FLIB_API LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_cctx* cctx);
/*---- Compression ----*/
#define LZ4F_HEADER_SIZE_MAX 19 /* LZ4 Frame header size can vary from 7 to 19 bytes */
#define LZ4F_HEADER_SIZE_MIN 7 /* LZ4 Frame header size can vary, depending on selected paramaters */
#define LZ4F_HEADER_SIZE_MAX 19
/*! LZ4F_compressBegin() :
* will write the frame header into dstBuffer.
@ -352,23 +353,58 @@ LZ4FLIB_API LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* dctx);
* Streaming decompression functions
*************************************/
#define LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH 5
/*! LZ4F_headerSize() : v1.9.0+
* Provide the header size of a frame starting at `src`.
* `srcSize` must be >= LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH,
* which is enough to decode the header length.
* @return : size of frame header
* or an error code, which can be tested using LZ4F_isError()
* note : Frame header size is variable, but is guaranteed to be
* >= LZ4F_HEADER_SIZE_MIN bytes, and <= LZ4F_HEADER_SIZE_MAX bytes.
*/
size_t LZ4F_headerSize(const void* src, size_t srcSize);
/*! LZ4F_getFrameInfo() :
* This function extracts frame parameters (max blockSize, dictID, etc.).
* Its usage is optional.
* Extracted information is typically useful for allocation and dictionary.
* This function works in 2 situations :
* - At the beginning of a new frame, in which case
* it will decode information from `srcBuffer`, starting the decoding process.
* Input size must be large enough to successfully decode the entire frame header.
* Frame header size is variable, but is guaranteed to be <= LZ4F_HEADER_SIZE_MAX bytes.
* It's allowed to provide more input data than this minimum.
* - After decoding has been started.
* In which case, no input is read, frame parameters are extracted from dctx.
* - If decoding has barely started, but not yet extracted information from header,
* Its usage is optional: user can call LZ4F_decompress() directly.
*
* Extracted information will fill an existing LZ4F_frameInfo_t structure.
* This can be useful for allocation and dictionary identification purposes.
*
* LZ4F_getFrameInfo() can work in the following situations :
*
* 1) At the beginning of a new frame, before any invocation of LZ4F_decompress().
* It will decode header from `srcBuffer`,
* consuming the header and starting the decoding process.
*
* Input size must be large enough to contain the full frame header.
* Frame header size can be known beforehand by LZ4F_headerSize().
* Frame header size is variable, but is guaranteed to be >= LZ4F_HEADER_SIZE_MIN bytes,
* and not more than <= LZ4F_HEADER_SIZE_MAX bytes.
* Hence, blindly providing LZ4F_HEADER_SIZE_MAX bytes or more will always work.
* It's allowed to provide more input data than the header size,
* LZ4F_getFrameInfo() will only consume the header.
*
* If input size is not large enough,
* aka if it's smaller than header size,
* function will fail and return an error code.
*
* 2) After decoding has been started,
* it's possible to invoke LZ4F_getFrameInfo() anytime
* to extract already decoded frame parameters stored within dctx.
*
* Note that, if decoding has barely started,
* and not yet read enough information to decode the header,
* LZ4F_getFrameInfo() will fail.
* The number of bytes consumed from srcBuffer will be updated within *srcSizePtr (necessarily <= original value).
* Decompression must resume from (srcBuffer + *srcSizePtr).
* @return : an hint about how many srcSize bytes LZ4F_decompress() expects for next call,
*
* The number of bytes consumed from srcBuffer will be updated in *srcSizePtr (necessarily <= original value).
* LZ4F_getFrameInfo() only consumes bytes when decoding has not yet started,
* and when decoding the header has been successful.
* Decompression must then resume from (srcBuffer + *srcSizePtr).
*
* @return : a hint about how many srcSize bytes LZ4F_decompress() expects for next call,
* or an error code which can be tested using LZ4F_isError().
* note 1 : in case of error, dctx is not modified. Decoding operation can resume from beginning safely.
* note 2 : frame parameters are *copied into* an already allocated LZ4F_frameInfo_t structure.

View File

@ -211,9 +211,13 @@ int basicTests(U32 seed, double compressibility)
CHECK ( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
DISPLAYLEVEL(3, "LZ4F_getFrameInfo on null-content frame (#157) \n");
{ size_t avail_in = cSize;
LZ4F_frameInfo_t frame_info;
assert(cSize >= LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH);
{ LZ4F_frameInfo_t frame_info;
size_t const fhs = LZ4F_headerSize(compressedBuffer, LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH);
size_t avail_in = fhs;
CHECK( fhs );
CHECK( LZ4F_getFrameInfo(dCtx, &frame_info, compressedBuffer, &avail_in) );
if (avail_in != fhs) goto _output_error; /* must consume all, since header size is supposed to be exact */
}
DISPLAYLEVEL(3, "LZ4F_freeDecompressionContext \n");
@ -306,7 +310,8 @@ int basicTests(U32 seed, double compressibility)
}
DISPLAYLEVEL(3, "LZ4F_getFrameInfo on enough input : ");
iSize = 15 - iSize;
iSize = LZ4F_headerSize(ip, LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH);
CHECK( iSize );
CHECK( LZ4F_getFrameInfo(dCtx, &fi, ip, &iSize) );
DISPLAYLEVEL(3, " correctly decoded \n");
}