added dictID inside LZ4F_frameInfo_t
authorYann Collet <cyan@fb.com>
Wed, 9 Aug 2017 00:43:11 +0000 (17:43 -0700)
committerYann Collet <cyan@fb.com>
Wed, 9 Aug 2017 00:43:11 +0000 (17:43 -0700)
Compressor can set dictID on LZ4F_compressBegin()
Decompressor can retrieve it using LZ4F_getFrameInfo()

doc/lz4_Frame_format.md
lib/lz4frame.c
lib/lz4frame.h
tests/frametest.c

index bae2b06..77454b2 100644 (file)
@@ -237,8 +237,7 @@ __Header Checksum__
 
 One-byte checksum of combined descriptor fields, including optional ones.
 The value is the second byte of `xxh32()` : ` (xxh32()>>8) & 0xFF `
-using zero as a seed,
-and the full Frame Descriptor as an input
+using zero as a seed, and the full Frame Descriptor as an input
 (including optional fields when they are present).
 A wrong checksum indicates an error in the descriptor.
 Header checksum is informational and can be skipped.
index 994cc8b..c2d6d5c 100644 (file)
@@ -158,7 +158,7 @@ static void LZ4F_writeLE64 (void* dst, U64 value64)
 #define LZ4F_BLOCKSIZEID_DEFAULT LZ4F_max64KB
 
 static const size_t minFHSize = 7;
-static const size_t maxFHSize = LZ4F_HEADER_SIZE_MAX;   /* 15 */
+static const size_t maxFHSize = LZ4F_HEADER_SIZE_MAX;   /* 19 */
 static const size_t BHSize = 4;
 
 
@@ -291,7 +291,7 @@ static size_t LZ4F_compressBound_internal(size_t srcSize,
 size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr)
 {
     LZ4F_preferences_t prefs;
-    size_t const headerSize = maxFHSize;      /* max header size, including magic number and frame content size */
+    size_t const headerSize = maxFHSize;      /* max header size, including optional fields */
 
     if (preferencesPtr!=NULL) prefs = *preferencesPtr;
     else memset(&prefs, 0, sizeof(prefs));
@@ -470,9 +470,10 @@ size_t LZ4F_compressBegin(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstCapacit
 
     /* FLG Byte */
     *dstPtr++ = (BYTE)(((1 & _2BITS) << 6)    /* Version('01') */
-        + ((cctxPtr->prefs.frameInfo.blockMode & _1BIT ) << 5)    /* Block mode */
+        + ((cctxPtr->prefs.frameInfo.blockMode & _1BIT ) << 5)  /* Block mode */
+        + ((cctxPtr->prefs.frameInfo.contentSize > 0) << 3)     /* Frame content size */
         + ((cctxPtr->prefs.frameInfo.contentChecksumFlag & _1BIT ) << 2)   /* Frame checksum */
-        + ((cctxPtr->prefs.frameInfo.contentSize > 0) << 3));   /* Frame content size */
+        +  (cctxPtr->prefs.frameInfo.dictID > 0) );   /* Dictionary ID */
     /* BD Byte */
     *dstPtr++ = (BYTE)((cctxPtr->prefs.frameInfo.blockSizeID & _3BITS) << 4);
     /* Optional Frame content size field */
@@ -481,6 +482,11 @@ size_t LZ4F_compressBegin(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstCapacit
         dstPtr += 8;
         cctxPtr->totalInSize = 0;
     }
+    /* Optional dictionary ID field */
+    if (cctxPtr->prefs.frameInfo.dictID) {
+        LZ4F_writeLE32(dstPtr, cctxPtr->prefs.frameInfo.dictID);
+        dstPtr += 4;
+    }
     /* CRC Byte */
     *dstPtr = LZ4F_headerChecksum(headerStart, dstPtr - headerStart);
     dstPtr++;
@@ -817,12 +823,14 @@ static size_t LZ4F_headerSize(const void* src, size_t srcSize)
     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);
+    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;
-        return contentSizeFlag ? maxFHSize : minFHSize;
+        U32 const dictIDFlag = FLG & _1BIT;
+        return minFHSize + (contentSizeFlag*8) + (dictIDFlag*4);
     }
 }
 
