-v0.7.5
+v0.8.0
Fixed : premature end of frame when zero-sized raw block, reported by Eric Biggers
Fixed : legacy mode with ZSTD_HEAPMODE=0, by Christopher Bergqvist
+Fixed : checksum correctly checked in single-pass mode
Modified : minor compression level adaptations
-Update : specification, to v0.1.2 : max huffman depth at 11 bits
+Updated : compression format specification to v0.2.0
changed : zstd.h moved to /lib directory
v0.7.4
}
}
+MEM_STATIC U32 MEM_readLE24(const void* memPtr)
+{
+ return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16);
+}
+
+MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val)
+{
+ MEM_writeLE16(memPtr, (U16)val);
+ ((BYTE*)memPtr)[2] = (BYTE)(val>>16);
+}
+
MEM_STATIC U32 MEM_readLE32(const void* memPtr)
{
if (MEM_isLittleEndian())
size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
{
- BYTE* const ostart = (BYTE* const)dst;
-
if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
- memcpy(ostart + ZSTD_blockHeaderSize, src, srcSize);
-
- /* Build header */
- ostart[0] = (BYTE)(srcSize>>16);
- ostart[1] = (BYTE)(srcSize>>8);
- ostart[2] = (BYTE) srcSize;
- ostart[0] += (BYTE)(bt_raw<<6); /* is a raw (uncompressed) block */
-
+ memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
+ MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
return ZSTD_blockHeaderSize+srcSize;
}
cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize);
if (ZSTD_isError(cSize)) return cSize;
} else {
- op[0] = (BYTE)(cSize>>16);
- op[1] = (BYTE)(cSize>>8);
- op[2] = (BYTE)cSize;
- op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
+ U32 const cBlockHeader24 = (U32)bt_compressed + (U32)(cSize << 2);
+ MEM_writeLE24(op, cBlockHeader24);
cSize += 3;
}
op += cSize;
}
- ZSTD_statsPrint(stats, cctx->params.cParams.searchLength);
+ ZSTD_statsPrint(stats, cctx->params.cParams.searchLength); /* debug only */
return op-ostart;
}
/* frame epilogue */
if (dstCapacity < 3) return ERROR(dstSize_tooSmall);
{ U32 const checksum = cctx->params.fParams.checksumFlag ?
- (U32)((XXH64_digest(&cctx->xxhState) >> 11) & ((1<<22)-1)) :
+ (U32)(XXH64_digest(&cctx->xxhState) >> 11) :
0;
- op[0] = (BYTE)((bt_end<<6) + (checksum>>16));
- op[1] = (BYTE)(checksum>>8);
- op[2] = (BYTE)checksum;
+ MEM_writeLE24(op, (U32)bt_end + (checksum << 2));
}
cctx->stage = 0; /* return to "created but not init" status */
* Provides the size of compressed block from block header `src` */
size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr)
{
- const BYTE* const in = (const BYTE* const)src;
- U32 cSize;
-
if (srcSize < ZSTD_blockHeaderSize) return ERROR(srcSize_wrong);
-
- bpPtr->blockType = (blockType_t)((*in) >> 6);
- cSize = in[2] + (in[1]<<8) + ((in[0] & 7)<<16);
- bpPtr->origSize = (bpPtr->blockType == bt_rle) ? cSize : 0;
-
- if (bpPtr->blockType == bt_end) return 0;
- if (bpPtr->blockType == bt_rle) return 1;
- return cSize;
+ { U32 const cBlockHeader = MEM_readLE24(src);
+ U32 const cSize = cBlockHeader >> 2;
+ bpPtr->blockType = (blockType_t)(cBlockHeader & 3);
+ bpPtr->origSize = cSize; /* only useful for RLE */
+ if (bpPtr->blockType == bt_end) return 0;
+ if (bpPtr->blockType == bt_rle) return 1;
+ return cSize;
+ }
}
/* last literal segment */
{ size_t const lastLLSize = litEnd - litPtr;
- //if (litPtr > litEnd) return ERROR(corruption_detected); /* too many literals already used */
if (lastLLSize > (size_t)(oend-op)) return ERROR(dstSize_tooSmall);
memcpy(op, litPtr, lastLLSize);
op += lastLLSize;
case bt_end :
/* end of frame */
if (remainingSize) return ERROR(srcSize_wrong);
+ if (dctx->fParams.checksumFlag) {
+ U64 const h64 = XXH64_digest(&dctx->xxhState);
+ U32 const h32 = (U32)(h64>>11) & ((1<<22)-1);
+ U32 const check32 = MEM_readLE24(src) >> 2;
+ if (check32 != h32) return ERROR(checksum_wrong);
+ }
decodedSize = 0;
break;
default:
if (dctx->fParams.checksumFlag) {
U64 const h64 = XXH64_digest(&dctx->xxhState);
U32 const h32 = (U32)(h64>>11) & ((1<<22)-1);
- const BYTE* const ip = (const BYTE*)src;
- U32 const check32 = ip[2] + (ip[1] << 8) + ((ip[0] & 0x3F) << 16);
+ U32 const check32 = MEM_readLE24(src) >> 2;
if (check32 != h32) return ERROR(checksum_wrong);
}
dctx->expected = 0;
/*-************************************
* Includes
**************************************/
-#include <stdlib.h> /* free */
-#include <stdio.h> /* fgets, sscanf */
-#include <sys/timeb.h> /* timeb */
-#include <string.h> /* strcmp */
-#include <time.h> /* clock_t */
+#include <stdlib.h> /* free */
+#include <stdio.h> /* fgets, sscanf */
+#include <sys/timeb.h> /* timeb */
+#include <string.h> /* strcmp */
+#include <time.h> /* clock_t */
#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_compressContinue, ZSTD_compressBlock */
-#include "zstd.h" /* ZSTD_VERSION_STRING */
+#include "zstd.h" /* ZSTD_VERSION_STRING */
#include "error_public.h" /* ZSTD_getErrorCode */
-#include "zdict.h" /* ZDICT_trainFromBuffer */
-#include "datagen.h" /* RDG_genBuffer */
+#include "zdict.h" /* ZDICT_trainFromBuffer */
+#include "datagen.h" /* RDG_genBuffer */
#include "mem.h"
#define XXH_STATIC_LINKING_ONLY
-#include "xxhash.h" /* XXH64 */
+#include "xxhash.h" /* XXH64 */
/*-************************************
### Version
-0.1.2 (15/07/16)
+0.2.0 (22/07/16)
Introduction
General Structure of Zstandard Frame format
-------------------------------------------
-| MagicNb | Frame Header | Block | (More blocks) | EndMark |
+| MagicNb | Frame Header | Block | [More blocks] | EndMark |
|:-------:|:-------------:| ----- | ------------- | ------- |
| 4 bytes | 2-14 bytes | | | 3 bytes |
Frame Header
-------------
-| FHD | (WD) | (dictID) | (Content Size) |
+| FHD | [WD] | [dictID] | [Content Size] |
| ------- | --------- | --------- |:--------------:|
| 1 byte | 0-1 byte | 0-4 bytes | 0 - 8 bytes |
__Block Header__
-This field uses 3-bytes, format is __big-endian__.
+This field uses 3-bytes, format is __little-endian__.
-The 2 highest bits represent the `block type`,
+The 2 lowest bits represent the `block type`,
while the remaining 22 bits represent the (compressed) block size.
There are 4 block types :
They can be decoded first, and then copied during sequence operations,
or they can be decoded on the flow, as needed by sequence commands.
-| Header | (Tree Description) | Stream1 | (Stream2) | (Stream3) | (Stream4) |
+| Header | [Tree Description] | Stream1 | [Stream2] | [Stream3] | [Stream4] |
| ------ | ------------------ | ------- | --------- | --------- | --------- |
Literals can be compressed, or uncompressed.
It's a byte-aligned variable-size bitfield, ranging from 1 to 5 bytes,
using big-endian convention.
-| BlockType | sizes format | (compressed size) | regenerated size |
+| BlockType | sizes format | [compressed size] | regenerated size |
| --------- | ------------ | ----------------- | ---------------- |
| 2 bits | 1 - 2 bits | 0 - 18 bits | 5 - 20 bits |
followed by optional Probability tables for each symbol type,
followed by the bitstream.
-| Header | (LitLengthTable) | (OffsetTable) | (MatchLengthTable) | bitStream |
+| Header | [LitLengthTable] | [OffsetTable] | [MatchLengthTable] | bitStream |
| ------ | ---------------- | ------------- | ------------------ | --------- |
To decode the Sequence section, it's required to know its size.
Version changes
---------------
+- 0.2.0 : numerous format adjustments for zstd v0.8
- 0.1.2 : limit huffman tree depth to 11 bits
- 0.1.1 : reserved dictID ranges
- 0.1.0 : initial release