Decompression can decode frame content size

This commit is contained in:
Yann Collet 2016-03-12 01:25:40 +01:00
parent 0e491c01fe
commit 03ea59b17b
2 changed files with 66 additions and 38 deletions

View File

@ -94,13 +94,13 @@ typedef struct
} blockProperties_t; } blockProperties_t;
/* ******************************************************* /*_*******************************************************
* Memory operations * Memory operations
**********************************************************/ **********************************************************/
static void ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); } static void ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); }
/* ************************************* /*-*************************************
* Error Management * Error Management
***************************************/ ***************************************/
unsigned ZSTD_versionNumber (void) { return ZSTD_VERSION_NUMBER; } unsigned ZSTD_versionNumber (void) { return ZSTD_VERSION_NUMBER; }
@ -118,7 +118,7 @@ ZSTD_ErrorCode ZSTD_getError(size_t code) { return ERR_getError(code); }
const char* ZSTD_getErrorName(size_t code) { return ERR_getErrorName(code); } const char* ZSTD_getErrorName(size_t code) { return ERR_getErrorName(code); }
/* ************************************************************* /*-*************************************************************
* Context management * Context management
***************************************************************/ ***************************************************************/
typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader, typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader,
@ -185,15 +185,15 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
} }
/* ************************************************************* /*-*************************************************************
* Decompression section * Decompression section
***************************************************************/ ***************************************************************/
/* Frame format description /* Frame format description
Frame Header - [ Block Header - Block ] - Frame End Frame Header - [ Block Header - Block ] - Frame End
1) Frame Header 1) Frame Header
- 4 bytes - Magic Number : ZSTD_MAGICNUMBER (defined within zstd_internal.h) - 4 bytes - Magic Number : ZSTD_MAGICNUMBER (defined within zstd_static.h)
- 1 byte - Window Descriptor - 1 byte - Frame Descriptor
2) Block Header 2) Block Header
- 3 bytes, starting with a 2-bits descriptor - 3 bytes, starting with a 2-bits descriptor
Uncompressed, Compressed, Frame End, unused Uncompressed, Compressed, Frame End, unused
@ -203,7 +203,18 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
- 3 bytes, compatible with Block Header - 3 bytes, compatible with Block Header
*/ */
/* Block format description
/* 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
*/
/* Compressed Block, format description
Block = Literal Section - Sequences Section Block = Literal Section - Sequences Section
Prerequisite : size of (compressed) block, maximum size of regenerated data Prerequisite : size of (compressed) block, maximum size of regenerated data
@ -269,46 +280,63 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
TO DO TO DO
*/ */
static const size_t ZSTD_fcs_fieldSize[4] = { 0, 1, 2, 8 };
/** ZSTD_decodeFrameHeader_Part1() : /** ZSTD_frameHeaderSize() :
* decode the 1st part of the Frame Header, which tells Frame Header size. * srcSize must be >= ZSTD_frameHeaderSize_min.
* srcSize must be == ZSTD_frameHeaderSize_min. * @return : size of the Frame Header */
* @return : the full size of the Frame Header */ static size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)
static size_t ZSTD_decodeFrameHeader_Part1(ZSTD_DCtx* zc, const void* src, size_t srcSize)
{ {
U32 magicNumber; U32 fcsId;
if (srcSize != ZSTD_frameHeaderSize_min) if (srcSize < ZSTD_frameHeaderSize_min) return ERROR(srcSize_wrong);
return ERROR(srcSize_wrong); fcsId = (((const BYTE*)src)[4]) >> 6;
magicNumber = MEM_readLE32(src); return ZSTD_frameHeaderSize_min + ZSTD_fcs_fieldSize[fcsId];
if (magicNumber != ZSTD_MAGICNUMBER) return ERROR(prefix_unknown);
zc->headerSize = ZSTD_frameHeaderSize_min;
return zc->headerSize;
} }
/** ZSTD_getFrameParams() :
* decode Frame Header, or provide expected `srcSize`.
* @return : 0, `fparamsPtr` is correctly filled,
* >0, not enough srcSize, provide expected `srcSize`,
* or an error code, which can be tested using ZSTD_isError() */
size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t srcSize) size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t srcSize)
{ {
U32 magicNumber; U32 magicNumber, fcsId;
if (srcSize < ZSTD_frameHeaderSize_min) return ZSTD_frameHeaderSize_max; const BYTE* ip = (const BYTE*)src;
BYTE frameDesc;
if (srcSize < ZSTD_frameHeaderSize_min) return ZSTD_frameHeaderSize_min;
magicNumber = MEM_readLE32(src); magicNumber = MEM_readLE32(src);
if (magicNumber != ZSTD_MAGICNUMBER) return ERROR(prefix_unknown); if (magicNumber != ZSTD_MAGICNUMBER) return ERROR(prefix_unknown);
{ size_t fhsize = ZSTD_frameHeaderSize(src, srcSize);
if (srcSize < fhsize) return fhsize; }
memset(fparamsPtr, 0, sizeof(*fparamsPtr)); memset(fparamsPtr, 0, sizeof(*fparamsPtr));
fparamsPtr->windowLog = (((const BYTE*)src)[4] & 15) + ZSTD_WINDOWLOG_ABSOLUTEMIN; frameDesc = ip[4];
fparamsPtr->mml = (((const BYTE*)src)[4] & 16) ? MINMATCH-1 : MINMATCH; fparamsPtr->windowLog = (frameDesc & 0xF) + ZSTD_WINDOWLOG_ABSOLUTEMIN;
if ((((const BYTE*)src)[4] >> 5) != 0) return ERROR(frameParameter_unsupported); /* reserved 3 bits */ fparamsPtr->mml = (frameDesc & 0x10) ? MINMATCH-1 : MINMATCH;
if ((frameDesc & 0x20) != 0) return ERROR(frameParameter_unsupported); /* reserved 1 bit */
fcsId = frameDesc >> 6;
switch(fcsId)
{
default: /* impossible */
case 0 : fparamsPtr->frameContentSize = 0; break;
case 1 : fparamsPtr->frameContentSize = ip[5]; break;
case 2 : fparamsPtr->frameContentSize = MEM_readLE16(ip+5); break;
case 3 : fparamsPtr->frameContentSize = MEM_readLE64(ip+5); break;
}
return 0; return 0;
} }
/** ZSTD_decodeFrameHeader_Part2() :
* decode the full Frame Header. /** ZSTD_decodeFrameHeader() :
* decode Frame Header.
* srcSize must be the size provided by ZSTD_decodeFrameHeader_Part1(). * srcSize must be the size provided by ZSTD_decodeFrameHeader_Part1().
* @return : 0, or an error code, which can be tested using ZSTD_isError() */ * @return : 0, or an error code, which can be tested using ZSTD_isError() */
static size_t ZSTD_decodeFrameHeader_Part2(ZSTD_DCtx* zc, const void* src, size_t srcSize) static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* zc, const void* src, size_t srcSize)
{ {
size_t result; size_t result = ZSTD_getFrameParams(&(zc->fParams), src, srcSize);
if (srcSize != zc->headerSize)
return ERROR(srcSize_wrong);
result = ZSTD_getFrameParams(&(zc->fParams), src, srcSize);
if ((MEM_32bits()) && (zc->fParams.windowLog > 25)) return ERROR(frameParameter_unsupportedBy32bits); if ((MEM_32bits()) && (zc->fParams.windowLog > 25)) return ERROR(frameParameter_unsupportedBy32bits);
return result; return result;
} }
@ -901,7 +929,7 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
/* Frame Header */ /* Frame Header */
{ {
size_t frameHeaderSize; size_t frameHeaderSize, errorCode;
if (srcSize < ZSTD_frameHeaderSize_min+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); if (srcSize < ZSTD_frameHeaderSize_min+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong);
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT==1) #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT==1)
{ {
@ -910,12 +938,12 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
return ZSTD_decompressLegacy(dst, maxDstSize, src, srcSize, magicNumber); return ZSTD_decompressLegacy(dst, maxDstSize, src, srcSize, magicNumber);
} }
#endif #endif
frameHeaderSize = ZSTD_decodeFrameHeader_Part1(dctx, src, ZSTD_frameHeaderSize_min); frameHeaderSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_min);
if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize; if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize;
if (srcSize < frameHeaderSize+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); if (srcSize < frameHeaderSize+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong);
errorCode = ZSTD_decodeFrameHeader(dctx, src, frameHeaderSize);
if (ZSTD_isError(errorCode)) return errorCode;
ip += frameHeaderSize; remainingSize -= frameHeaderSize; ip += frameHeaderSize; remainingSize -= frameHeaderSize;
frameHeaderSize = ZSTD_decodeFrameHeader_Part2(dctx, src, frameHeaderSize);
if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize;
} }
/* Loop on each block */ /* Loop on each block */
@ -1024,7 +1052,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, co
{ {
/* get frame header size */ /* get frame header size */
if (srcSize != ZSTD_frameHeaderSize_min) return ERROR(srcSize_wrong); /* impossible */ if (srcSize != ZSTD_frameHeaderSize_min) return ERROR(srcSize_wrong); /* impossible */
dctx->headerSize = ZSTD_decodeFrameHeader_Part1(dctx, src, ZSTD_frameHeaderSize_min); dctx->headerSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_min);
if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize; if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize;
memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_min); memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_min);
if (dctx->headerSize > ZSTD_frameHeaderSize_min) { if (dctx->headerSize > ZSTD_frameHeaderSize_min) {
@ -1039,7 +1067,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, co
/* get frame header */ /* get frame header */
size_t result; size_t result;
memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_min, src, dctx->expected); memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_min, src, dctx->expected);
result = ZSTD_decodeFrameHeader_Part2(dctx, dctx->headerBuffer, dctx->headerSize); result = ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize);
if (ZSTD_isError(result)) return result; if (ZSTD_isError(result)) return result;
dctx->expected = ZSTD_blockHeaderSize; dctx->expected = ZSTD_blockHeaderSize;
dctx->stage = ZSTDds_decodeBlockHeader; dctx->stage = ZSTDds_decodeBlockHeader;

View File

@ -165,7 +165,7 @@ ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapaci
You can then reuse ZSTD_CCtx to compress some new frame. You can then reuse ZSTD_CCtx to compress some new frame.
*/ */
typedef struct { U64 frameSize; U32 windowLog; U32 mml; } ZSTD_frameParams; typedef struct { U64 frameContentSize; U32 windowLog; U32 mml; } ZSTD_frameParams;
#define ZSTD_FRAMEHEADERSIZE_MAX 13 /* for static allocation */ #define ZSTD_FRAMEHEADERSIZE_MAX 13 /* for static allocation */
static const size_t ZSTD_frameHeaderSize_min = 5; static const size_t ZSTD_frameHeaderSize_min = 5;