@@ -837,7 +845,7 @@ static size_t LZ4F_headerSize(const void* src, size_t srcSize)
  */
 static size_t LZ4F_decodeHeader(LZ4F_dctx* dctxPtr, const void* src, size_t srcSize)
 {
-    unsigned blockMode, contentSizeFlag, contentChecksumFlag, blockSizeID;
+    unsigned blockMode, contentSizeFlag, contentChecksumFlag, dictIDFlag, blockSizeID;
     size_t frameHeaderSize;
     const BYTE* srcPtr = (const BYTE*)src;
 
@@ -860,7 +868,8 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctxPtr, const void* src, size_t srcS
     }
 
     /* control magic number */
-    if (LZ4F_readLE32(srcPtr) != LZ4F_MAGICNUMBER) return err0r(LZ4F_ERROR_frameType_unknown);
+    if (LZ4F_readLE32(srcPtr) != LZ4F_MAGICNUMBER)
+        return err0r(LZ4F_ERROR_frameType_unknown);
     dctxPtr->frameInfo.frameType = LZ4F_frame;
 
     /* Flags */
@@ -870,14 +879,15 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctxPtr, const void* src, size_t srcS
         blockMode = (FLG>>5) & _1BIT;
         contentSizeFlag = (FLG>>3) & _1BIT;
         contentChecksumFlag = (FLG>>2) & _1BIT;
+        dictIDFlag = FLG & _1BIT;
         /* validate */
-        if (((FLG>>0)&_2BITS) != 0) return err0r(LZ4F_ERROR_reservedFlag_set); /* Reserved bits */
+        if (((FLG>>1)&_1BIT) != 0) return err0r(LZ4F_ERROR_reservedFlag_set); /* Reserved bits */
         if (version != 1) return err0r(LZ4F_ERROR_headerVersion_wrong);        /* Version Number, only supported value */
         if (blockChecksumFlag != 0) return err0r(LZ4F_ERROR_blockChecksum_unsupported); /* Not supported for the time being */
     }
 
     /* Frame Header Size */
-    frameHeaderSize = contentSizeFlag ? maxFHSize : minFHSize;
+    frameHeaderSize = minFHSize + (contentSizeFlag*8) + (dictIDFlag*4);
 
     if (srcSize < frameHeaderSize) {
         /* not enough input to fully decode frame header */
@@ -898,8 +908,10 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctxPtr, const void* src, size_t srcS
     }
 
     /* check header */
-    { BYTE const HC = LZ4F_headerChecksum(srcPtr+4, frameHeaderSize-5);
-      if (HC != srcPtr[frameHeaderSize-1]) return err0r(LZ4F_ERROR_headerChecksum_invalid); }
+    {   BYTE const HC = LZ4F_headerChecksum(srcPtr+4, frameHeaderSize-5);
+        if (HC != srcPtr[frameHeaderSize-1])
+            return err0r(LZ4F_ERROR_headerChecksum_invalid);
+    }
 
     /* save */
     dctxPtr->frameInfo.blockMode = (LZ4F_blockMode_t)blockMode;
@@ -907,7 +919,10 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctxPtr, const void* src, size_t srcS
     dctxPtr->frameInfo.blockSizeID = (LZ4F_blockSizeID_t)blockSizeID;
     dctxPtr->maxBlockSize = LZ4F_getBlockSize(blockSizeID);
     if (contentSizeFlag)
-        dctxPtr->frameRemainingSize = dctxPtr->frameInfo.contentSize = LZ4F_readLE64(srcPtr+6);
+        dctxPtr->frameRemainingSize =
+            dctxPtr->frameInfo.contentSize = LZ4F_readLE64(srcPtr+6);
+    if (dictIDFlag)
+        dctxPtr->frameInfo.dictID = LZ4F_readLE32(srcPtr + frameHeaderSize - 5);
 
     dctxPtr->dStage = dstage_init;
 
index dd2be58..0efe220 100644 (file)
@@ -162,7 +162,8 @@ typedef struct {
   LZ4F_contentChecksum_t contentChecksumFlag;   /* noContentChecksum, contentChecksumEnabled ; 0 == default  */
   LZ4F_frameType_t       frameType;             /* LZ4F_frame, skippableFrame ; 0 == default */
   unsigned long long     contentSize;           /* Size of uncompressed (original) content ; 0 == unknown */
-  unsigned               reserved[2];           /* must be zero for forward compatibility */
+  unsigned               dictID;                /* Dictionary ID, sent by the compressor, to help the decoder select the right dictionary; 0 == no dictionary used */
+  unsigned               reserved[1];           /* must be zero for forward compatibility */
 } LZ4F_frameInfo_t;
 
 /*! LZ4F_preferences_t :
@@ -228,7 +229,7 @@ LZ4FLIB_API LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_cctx* cctx);
 
 /*----    Compression    ----*/
 
-#define LZ4F_HEADER_SIZE_MAX 15
+#define LZ4F_HEADER_SIZE_MAX 19
 /*! LZ4F_compressBegin() :
  * will write the frame header into dstBuffer.
  * dstCapacity must be large enough to store the header. Maximum header size is LZ4F_HEADER_SIZE_MAX bytes.
index 0dadf9f..02d7e5b 100644 (file)
@@ -164,6 +164,9 @@ static unsigned FUZ_highbit(U32 v32)
 /*-*******************************************************
 *  Tests
 *********************************************************/
+#define CHECK_V(v,f) v = f; if (LZ4F_isError(v)) goto _output_error
+#define CHECK(f)   { LZ4F_errorCode_t const CHECK_V(err_ , f); }
+
 int basicTests(U32 seed, double compressibility)
 {
 #define COMPRESSIBLE_NOISE_LENGTH (2 MB)
@@ -197,24 +200,20 @@ int basicTests(U32 seed, double compressibility)
     /* Special case : null-content frame */
     testSize = 0;
     DISPLAYLEVEL(3, "LZ4F_compressFrame, compress null content : ");
-    cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL);
-    if (LZ4F_isError(cSize)) goto _output_error;
+    CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL));
     DISPLAYLEVEL(3, "null content encoded into a %u bytes frame \n", (unsigned)cSize);
 
     DISPLAYLEVEL(3, "LZ4F_createDecompressionContext \n");
-    { LZ4F_errorCode_t const errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
-      if (LZ4F_isError(errorCode)) goto _output_error; }
+    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;
-        LZ4F_errorCode_t const errorCode = LZ4F_getFrameInfo(dCtx, &frame_info, compressedBuffer, &avail_in);
-        if (LZ4F_isError(errorCode)) goto _output_error;
+        CHECK( LZ4F_getFrameInfo(dCtx, &frame_info, compressedBuffer, &avail_in) );
     }
 
     DISPLAYLEVEL(3, "LZ4F_freeDecompressionContext \n");
-    { LZ4F_errorCode_t const errorCode = LZ4F_freeDecompressionContext(dCtx);
-      if (LZ4F_isError(errorCode)) goto _output_error; }
+    CHECK( LZ4F_freeDecompressionContext(dCtx) );
     dCtx = NULL;
 
     /* test one-pass frame compression */
@@ -224,26 +223,22 @@ int basicTests(U32 seed, double compressibility)
     {   LZ4F_preferences_t fastCompressPrefs;
         memset(&fastCompressPrefs, 0, sizeof(fastCompressPrefs));
         fastCompressPrefs.compressionLevel = -3;
-        cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, &fastCompressPrefs);
-        if (LZ4F_isError(cSize)) goto _output_error;
+        CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, &fastCompressPrefs));
         DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
     }
 
     DISPLAYLEVEL(3, "LZ4F_compressFrame, using default preferences : ");
-    cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL);
-    if (LZ4F_isError(cSize)) goto _output_error;
+    CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL));
     DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
 
     DISPLAYLEVEL(3, "Decompression test : \n");
     {   size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
         size_t compressedBufferSize = cSize;
 
-        LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
-        if (LZ4F_isError(errorCode)) goto _output_error;
+        CHECK( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
 
         DISPLAYLEVEL(3, "Single Pass decompression : ");
-        { size_t const decompressError = LZ4F_decompress(dCtx, decodedBuffer, &decodedBufferSize, compressedBuffer, &compressedBufferSize, NULL);
-          if (LZ4F_isError(decompressError)) goto _output_error; }
+        CHECK( LZ4F_decompress(dCtx, decodedBuffer, &decodedBufferSize, compressedBuffer, &compressedBufferSize, NULL) );
         { U64 const crcDest = XXH64(decodedBuffer, decodedBufferSize, 1);
           if (crcDest != crcOrig) goto _output_error; }
         DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedBufferSize);
@@ -257,8 +252,7 @@ int basicTests(U32 seed, double compressibility)
             BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
             size_t decResult, oSize = COMPRESSIBLE_NOISE_LENGTH;
             DISPLAYLEVEL(3, "Missing last %u bytes : ", (U32)missingBytes);
-            decResult = LZ4F_decompress(dCtx, op, &oSize, cBuff, &iSize, NULL);
-            if (LZ4F_isError(decResult)) goto _output_error;
+            CHECK_V(decResult, LZ4F_decompress(dCtx, op, &oSize, cBuff, &iSize, NULL));
             if (decResult != missingBytes) {
                 DISPLAY("%u bytes missing != %u bytes requested \n", (U32)missingBytes, (U32)decResult);
                 goto _output_error;
@@ -282,9 +276,9 @@ int basicTests(U32 seed, double compressibility)
             const BYTE* ip = (BYTE*)compressedBuffer;
 
             DISPLAYLEVEL(3, "Start by feeding 0 bytes, to get next input size : ");
-            errorCode = LZ4F_decompress(dCtx, NULL, &oSize, ip, &iSize, NULL);
-            if (LZ4F_isError(errorCode)) goto _output_error;
-            DISPLAYLEVEL(3, " %u  \n", (unsigned)errorCode);
+            CHECK( LZ4F_decompress(dCtx, NULL, &oSize, ip, &iSize, NULL) );
+            //DISPLAYLEVEL(3, " %u  \n", (unsigned)errorCode);
+            DISPLAYLEVEL(3, " OK  \n");
 
             DISPLAYLEVEL(3, "LZ4F_getFrameInfo on zero-size input : ");
             {   size_t nullSize = 0;
@@ -309,8 +303,7 @@ int basicTests(U32 seed, double compressibility)
 
             DISPLAYLEVEL(3, "LZ4F_getFrameInfo on enough input : ");
             iSize = 15 - iSize;
-            errorCode = LZ4F_getFrameInfo(dCtx, &fi, ip, &iSize);
-            if (LZ4F_isError(errorCode)) goto _output_error;
+            CHECK( LZ4F_getFrameInfo(dCtx, &fi, ip, &iSize) );
             DISPLAYLEVEL(3, " correctly decoded \n");
             ip += iSize;
         }
@@ -342,8 +335,7 @@ int basicTests(U32 seed, double compressibility)
             while (ip < iend) {
                 size_t oSize = oend-op;
                 size_t iSize = 1;
-                errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL);
-                if (LZ4F_isError(errorCode)) goto _output_error;
+                CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
                 op += oSize;
                 ip += iSize;
             }
@@ -356,21 +348,18 @@ int basicTests(U32 seed, double compressibility)
     DISPLAYLEVEL(3, "Using 64 KB block : ");
     prefs.frameInfo.blockSizeID = LZ4F_max64KB;
     prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
-    cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
-    if (LZ4F_isError(cSize)) goto _output_error;
+    CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs));
     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
 
     DISPLAYLEVEL(3, "without checksum : ");
     prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
-    cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
-    if (LZ4F_isError(cSize)) goto _output_error;
+    CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs));
     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
 
     DISPLAYLEVEL(3, "Using 256 KB block : ");
     prefs.frameInfo.blockSizeID = LZ4F_max256KB;
     prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
-    cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
-    if (LZ4F_isError(cSize)) goto _output_error;
+    CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs));
     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
 
     DISPLAYLEVEL(3, "Decompression test : \n");
@@ -388,8 +377,7 @@ int basicTests(U32 seed, double compressibility)
             size_t iSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + 1;
             size_t oSize = oend-op;
             if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
-            { size_t const decompressError = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL);
-              if (LZ4F_isError(decompressError)) goto _output_error; }
+            CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
             op += oSize;
             ip += iSize;
         }
@@ -399,28 +387,24 @@ int basicTests(U32 seed, double compressibility)
             DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
          }
 
-        { LZ4F_errorCode_t const freeError = LZ4F_freeDecompressionContext(dCtx);
-          if (LZ4F_isError(freeError)) goto _output_error; }
+        CHECK( LZ4F_freeDecompressionContext(dCtx) );
         dCtx = NULL;
     }
 
     DISPLAYLEVEL(3, "without checksum : ");
     prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
-    cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
-    if (LZ4F_isError(cSize)) goto _output_error;
+    CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
 
     DISPLAYLEVEL(3, "Using 1 MB block : ");
     prefs.frameInfo.blockSizeID = LZ4F_max1MB;
     prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
-    cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
-    if (LZ4F_isError(cSize)) goto _output_error;
+    CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
 
     DISPLAYLEVEL(3, "without checksum : ");
     prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
-    cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
-    if (LZ4F_isError(cSize)) goto _output_error;
+    CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
 
     DISPLAYLEVEL(3, "Using 4 MB block : ");
@@ -428,8 +412,7 @@ int basicTests(U32 seed, double compressibility)
     prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
     {   size_t const dstCapacity = LZ4F_compressFrameBound(testSize, &prefs);
         DISPLAYLEVEL(4, "dstCapacity = %u  ; ", (U32)dstCapacity)
-        cSize = LZ4F_compressFrame(compressedBuffer, dstCapacity, CNBuffer, testSize, &prefs);
-        if (LZ4F_isError(cSize)) goto _output_error;
+        CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, dstCapacity, CNBuffer, testSize, &prefs) );
         DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
     }
 
@@ -437,61 +420,72 @@ int basicTests(U32 seed, double compressibility)
     prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
     {   size_t const dstCapacity = LZ4F_compressFrameBound(testSize, &prefs);
         DISPLAYLEVEL(4, "dstCapacity = %u  ; ", (U32)dstCapacity)
-        cSize = LZ4F_compressFrame(compressedBuffer, dstCapacity, CNBuffer, testSize, &prefs);
-        if (LZ4F_isError(cSize)) goto _output_error;
+        CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, dstCapacity, CNBuffer, testSize, &prefs) );
         DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
     }
 
-    {   size_t errorCode;
+    /* frame content size tests */
+    {   size_t cErr;
         BYTE* const ostart = (BYTE*)compressedBuffer;
         BYTE* op = ostart;
-        errorCode = LZ4F_createCompressionContext(&cctx, LZ4F_VERSION);
-        if (LZ4F_isError(errorCode)) goto _output_error;
+        CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
 
         DISPLAYLEVEL(3, "compress without frameSize : ");
         memset(&(prefs.frameInfo), 0, sizeof(prefs.frameInfo));
-        errorCode = LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs);
-        if (LZ4F_isError(errorCode)) goto _output_error;
-        op += errorCode;
-        errorCode = LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL);
-        if (LZ4F_isError(errorCode)) goto _output_error;
-        op += errorCode;
-        errorCode = LZ4F_compressEnd(cctx, compressedBuffer, testSize, NULL);
-        if (LZ4F_isError(errorCode)) goto _output_error;
+        CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
+        op += cErr;
+        CHECK_V(cErr, LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL));
+        op += cErr;
+        CHECK( LZ4F_compressEnd(cctx, compressedBuffer, testSize, NULL) );
         DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)(op-ostart));
 
         DISPLAYLEVEL(3, "compress with frameSize : ");
         prefs.frameInfo.contentSize = testSize;
         op = ostart;
-        errorCode = LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs);
-        if (LZ4F_isError(errorCode)) goto _output_error;
-        op += errorCode;
-        errorCode = LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL);
-        if (LZ4F_isError(errorCode)) goto _output_error;
-        op += errorCode;
-        errorCode = LZ4F_compressEnd(cctx, compressedBuffer, testSize, NULL);
-        if (LZ4F_isError(errorCode)) goto _output_error;
+        CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
+        op += cErr;
+        CHECK_V(cErr, LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL));
+        op += cErr;
+        CHECK( LZ4F_compressEnd(cctx, compressedBuffer, testSize, NULL) );
         DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)(op-ostart));
 
         DISPLAYLEVEL(3, "compress with wrong frameSize : ");
         prefs.frameInfo.contentSize = testSize+1;
         op = ostart;
-        errorCode = LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs);
-        if (LZ4F_isError(errorCode)) goto _output_error;
-        op += errorCode;
-        errorCode = LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL);
-        if (LZ4F_isError(errorCode)) goto _output_error;
-        op += errorCode;
-        errorCode = LZ4F_compressEnd(cctx, op, testSize, NULL);
-        if (LZ4F_isError(errorCode)) { DISPLAYLEVEL(3, "Error correctly detected : %s \n", LZ4F_getErrorName(errorCode)); }
-        else
-            goto _output_error;
-
-        errorCode = LZ4F_freeCompressionContext(cctx);
-        if (LZ4F_isError(errorCode)) goto _output_error;
+        CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
+        op += cErr;
+        CHECK_V(cErr, LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL));
+        op += cErr;
+        cErr = LZ4F_compressEnd(cctx, op, testSize, NULL);
+        if (!LZ4F_isError(cErr)) goto _output_error;
+        DISPLAYLEVEL(3, "Error correctly detected : %s \n", LZ4F_getErrorName(cErr));
+
+        CHECK( LZ4F_freeCompressionContext(cctx) );
         cctx = NULL;
     }
 
+    /* dictID tests */
+    {   size_t cErr;
+        U32 const dictID = 0x99;
+        CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
+
+        DISPLAYLEVEL(3, "insert a dictID : ");
+        memset(&prefs.frameInfo, 0, sizeof(prefs.frameInfo));
+        prefs.frameInfo.dictID = dictID;
+        CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
+        DISPLAYLEVEL(3, "created frame header of size %i bytes  \n", (int)cErr);
+
+        DISPLAYLEVEL(3, "read a dictID : ");
+        CHECK( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
+        memset(&prefs.frameInfo, 0, sizeof(prefs.frameInfo));
+        CHECK( LZ4F_getFrameInfo(dCtx, &prefs.frameInfo, compressedBuffer, &cErr) );
+        if (prefs.frameInfo.dictID != dictID) goto _output_error;
+        DISPLAYLEVEL(3, "%u \n", (U32)prefs.frameInfo.dictID);
+
+        CHECK( LZ4F_freeCompressionContext(cctx) ); cctx = NULL;
+        CHECK( LZ4F_freeDecompressionContext(dCtx) ); dCtx = NULL;
+    }
+
     DISPLAYLEVEL(3, "Skippable frame test : \n");
     {   size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
         unsigned maxBits = FUZ_highbit((U32)decodedBufferSize);
@@ -500,8 +494,7 @@ int basicTests(U32 seed, double compressibility)
         BYTE* ip = (BYTE*)compressedBuffer;
         BYTE* iend = (BYTE*)compressedBuffer + cSize + 8;
 
-        LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
-        if (LZ4F_isError(errorCode)) goto _output_error;
+        CHECK( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
 
         /* generate skippable frame */
         FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START);
@@ -513,8 +506,7 @@ int basicTests(U32 seed, double compressibility)
             size_t iSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + 1;
             size_t oSize = oend-op;
             if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
-            errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL);
-            if (LZ4F_isError(errorCode)) goto _output_error;
+            CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
             op += oSize;
             ip += iSize;
         }
@@ -533,8 +525,7 @@ int basicTests(U32 seed, double compressibility)
             size_t iSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + 1;
             size_t oSize = oend-op;
             if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
-            errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL);
-            if (LZ4F_isError(errorCode)) goto _output_error;
+            CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
             op += oSize;
             ip += iSize;
         }
@@ -550,8 +541,7 @@ int basicTests(U32 seed, double compressibility)
             size_t iSize = 10;
             size_t oSize = 10;
             if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
-            errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL);
-            if (LZ4F_isError(errorCode)) goto _output_error;
+            CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
             op += oSize;
             ip += iSize;
         }
@@ -603,6 +593,7 @@ int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressi
     size_t result;
     clock_t const startClock = clock();
     clock_t const clockDuration = duration_s * CLOCKS_PER_SEC;
+#   undef CHECK
 #   define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \
                             DISPLAY(" (seed %u, test nb %u)  \n", seed, testNb); goto _output_error; }