diff --git a/NEWS b/NEWS index bb7eaaca..cddc8fc1 100644 --- a/NEWS +++ b/NEWS @@ -3,7 +3,8 @@ new : long range mode, using --long command, by Stella Lau (@stellamplau) license : changed /examples license to BSD + GPLv2 license : fix a few header files to reflect new license (#825) fix : multi-threading compression works with custom allocators -fix : a rare compression bug when compression generates very large distances (only possible at --ultra -22) +fix : ZSTD_sizeof_CStream() was over-evaluating memory usage +fix : a rare compression bug when compression generates very large distances and bunch of other conditions (only possible at --ultra -22) fix : 32-bits build can now decode large offsets (levels 21+) cli : new : can split input file for dictionary training, using command -B# cli : fix : do not change /dev/null permissions when using command -t with root access, reported by @mike155 (#851) diff --git a/doc/zstd_manual.html b/doc/zstd_manual.html index e7d86170..f1d161f3 100644 --- a/doc/zstd_manual.html +++ b/doc/zstd_manual.html @@ -27,8 +27,8 @@
  • Buffer-less and synchronous inner streaming functions
  • Buffer-less streaming compression (synchronous mode)
  • Buffer-less streaming decompression (synchronous mode)
  • -
  • ZSTD_CCtx_params
  • -
  • Block functions
  • +
  • New advanced API (experimental)
  • +
  • Block level API

  • Introduction

    @@ -399,33 +399,33 @@ size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds);
     size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict);
     size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
     

    These functions give the current memory usage of selected object. - Object memory usage can evolve if it's re-used multiple times. + Object memory usage can evolve when re-used multiple times.


    size_t ZSTD_estimateCCtxSize(int compressionLevel);
    -size_t ZSTD_estimateCCtxSize_advanced_usingCParams(ZSTD_compressionParameters cParams);
    -size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params);
    +size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams);
    +size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params);
     size_t ZSTD_estimateDCtxSize(void);
     

    These functions make it possible to estimate memory usage of a future {D,C}Ctx, before its creation. ZSTD_estimateCCtxSize() will provide a budget large enough for any compression level up to selected one. It will also consider src size to be arbitrarily "large", which is worst case. - If srcSize is known to always be small, ZSTD_estimateCCtxSize_advanced_usingCParams() can provide a tighter estimation. - ZSTD_estimateCCtxSize_advanced_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. - ZSTD_estimateCCtxSize_advanced_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is > 1. + If srcSize is known to always be small, ZSTD_estimateCCtxSize_usingCParams() can provide a tighter estimation. + ZSTD_estimateCCtxSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. + ZSTD_estimateCCtxSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is > 1. Note : CCtx estimation is only correct for single-threaded compression


    size_t ZSTD_estimateCStreamSize(int compressionLevel);
    -size_t ZSTD_estimateCStreamSize_advanced_usingCParams(ZSTD_compressionParameters cParams);
    -size_t ZSTD_estimateCStreamSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params);
    +size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams);
    +size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params);
     size_t ZSTD_estimateDStreamSize(size_t windowSize);
     size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);
     

    ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one. It will also consider src size to be arbitrarily "large", which is worst case. - If srcSize is known to always be small, ZSTD_estimateCStreamSize_advanced_usingCParams() can provide a tighter estimation. - ZSTD_estimateCStreamSize_advanced_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. - ZSTD_estimateCStreamSize_advanced_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is set to a value > 1. + If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation. + ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. + ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is set to a value > 1. Note : CStream estimation is only correct for single-threaded compression. ZSTD_DStream memory budget depends on window Size. This information can be passed manually, using ZSTD_estimateDStreamSize, @@ -436,8 +436,8 @@ size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);


    typedef enum {
    -    ZSTD_dlm_byCopy = 0,      /* Copy dictionary content internally. */
    -    ZSTD_dlm_byRef,           /* Reference dictionary content -- the dictionary buffer must outlives its users. */
    +    ZSTD_dlm_byCopy = 0,     /**< Copy dictionary content internally */
    +    ZSTD_dlm_byRef,          /**< Reference dictionary content -- the dictionary buffer must outlive its users. */
     } ZSTD_dictLoadMethod_e;
     

    size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel);
    @@ -646,18 +646,18 @@ size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict*
       @return : 0, or an error code (which can be tested using ZSTD_isError()) 
     


    -

    Advanced Streaming decompression functions

    typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e;
    -ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem);
    +

    Advanced Streaming decompression functions

    ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem);
     ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize);    /**< same as ZSTD_initStaticDCtx() */
    -size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue);
    -size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); /**< note: a dict will not be used if dict == NULL or dictSize < 8 */
    -size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict);  /**< note : ddict will just be referenced, and must outlive decompression session */
    +typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e;
    +size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue);   /* obsolete : this API will be removed in a future version */
    +size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); /**< note: no dictionary will be used if dict == NULL or dictSize < 8 */
    +size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict);  /**< note : ddict is referenced, it must outlive decompression session */
     size_t ZSTD_resetDStream(ZSTD_DStream* zds);  /**< re-use decompression parameters from previous init; saves dictionary loading */
     

    Buffer-less and synchronous inner streaming functions

       This is an advanced API, giving full control over buffer management, for users which need direct control over memory.
    -  But it's also a complex one, with many restrictions (documented below).
    -  Prefer using normal streaming API for an easier experience
    +  But it's also a complex one, with several restrictions, documented below.
    +  Prefer normal streaming API for an easier experience.
      
     
    @@ -673,8 +673,8 @@ size_t ZSTD_resetDStream(ZSTD_DStream* zds);
    /**< re-use decompression para Then, consume your input using ZSTD_compressContinue(). There are some important considerations to keep in mind when using this advanced function : - - ZSTD_compressContinue() has no internal buffer. It uses externally provided buffer only. - - Interface is synchronous : input is consumed entirely and produce 1+ (or more) compressed blocks. + - ZSTD_compressContinue() has no internal buffer. It uses externally provided buffers only. + - Interface is synchronous : input is consumed entirely and produces 1+ compressed blocks. - Caller must ensure there is enough space in `dst` to store compressed data under worst case scenario. Worst case evaluation is provided by ZSTD_compressBound(). ZSTD_compressContinue() doesn't guarantee recover after a failed compression. @@ -685,9 +685,9 @@ size_t ZSTD_resetDStream(ZSTD_DStream* zds);
    /**< re-use decompression para Finish a frame with ZSTD_compressEnd(), which will write the last block(s) and optional checksum. It's possible to use srcSize==0, in which case, it will write a final empty block to end the frame. - Without last block mark, frames will be considered unfinished (corrupted) by decoders. + Without last block mark, frames are considered unfinished (hence corrupted) by compliant decoders. - `ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress some new frame. + `ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress again.

    Buffer-less streaming compression functions

    size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel);
    @@ -783,8 +783,29 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
     

    typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e;
     

    -

    New advanced API (experimental, and compression only)


    +

    New advanced API (experimental)

    
    +
     
    typedef enum {
    +    /* Question : should we have a format ZSTD_f_auto ?
    +     * For the time being, it would mean exactly the same as ZSTD_f_zstd1.
    +     * But, in the future, should several formats be supported,
    +     * on the compression side, it would mean "default format".
    +     * On the decompression side, it would mean "multi format",
    +     * and ZSTD_f_zstd1 could be reserved to mean "accept *only* zstd frames".
    +     * Since meaning is a little different, another option could be to define different enums for compression and decompression.
    +     * This question could be kept for later, when there are actually multiple formats to support,
    +     * but there is also the question of pinning enum values, and pinning value `0` is especially important */
    +    ZSTD_f_zstd1 = 0,        /* zstd frame format, specified in zstd_compression_format.md (default) */
    +    ZSTD_f_zstd1_magicless,  /* Variant of zstd frame format, without initial 4-bytes magic number.
    +                              * Useful to save 4 bytes per generated frame.
    +                              * Decoder cannot recognise automatically this format, requiring instructions. */
    +} ZSTD_format_e;
    +

    +
    typedef enum {
    +    /* compression format */
    +    ZSTD_p_format = 10,      /* See ZSTD_format_e enum definition.
    +                              * Cast selected format as unsigned for ZSTD_CCtx_setParameter() compatibility. */
    +
         /* compression parameters */
         ZSTD_p_compressionLevel=100, /* Update all compression parameters according to pre-defined cLevel table
                                   * Default level is ZSTD_CLEVEL_DEFAULT==3.
    @@ -949,7 +970,7 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
     
    typedef enum {
         ZSTD_e_continue=0, /* collect more data, encoder transparently decides when to output result, for optimal conditions */
         ZSTD_e_flush,      /* flush any data provided so far - frame will continue, future data can still reference previous data for better compression */
    -    ZSTD_e_end         /* flush any remaining data and ends current frame. Any future compression starts a new frame. */
    +    ZSTD_e_end         /* flush any remaining data and close current frame. Any additional data starts a new frame. */
     } ZSTD_EndDirective;
     

    size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
    @@ -959,8 +980,8 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
     

    Behave about the same as ZSTD_compressStream. To note : - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_setParameter() - Compression parameters cannot be changed once compression is started. - - *dstPos must be <= dstCapacity, *srcPos must be <= srcSize - - *dspPos and *srcPos will be updated. They are guaranteed to remain below their respective limit. + - outpot->pos must be <= dstCapacity, input->pos must be <= srcSize + - outpot->pos and input->pos will be updated. They are guaranteed to remain below their respective limit. - @return provides the minimum amount of data still to flush from internal buffers or an error code, which can be tested using ZSTD_isError(). if @return != 0, flush is not fully completed, there is some data left within internal buffers. @@ -976,6 +997,7 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t Useful after an error, or to interrupt an ongoing compression job and start a new one. Any internal data not yet flushed is cancelled. Dictionary (if any) is dropped. + All parameters are back to default values. It's possible to modify compression parameters after a reset.


    @@ -987,26 +1009,30 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t ZSTD_EndDirective endOp);

    Same as ZSTD_compress_generic(), but using only integral types as arguments. - Argument list is larger and less expressive than ZSTD_{in,out}Buffer, + Argument list is larger than ZSTD_{in,out}Buffer, but can be helpful for binders from dynamic languages which have troubles handling structures containing memory pointers.


    -

    ZSTD_CCtx_params

    +
    ZSTD_CCtx_params* ZSTD_createCCtxParams(void);
    +

    Quick howto : - ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure - - ZSTD_CCtxParam_setParameter() : Push parameters one by one into an - existing ZSTD_CCtx_params structure. This is similar to - ZSTD_CCtx_setParameter(). - - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to an existing CCtx. These - parameters will be applied to all subsequent compression jobs. + - ZSTD_CCtxParam_setParameter() : Push parameters one by one into + an existing ZSTD_CCtx_params structure. + This is similar to + ZSTD_CCtx_setParameter(). + - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to + an existing CCtx. + These parameters will be applied to + all subsequent compression jobs. - ZSTD_compress_generic() : Do compression using the CCtx. - ZSTD_freeCCtxParams() : Free the memory. - This can be used with ZSTD_estimateCCtxSize_opaque() for static allocation - for single-threaded compression. + This can be used with ZSTD_estimateCCtxSize_advanced_usingCCtxParams() + for static allocation for single-threaded compression. -

    +


    size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params);
     

    Reset params to default, with the default compression level. @@ -1030,22 +1056,116 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t Set one compression parameter, selected by enum ZSTD_cParameter. Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_setParametersUsingCCtxParams(). Note : when `value` is an enum, cast it to unsigned for proper type checking. - @result : 0, or an error code (which can be tested with ZSTD_isError()). + @result : 0, or an error code (which can be tested with ZSTD_isError()).


    size_t ZSTD_CCtx_setParametersUsingCCtxParams(
             ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params);
    -

    Apply a set of ZSTD_CCtx_params to the compression context. - This must be done before the dictionary is loaded. - The pledgedSrcSize is treated as unknown. - Multithreading parameters are applied only if nbThreads > 1. +

    Apply a set of ZSTD_CCtx_params to the compression context. + This must be done before the dictionary is loaded. + The pledgedSrcSize is treated as unknown. + Multithreading parameters are applied only if nbThreads > 1.


    -

    Block functions

    -    Block functions produce and decode raw zstd blocks, without frame metadata.
    -    Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes).
    +

    Advanced parameters for decompression API


    +
    size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);   /* not implemented */
    +size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);   /* not implemented */
    +size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode);   /* not implemented */
    +

    Create an internal DDict from dict buffer, + to be used to decompress next frames. + @result : 0, or an error code (which can be tested with ZSTD_isError()). + Special : Adding a NULL (or 0-size) dictionary invalidates any previous dictionary, + meaning "return to no-dictionary mode". + Note 1 : `dict` content will be copied internally. + Use ZSTD_DCtx_loadDictionary_byReference() + to reference dictionary content instead. + In which case, the dictionary buffer must outlive its users. + Note 2 : Loading a dictionary involves building tables, + which has a non-negligible impact on CPU usage and latency. + Note 3 : Use ZSTD_DCtx_loadDictionary_advanced() to select + how dictionary content will be interpreted and loaded. + +


    + +
    size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);   /* not implemented */
    +

    Reference a prepared dictionary, to be used to decompress next frames. + The dictionary remains active for decompression of future frames using same DCtx. + @result : 0, or an error code (which can be tested with ZSTD_isError()). + Note 1 : Currently, only one dictionary can be managed. + Referencing a new dictionary effectively "discards" any previous one. + Special : adding a NULL DDict means "return to no-dictionary mode". + Note 2 : DDict is just referenced, its lifetime must outlive its usage from DCtx. + +


    + +
    size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize);   /* not implemented */
    +size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode);   /* not implemented */
    +

    Reference a prefix (single-usage dictionary) for next compression job. + Prefix is **only used once**. It must be explicitly referenced before each frame. + If there is a need to use same prefix multiple times, consider embedding it into a ZSTD_DDict instead. + @result : 0, or an error code (which can be tested with ZSTD_isError()). + Note 1 : Adding any prefix (including NULL) invalidates any previously set prefix or dictionary + Note 2 : Prefix buffer is referenced. It must outlive compression job. + Note 3 : By default, the prefix is treated as raw content (ZSTD_dm_rawContent). + Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode. + Note 4 : Referencing a raw content prefix has almost no cpu nor memory cost. + +


    + +
    size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize);
    +

    Refuses allocating internal buffers for frames requiring a window size larger than provided limit. + This is useful to prevent a decoder context from reserving too much memory for itself (potential attack scenario). + This parameter is only useful in streaming mode, since no internal buffer is allocated in direct mode. + By default, a decompression context accepts all window sizes <= (1 << ZSTD_WINDOWLOG_MAX) + @return : 0, or an error code (which can be tested using ZSTD_isError()). + +


    + +
    size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format);
    +

    Instruct the decoder context about what kind of data to decode next. + This instruction is mandatory to decode data without a fully-formed header, + such ZSTD_f_zstd1_magicless for example. + @return : 0, or an error code (which can be tested using ZSTD_isError()). + +


    + +
    size_t ZSTD_decompress_generic(ZSTD_DCtx* dctx,
    +                               ZSTD_outBuffer* output,
    +                               ZSTD_inBuffer* input);
    +

    Behave the same as ZSTD_decompressStream. + Decompression parameters cannot be changed once decompression is started. + @return : an error code, which can be tested using ZSTD_isError() + if >0, a hint, nb of expected input bytes for next invocation. + `0` means : a frame has just been fully decoded and flushed. + +


    + +
    size_t ZSTD_decompress_generic_simpleArgs (
    +                ZSTD_DCtx* dctx,
    +                void* dst, size_t dstCapacity, size_t* dstPos,
    +          const void* src, size_t srcSize, size_t* srcPos);
    +

    Same as ZSTD_decompress_generic(), + but using only integral types as arguments. + Argument list is larger than ZSTD_{in,out}Buffer, + but can be helpful for binders from dynamic languages + which have troubles handling structures containing memory pointers. + +


    + +
    void ZSTD_DCtx_reset(ZSTD_DCtx* dctx);
    +

    Return a DCtx to clean state. + If a decompression was ongoing, any internal data not yet flushed is cancelled. + All parameters are back to default values, including sticky ones. + Dictionary (if any) is dropped. + Parameters can be modified again after a reset. + +


    + +

    Block level API

    
    +
    +

    Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes). User will have to take in charge required information to regenerate data, such as compressed and content sizes. A few rules to respect : @@ -1055,7 +1175,7 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t + compression : any ZSTD_compressBegin*() variant, including with dictionary + decompression : any ZSTD_decompressBegin*() variant, including with dictionary + copyCCtx() and copyDCtx() can be used too - - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX + - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB + If input is larger than a block size, it's necessary to split input data into multiple blocks + For inputs larger than a single block size, consider using the regular ZSTD_compress() instead. Frame metadata is not that costly, and quickly becomes negligible as source size grows larger. @@ -1066,7 +1186,7 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t + In case of multiple successive blocks, should some of them be uncompressed, decoder must be informed of their existence in order to follow proper history. Use ZSTD_insertBlock() for such a case. -

    +


    Raw zstd block functions

    size_t ZSTD_getBlockSize   (const ZSTD_CCtx* cctx);
     size_t ZSTD_compressBlock  (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
    diff --git a/examples/streaming_memory_usage.c b/examples/streaming_memory_usage.c
    index b709f50b..b056c2a5 100644
    --- a/examples/streaming_memory_usage.c
    +++ b/examples/streaming_memory_usage.c
    @@ -85,7 +85,7 @@ int main(int argc, char const *argv[]) {
                     return 1;
                 }
             }
    -        
    +
             size_t compressedSize;
             {   ZSTD_inBuffer inBuff = { dataToCompress, sizeof(dataToCompress), 0 };
                 ZSTD_outBuffer outBuff = { compressedData, sizeof(compressedData), 0 };
    @@ -133,7 +133,7 @@ int main(int argc, char const *argv[]) {
     
             size_t const cstreamSize = ZSTD_sizeof_CStream(cstream);
             size_t const cstreamEstimatedSize = wLog ?
    -                ZSTD_estimateCStreamSize_advanced_usingCParams(params.cParams) :
    +                ZSTD_estimateCStreamSize_usingCParams(params.cParams) :
                     ZSTD_estimateCStreamSize(compressionLevel);
             size_t const dstreamSize = ZSTD_sizeof_DStream(dstream);
     
    diff --git a/lib/common/error_private.c b/lib/common/error_private.c
    index 8045e445..11f7cdab 100644
    --- a/lib/common/error_private.c
    +++ b/lib/common/error_private.c
    @@ -30,14 +30,15 @@ const char* ERR_getErrorString(ERR_enum code)
         case PREFIX(init_missing): return "Context should be init first";
         case PREFIX(memory_allocation): return "Allocation error : not enough memory";
         case PREFIX(stage_wrong): return "Operation not authorized at current processing stage";
    -    case PREFIX(dstSize_tooSmall): return "Destination buffer is too small";
    -    case PREFIX(srcSize_wrong): return "Src size is incorrect";
         case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported";
         case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large";
         case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small";
         case PREFIX(dictionary_corrupted): return "Dictionary is corrupted";
         case PREFIX(dictionary_wrong): return "Dictionary mismatch";
         case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples";
    +    case PREFIX(dstSize_tooSmall): return "Destination buffer is too small";
    +    case PREFIX(srcSize_wrong): return "Src size is incorrect";
    +        /* following error codes are not stable and may be removed or changed in a future version */
         case PREFIX(frameIndex_tooLarge): return "Frame index is too large";
         case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking";
         case PREFIX(maxCode):
    diff --git a/lib/common/pool.c b/lib/common/pool.c
    index 5f19f331..9e6f802e 100644
    --- a/lib/common/pool.c
    +++ b/lib/common/pool.c
    @@ -33,7 +33,7 @@ typedef struct POOL_job_s {
     struct POOL_ctx_s {
         ZSTD_customMem customMem;
         /* Keep track of the threads */
    -    pthread_t *threads;
    +    ZSTD_pthread_t *threads;
         size_t numThreads;
     
         /* The queue is a circular buffer */
    @@ -48,11 +48,11 @@ struct POOL_ctx_s {
         int queueEmpty;
     
         /* The mutex protects the queue */
    -    pthread_mutex_t queueMutex;
    +    ZSTD_pthread_mutex_t queueMutex;
         /* Condition variable for pushers to wait on when the queue is full */
    -    pthread_cond_t queuePushCond;
    +    ZSTD_pthread_cond_t queuePushCond;
         /* Condition variables for poppers to wait on when the queue is empty */
    -    pthread_cond_t queuePopCond;
    +    ZSTD_pthread_cond_t queuePopCond;
         /* Indicates if the queue is shutting down */
         int shutdown;
     };
    @@ -67,14 +67,14 @@ static void* POOL_thread(void* opaque) {
         if (!ctx) { return NULL; }
         for (;;) {
             /* Lock the mutex and wait for a non-empty queue or until shutdown */
    -        pthread_mutex_lock(&ctx->queueMutex);
    +        ZSTD_pthread_mutex_lock(&ctx->queueMutex);
     
             while (ctx->queueEmpty && !ctx->shutdown) {
    -            pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex);
    +            ZSTD_pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex);
             }
             /* empty => shutting down: so stop */
             if (ctx->queueEmpty) {
    -            pthread_mutex_unlock(&ctx->queueMutex);
    +            ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
                 return opaque;
             }
             /* Pop a job off the queue */
    @@ -83,17 +83,17 @@ static void* POOL_thread(void* opaque) {
                 ctx->numThreadsBusy++;
                 ctx->queueEmpty = ctx->queueHead == ctx->queueTail;
                 /* Unlock the mutex, signal a pusher, and run the job */
    -            pthread_mutex_unlock(&ctx->queueMutex);
    -            pthread_cond_signal(&ctx->queuePushCond);
    +            ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
    +            ZSTD_pthread_cond_signal(&ctx->queuePushCond);
     
                 job.function(job.opaque);
     
                 /* If the intended queue size was 0, signal after finishing job */
                 if (ctx->queueSize == 1) {
    -                pthread_mutex_lock(&ctx->queueMutex);
    +                ZSTD_pthread_mutex_lock(&ctx->queueMutex);
                     ctx->numThreadsBusy--;
    -                pthread_mutex_unlock(&ctx->queueMutex);
    -                pthread_cond_signal(&ctx->queuePushCond);
    +                ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
    +                ZSTD_pthread_cond_signal(&ctx->queuePushCond);
             }   }
         }  /* for (;;) */
         /* Unreachable */
    @@ -120,12 +120,12 @@ POOL_ctx *POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customM
         ctx->queueTail = 0;
         ctx->numThreadsBusy = 0;
         ctx->queueEmpty = 1;
    -    (void)pthread_mutex_init(&ctx->queueMutex, NULL);
    -    (void)pthread_cond_init(&ctx->queuePushCond, NULL);
    -    (void)pthread_cond_init(&ctx->queuePopCond, NULL);
    +    (void)ZSTD_pthread_mutex_init(&ctx->queueMutex, NULL);
    +    (void)ZSTD_pthread_cond_init(&ctx->queuePushCond, NULL);
    +    (void)ZSTD_pthread_cond_init(&ctx->queuePopCond, NULL);
         ctx->shutdown = 0;
         /* Allocate space for the thread handles */
    -    ctx->threads = (pthread_t*)ZSTD_malloc(numThreads * sizeof(pthread_t), customMem);
    +    ctx->threads = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), customMem);
         ctx->numThreads = 0;
         ctx->customMem = customMem;
         /* Check for errors */
    @@ -133,7 +133,7 @@ POOL_ctx *POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customM
         /* Initialize the threads */
         {   size_t i;
             for (i = 0; i < numThreads; ++i) {
    -            if (pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) {
    +            if (ZSTD_pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) {
                     ctx->numThreads = i;
                     POOL_free(ctx);
                     return NULL;
    @@ -148,25 +148,25 @@ POOL_ctx *POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customM
     */
     static void POOL_join(POOL_ctx *ctx) {
         /* Shut down the queue */
    -    pthread_mutex_lock(&ctx->queueMutex);
    +    ZSTD_pthread_mutex_lock(&ctx->queueMutex);
         ctx->shutdown = 1;
    -    pthread_mutex_unlock(&ctx->queueMutex);
    +    ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
         /* Wake up sleeping threads */
    -    pthread_cond_broadcast(&ctx->queuePushCond);
    -    pthread_cond_broadcast(&ctx->queuePopCond);
    +    ZSTD_pthread_cond_broadcast(&ctx->queuePushCond);
    +    ZSTD_pthread_cond_broadcast(&ctx->queuePopCond);
         /* Join all of the threads */
         {   size_t i;
             for (i = 0; i < ctx->numThreads; ++i) {
    -            pthread_join(ctx->threads[i], NULL);
    +            ZSTD_pthread_join(ctx->threads[i], NULL);
         }   }
     }
     
     void POOL_free(POOL_ctx *ctx) {
         if (!ctx) { return; }
         POOL_join(ctx);
    -    pthread_mutex_destroy(&ctx->queueMutex);
    -    pthread_cond_destroy(&ctx->queuePushCond);
    -    pthread_cond_destroy(&ctx->queuePopCond);
    +    ZSTD_pthread_mutex_destroy(&ctx->queueMutex);
    +    ZSTD_pthread_cond_destroy(&ctx->queuePushCond);
    +    ZSTD_pthread_cond_destroy(&ctx->queuePopCond);
         ZSTD_free(ctx->queue, ctx->customMem);
         ZSTD_free(ctx->threads, ctx->customMem);
         ZSTD_free(ctx, ctx->customMem);
    @@ -176,7 +176,7 @@ size_t POOL_sizeof(POOL_ctx *ctx) {
         if (ctx==NULL) return 0;  /* supports sizeof NULL */
         return sizeof(*ctx)
             + ctx->queueSize * sizeof(POOL_job)
    -        + ctx->numThreads * sizeof(pthread_t);
    +        + ctx->numThreads * sizeof(ZSTD_pthread_t);
     }
     
     /**
    @@ -198,12 +198,12 @@ void POOL_add(void* ctxVoid, POOL_function function, void *opaque) {
         POOL_ctx* const ctx = (POOL_ctx*)ctxVoid;
         if (!ctx) { return; }
     
    -    pthread_mutex_lock(&ctx->queueMutex);
    +    ZSTD_pthread_mutex_lock(&ctx->queueMutex);
         {   POOL_job const job = {function, opaque};
     
             /* Wait until there is space in the queue for the new job */
             while (isQueueFull(ctx) && !ctx->shutdown) {
    -          pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex);
    +          ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex);
             }
             /* The queue is still going => there is space */
             if (!ctx->shutdown) {
    @@ -212,8 +212,8 @@ void POOL_add(void* ctxVoid, POOL_function function, void *opaque) {
                 ctx->queueTail = (ctx->queueTail + 1) % ctx->queueSize;
             }
         }
    -    pthread_mutex_unlock(&ctx->queueMutex);
    -    pthread_cond_signal(&ctx->queuePopCond);
    +    ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
    +    ZSTD_pthread_cond_signal(&ctx->queuePopCond);
     }
     
     #else  /* ZSTD_MULTITHREAD  not defined */
    diff --git a/lib/common/threading.c b/lib/common/threading.c
    index a82c975b..8be8c8da 100644
    --- a/lib/common/threading.c
    +++ b/lib/common/threading.c
    @@ -35,12 +35,12 @@ int g_ZSTD_threading_useles_symbol;
     
     static unsigned __stdcall worker(void *arg)
     {
    -    pthread_t* const thread = (pthread_t*) arg;
    +    ZSTD_pthread_t* const thread = (ZSTD_pthread_t*) arg;
         thread->arg = thread->start_routine(thread->arg);
         return 0;
     }
     
    -int pthread_create(pthread_t* thread, const void* unused,
    +int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused,
                 void* (*start_routine) (void*), void* arg)
     {
         (void)unused;
    @@ -54,16 +54,16 @@ int pthread_create(pthread_t* thread, const void* unused,
             return 0;
     }
     
    -int _pthread_join(pthread_t * thread, void **value_ptr)
    +int ZSTD_pthread_join(ZSTD_pthread_t thread, void **value_ptr)
     {
         DWORD result;
     
    -    if (!thread->handle) return 0;
    +    if (!thread.handle) return 0;
     
    -    result = WaitForSingleObject(thread->handle, INFINITE);
    +    result = WaitForSingleObject(thread.handle, INFINITE);
         switch (result) {
         case WAIT_OBJECT_0:
    -        if (value_ptr) *value_ptr = thread->arg;
    +        if (value_ptr) *value_ptr = thread.arg;
             return 0;
         case WAIT_ABANDONED:
             return EINVAL;
    diff --git a/lib/common/threading.h b/lib/common/threading.h
    index 8194bc6f..197770db 100644
    --- a/lib/common/threading.h
    +++ b/lib/common/threading.h
    @@ -44,32 +44,31 @@ extern "C" {
     
     
     /* mutex */
    -#define pthread_mutex_t           CRITICAL_SECTION
    -#define pthread_mutex_init(a,b)   (InitializeCriticalSection((a)), 0)
    -#define pthread_mutex_destroy(a)  DeleteCriticalSection((a))
    -#define pthread_mutex_lock(a)     EnterCriticalSection((a))
    -#define pthread_mutex_unlock(a)   LeaveCriticalSection((a))
    +#define ZSTD_pthread_mutex_t           CRITICAL_SECTION
    +#define ZSTD_pthread_mutex_init(a, b)  (InitializeCriticalSection((a)), 0)
    +#define ZSTD_pthread_mutex_destroy(a)  DeleteCriticalSection((a))
    +#define ZSTD_pthread_mutex_lock(a)     EnterCriticalSection((a))
    +#define ZSTD_pthread_mutex_unlock(a)   LeaveCriticalSection((a))
     
     /* condition variable */
    -#define pthread_cond_t             CONDITION_VARIABLE
    -#define pthread_cond_init(a, b)    (InitializeConditionVariable((a)), 0)
    -#define pthread_cond_destroy(a)    /* No delete */
    -#define pthread_cond_wait(a, b)    SleepConditionVariableCS((a), (b), INFINITE)
    -#define pthread_cond_signal(a)     WakeConditionVariable((a))
    -#define pthread_cond_broadcast(a)  WakeAllConditionVariable((a))
    +#define ZSTD_pthread_cond_t             CONDITION_VARIABLE
    +#define ZSTD_pthread_cond_init(a, b)    (InitializeConditionVariable((a)), 0)
    +#define ZSTD_pthread_cond_destroy(a)    /* No delete */
    +#define ZSTD_pthread_cond_wait(a, b)    SleepConditionVariableCS((a), (b), INFINITE)
    +#define ZSTD_pthread_cond_signal(a)     WakeConditionVariable((a))
    +#define ZSTD_pthread_cond_broadcast(a)  WakeAllConditionVariable((a))
     
    -/* pthread_create() and pthread_join() */
    +/* ZSTD_pthread_create() and ZSTD_pthread_join() */
     typedef struct {
         HANDLE handle;
         void* (*start_routine)(void*);
         void* arg;
    -} pthread_t;
    +} ZSTD_pthread_t;
     
    -int pthread_create(pthread_t* thread, const void* unused,
    +int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused,
                        void* (*start_routine) (void*), void* arg);
     
    -#define pthread_join(a, b) _pthread_join(&(a), (b))
    -int _pthread_join(pthread_t* thread, void** value_ptr);
    +int ZSTD_pthread_join(ZSTD_pthread_t thread, void** value_ptr);
     
     /**
      * add here more wrappers as required
    @@ -80,23 +79,40 @@ int _pthread_join(pthread_t* thread, void** value_ptr);
     /* ===   POSIX Systems   === */
     #  include 
     
    +#define ZSTD_pthread_mutex_t            pthread_mutex_t
    +#define ZSTD_pthread_mutex_init(a, b)   pthread_mutex_init((a), (b))
    +#define ZSTD_pthread_mutex_destroy(a)   pthread_mutex_destroy((a))
    +#define ZSTD_pthread_mutex_lock(a)      pthread_mutex_lock((a))
    +#define ZSTD_pthread_mutex_unlock(a)    pthread_mutex_unlock((a))
    +
    +#define ZSTD_pthread_cond_t             pthread_cond_t
    +#define ZSTD_pthread_cond_init(a, b)    pthread_cond_init((a), (b))
    +#define ZSTD_pthread_cond_destroy(a)    pthread_cond_destroy((a))
    +#define ZSTD_pthread_cond_wait(a, b)    pthread_cond_wait((a), (b))
    +#define ZSTD_pthread_cond_signal(a)     pthread_cond_signal((a))
    +#define ZSTD_pthread_cond_broadcast(a)  pthread_cond_broadcast((a))
    +
    +#define ZSTD_pthread_t                  pthread_t
    +#define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d))
    +#define ZSTD_pthread_join(a, b)         pthread_join((a),(b))
    +
     #else  /* ZSTD_MULTITHREAD not defined */
     /* No multithreading support */
     
    -#define pthread_mutex_t int   /* #define rather than typedef, because sometimes pthread support is implicit, resulting in duplicated symbols */
    -#define pthread_mutex_init(a,b)    ((void)a, 0)
    -#define pthread_mutex_destroy(a)
    -#define pthread_mutex_lock(a)
    -#define pthread_mutex_unlock(a)
    +typedef int ZSTD_pthread_mutex_t;
    +#define ZSTD_pthread_mutex_init(a, b)   ((void)a, 0)
    +#define ZSTD_pthread_mutex_destroy(a)
    +#define ZSTD_pthread_mutex_lock(a)
    +#define ZSTD_pthread_mutex_unlock(a)
     
    -#define pthread_cond_t int
    -#define pthread_cond_init(a,b)     ((void)a, 0)
    -#define pthread_cond_destroy(a)
    -#define pthread_cond_wait(a,b)
    -#define pthread_cond_signal(a)
    -#define pthread_cond_broadcast(a)
    +typedef int ZSTD_pthread_cond_t;
    +#define ZSTD_pthread_cond_init(a, b)    ((void)a, 0)
    +#define ZSTD_pthread_cond_destroy(a)
    +#define ZSTD_pthread_cond_wait(a, b)
    +#define ZSTD_pthread_cond_signal(a)
    +#define ZSTD_pthread_cond_broadcast(a)
     
    -/* do not use pthread_t */
    +/* do not use ZSTD_pthread_t */
     
     #endif /* ZSTD_MULTITHREAD */
     
    diff --git a/lib/common/zstd_errors.h b/lib/common/zstd_errors.h
    index bde4304c..4bcb7769 100644
    --- a/lib/common/zstd_errors.h
    +++ b/lib/common/zstd_errors.h
    @@ -63,9 +63,10 @@ typedef enum {
       ZSTD_error_memory_allocation = 64,
       ZSTD_error_dstSize_tooSmall = 70,
       ZSTD_error_srcSize_wrong    = 72,
    +  /* following error codes are not stable and may be removed or changed in a future version */
       ZSTD_error_frameIndex_tooLarge = 100,
       ZSTD_error_seekableIO          = 102,
    -  ZSTD_error_maxCode = 120  /* never EVER use this value directly, it may change in future versions! Use ZSTD_isError() instead */
    +  ZSTD_error_maxCode = 120  /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */
     } ZSTD_ErrorCode;
     
     /*! ZSTD_getErrorCode() :
    diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h
    index 1defee67..e91cd20b 100644
    --- a/lib/common/zstd_internal.h
    +++ b/lib/common/zstd_internal.h
    @@ -106,6 +106,9 @@ static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 };
     static const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 };
     static const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 };
     
    +#define ZSTD_FRAMEIDSIZE 4
    +static const size_t ZSTD_frameIdSize = ZSTD_FRAMEIDSIZE;  /* magic number size */
    +
     #define ZSTD_BLOCKHEADERSIZE 3   /* C standard doesn't allow `static const` variable to be init using another `static const` variable */
     static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE;
     typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e;
    @@ -284,6 +287,7 @@ typedef struct {
     } ZSTD_entropyCTables_t;
     
     struct ZSTD_CCtx_params_s {
    +    ZSTD_format_e format;
         ZSTD_compressionParameters cParams;
         ZSTD_frameParameters fParams;
     
    diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c
    index 117a1f58..7e2dbffd 100644
    --- a/lib/compress/zstd_compress.c
    +++ b/lib/compress/zstd_compress.c
    @@ -256,6 +256,9 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v
     
         switch(param)
         {
    +    case ZSTD_p_format :
    +        return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
    +
         case ZSTD_p_compressionLevel:
             if (value == 0) return 0;  /* special value : 0 means "don't change anything" */
             if (cctx->cdict) return ERROR(stage_wrong);
    @@ -326,6 +329,12 @@ size_t ZSTD_CCtxParam_setParameter(
     {
         switch(param)
         {
    +    case ZSTD_p_format :
    +        if (value > (unsigned)ZSTD_f_zstd1_magicless)
    +            return ERROR(parameter_unsupported);
    +        params->format = (ZSTD_format_e)value;
    +        return 0;
    +
         case ZSTD_p_compressionLevel :
             if ((int)value > ZSTD_maxCLevel()) value = ZSTD_maxCLevel();
             if (value == 0) return 0;
    @@ -669,7 +678,7 @@ ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, u
         return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize);
     }
     
    -size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params)
    +size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
     {
         /* Estimate CCtx size is supported for single-threaded compression only. */
         if (params->nbThreads > 1) { return ERROR(GENERIC); }
    @@ -706,22 +715,22 @@ size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* pa
         }
     }
     
    -size_t ZSTD_estimateCCtxSize_advanced_usingCParams(ZSTD_compressionParameters cParams)
    +size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
     {
         ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
    -    return ZSTD_estimateCCtxSize_advanced_usingCCtxParams(¶ms);
    +    return ZSTD_estimateCCtxSize_usingCCtxParams(¶ms);
     }
     
     size_t ZSTD_estimateCCtxSize(int compressionLevel)
     {
         ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
    -    return ZSTD_estimateCCtxSize_advanced_usingCParams(cParams);
    +    return ZSTD_estimateCCtxSize_usingCParams(cParams);
     }
     
    -size_t ZSTD_estimateCStreamSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params)
    +size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
     {
         if (params->nbThreads > 1) { return ERROR(GENERIC); }
    -    {   size_t const CCtxSize = ZSTD_estimateCCtxSize_advanced_usingCCtxParams(params);
    +    {   size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
             size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params->cParams.windowLog);
             size_t const inBuffSize = ((size_t)1 << params->cParams.windowLog) + blockSize;
             size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
    @@ -731,15 +740,15 @@ size_t ZSTD_estimateCStreamSize_advanced_usingCCtxParams(const ZSTD_CCtx_params*
         }
     }
     
    -size_t ZSTD_estimateCStreamSize_advanced_usingCParams(ZSTD_compressionParameters cParams)
    +size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
     {
         ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
    -    return ZSTD_estimateCStreamSize_advanced_usingCCtxParams(¶ms);
    +    return ZSTD_estimateCStreamSize_usingCCtxParams(¶ms);
     }
     
     size_t ZSTD_estimateCStreamSize(int compressionLevel) {
         ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
    -    return ZSTD_estimateCStreamSize_advanced_usingCParams(cParams);
    +    return ZSTD_estimateCStreamSize_usingCParams(cParams);
     }
     
     static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1,
    @@ -1699,14 +1708,18 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
         U32   const fcsCode = params.fParams.contentSizeFlag ?
                          (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0;  /* 0-3 */
         BYTE  const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
    -    size_t pos;
    +    size_t pos=0;
     
         if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
    -    DEBUGLOG(5, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
    +    DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
                     !params.fParams.noDictIDFlag, dictID,  dictIDSizeCode);
     
    -    MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
    -    op[4] = frameHeaderDecriptionByte; pos=5;
    +    if (params.format == ZSTD_f_zstd1) {
    +        DEBUGLOG(4, "writing zstd magic number");
    +        MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
    +        pos = 4;
    +    }
    +    op[pos++] = frameHeaderDecriptionByte;
         if (!singleSegment) op[pos++] = windowLogByte;
         switch(dictIDSizeCode)
         {
    @@ -2191,8 +2204,8 @@ size_t ZSTD_estimateCDictSize_advanced(
     {
         DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict));
         DEBUGLOG(5, "CCtx estimate : %u",
    -             (U32)ZSTD_estimateCCtxSize_advanced_usingCParams(cParams));
    -    return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_advanced_usingCParams(cParams)
    +             (U32)ZSTD_estimateCCtxSize_usingCParams(cParams));
    +    return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_usingCParams(cParams)
                + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
     }
     
    @@ -2317,7 +2330,7 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
                                      ZSTD_dictMode_e dictMode,
                                      ZSTD_compressionParameters cParams)
     {
    -    size_t const cctxSize = ZSTD_estimateCCtxSize_advanced_usingCParams(cParams);
    +    size_t const cctxSize = ZSTD_estimateCCtxSize_usingCParams(cParams);
         size_t const neededSize = sizeof(ZSTD_CDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize)
                                 + cctxSize;
         ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace;
    @@ -2579,6 +2592,7 @@ MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity,
     
     /** ZSTD_compressStream_generic():
      *  internal function for all *compressStream*() variants and *compress_generic()
    + *  non-static, because can be called from zstdmt.c
      * @return : hint size for next input */
     size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
                                        ZSTD_outBuffer* output,
    diff --git a/lib/compress/zstd_opt.c b/lib/compress/zstd_opt.c
    index fd102da2..c47ce23a 100644
    --- a/lib/compress/zstd_opt.c
    +++ b/lib/compress/zstd_opt.c
    @@ -529,7 +529,14 @@ size_t ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
                } else {
                     opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2];
                     opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1];
    -                opt[cur].rep[0] = ((opt[cur].off==ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]);
    +                /* If opt[cur].off == ZSTD_REP_MOVE_OPT, then mlen != 1.
    +                 * offset ZSTD_REP_MOVE_OPT is used for the special case
    +                 * litLength == 0, where offset 0 means something special.
    +                 * mlen == 1 means the previous byte was stored as a literal,
    +                 * so they are mutually exclusive.
    +                 */
    +                assert(!(opt[cur].off == ZSTD_REP_MOVE_OPT && mlen == 1));
    +                opt[cur].rep[0] = (opt[cur].off == ZSTD_REP_MOVE_OPT) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]);
                }
     
                 best_mlen = minMatch;
    @@ -804,7 +811,8 @@ size_t ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx,
                 } else {
                     opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2];
                     opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1];
    -                opt[cur].rep[0] = ((opt[cur].off==ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]);
    +                assert(!(opt[cur].off == ZSTD_REP_MOVE_OPT && mlen == 1));
    +                opt[cur].rep[0] = (opt[cur].off == ZSTD_REP_MOVE_OPT) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]);
                 }
     
                 best_mlen = minMatch;
    diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c
    index d83abaf3..bc7d1e54 100644
    --- a/lib/compress/zstdmt_compress.c
    +++ b/lib/compress/zstdmt_compress.c
    @@ -53,22 +53,24 @@ static unsigned long long GetCurrentClockTimeMicroseconds(void)
     }
     
     #define MUTEX_WAIT_TIME_DLEVEL 6
    -#define PTHREAD_MUTEX_LOCK(mutex) {               \
    -    if (ZSTD_DEBUG>=MUTEX_WAIT_TIME_DLEVEL) {   \
    +#define ZSTD_PTHREAD_MUTEX_LOCK(mutex) {          \
    +    if (ZSTD_DEBUG >= MUTEX_WAIT_TIME_DLEVEL) {   \
             unsigned long long const beforeTime = GetCurrentClockTimeMicroseconds(); \
    -        pthread_mutex_lock(mutex);                \
    +        ZSTD_pthread_mutex_lock(mutex);           \
             {   unsigned long long const afterTime = GetCurrentClockTimeMicroseconds(); \
                 unsigned long long const elapsedTime = (afterTime-beforeTime); \
                 if (elapsedTime > 1000) {  /* or whatever threshold you like; I'm using 1 millisecond here */ \
                     DEBUGLOG(MUTEX_WAIT_TIME_DLEVEL, "Thread took %llu microseconds to acquire mutex %s \n", \
                        elapsedTime, #mutex);          \
             }   }                                     \
    -    } else pthread_mutex_lock(mutex);             \
    +    } else {                                      \
    +        ZSTD_pthread_mutex_lock(mutex);           \
    +    }                                             \
     }
     
     #else
     
    -#  define PTHREAD_MUTEX_LOCK(m) pthread_mutex_lock(m)
    +#  define ZSTD_PTHREAD_MUTEX_LOCK(m) ZSTD_pthread_mutex_lock(m)
     #  define DEBUG_PRINTHEX(l,p,n) {}
     
     #endif
    @@ -85,7 +87,7 @@ typedef struct buffer_s {
     static const buffer_t g_nullBuffer = { NULL, 0 };
     
     typedef struct ZSTDMT_bufferPool_s {
    -    pthread_mutex_t poolMutex;
    +    ZSTD_pthread_mutex_t poolMutex;
         size_t bufferSize;
         unsigned totalBuffers;
         unsigned nbBuffers;
    @@ -99,7 +101,7 @@ static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned nbThreads, ZSTD_custo
         ZSTDMT_bufferPool* const bufPool = (ZSTDMT_bufferPool*)ZSTD_calloc(
             sizeof(ZSTDMT_bufferPool) + (maxNbBuffers-1) * sizeof(buffer_t), cMem);
         if (bufPool==NULL) return NULL;
    -    if (pthread_mutex_init(&bufPool->poolMutex, NULL)) {
    +    if (ZSTD_pthread_mutex_init(&bufPool->poolMutex, NULL)) {
             ZSTD_free(bufPool, cMem);
             return NULL;
         }
    @@ -116,7 +118,7 @@ static void ZSTDMT_freeBufferPool(ZSTDMT_bufferPool* bufPool)
         if (!bufPool) return;   /* compatibility with free on NULL */
         for (u=0; utotalBuffers; u++)
             ZSTD_free(bufPool->bTable[u].start, bufPool->cMem);
    -    pthread_mutex_destroy(&bufPool->poolMutex);
    +    ZSTD_pthread_mutex_destroy(&bufPool->poolMutex);
         ZSTD_free(bufPool, bufPool->cMem);
     }
     
    @@ -127,10 +129,10 @@ static size_t ZSTDMT_sizeof_bufferPool(ZSTDMT_bufferPool* bufPool)
                                 + (bufPool->totalBuffers - 1) * sizeof(buffer_t);
         unsigned u;
         size_t totalBufferSize = 0;
    -    pthread_mutex_lock(&bufPool->poolMutex);
    +    ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
         for (u=0; utotalBuffers; u++)
             totalBufferSize += bufPool->bTable[u].size;
    -    pthread_mutex_unlock(&bufPool->poolMutex);
    +    ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
     
         return poolSize + totalBufferSize;
     }
    @@ -146,20 +148,20 @@ static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* bufPool)
     {
         size_t const bSize = bufPool->bufferSize;
         DEBUGLOG(5, "ZSTDMT_getBuffer");
    -    pthread_mutex_lock(&bufPool->poolMutex);
    +    ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
         if (bufPool->nbBuffers) {   /* try to use an existing buffer */
             buffer_t const buf = bufPool->bTable[--(bufPool->nbBuffers)];
             size_t const availBufferSize = buf.size;
             if ((availBufferSize >= bSize) & (availBufferSize <= 10*bSize)) {
                 /* large enough, but not too much */
    -            pthread_mutex_unlock(&bufPool->poolMutex);
    +            ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
                 return buf;
             }
             /* size conditions not respected : scratch this buffer, create new one */
             DEBUGLOG(5, "existing buffer does not meet size conditions => freeing");
             ZSTD_free(buf.start, bufPool->cMem);
         }
    -    pthread_mutex_unlock(&bufPool->poolMutex);
    +    ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
         /* create new buffer */
         DEBUGLOG(5, "create a new buffer");
         {   buffer_t buffer;
    @@ -175,13 +177,13 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf)
     {
         if (buf.start == NULL) return;   /* compatible with release on NULL */
         DEBUGLOG(5, "ZSTDMT_releaseBuffer");
    -    pthread_mutex_lock(&bufPool->poolMutex);
    +    ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
         if (bufPool->nbBuffers < bufPool->totalBuffers) {
             bufPool->bTable[bufPool->nbBuffers++] = buf;  /* stored for later use */
    -        pthread_mutex_unlock(&bufPool->poolMutex);
    +        ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
             return;
         }
    -    pthread_mutex_unlock(&bufPool->poolMutex);
    +    ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
         /* Reached bufferPool capacity (should not happen) */
         DEBUGLOG(5, "buffer pool capacity reached => freeing ");
         ZSTD_free(buf.start, bufPool->cMem);
    @@ -206,7 +208,7 @@ static ZSTD_CCtx_params ZSTDMT_makeJobCCtxParams(ZSTD_CCtx_params const params)
     /* a single CCtx Pool can be invoked from multiple threads in parallel */
     
     typedef struct {
    -    pthread_mutex_t poolMutex;
    +    ZSTD_pthread_mutex_t poolMutex;
         unsigned totalCCtx;
         unsigned availCCtx;
         ZSTD_customMem cMem;
    @@ -219,7 +221,7 @@ static void ZSTDMT_freeCCtxPool(ZSTDMT_CCtxPool* pool)
         unsigned u;
         for (u=0; utotalCCtx; u++)
             ZSTD_freeCCtx(pool->cctx[u]);  /* note : compatible with free on NULL */
    -    pthread_mutex_destroy(&pool->poolMutex);
    +    ZSTD_pthread_mutex_destroy(&pool->poolMutex);
         ZSTD_free(pool, pool->cMem);
     }
     
    @@ -231,7 +233,7 @@ static ZSTDMT_CCtxPool* ZSTDMT_createCCtxPool(unsigned nbThreads,
         ZSTDMT_CCtxPool* const cctxPool = (ZSTDMT_CCtxPool*) ZSTD_calloc(
             sizeof(ZSTDMT_CCtxPool) + (nbThreads-1)*sizeof(ZSTD_CCtx*), cMem);
         if (!cctxPool) return NULL;
    -    if (pthread_mutex_init(&cctxPool->poolMutex, NULL)) {
    +    if (ZSTD_pthread_mutex_init(&cctxPool->poolMutex, NULL)) {
             ZSTD_free(cctxPool, cMem);
             return NULL;
         }
    @@ -247,7 +249,7 @@ static ZSTDMT_CCtxPool* ZSTDMT_createCCtxPool(unsigned nbThreads,
     /* only works during initialization phase, not during compression */
     static size_t ZSTDMT_sizeof_CCtxPool(ZSTDMT_CCtxPool* cctxPool)
     {
    -    pthread_mutex_lock(&cctxPool->poolMutex);
    +    ZSTD_pthread_mutex_lock(&cctxPool->poolMutex);
         {   unsigned const nbThreads = cctxPool->totalCCtx;
             size_t const poolSize = sizeof(*cctxPool)
                                     + (nbThreads-1)*sizeof(ZSTD_CCtx*);
    @@ -256,7 +258,7 @@ static size_t ZSTDMT_sizeof_CCtxPool(ZSTDMT_CCtxPool* cctxPool)
             for (u=0; ucctx[u]);
             }
    -        pthread_mutex_unlock(&cctxPool->poolMutex);
    +        ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex);
             return poolSize + totalCCtxSize;
         }
     }
    @@ -264,14 +266,14 @@ static size_t ZSTDMT_sizeof_CCtxPool(ZSTDMT_CCtxPool* cctxPool)
     static ZSTD_CCtx* ZSTDMT_getCCtx(ZSTDMT_CCtxPool* cctxPool)
     {
         DEBUGLOG(5, "ZSTDMT_getCCtx");
    -    pthread_mutex_lock(&cctxPool->poolMutex);
    +    ZSTD_pthread_mutex_lock(&cctxPool->poolMutex);
         if (cctxPool->availCCtx) {
             cctxPool->availCCtx--;
             {   ZSTD_CCtx* const cctx = cctxPool->cctx[cctxPool->availCCtx];
    -            pthread_mutex_unlock(&cctxPool->poolMutex);
    +            ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex);
                 return cctx;
         }   }
    -    pthread_mutex_unlock(&cctxPool->poolMutex);
    +    ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex);
         DEBUGLOG(5, "create one more CCtx");
         return ZSTD_createCCtx_advanced(cctxPool->cMem);   /* note : can be NULL, when creation fails ! */
     }
    @@ -279,7 +281,7 @@ static ZSTD_CCtx* ZSTDMT_getCCtx(ZSTDMT_CCtxPool* cctxPool)
     static void ZSTDMT_releaseCCtx(ZSTDMT_CCtxPool* pool, ZSTD_CCtx* cctx)
     {
         if (cctx==NULL) return;   /* compatibility with release on NULL */
    -    pthread_mutex_lock(&pool->poolMutex);
    +    ZSTD_pthread_mutex_lock(&pool->poolMutex);
         if (pool->availCCtx < pool->totalCCtx)
             pool->cctx[pool->availCCtx++] = cctx;
         else {
    @@ -287,7 +289,7 @@ static void ZSTDMT_releaseCCtx(ZSTDMT_CCtxPool* pool, ZSTD_CCtx* cctx)
             DEBUGLOG(5, "CCtx pool overflow : free cctx");
             ZSTD_freeCCtx(cctx);
         }
    -    pthread_mutex_unlock(&pool->poolMutex);
    +    ZSTD_pthread_mutex_unlock(&pool->poolMutex);
     }
     
     
    @@ -305,8 +307,8 @@ typedef struct {
         unsigned lastChunk;
         unsigned jobCompleted;
         unsigned jobScanned;
    -    pthread_mutex_t* jobCompleted_mutex;
    -    pthread_cond_t* jobCompleted_cond;
    +    ZSTD_pthread_mutex_t* jobCompleted_mutex;
    +    ZSTD_pthread_cond_t* jobCompleted_cond;
         ZSTD_CCtx_params params;
         const ZSTD_CDict* cdict;
         ZSTDMT_CCtxPool* cctxPool;
    @@ -373,11 +375,11 @@ _endJob:
         ZSTDMT_releaseCCtx(job->cctxPool, cctx);
         ZSTDMT_releaseBuffer(job->bufPool, job->src);
         job->src = g_nullBuffer; job->srcStart = NULL;
    -    PTHREAD_MUTEX_LOCK(job->jobCompleted_mutex);
    +    ZSTD_PTHREAD_MUTEX_LOCK(job->jobCompleted_mutex);
         job->jobCompleted = 1;
         job->jobScanned = 0;
    -    pthread_cond_signal(job->jobCompleted_cond);
    -    pthread_mutex_unlock(job->jobCompleted_mutex);
    +    ZSTD_pthread_cond_signal(job->jobCompleted_cond);
    +    ZSTD_pthread_mutex_unlock(job->jobCompleted_mutex);
     }
     
     
    @@ -395,8 +397,8 @@ struct ZSTDMT_CCtx_s {
         ZSTDMT_jobDescription* jobs;
         ZSTDMT_bufferPool* bufPool;
         ZSTDMT_CCtxPool* cctxPool;
    -    pthread_mutex_t jobCompleted_mutex;
    -    pthread_cond_t jobCompleted_cond;
    +    ZSTD_pthread_mutex_t jobCompleted_mutex;
    +    ZSTD_pthread_cond_t jobCompleted_cond;
         size_t targetSectionSize;
         size_t inBuffSize;
         size_t dictSize;
    @@ -459,11 +461,11 @@ ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads, ZSTD_customMem cMem)
             ZSTDMT_freeCCtx(mtctx);
             return NULL;
         }
    -    if (pthread_mutex_init(&mtctx->jobCompleted_mutex, NULL)) {
    +    if (ZSTD_pthread_mutex_init(&mtctx->jobCompleted_mutex, NULL)) {
             ZSTDMT_freeCCtx(mtctx);
             return NULL;
         }
    -    if (pthread_cond_init(&mtctx->jobCompleted_cond, NULL)) {
    +    if (ZSTD_pthread_cond_init(&mtctx->jobCompleted_cond, NULL)) {
             ZSTDMT_freeCCtx(mtctx);
             return NULL;
         }
    @@ -499,12 +501,12 @@ static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* zcs)
         DEBUGLOG(4, "ZSTDMT_waitForAllJobsCompleted");
         while (zcs->doneJobID < zcs->nextJobID) {
             unsigned const jobID = zcs->doneJobID & zcs->jobIDMask;
    -        PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex);
    +        ZSTD_PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex);
             while (zcs->jobs[jobID].jobCompleted==0) {
                 DEBUGLOG(5, "waiting for jobCompleted signal from chunk %u", zcs->doneJobID);   /* we want to block when waiting for data to flush */
    -            pthread_cond_wait(&zcs->jobCompleted_cond, &zcs->jobCompleted_mutex);
    +            ZSTD_pthread_cond_wait(&zcs->jobCompleted_cond, &zcs->jobCompleted_mutex);
             }
    -        pthread_mutex_unlock(&zcs->jobCompleted_mutex);
    +        ZSTD_pthread_mutex_unlock(&zcs->jobCompleted_mutex);
             zcs->doneJobID++;
         }
     }
    @@ -521,8 +523,8 @@ size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx)
         ZSTD_free(mtctx->jobs, mtctx->cMem);
         ZSTDMT_freeCCtxPool(mtctx->cctxPool);
         ZSTD_freeCDict(mtctx->cdictLocal);
    -    pthread_mutex_destroy(&mtctx->jobCompleted_mutex);
    -    pthread_cond_destroy(&mtctx->jobCompleted_cond);
    +    ZSTD_pthread_mutex_destroy(&mtctx->jobCompleted_mutex);
    +    ZSTD_pthread_cond_destroy(&mtctx->jobCompleted_cond);
         ZSTD_free(mtctx, mtctx->cMem);
         return 0;
     }
    @@ -667,12 +669,12 @@ static size_t ZSTDMT_compress_advanced_internal(
             unsigned chunkID;
             for (chunkID=0; chunkIDjobCompleted_mutex);
    +            ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobCompleted_mutex);
                 while (mtctx->jobs[chunkID].jobCompleted==0) {
                     DEBUGLOG(5, "waiting for jobCompleted signal from chunk %u", chunkID);
    -                pthread_cond_wait(&mtctx->jobCompleted_cond, &mtctx->jobCompleted_mutex);
    +                ZSTD_pthread_cond_wait(&mtctx->jobCompleted_cond, &mtctx->jobCompleted_mutex);
                 }
    -            pthread_mutex_unlock(&mtctx->jobCompleted_mutex);
    +            ZSTD_pthread_mutex_unlock(&mtctx->jobCompleted_mutex);
                 DEBUGLOG(5, "ready to write chunk %u ", chunkID);
     
                 mtctx->jobs[chunkID].srcStart = NULL;
    @@ -926,13 +928,13 @@ static size_t ZSTDMT_flushNextJob(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, unsi
     {
         unsigned const wJobID = zcs->doneJobID & zcs->jobIDMask;
         if (zcs->doneJobID == zcs->nextJobID) return 0;   /* all flushed ! */
    -    PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex);
    +    ZSTD_PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex);
         while (zcs->jobs[wJobID].jobCompleted==0) {
             DEBUGLOG(5, "waiting for jobCompleted signal from job %u", zcs->doneJobID);
    -        if (!blockToFlush) { pthread_mutex_unlock(&zcs->jobCompleted_mutex); return 0; }  /* nothing ready to be flushed => skip */
    -        pthread_cond_wait(&zcs->jobCompleted_cond, &zcs->jobCompleted_mutex);  /* block when nothing available to flush */
    +        if (!blockToFlush) { ZSTD_pthread_mutex_unlock(&zcs->jobCompleted_mutex); return 0; }  /* nothing ready to be flushed => skip */
    +        ZSTD_pthread_cond_wait(&zcs->jobCompleted_cond, &zcs->jobCompleted_mutex);  /* block when nothing available to flush */
         }
    -    pthread_mutex_unlock(&zcs->jobCompleted_mutex);
    +    ZSTD_pthread_mutex_unlock(&zcs->jobCompleted_mutex);
         /* compression job completed : output can be flushed */
         {   ZSTDMT_jobDescription job = zcs->jobs[wJobID];
             if (!job.jobScanned) {
    diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c
    index ebfa93c3..0a709f9f 100644
    --- a/lib/decompress/zstd_decompress.c
    +++ b/lib/decompress/zstd_decompress.c
    @@ -110,6 +110,7 @@ struct ZSTD_DCtx_s
         XXH64_state_t xxhState;
         size_t headerSize;
         U32 dictID;
    +    ZSTD_format_e format;
         const BYTE* litPtr;
         ZSTD_customMem customMem;
         size_t litSize;
    @@ -149,30 +150,21 @@ size_t ZSTD_sizeof_DCtx (const ZSTD_DCtx* dctx)
     
     size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); }
     
    -size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
    +
    +static size_t ZSTD_startingInputLength(ZSTD_format_e format)
     {
    -    dctx->expected = ZSTD_frameHeaderSize_prefix;
    -    dctx->stage = ZSTDds_getFrameHeaderSize;
    -    dctx->decodedSize = 0;
    -    dctx->previousDstEnd = NULL;
    -    dctx->base = NULL;
    -    dctx->vBase = NULL;
    -    dctx->dictEnd = NULL;
    -    dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001);  /* cover both little and big endian */
    -    dctx->litEntropy = dctx->fseEntropy = 0;
    -    dctx->dictID = 0;
    -    MEM_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));
    -    memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue));  /* initial repcodes */
    -    dctx->LLTptr = dctx->entropy.LLTable;
    -    dctx->MLTptr = dctx->entropy.MLTable;
    -    dctx->OFTptr = dctx->entropy.OFTable;
    -    dctx->HUFptr = dctx->entropy.hufTable;
    -    return 0;
    +    size_t const startingInputLength = (format==ZSTD_f_zstd1_magicless) ?
    +                    ZSTD_frameHeaderSize_prefix - ZSTD_frameIdSize :
    +                    ZSTD_frameHeaderSize_prefix;
    +    ZSTD_STATIC_ASSERT(ZSTD_FRAMEHEADERSIZE_PREFIX >= ZSTD_FRAMEIDSIZE);
    +    /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */
    +    assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) );
    +    return startingInputLength;
     }
     
     static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
     {
    -    ZSTD_decompressBegin(dctx);   /* cannot fail */
    +    dctx->format = ZSTD_f_zstd1;  /* ZSTD_decompressBegin() invokes ZSTD_startingInputLength() with argument dctx->format */
         dctx->staticSize  = 0;
         dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
         dctx->ddict       = NULL;
    @@ -183,6 +175,19 @@ static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
         dctx->streamStage = zdss_init;
     }
     
    +ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize)
    +{
    +    ZSTD_DCtx* const dctx = (ZSTD_DCtx*) workspace;
    +
    +    if ((size_t)workspace & 7) return NULL;  /* 8-aligned */
    +    if (workspaceSize < sizeof(ZSTD_DCtx)) return NULL;  /* minimum size */
    +
    +    ZSTD_initDCtx_internal(dctx);
    +    dctx->staticSize = workspaceSize;
    +    dctx->inBuff = (char*)(dctx+1);
    +    return dctx;
    +}
    +
     ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
     {
         if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
    @@ -197,19 +202,6 @@ ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
         }
     }
     
    -ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize)
    -{
    -    ZSTD_DCtx* dctx = (ZSTD_DCtx*) workspace;
    -
    -    if ((size_t)workspace & 7) return NULL;  /* 8-aligned */
    -    if (workspaceSize < sizeof(ZSTD_DCtx)) return NULL;  /* minimum size */
    -
    -    ZSTD_initDCtx_internal(dctx);
    -    dctx->staticSize = workspaceSize;
    -    dctx->inBuff = (char*)(dctx+1);
    -    return dctx;
    -}
    -
     ZSTD_DCtx* ZSTD_createDCtx(void)
     {
         return ZSTD_createDCtx_advanced(ZSTD_defaultCMem);
    @@ -252,7 +244,7 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
      *  Note 3 : Skippable Frame Identifiers are considered valid. */
     unsigned ZSTD_isFrame(const void* buffer, size_t size)
     {
    -    if (size < 4) return 0;
    +    if (size < ZSTD_frameIdSize) return 0;
         {   U32 const magic = MEM_readLE32(buffer);
             if (magic == ZSTD_MAGICNUMBER) return 1;
             if ((magic & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) return 1;
    @@ -263,40 +255,56 @@ unsigned ZSTD_isFrame(const void* buffer, size_t size)
         return 0;
     }
     
    -
    -/** ZSTD_frameHeaderSize() :
    -*   srcSize must be >= ZSTD_frameHeaderSize_prefix.
    -*   @return : size of the Frame Header */
    -size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)
    +/** ZSTD_frameHeaderSize_internal() :
    + *  srcSize must be large enough to reach header size fields.
    + *  note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless
    + * @return : size of the Frame Header
    + *           or an error code, which can be tested with ZSTD_isError() */
    +static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format)
     {
    -    if (srcSize < ZSTD_frameHeaderSize_prefix) return ERROR(srcSize_wrong);
    -    {   BYTE const fhd = ((const BYTE*)src)[4];
    +    size_t const minInputSize = ZSTD_startingInputLength(format);
    +    if (srcSize < minInputSize) return ERROR(srcSize_wrong);
    +
    +    {   BYTE const fhd = ((const BYTE*)src)[minInputSize-1];
             U32 const dictID= fhd & 3;
             U32 const singleSegment = (fhd >> 5) & 1;
             U32 const fcsId = fhd >> 6;
    -        return ZSTD_frameHeaderSize_prefix + !singleSegment + ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId]
    -                + (singleSegment && !fcsId);
    +        return minInputSize + !singleSegment
    +             + ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId]
    +             + (singleSegment && !fcsId);
         }
     }
     
    +/** ZSTD_frameHeaderSize() :
    + *  srcSize must be >= ZSTD_frameHeaderSize_prefix.
    + * @return : size of the Frame Header */
    +size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)
    +{
    +    return ZSTD_frameHeaderSize_internal(src, srcSize, ZSTD_f_zstd1);
    +}
     
    -/** ZSTD_getFrameHeader() :
    -*   decode Frame Header, or require larger `srcSize`.
    -*   @return : 0, `zfhPtr` is correctly filled,
    -*            >0, `srcSize` is too small, result is expected `srcSize`,
    -*             or an error code, which can be tested using ZSTD_isError() */
    -size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize)
    +
    +/** ZSTD_getFrameHeader_internal() :
    + *  decode Frame Header, or require larger `srcSize`.
    + *  note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless
    + * @return : 0, `zfhPtr` is correctly filled,
    + *          >0, `srcSize` is too small, value is wanted `srcSize` amount,
    + *           or an error code, which can be tested using ZSTD_isError() */
    +static size_t ZSTD_getFrameHeader_internal(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format)
     {
         const BYTE* ip = (const BYTE*)src;
    -    if (srcSize < ZSTD_frameHeaderSize_prefix) return ZSTD_frameHeaderSize_prefix;
    +    size_t const minInputSize = ZSTD_startingInputLength(format);
     
    -    if (MEM_readLE32(src) != ZSTD_MAGICNUMBER) {
    +    if (srcSize < minInputSize) return minInputSize;
    +
    +    if ( (format != ZSTD_f_zstd1_magicless)
    +      && (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) {
             if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
                 /* skippable frame */
                 if (srcSize < ZSTD_skippableHeaderSize)
                     return ZSTD_skippableHeaderSize; /* magic number + frame length */
                 memset(zfhPtr, 0, sizeof(*zfhPtr));
    -            zfhPtr->frameContentSize = MEM_readLE32((const char *)src + 4);
    +            zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_frameIdSize);
                 zfhPtr->frameType = ZSTD_skippableFrame;
                 return 0;
             }
    @@ -304,13 +312,13 @@ size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t src
         }
     
         /* ensure there is enough `srcSize` to fully read/decode frame header */
    -    {   size_t const fhsize = ZSTD_frameHeaderSize(src, srcSize);
    +    {   size_t const fhsize = ZSTD_frameHeaderSize_internal(src, srcSize, format);
             if (srcSize < fhsize) return fhsize;
             zfhPtr->headerSize = (U32)fhsize;
         }
     
    -    {   BYTE const fhdByte = ip[4];
    -        size_t pos = 5;
    +    {   BYTE const fhdByte = ip[minInputSize-1];
    +        size_t pos = minInputSize;
             U32 const dictIDSizeCode = fhdByte&3;
             U32 const checksumFlag = (fhdByte>>2)&1;
             U32 const singleSegment = (fhdByte>>5)&1;
    @@ -357,6 +365,18 @@ size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t src
         return 0;
     }
     
    +/** ZSTD_getFrameHeader() :
    + *  decode Frame Header, or require larger `srcSize`.
    + *  note : this function does not consume input, it only reads it.
    + * @return : 0, `zfhPtr` is correctly filled,
    + *          >0, `srcSize` is too small, value is wanted `srcSize` amount,
    + *           or an error code, which can be tested using ZSTD_isError() */
    +size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize)
    +{
    +    return ZSTD_getFrameHeader_internal(zfhPtr, src, srcSize, ZSTD_f_zstd1);
    +}
    +
    +
     /** ZSTD_getFrameContentSize() :
      *  compatible with legacy mode
      * @return : decompressed size of the single frame pointed to be `src` if known, otherwise
    @@ -390,14 +410,14 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
         unsigned long long totalDstSize = 0;
     
         while (srcSize >= ZSTD_frameHeaderSize_prefix) {
    -        const U32 magicNumber = MEM_readLE32(src);
    +        U32 const magicNumber = MEM_readLE32(src);
     
             if ((magicNumber & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
                 size_t skippableSize;
                 if (srcSize < ZSTD_skippableHeaderSize)
                     return ERROR(srcSize_wrong);
    -            skippableSize = MEM_readLE32((const BYTE *)src + 4) +
    -                            ZSTD_skippableHeaderSize;
    +            skippableSize = MEM_readLE32((const BYTE *)src + ZSTD_frameIdSize)
    +                          + ZSTD_skippableHeaderSize;
                 if (srcSize < skippableSize) {
                     return ZSTD_CONTENTSIZE_ERROR;
                 }
    @@ -422,11 +442,9 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
                 src = (const BYTE *)src + frameSrcSize;
                 srcSize -= frameSrcSize;
             }
    -    }
    +    }  /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */
     
    -    if (srcSize) {
    -        return ZSTD_CONTENTSIZE_ERROR;
    -    }
    +    if (srcSize) return ZSTD_CONTENTSIZE_ERROR;
     
         return totalDstSize;
     }
    @@ -442,7 +460,8 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
     unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)
     {
         unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);
    -    return ret >= ZSTD_CONTENTSIZE_ERROR ? 0 : ret;
    +    ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_ERROR < ZSTD_CONTENTSIZE_UNKNOWN);
    +    return (ret >= ZSTD_CONTENTSIZE_ERROR) ? 0 : ret;
     }
     
     
    @@ -451,9 +470,9 @@ unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)
     *   @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */
     static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize)
     {
    -    size_t const result = ZSTD_getFrameHeader(&(dctx->fParams), src, headerSize);
    -    if (ZSTD_isError(result)) return result;  /* invalid header */
    -    if (result>0) return ERROR(srcSize_wrong);   /* headerSize too small */
    +    size_t const result = ZSTD_getFrameHeader_internal(&(dctx->fParams), src, headerSize, dctx->format);
    +    if (ZSTD_isError(result)) return result;    /* invalid header */
    +    if (result>0) return ERROR(srcSize_wrong);  /* headerSize too small */
         if (dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID))
             return ERROR(dictionary_wrong);
         if (dctx->fParams.checksumFlag) XXH64_reset(&dctx->xxhState, 0);
    @@ -499,7 +518,8 @@ static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity,
     }
     
     /*! ZSTD_decodeLiteralsBlock() :
    -    @return : nb of bytes read from src (< srcSize ) */
    + * @return : nb of bytes read from src (< srcSize )
    + *  note : symbol not declared but exposed for fullbench */
     size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
                               const void* src, size_t srcSize)   /* note : srcSize < BLOCKSIZE */
     {
    @@ -700,9 +720,9 @@ static const FSE_decode_t4 OF_defaultDTable[(1< dstCapacity) return ERROR(dstSize_tooSmall);
         memset(dst, byte, length);
    @@ -1465,7 +1485,7 @@ size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)
     #endif
         if ( (srcSize >= ZSTD_skippableHeaderSize)
           && (MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START ) {
    -        return ZSTD_skippableHeaderSize + MEM_readLE32((const BYTE*)src + 4);
    +        return ZSTD_skippableHeaderSize + MEM_readLE32((const BYTE*)src + ZSTD_frameIdSize);
         } else {
             const BYTE* ip = (const BYTE*)src;
             const BYTE* const ipstart = ip;
    @@ -1628,13 +1648,15 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
     #endif
     
             magicNumber = MEM_readLE32(src);
    +        DEBUGLOG(4, "reading magic number %08X (expecting %08X)",
    +                    (U32)magicNumber, (U32)ZSTD_MAGICNUMBER);
             if (magicNumber != ZSTD_MAGICNUMBER) {
                 if ((magicNumber & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
                     size_t skippableSize;
                     if (srcSize < ZSTD_skippableHeaderSize)
                         return ERROR(srcSize_wrong);
    -                skippableSize = MEM_readLE32((const BYTE *)src + 4) +
    -                                ZSTD_skippableHeaderSize;
    +                skippableSize = MEM_readLE32((const BYTE*)src + ZSTD_frameIdSize)
    +                              + ZSTD_skippableHeaderSize;
                     if (srcSize < skippableSize) return ERROR(srcSize_wrong);
     
                     src = (const BYTE *)src + skippableSize;
    @@ -1737,33 +1759,31 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
     {
         DEBUGLOG(5, "ZSTD_decompressContinue");
         /* Sanity check */
    -    if (srcSize != dctx->expected) return ERROR(srcSize_wrong);   /* unauthorized */
    +    if (srcSize != dctx->expected) return ERROR(srcSize_wrong);  /* not allowed */
         if (dstCapacity) ZSTD_checkContinuity(dctx, dst);
     
         switch (dctx->stage)
         {
         case ZSTDds_getFrameHeaderSize :
    -        if (srcSize != ZSTD_frameHeaderSize_prefix) return ERROR(srcSize_wrong);      /* unauthorized */
             assert(src != NULL);
    -        if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {        /* skippable frame */
    -            memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_prefix);
    -            dctx->expected = ZSTD_skippableHeaderSize - ZSTD_frameHeaderSize_prefix;  /* magic number + skippable frame length */
    -            dctx->stage = ZSTDds_decodeSkippableHeader;
    -            return 0;
    -        }
    -        dctx->headerSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_prefix);
    +        if (dctx->format == ZSTD_f_zstd1) {  /* allows header */
    +            assert(srcSize >= ZSTD_frameIdSize);  /* to read skippable magic number */
    +            if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {        /* skippable frame */
    +                memcpy(dctx->headerBuffer, src, srcSize);
    +                dctx->expected = ZSTD_skippableHeaderSize - srcSize;  /* remaining to load to get full skippable frame header */
    +                dctx->stage = ZSTDds_decodeSkippableHeader;
    +                return 0;
    +        }   }
    +        dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format);
             if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize;
    -        memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_prefix);
    -        if (dctx->headerSize > ZSTD_frameHeaderSize_prefix) {
    -            dctx->expected = dctx->headerSize - ZSTD_frameHeaderSize_prefix;
    -            dctx->stage = ZSTDds_decodeFrameHeader;
    -            return 0;
    -        }
    -        dctx->expected = 0;   /* not necessary to copy more */
    -        /* fall-through */
    +        memcpy(dctx->headerBuffer, src, srcSize);
    +        dctx->expected = dctx->headerSize - srcSize;
    +        dctx->stage = ZSTDds_decodeFrameHeader;
    +        return 0;
    +
         case ZSTDds_decodeFrameHeader:
             assert(src != NULL);
    -        memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected);
    +        memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize);
             CHECK_F(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize));
             dctx->expected = ZSTD_blockHeaderSize;
             dctx->stage = ZSTDds_decodeBlockHeader;
    @@ -1795,6 +1815,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
                 }
                 return 0;
             }
    +
         case ZSTDds_decompressLastBlock:
         case ZSTDds_decompressBlock:
             DEBUGLOG(5, "case ZSTDds_decompressBlock");
    @@ -1840,29 +1861,31 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
                 }
                 return rSize;
             }
    +
         case ZSTDds_checkChecksum:
    -        DEBUGLOG(4, "case ZSTDds_checkChecksum");
             assert(srcSize == 4);  /* guaranteed by dctx->expected */
             {   U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);
                 U32 const check32 = MEM_readLE32(src);
    -            DEBUGLOG(4, "calculated %08X :: %08X read", h32, check32);
    +            DEBUGLOG(4, "checksum : calculated %08X :: %08X read", h32, check32);
                 if (check32 != h32) return ERROR(checksum_wrong);
                 dctx->expected = 0;
                 dctx->stage = ZSTDds_getFrameHeaderSize;
                 return 0;
             }
    +
         case ZSTDds_decodeSkippableHeader:
    -        {   assert(src != NULL);
    -            memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected);
    -            dctx->expected = MEM_readLE32(dctx->headerBuffer + 4);
    -            dctx->stage = ZSTDds_skipFrame;
    -            return 0;
    -        }
    +        assert(src != NULL);
    +        assert(srcSize <= ZSTD_skippableHeaderSize);
    +        memcpy(dctx->headerBuffer + (ZSTD_skippableHeaderSize - srcSize), src, srcSize);   /* complete skippable header */
    +        dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_frameIdSize);   /* note : dctx->expected can grow seriously large, beyond local buffer size */
    +        dctx->stage = ZSTDds_skipFrame;
    +        return 0;
    +
         case ZSTDds_skipFrame:
    -        {   dctx->expected = 0;
    -            dctx->stage = ZSTDds_getFrameHeaderSize;
    -            return 0;
    -        }
    +        dctx->expected = 0;
    +        dctx->stage = ZSTDds_getFrameHeaderSize;
    +        return 0;
    +
         default:
             return ERROR(GENERIC);   /* impossible */
         }
    @@ -1943,7 +1966,7 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict
             if (magic != ZSTD_MAGIC_DICTIONARY) {
                 return ZSTD_refDictContent(dctx, dict, dictSize);   /* pure content mode */
         }   }
    -    dctx->dictID = MEM_readLE32((const char*)dict + 4);
    +    dctx->dictID = MEM_readLE32((const char*)dict + ZSTD_frameIdSize);
     
         /* load entropy tables */
         {   size_t const eSize = ZSTD_loadEntropy(&dctx->entropy, dict, dictSize);
    @@ -1957,6 +1980,29 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict
         return ZSTD_refDictContent(dctx, dict, dictSize);
     }
     
    +/* Note : this function cannot fail */
    +size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
    +{
    +    assert(dctx != NULL);
    +    dctx->expected = ZSTD_startingInputLength(dctx->format);  /* dctx->format must be properly set */
    +    dctx->stage = ZSTDds_getFrameHeaderSize;
    +    dctx->decodedSize = 0;
    +    dctx->previousDstEnd = NULL;
    +    dctx->base = NULL;
    +    dctx->vBase = NULL;
    +    dctx->dictEnd = NULL;
    +    dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001);  /* cover both little and big endian */
    +    dctx->litEntropy = dctx->fseEntropy = 0;
    +    dctx->dictID = 0;
    +    ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));
    +    memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue));  /* initial repcodes */
    +    dctx->LLTptr = dctx->entropy.LLTable;
    +    dctx->MLTptr = dctx->entropy.MLTable;
    +    dctx->OFTptr = dctx->entropy.OFTable;
    +    dctx->HUFptr = dctx->entropy.hufTable;
    +    return 0;
    +}
    +
     size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
     {
         CHECK_F( ZSTD_decompressBegin(dctx) );
    @@ -2023,7 +2069,7 @@ static size_t ZSTD_loadEntropy_inDDict(ZSTD_DDict* ddict)
         {   U32 const magic = MEM_readLE32(ddict->dictContent);
             if (magic != ZSTD_MAGIC_DICTIONARY) return 0;   /* pure content mode */
         }
    -    ddict->dictID = MEM_readLE32((const char*)ddict->dictContent + 4);
    +    ddict->dictID = MEM_readLE32((const char*)ddict->dictContent + ZSTD_frameIdSize);
     
         /* load entropy tables */
         CHECK_E( ZSTD_loadEntropy(&ddict->entropy, ddict->dictContent, ddict->dictSize), dictionary_corrupted );
    @@ -2144,7 +2190,7 @@ unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize)
     {
         if (dictSize < 8) return 0;
         if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) return 0;
    -    return MEM_readLE32((const char*)dict + 4);
    +    return MEM_readLE32((const char*)dict + ZSTD_frameIdSize);
     }
     
     /*! ZSTD_getDictID_fromDDict() :
    @@ -2239,13 +2285,15 @@ size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t di
         return ZSTD_frameHeaderSize_prefix;
     }
     
    +/* note : this variant can't fail */
     size_t ZSTD_initDStream(ZSTD_DStream* zds)
     {
         return ZSTD_initDStream_usingDict(zds, NULL, 0);
     }
     
     /* ZSTD_initDStream_usingDDict() :
    - * ddict will just be referenced, and must outlive decompression session */
    + * ddict will just be referenced, and must outlive decompression session
    + * this function cannot fail */
     size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict)
     {
         size_t const initResult = ZSTD_initDStream(zds);
    @@ -2265,14 +2313,39 @@ size_t ZSTD_resetDStream(ZSTD_DStream* zds)
     size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds,
                                     ZSTD_DStreamParameter_e paramType, unsigned paramValue)
     {
    +    ZSTD_STATIC_ASSERT((unsigned)zdss_loadHeader >= (unsigned)zdss_init);
    +    if ((unsigned)zds->streamStage > (unsigned)zdss_loadHeader)
    +        return ERROR(stage_wrong);
         switch(paramType)
         {
             default : return ERROR(parameter_unsupported);
    -        case DStream_p_maxWindowSize : zds->maxWindowSize = paramValue ? paramValue : (U32)(-1); break;
    +        case DStream_p_maxWindowSize :
    +            DEBUGLOG(4, "setting maxWindowSize = %u KB", paramValue >> 10);
    +            zds->maxWindowSize = paramValue ? paramValue : (U32)(-1);
    +            break;
         }
         return 0;
     }
     
    +size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize)
    +{
    +    ZSTD_STATIC_ASSERT((unsigned)zdss_loadHeader >= (unsigned)zdss_init);
    +    if ((unsigned)dctx->streamStage > (unsigned)zdss_loadHeader)
    +        return ERROR(stage_wrong);
    +    dctx->maxWindowSize = maxWindowSize;
    +    return 0;
    +}
    +
    +size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format)
    +{
    +    DEBUGLOG(4, "ZSTD_DCtx_setFormat : %u", (unsigned)format);
    +    ZSTD_STATIC_ASSERT((unsigned)zdss_loadHeader >= (unsigned)zdss_init);
    +    if ((unsigned)dctx->streamStage > (unsigned)zdss_loadHeader)
    +        return ERROR(stage_wrong);
    +    dctx->format = format;
    +    return 0;
    +}
    +
     
     size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds)
     {
    @@ -2297,7 +2370,7 @@ size_t ZSTD_estimateDStreamSize(size_t windowSize)
         return ZSTD_estimateDCtxSize() + inBuffSize + outBuffSize;
     }
     
    -ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize)
    +size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize)
     {
         U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX;   /* note : should be user-selectable */
         ZSTD_frameHeader zfh;
    @@ -2331,7 +2404,18 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
         U32 someMoreWork = 1;
     
         DEBUGLOG(5, "ZSTD_decompressStream");
    +    if (input->pos > input->size) {  /* forbidden */
    +        DEBUGLOG(5, "in: pos: %u   vs size: %u",
    +                    (U32)input->pos, (U32)input->size);
    +        return ERROR(srcSize_wrong);
    +    }
    +    if (output->pos > output->size) {  /* forbidden */
    +        DEBUGLOG(5, "out: pos: %u   vs size: %u",
    +                    (U32)output->pos, (U32)output->size);
    +        return ERROR(dstSize_tooSmall);
    +    }
         DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos));
    +
     #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
         if (zds->legacyVersion) {
             /* legacy support is incompatible with static dctx */
    @@ -2348,7 +2432,9 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
                 /* fall-through */
     
             case zdss_loadHeader :
    -            {   size_t const hSize = ZSTD_getFrameHeader(&zds->fParams, zds->headerBuffer, zds->lhSize);
    +            DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip));
    +            {   size_t const hSize = ZSTD_getFrameHeader_internal(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format);
    +                DEBUGLOG(5, "header size : %u", (U32)hSize);
                     if (ZSTD_isError(hSize)) {
     #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
                         U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart);
    @@ -2401,7 +2487,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
                 CHECK_F(ZSTD_decompressBegin_usingDDict(zds, zds->ddict));
     
                 if ((MEM_readLE32(zds->headerBuffer) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {  /* skippable frame */
    -                zds->expected = MEM_readLE32(zds->headerBuffer + 4);
    +                zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_frameIdSize);
                     zds->stage = ZSTDds_skipFrame;
                 } else {
                     CHECK_F(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize));
    @@ -2410,7 +2496,8 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
                 }
     
                 /* control buffer memory usage */
    -            DEBUGLOG(4, "Control max buffer memory usage");
    +            DEBUGLOG(4, "Control max buffer memory usage (max %u KB)",
    +                        (U32)(zds->maxWindowSize >> 10));
                 zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);
                 if (zds->fParams.windowSize > zds->maxWindowSize) return ERROR(frameParameter_windowTooLarge);
     
    @@ -2539,3 +2626,30 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
             return nextSrcSizeHint;
         }
     }
    +
    +
    +size_t ZSTD_decompress_generic(ZSTD_DCtx* dctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
    +{
    +    return ZSTD_decompressStream(dctx, output, input);
    +}
    +
    +size_t ZSTD_decompress_generic_simpleArgs (
    +                            ZSTD_DCtx* dctx,
    +                            void* dst, size_t dstCapacity, size_t* dstPos,
    +                      const void* src, size_t srcSize, size_t* srcPos)
    +{
    +    ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
    +    ZSTD_inBuffer  input  = { src, srcSize, *srcPos };
    +    /* ZSTD_compress_generic() will check validity of dstPos and srcPos */
    +    size_t const cErr = ZSTD_decompress_generic(dctx, &output, &input);
    +    *dstPos = output.pos;
    +    *srcPos = input.pos;
    +    return cErr;
    +}
    +
    +void ZSTD_DCtx_reset(ZSTD_DCtx* dctx)
    +{
    +    (void)ZSTD_initDStream(dctx);
    +    dctx->format = ZSTD_f_zstd1;
    +    dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
    +}
    diff --git a/lib/dictBuilder/cover.c b/lib/dictBuilder/cover.c
    index f6500b3d..efdffddb 100644
    --- a/lib/dictBuilder/cover.c
    +++ b/lib/dictBuilder/cover.c
    @@ -711,8 +711,8 @@ ZDICTLIB_API size_t ZDICT_trainFromBuffer_cover(
      * compiled with multithreaded support.
      */
     typedef struct COVER_best_s {
    -  pthread_mutex_t mutex;
    -  pthread_cond_t cond;
    +  ZSTD_pthread_mutex_t mutex;
    +  ZSTD_pthread_cond_t cond;
       size_t liveJobs;
       void *dict;
       size_t dictSize;
    @@ -725,8 +725,8 @@ typedef struct COVER_best_s {
      */
     static void COVER_best_init(COVER_best_t *best) {
       if (best==NULL) return; /* compatible with init on NULL */
    -  (void)pthread_mutex_init(&best->mutex, NULL);
    -  (void)pthread_cond_init(&best->cond, NULL);
    +  (void)ZSTD_pthread_mutex_init(&best->mutex, NULL);
    +  (void)ZSTD_pthread_cond_init(&best->cond, NULL);
       best->liveJobs = 0;
       best->dict = NULL;
       best->dictSize = 0;
    @@ -741,11 +741,11 @@ static void COVER_best_wait(COVER_best_t *best) {
       if (!best) {
         return;
       }
    -  pthread_mutex_lock(&best->mutex);
    +  ZSTD_pthread_mutex_lock(&best->mutex);
       while (best->liveJobs != 0) {
    -    pthread_cond_wait(&best->cond, &best->mutex);
    +    ZSTD_pthread_cond_wait(&best->cond, &best->mutex);
       }
    -  pthread_mutex_unlock(&best->mutex);
    +  ZSTD_pthread_mutex_unlock(&best->mutex);
     }
     
     /**
    @@ -759,8 +759,8 @@ static void COVER_best_destroy(COVER_best_t *best) {
       if (best->dict) {
         free(best->dict);
       }
    -  pthread_mutex_destroy(&best->mutex);
    -  pthread_cond_destroy(&best->cond);
    +  ZSTD_pthread_mutex_destroy(&best->mutex);
    +  ZSTD_pthread_cond_destroy(&best->cond);
     }
     
     /**
    @@ -771,9 +771,9 @@ static void COVER_best_start(COVER_best_t *best) {
       if (!best) {
         return;
       }
    -  pthread_mutex_lock(&best->mutex);
    +  ZSTD_pthread_mutex_lock(&best->mutex);
       ++best->liveJobs;
    -  pthread_mutex_unlock(&best->mutex);
    +  ZSTD_pthread_mutex_unlock(&best->mutex);
     }
     
     /**
    @@ -789,7 +789,7 @@ static void COVER_best_finish(COVER_best_t *best, size_t compressedSize,
       }
       {
         size_t liveJobs;
    -    pthread_mutex_lock(&best->mutex);
    +    ZSTD_pthread_mutex_lock(&best->mutex);
         --best->liveJobs;
         liveJobs = best->liveJobs;
         /* If the new dictionary is better */
    @@ -812,9 +812,9 @@ static void COVER_best_finish(COVER_best_t *best, size_t compressedSize,
           best->parameters = parameters;
           best->compressedSize = compressedSize;
         }
    -    pthread_mutex_unlock(&best->mutex);
    +    ZSTD_pthread_mutex_unlock(&best->mutex);
         if (liveJobs == 0) {
    -      pthread_cond_broadcast(&best->cond);
    +      ZSTD_pthread_cond_broadcast(&best->cond);
         }
       }
     }
    diff --git a/lib/zstd.h b/lib/zstd.h
    index 59aa0b02..02241fd3 100644
    --- a/lib/zstd.h
    +++ b/lib/zstd.h
    @@ -395,11 +395,12 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void);   /*!< recommended size for output
     #define ZSTD_LDM_MINMATCH_MAX 4096
     #define ZSTD_LDM_BUCKETSIZELOG_MAX 8
     
    -#define ZSTD_FRAMEHEADERSIZE_MAX 18    /* for static allocation */
    -#define ZSTD_FRAMEHEADERSIZE_MIN  6
    -static const size_t ZSTD_frameHeaderSize_prefix = 5;  /* minimum input size to know frame header size */
    -static const size_t ZSTD_frameHeaderSize_max = ZSTD_FRAMEHEADERSIZE_MAX;
    +#define ZSTD_FRAMEHEADERSIZE_PREFIX 5   /* minimum input size to know frame header size */
    +#define ZSTD_FRAMEHEADERSIZE_MIN    6
    +#define ZSTD_FRAMEHEADERSIZE_MAX   18   /* for static allocation */
    +static const size_t ZSTD_frameHeaderSize_prefix = ZSTD_FRAMEHEADERSIZE_PREFIX;
     static const size_t ZSTD_frameHeaderSize_min = ZSTD_FRAMEHEADERSIZE_MIN;
    +static const size_t ZSTD_frameHeaderSize_max = ZSTD_FRAMEHEADERSIZE_MAX;
     static const size_t ZSTD_skippableHeaderSize = 8;  /* magic number + skippable frame length */
     
     
    @@ -486,7 +487,7 @@ ZSTDLIB_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize);
     
     /*! ZSTD_sizeof_*() :
      *  These functions give the current memory usage of selected object.
    - *  Object memory usage can evolve if it's re-used multiple times. */
    + *  Object memory usage can evolve when re-used multiple times. */
     ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx);
     ZSTDLIB_API size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx);
     ZSTDLIB_API size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs);
    @@ -499,21 +500,21 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
      *  of a future {D,C}Ctx, before its creation.
      *  ZSTD_estimateCCtxSize() will provide a budget large enough for any compression level up to selected one.
      *  It will also consider src size to be arbitrarily "large", which is worst case.
    - *  If srcSize is known to always be small, ZSTD_estimateCCtxSize_advanced_usingCParams() can provide a tighter estimation.
    - *  ZSTD_estimateCCtxSize_advanced_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
    - *  ZSTD_estimateCCtxSize_advanced_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is > 1.
    + *  If srcSize is known to always be small, ZSTD_estimateCCtxSize_usingCParams() can provide a tighter estimation.
    + *  ZSTD_estimateCCtxSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
    + *  ZSTD_estimateCCtxSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is > 1.
      *  Note : CCtx estimation is only correct for single-threaded compression */
     ZSTDLIB_API size_t ZSTD_estimateCCtxSize(int compressionLevel);
    -ZSTDLIB_API size_t ZSTD_estimateCCtxSize_advanced_usingCParams(ZSTD_compressionParameters cParams);
    -ZSTDLIB_API size_t ZSTD_estimateCCtxSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params);
    +ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams);
    +ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params);
     ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void);
     
     /*! ZSTD_estimateCStreamSize() :
      *  ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one.
      *  It will also consider src size to be arbitrarily "large", which is worst case.
    - *  If srcSize is known to always be small, ZSTD_estimateCStreamSize_advanced_usingCParams() can provide a tighter estimation.
    - *  ZSTD_estimateCStreamSize_advanced_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
    - *  ZSTD_estimateCStreamSize_advanced_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is set to a value > 1.
    + *  If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation.
    + *  ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
    + *  ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParam_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_p_nbThreads is set to a value > 1.
      *  Note : CStream estimation is only correct for single-threaded compression.
      *  ZSTD_DStream memory budget depends on window Size.
      *  This information can be passed manually, using ZSTD_estimateDStreamSize,
    @@ -522,14 +523,14 @@ ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void);
      *         an internal ?Dict will be created, which additional size is not estimated here.
      *         In this case, get total size by adding ZSTD_estimate?DictSize */
     ZSTDLIB_API size_t ZSTD_estimateCStreamSize(int compressionLevel);
    -ZSTDLIB_API size_t ZSTD_estimateCStreamSize_advanced_usingCParams(ZSTD_compressionParameters cParams);
    -ZSTDLIB_API size_t ZSTD_estimateCStreamSize_advanced_usingCCtxParams(const ZSTD_CCtx_params* params);
    +ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams);
    +ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params);
     ZSTDLIB_API size_t ZSTD_estimateDStreamSize(size_t windowSize);
     ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);
     
     typedef enum {
    -    ZSTD_dlm_byCopy = 0,      /* Copy dictionary content internally. */
    -    ZSTD_dlm_byRef,           /* Reference dictionary content -- the dictionary buffer must outlives its users. */
    +    ZSTD_dlm_byCopy = 0,     /**< Copy dictionary content internally */
    +    ZSTD_dlm_byRef,          /**< Reference dictionary content -- the dictionary buffer must outlive its users. */
     } ZSTD_dictLoadMethod_e;
     
     /*! ZSTD_estimate?DictSize() :
    @@ -747,12 +748,12 @@ ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledg
     
     
     /*=====   Advanced Streaming decompression functions  =====*/
    -typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e;
     ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem);
     ZSTDLIB_API ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize);    /**< same as ZSTD_initStaticDCtx() */
    -ZSTDLIB_API size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue);
    -ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); /**< note: a dict will not be used if dict == NULL or dictSize < 8 */
    -ZSTDLIB_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict);  /**< note : ddict will just be referenced, and must outlive decompression session */
    +typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e;
    +ZSTDLIB_API size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue);   /* obsolete : this API will be removed in a future version */
    +ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); /**< note: no dictionary will be used if dict == NULL or dictSize < 8 */
    +ZSTDLIB_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict);  /**< note : ddict is referenced, it must outlive decompression session */
     ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);  /**< re-use decompression parameters from previous init; saves dictionary loading */
     
     
    @@ -760,8 +761,8 @@ ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);  /**< re-use decompress
     *  Buffer-less and synchronous inner streaming functions
     *
     *  This is an advanced API, giving full control over buffer management, for users which need direct control over memory.
    -*  But it's also a complex one, with many restrictions (documented below).
    -*  Prefer using normal streaming API for an easier experience
    +*  But it's also a complex one, with several restrictions, documented below.
    +*  Prefer normal streaming API for an easier experience.
     ********************************************************************* */
     
     /**
    @@ -778,8 +779,8 @@ ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);  /**< re-use decompress
     
       Then, consume your input using ZSTD_compressContinue().
       There are some important considerations to keep in mind when using this advanced function :
    -  - ZSTD_compressContinue() has no internal buffer. It uses externally provided buffer only.
    -  - Interface is synchronous : input is consumed entirely and produce 1+ (or more) compressed blocks.
    +  - ZSTD_compressContinue() has no internal buffer. It uses externally provided buffers only.
    +  - Interface is synchronous : input is consumed entirely and produces 1+ compressed blocks.
       - Caller must ensure there is enough space in `dst` to store compressed data under worst case scenario.
         Worst case evaluation is provided by ZSTD_compressBound().
         ZSTD_compressContinue() doesn't guarantee recover after a failed compression.
    @@ -790,9 +791,9 @@ ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);  /**< re-use decompress
     
       Finish a frame with ZSTD_compressEnd(), which will write the last block(s) and optional checksum.
       It's possible to use srcSize==0, in which case, it will write a final empty block to end the frame.
    -  Without last block mark, frames will be considered unfinished (corrupted) by decoders.
    +  Without last block mark, frames are considered unfinished (hence corrupted) by compliant decoders.
     
    -  `ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress some new frame.
    +  `ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress again.
     */
     
     /*=====   Buffer-less streaming compression functions  =====*/
    @@ -908,33 +909,55 @@ ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx);
     
     
     
    -/*===   New advanced API (experimental, and compression only)  ===*/
    +/* ============================================ */
    +/**       New advanced API (experimental)       */
    +/* ============================================ */
     
     /* notes on API design :
    - *   In this proposal, parameters are pushed one by one into an existing CCtx,
    + *   In this proposal, parameters are pushed one by one into an existing context,
      *   and then applied on all subsequent compression jobs.
      *   When no parameter is ever provided, CCtx is created with compression level ZSTD_CLEVEL_DEFAULT.
      *
      *   This API is intended to replace all others experimental API.
      *   It can basically do all other use cases, and even new ones.
    - *   It stands a good chance to become "stable",
    - *   after a reasonable testing period.
    + *   In constrast with _advanced() variants, it stands a reasonable chance to become "stable",
    + *   after a good testing period.
      */
     
     /* note on naming convention :
      *   Initially, the API favored names like ZSTD_setCCtxParameter() .
      *   In this proposal, convention is changed towards ZSTD_CCtx_setParameter() .
      *   The main driver is that it identifies more clearly the target object type.
    - *   It feels clearer in light of potential variants :
    + *   It feels clearer when considering multiple targets :
      *   ZSTD_CDict_setParameter() (rather than ZSTD_setCDictParameter())
    - *   ZSTD_DCtx_setParameter()  (rather than ZSTD_setDCtxParameter() )
    - *   Left variant feels easier to distinguish.
    + *   ZSTD_CCtxParams_setParameter()  (rather than ZSTD_setCCtxParamsParameter() )
    + *   etc...
      */
     
     /* note on enum design :
    - * All enum will be manually set to explicit values before reaching "stable API" status */
    + * All enum will be pinned to explicit values before reaching "stable API" status */
     
     typedef enum {
    +    /* Question : should we have a format ZSTD_f_auto ?
    +     * For the time being, it would mean exactly the same as ZSTD_f_zstd1.
    +     * But, in the future, should several formats be supported,
    +     * on the compression side, it would mean "default format".
    +     * On the decompression side, it would mean "multi format",
    +     * and ZSTD_f_zstd1 could be reserved to mean "accept *only* zstd frames".
    +     * Since meaning is a little different, another option could be to define different enums for compression and decompression.
    +     * This question could be kept for later, when there are actually multiple formats to support,
    +     * but there is also the question of pinning enum values, and pinning value `0` is especially important */
    +    ZSTD_f_zstd1 = 0,        /* zstd frame format, specified in zstd_compression_format.md (default) */
    +    ZSTD_f_zstd1_magicless,  /* Variant of zstd frame format, without initial 4-bytes magic number.
    +                              * Useful to save 4 bytes per generated frame.
    +                              * Decoder cannot recognise automatically this format, requiring instructions. */
    +} ZSTD_format_e;
    +
    +typedef enum {
    +    /* compression format */
    +    ZSTD_p_format = 10,      /* See ZSTD_format_e enum definition.
    +                              * Cast selected format as unsigned for ZSTD_CCtx_setParameter() compatibility. */
    +
         /* compression parameters */
         ZSTD_p_compressionLevel=100, /* Update all compression parameters according to pre-defined cLevel table
                                   * Default level is ZSTD_CLEVEL_DEFAULT==3.
    @@ -1105,15 +1128,15 @@ ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* pre
     typedef enum {
         ZSTD_e_continue=0, /* collect more data, encoder transparently decides when to output result, for optimal conditions */
         ZSTD_e_flush,      /* flush any data provided so far - frame will continue, future data can still reference previous data for better compression */
    -    ZSTD_e_end         /* flush any remaining data and ends current frame. Any future compression starts a new frame. */
    +    ZSTD_e_end         /* flush any remaining data and close current frame. Any additional data starts a new frame. */
     } ZSTD_EndDirective;
     
     /*! ZSTD_compress_generic() :
      *  Behave about the same as ZSTD_compressStream. To note :
      *  - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_setParameter()
      *  - Compression parameters cannot be changed once compression is started.
    - *  - *dstPos must be <= dstCapacity, *srcPos must be <= srcSize
    - *  - *dspPos and *srcPos will be updated. They are guaranteed to remain below their respective limit.
    + *  - outpot->pos must be <= dstCapacity, input->pos must be <= srcSize
    + *  - outpot->pos and input->pos will be updated. They are guaranteed to remain below their respective limit.
      *  - @return provides the minimum amount of data still to flush from internal buffers
      *            or an error code, which can be tested using ZSTD_isError().
      *            if @return != 0, flush is not fully completed, there is some data left within internal buffers.
    @@ -1132,6 +1155,7 @@ ZSTDLIB_API size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
      *  Useful after an error, or to interrupt an ongoing compression job and start a new one.
      *  Any internal data not yet flushed is cancelled.
      *  Dictionary (if any) is dropped.
    + *  All parameters are back to default values.
      *  It's possible to modify compression parameters after a reset.
      */
     ZSTDLIB_API void ZSTD_CCtx_reset(ZSTD_CCtx* cctx);   /* Not ready yet ! */
    @@ -1140,30 +1164,33 @@ ZSTDLIB_API void ZSTD_CCtx_reset(ZSTD_CCtx* cctx);   /* Not ready yet ! */
     /*! ZSTD_compress_generic_simpleArgs() :
      *  Same as ZSTD_compress_generic(),
      *  but using only integral types as arguments.
    - *  Argument list is larger and less expressive than ZSTD_{in,out}Buffer,
    + *  Argument list is larger than ZSTD_{in,out}Buffer,
      *  but can be helpful for binders from dynamic languages
      *  which have troubles handling structures containing memory pointers.
      */
    -size_t ZSTD_compress_generic_simpleArgs (
    +ZSTDLIB_API size_t ZSTD_compress_generic_simpleArgs (
                                 ZSTD_CCtx* cctx,
                                 void* dst, size_t dstCapacity, size_t* dstPos,
                           const void* src, size_t srcSize, size_t* srcPos,
                                 ZSTD_EndDirective endOp);
     
     
    -/** ZSTD_CCtx_params
    - *
    +/*! ZSTD_CCtx_params :
    + *  Quick howto :
      *  - ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure
    - *  - ZSTD_CCtxParam_setParameter() : Push parameters one by one into an
    - *  existing ZSTD_CCtx_params structure. This is similar to
    - *  ZSTD_CCtx_setParameter().
    - *  - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to an existing CCtx. These
    - *  parameters will be applied to all subsequent compression jobs.
    + *  - ZSTD_CCtxParam_setParameter() : Push parameters one by one into
    + *                                    an existing ZSTD_CCtx_params structure.
    + *                                    This is similar to
    + *                                    ZSTD_CCtx_setParameter().
    + *  - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to
    + *                                    an existing CCtx.
    + *                                    These parameters will be applied to
    + *                                    all subsequent compression jobs.
      *  - ZSTD_compress_generic() : Do compression using the CCtx.
      *  - ZSTD_freeCCtxParams() : Free the memory.
      *
    - *  This can be used with ZSTD_estimateCCtxSize_opaque() for static allocation
    - *  for single-threaded compression.
    + *  This can be used with ZSTD_estimateCCtxSize_advanced_usingCCtxParams()
    + *  for static allocation for single-threaded compression.
      */
     ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void);
     
    @@ -1191,22 +1218,133 @@ ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params);
      *  Set one compression parameter, selected by enum ZSTD_cParameter.
      *  Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_setParametersUsingCCtxParams().
      *  Note : when `value` is an enum, cast it to unsigned for proper type checking.
    - *  @result : 0, or an error code (which can be tested with ZSTD_isError()).
    + * @result : 0, or an error code (which can be tested with ZSTD_isError()).
      */
     ZSTDLIB_API size_t ZSTD_CCtxParam_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned value);
     
     /*! ZSTD_CCtx_setParametersUsingCCtxParams() :
    - * Apply a set of ZSTD_CCtx_params to the compression context.
    - * This must be done before the dictionary is loaded.
    - * The pledgedSrcSize is treated as unknown.
    - * Multithreading parameters are applied only if nbThreads > 1.
    + *  Apply a set of ZSTD_CCtx_params to the compression context.
    + *  This must be done before the dictionary is loaded.
    + *  The pledgedSrcSize is treated as unknown.
    + *  Multithreading parameters are applied only if nbThreads > 1.
      */
     ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams(
             ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params);
     
    -/**
    -    Block functions
     
    +/*===   Advanced parameters for decompression API  ===*/
    +
    +/* The following parameters must be set after creating a ZSTD_DCtx* (or ZSTD_DStream*) object,
    + * but before starting decompression of a frame.
    + */
    +
    +/*! ZSTD_DCtx_loadDictionary() :
    + *  Create an internal DDict from dict buffer,
    + *  to be used to decompress next frames.
    + * @result : 0, or an error code (which can be tested with ZSTD_isError()).
    + *  Special : Adding a NULL (or 0-size) dictionary invalidates any previous dictionary,
    + *            meaning "return to no-dictionary mode".
    + *  Note 1 : `dict` content will be copied internally.
    + *            Use ZSTD_DCtx_loadDictionary_byReference()
    + *            to reference dictionary content instead.
    + *            In which case, the dictionary buffer must outlive its users.
    + *  Note 2 : Loading a dictionary involves building tables,
    + *           which has a non-negligible impact on CPU usage and latency.
    + *  Note 3 : Use ZSTD_DCtx_loadDictionary_advanced() to select
    + *           how dictionary content will be interpreted and loaded.
    + */
    +ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);   /* not implemented */
    +ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);   /* not implemented */
    +ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode);   /* not implemented */
    +
    +
    +/*! ZSTD_DCtx_refDDict() :
    + *  Reference a prepared dictionary, to be used to decompress next frames.
    + *  The dictionary remains active for decompression of future frames using same DCtx.
    + * @result : 0, or an error code (which can be tested with ZSTD_isError()).
    + *  Note 1 : Currently, only one dictionary can be managed.
    + *           Referencing a new dictionary effectively "discards" any previous one.
    + *  Special : adding a NULL DDict means "return to no-dictionary mode".
    + *  Note 2 : DDict is just referenced, its lifetime must outlive its usage from DCtx.
    + */
    +ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);   /* not implemented */
    +
    +
    +/*! ZSTD_DCtx_refPrefix() :
    + *  Reference a prefix (single-usage dictionary) for next compression job.
    + *  Prefix is **only used once**. It must be explicitly referenced before each frame.
    + *  If there is a need to use same prefix multiple times, consider embedding it into a ZSTD_DDict instead.
    + * @result : 0, or an error code (which can be tested with ZSTD_isError()).
    + *  Note 1 : Adding any prefix (including NULL) invalidates any previously set prefix or dictionary
    + *  Note 2 : Prefix buffer is referenced. It must outlive compression job.
    + *  Note 3 : By default, the prefix is treated as raw content (ZSTD_dm_rawContent).
    + *           Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode.
    + *  Note 4 : Referencing a raw content prefix has almost no cpu nor memory cost.
    + */
    +ZSTDLIB_API size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize);   /* not implemented */
    +ZSTDLIB_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode);   /* not implemented */
    +
    +
    +/*! ZSTD_DCtx_setMaxWindowSize() :
    + *  Refuses allocating internal buffers for frames requiring a window size larger than provided limit.
    + *  This is useful to prevent a decoder context from reserving too much memory for itself (potential attack scenario).
    + *  This parameter is only useful in streaming mode, since no internal buffer is allocated in direct mode.
    + *  By default, a decompression context accepts all window sizes <= (1 << ZSTD_WINDOWLOG_MAX)
    + * @return : 0, or an error code (which can be tested using ZSTD_isError()).
    + */
    +ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize);
    +
    +
    +/*! ZSTD_DCtx_setFormat() :
    + *  Instruct the decoder context about what kind of data to decode next.
    + *  This instruction is mandatory to decode data without a fully-formed header,
    + *  such ZSTD_f_zstd1_magicless for example.
    + * @return : 0, or an error code (which can be tested using ZSTD_isError()).
    + */
    +ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format);
    +
    +
    +/*! ZSTD_decompress_generic() :
    + *  Behave the same as ZSTD_decompressStream.
    + *  Decompression parameters cannot be changed once decompression is started.
    + * @return : an error code, which can be tested using ZSTD_isError()
    + *           if >0, a hint, nb of expected input bytes for next invocation.
    + *           `0` means : a frame has just been fully decoded and flushed.
    + */
    +ZSTDLIB_API size_t ZSTD_decompress_generic(ZSTD_DCtx* dctx,
    +                                           ZSTD_outBuffer* output,
    +                                           ZSTD_inBuffer* input);
    +
    +
    +/*! ZSTD_decompress_generic_simpleArgs() :
    + *  Same as ZSTD_decompress_generic(),
    + *  but using only integral types as arguments.
    + *  Argument list is larger than ZSTD_{in,out}Buffer,
    + *  but can be helpful for binders from dynamic languages
    + *  which have troubles handling structures containing memory pointers.
    + */
    +ZSTDLIB_API size_t ZSTD_decompress_generic_simpleArgs (
    +                            ZSTD_DCtx* dctx,
    +                            void* dst, size_t dstCapacity, size_t* dstPos,
    +                      const void* src, size_t srcSize, size_t* srcPos);
    +
    +
    +/*! ZSTD_DCtx_reset() :
    + *  Return a DCtx to clean state.
    + *  If a decompression was ongoing, any internal data not yet flushed is cancelled.
    + *  All parameters are back to default values, including sticky ones.
    + *  Dictionary (if any) is dropped.
    + *  Parameters can be modified again after a reset.
    + */
    +ZSTDLIB_API void ZSTD_DCtx_reset(ZSTD_DCtx* dctx);
    +
    +
    +
    +/* ============================ */
    +/**       Block level API       */
    +/* ============================ */
    +
    +/*!
         Block functions produce and decode raw zstd blocks, without frame metadata.
         Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes).
         User will have to take in charge required information to regenerate data, such as compressed and content sizes.
    @@ -1218,7 +1356,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams(
           + compression : any ZSTD_compressBegin*() variant, including with dictionary
           + decompression : any ZSTD_decompressBegin*() variant, including with dictionary
           + copyCCtx() and copyDCtx() can be used too
    -    - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX
    +    - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB
           + If input is larger than a block size, it's necessary to split input data into multiple blocks
           + For inputs larger than a single block size, consider using the regular ZSTD_compress() instead.
             Frame metadata is not that costly, and quickly becomes negligible as source size grows larger.
    diff --git a/programs/Makefile b/programs/Makefile
    index b13629df..179c1f62 100644
    --- a/programs/Makefile
    +++ b/programs/Makefile
    @@ -40,7 +40,7 @@ CPPFLAGS+= -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(ZSTDDIR)/compress \
                -DZSTD_NEWAPI \
                -DXXH_NAMESPACE=ZSTD_   # because xxhash.o already compiled with this macro from library
     CFLAGS  ?= -O3
    -DEBUGFLAGS= -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \
    +DEBUGFLAGS+=-Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \
                 -Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement \
                 -Wstrict-prototypes -Wundef -Wpointer-arith -Wformat-security \
                 -Wvla -Wformat=2 -Winit-self -Wfloat-equal -Wwrite-strings \
    diff --git a/programs/fileio.c b/programs/fileio.c
    index a4b50fc2..9c5e2c40 100644
    --- a/programs/fileio.c
    +++ b/programs/fileio.c
    @@ -348,13 +348,16 @@ static size_t FIO_createDictBuffer(void** bufferPtr, const char* fileName)
         fileHandle = fopen(fileName, "rb");
         if (fileHandle==0) EXM_THROW(31, "%s: %s", fileName, strerror(errno));
         fileSize = UTIL_getFileSize(fileName);
    -    if (fileSize > DICTSIZE_MAX)
    +    if (fileSize > DICTSIZE_MAX) {
             EXM_THROW(32, "Dictionary file %s is too large (> %u MB)",
                             fileName, DICTSIZE_MAX >> 20);   /* avoid extreme cases */
    +    }
         *bufferPtr = malloc((size_t)fileSize);
         if (*bufferPtr==NULL) EXM_THROW(34, "%s", strerror(errno));
    -    { size_t const readSize = fread(*bufferPtr, 1, (size_t)fileSize, fileHandle);
    -      if (readSize!=fileSize) EXM_THROW(35, "Error reading dictionary file %s", fileName); }
    +    {   size_t const readSize = fread(*bufferPtr, 1, (size_t)fileSize, fileHandle);
    +        if (readSize!=fileSize)
    +            EXM_THROW(35, "Error reading dictionary file %s", fileName);
    +    }
         fclose(fileHandle);
         return (size_t)fileSize;
     }
    @@ -971,7 +974,7 @@ int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFile
         char*  dstFileName = (char*)malloc(FNSPACE);
         size_t const suffixSize = suffix ? strlen(suffix) : 0;
         U64 const srcSize = (nbFiles != 1) ? 0 : UTIL_getFileSize(inFileNamesTable[0]) ;
    -    int const isRegularFile = (nbFiles != 1) ? 0 : UTIL_isRegularFile(inFileNamesTable[0]);
    +    int const isRegularFile = (nbFiles > 1) ? 0 : UTIL_isRegularFile(inFileNamesTable[0]);  /* won't write frame content size when nbFiles > 1 */
         cRess_t ress = FIO_createCResources(dictFileName, compressionLevel, srcSize, isRegularFile, comprParams);
     
         /* init */
    @@ -1037,7 +1040,7 @@ static dRess_t FIO_createDResources(const char* dictFileName)
         /* Allocation */
         ress.dctx = ZSTD_createDStream();
         if (ress.dctx==NULL) EXM_THROW(60, "Can't create ZSTD_DStream");
    -    ZSTD_setDStreamParameter(ress.dctx, DStream_p_maxWindowSize, g_memLimit);
    +    CHECK( ZSTD_setDStreamParameter(ress.dctx, DStream_p_maxWindowSize, g_memLimit) );
         ress.srcBufferSize = ZSTD_DStreamInSize();
         ress.srcBuffer = malloc(ress.srcBufferSize);
         ress.dstBufferSize = ZSTD_DStreamOutSize();
    @@ -1731,10 +1734,11 @@ int FIO_decompressMultipleFilenames(const char** srcNamesTable, unsigned nbFiles
     typedef struct {
         int numActualFrames;
         int numSkippableFrames;
    -    unsigned long long decompressedSize;
    +    U64 decompressedSize;
         int decompUnavailable;
    -    unsigned long long compressedSize;
    +    U64 compressedSize;
         int usesCheck;
    +    U32 nbFiles;
     } fileInfo_t;
     
     /** getFileInfo() :
    @@ -1751,14 +1755,16 @@ static int getFileInfo(fileInfo_t* info, const char* inFileName){
             DISPLAY("Error: could not open source file %s\n", inFileName);
             return 3;
         }
    -    info->compressedSize = (unsigned long long)UTIL_getFileSize(inFileName);
    +    info->compressedSize = UTIL_getFileSize(inFileName);
     
         /* begin analyzing frame */
         for ( ; ; ) {
             BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX];
             size_t const numBytesRead = fread(headerBuffer, 1, sizeof(headerBuffer), srcFile);
             if (numBytesRead < ZSTD_frameHeaderSize_min) {
    -            if (feof(srcFile) && numBytesRead == 0 && info->compressedSize > 0) {
    +            if ( feof(srcFile)
    +              && (numBytesRead == 0)
    +              && (info->compressedSize > 0) ) {
                     break;
                 }
                 else if (feof(srcFile)) {
    @@ -1860,6 +1866,7 @@ static int getFileInfo(fileInfo_t* info, const char* inFileName){
             }
         }  /* end analyzing frame */
         fclose(srcFile);
    +    info->nbFiles = 1;
         return detectError;
     }
     
    @@ -1872,25 +1879,28 @@ static void displayInfo(const char* inFileName, fileInfo_t* info, int displayLev
         const char* const checkString = (info->usesCheck ? "XXH64" : "None");
         if (displayLevel <= 2) {
             if (!info->decompUnavailable) {
    -            DISPLAYOUT("Skippable  Non-Skippable  Compressed  Uncompressed  Ratio  Check  Filename\n");
    -            DISPLAYOUT("%9d  %13d  %7.2f %2s  %9.2f %2s  %5.3f  %5s  %s\n",
    -                    info->numSkippableFrames, info->numActualFrames,
    +            DISPLAYOUT("%6d  %5d  %7.2f %2s  %9.2f %2s  %5.3f  %5s  %s\n",
    +                    info->numSkippableFrames + info->numActualFrames,
    +                    info->numSkippableFrames,
                         compressedSizeUnit, unitStr, decompressedSizeUnit, unitStr,
                         ratio, checkString, inFileName);
             } else {
    -            DISPLAYOUT("Skippable  Non-Skippable  Compressed  Check  Filename\n");
    -            DISPLAYOUT("%9d  %13d  %7.2f MB  %5s  %s\n",
    -                    info->numSkippableFrames, info->numActualFrames,
    -                    compressedSizeUnit, checkString, inFileName);
    +            DISPLAYOUT("%6d  %5d  %7.2f %2s                       %5s  %s\n",
    +                    info->numSkippableFrames + info->numActualFrames,
    +                    info->numSkippableFrames,
    +                    compressedSizeUnit, unitStr,
    +                    checkString, inFileName);
             }
         } else {
             DISPLAYOUT("# Zstandard Frames: %d\n", info->numActualFrames);
             DISPLAYOUT("# Skippable Frames: %d\n", info->numSkippableFrames);
             DISPLAYOUT("Compressed Size: %.2f %2s (%llu B)\n",
    -                    compressedSizeUnit, unitStr, info->compressedSize);
    +                    compressedSizeUnit, unitStr,
    +                    (unsigned long long)info->compressedSize);
             if (!info->decompUnavailable) {
                 DISPLAYOUT("Decompressed Size: %.2f %2s (%llu B)\n",
    -                    decompressedSizeUnit, unitStr, info->decompressedSize);
    +                    decompressedSizeUnit, unitStr,
    +                    (unsigned long long)info->decompressedSize);
                 DISPLAYOUT("Ratio: %.4f\n", ratio);
             }
             DISPLAYOUT("Check: %s\n", checkString);
    @@ -1898,33 +1908,40 @@ static void displayInfo(const char* inFileName, fileInfo_t* info, int displayLev
         }
     }
     
    +static fileInfo_t FIO_addFInfo(fileInfo_t fi1, fileInfo_t fi2)
    +{
    +    fileInfo_t total;
    +    total.numActualFrames = fi1.numActualFrames + fi2.numActualFrames;
    +    total.numSkippableFrames = fi1.numSkippableFrames + fi2.numSkippableFrames;
    +    total.compressedSize = fi1.compressedSize + fi2.compressedSize;
    +    total.decompressedSize = fi1.decompressedSize + fi2.decompressedSize;
    +    total.decompUnavailable = fi1.decompUnavailable | fi2.decompUnavailable;
    +    total.usesCheck = fi1.usesCheck & fi2.usesCheck;
    +    total.nbFiles = fi1.nbFiles + fi2.nbFiles;
    +    return total;
    +}
     
    -static int FIO_listFile(const char* inFileName, int displayLevel, unsigned fileNo, unsigned numFiles){
    +static int FIO_listFile(fileInfo_t* total, const char* inFileName, int displayLevel){
         /* initialize info to avoid warnings */
         fileInfo_t info;
         memset(&info, 0, sizeof(info));
    -    DISPLAYOUT("%s (%u/%u):\n", inFileName, fileNo, numFiles);
    -    {
    -        int const error = getFileInfo(&info, inFileName);
    +    {   int const error = getFileInfo(&info, inFileName);
             if (error == 1) {
                 /* display error, but provide output */
    -            DISPLAY("An error occurred with getting file info\n");
    +            DISPLAY("An error occurred while getting file info \n");
             }
             else if (error == 2) {
    -            DISPLAYOUT("File %s not compressed with zstd\n", inFileName);
    -            if (displayLevel > 2) {
    -                DISPLAYOUT("\n");
    -            }
    +            DISPLAYOUT("File %s not compressed by zstd \n", inFileName);
    +            if (displayLevel > 2) DISPLAYOUT("\n");
                 return 1;
             }
             else if (error == 3) {
    -            /* error occurred with opening the file */
    -            if (displayLevel > 2) {
    -                DISPLAYOUT("\n");
    -            }
    +            /* error occurred while opening the file */
    +            if (displayLevel > 2) DISPLAYOUT("\n");
                 return 1;
             }
             displayInfo(inFileName, &info, displayLevel);
    +        *total = FIO_addFInfo(*total, info);
             return error;
         }
     }
    @@ -1934,15 +1951,36 @@ int FIO_listMultipleFiles(unsigned numFiles, const char** filenameTable, int dis
             DISPLAYOUT("No files given\n");
             return 0;
         }
    -    DISPLAYOUT("===========================================\n");
    -    DISPLAYOUT("Printing information about compressed files\n");
    -    DISPLAYOUT("===========================================\n");
    -    DISPLAYOUT("Number of files listed: %u\n", numFiles);
    -    {
    -        int error = 0;
    +    DISPLAYOUT("Frames  Skips  Compressed  Uncompressed  Ratio  Check  Filename\n");
    +    {   int error = 0;
             unsigned u;
    +        fileInfo_t total;
    +        memset(&total, 0, sizeof(total));
    +        total.usesCheck = 1;
             for (u=0; u 1) {
    +            unsigned const unit = total.compressedSize < (1 MB) ? (1 KB) : (1 MB);
    +            const char* const unitStr = total.compressedSize < (1 MB) ? "KB" : "MB";
    +            double const compressedSizeUnit = (double)total.compressedSize / unit;
    +            double const decompressedSizeUnit = (double)total.decompressedSize / unit;
    +            double const ratio = (total.compressedSize == 0) ? 0 : ((double)total.decompressedSize)/total.compressedSize;
    +            const char* const checkString = (total.usesCheck ? "XXH64" : "");
    +            DISPLAYOUT("----------------------------------------------------------------- \n");
    +            if (total.decompUnavailable) {
    +                DISPLAYOUT("%6d  %5d  %7.2f %2s                       %5s  %u files\n",
    +                        total.numSkippableFrames + total.numActualFrames,
    +                        total.numSkippableFrames,
    +                        compressedSizeUnit, unitStr,
    +                        checkString, total.nbFiles);
    +            } else {
    +                DISPLAYOUT("%6d  %5d  %7.2f %2s  %9.2f %2s  %5.3f  %5s  %u files\n",
    +                        total.numSkippableFrames + total.numActualFrames,
    +                        total.numSkippableFrames,
    +                        compressedSizeUnit, unitStr, decompressedSizeUnit, unitStr,
    +                        ratio, checkString, total.nbFiles);
    +            }
             }
             return error;
         }
    diff --git a/tests/fullbench.c b/tests/fullbench.c
    index bd9dc613..db00ce21 100644
    --- a/tests/fullbench.c
    +++ b/tests/fullbench.c
    @@ -376,6 +376,7 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb)
                 skippedSize = frameHeaderSize + ZSTD_blockHeaderSize;
                 memcpy(buff2, dstBuff+skippedSize, g_cSize-skippedSize);
                 srcSize = srcSize > 128 KB ? 128 KB : srcSize;    /* speed relative to block */
    +            ZSTD_decompressBegin(g_zdc);
                 break;
             }
         case 32:   /* ZSTD_decodeSeqHeaders */
    diff --git a/tests/fuzz/.gitignore b/tests/fuzz/.gitignore
    new file mode 100644
    index 00000000..4ff28de9
    --- /dev/null
    +++ b/tests/fuzz/.gitignore
    @@ -0,0 +1,5 @@
    +# test artefacts
    +corpora
    +block_decompress
    +block_round_trip
    +simple_round_trip
    diff --git a/tests/fuzz/default.options b/tests/fuzz/default.options
    new file mode 100644
    index 00000000..8ea85883
    --- /dev/null
    +++ b/tests/fuzz/default.options
    @@ -0,0 +1,2 @@
    +[libfuzzer]
    +max_len = 8192
    diff --git a/tests/fuzz/fuzz.py b/tests/fuzz/fuzz.py
    index 9864d822..b591e4f6 100755
    --- a/tests/fuzz/fuzz.py
    +++ b/tests/fuzz/fuzz.py
    @@ -1,4 +1,4 @@
    -#! /usr/bin/env python
    +#!/usr/bin/env python
     
     # ################################################################
     # Copyright (c) 2016-present, Facebook, Inc.
    @@ -757,6 +757,10 @@ def zip_cmd(args):
             subprocess.check_call(cmd + seeds)
     
     
    +def list_cmd(args):
    +    print("\n".join(TARGETS))
    +
    +
     def short_help(args):
         name = args[0]
         print("Usage: {} [OPTIONS] COMMAND [ARGS]...\n".format(name))
    @@ -776,6 +780,7 @@ def help(args):
         print("\tgen\t\tGenerate a seed corpus for a fuzzer")
         print("\tminimize\tMinimize the test corpora")
         print("\tzip\t\tZip the minimized corpora up")
    +    print("\tlist\t\tList the available targets")
     
     
     def main():
    @@ -802,6 +807,8 @@ def main():
             return minimize(args)
         if command == "zip":
             return zip_cmd(args)
    +    if command == "list":
    +        return list_cmd(args)
         short_help(args)
         print("Error: No such command {} (pass -h for help)".format(command))
         return 1
    diff --git a/tests/fuzzer.c b/tests/fuzzer.c
    index bfa290c6..e77aab36 100644
    --- a/tests/fuzzer.c
    +++ b/tests/fuzzer.c
    @@ -918,6 +918,43 @@ static int basicUnitTests(U32 seed, double compressibility)
             ZSTD_freeCCtx(cctx);
         }
     
    +    /* custom formats tests */
    +    {   ZSTD_CCtx* const cctx = ZSTD_createCCtx();
    +        size_t const inputSize = CNBuffSize / 2;   /* won't cause pb with small dict size */
    +
    +        /* basic block compression */
    +        DISPLAYLEVEL(4, "test%3i : magic-less format test : ", testNb++);
    +        CHECK( ZSTD_CCtx_setParameter(cctx, ZSTD_p_format, ZSTD_f_zstd1_magicless) );
    +        {   ZSTD_inBuffer in = { CNBuffer, inputSize, 0 };
    +            ZSTD_outBuffer out = { compressedBuffer, ZSTD_compressBound(inputSize), 0 };
    +            size_t const result = ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end);
    +            if (result != 0) goto _output_error;
    +            if (in.pos != in.size) goto _output_error;
    +            cSize = out.pos;
    +        }
    +        DISPLAYLEVEL(4, "OK (compress : %u -> %u bytes)\n", (U32)inputSize, (U32)cSize);
    +
    +        DISPLAYLEVEL(4, "test%3i : decompress normally (should fail) : ", testNb++);
    +        {   size_t const decodeResult = ZSTD_decompressDCtx(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize);
    +            if (ZSTD_getErrorCode(decodeResult) != ZSTD_error_prefix_unknown) goto _output_error;
    +            DISPLAYLEVEL(4, "OK : %s \n", ZSTD_getErrorName(decodeResult));
    +        }
    +
    +        DISPLAYLEVEL(4, "test%3i : decompress with magic-less instruction : ", testNb++);
    +        ZSTD_DCtx_reset(dctx);
    +        CHECK( ZSTD_DCtx_setFormat(dctx, ZSTD_f_zstd1_magicless) );
    +        {   ZSTD_inBuffer in = { compressedBuffer, cSize, 0 };
    +            ZSTD_outBuffer out = { decodedBuffer, CNBuffSize, 0 };
    +            size_t const result = ZSTD_decompress_generic(dctx, &out, &in);
    +            if (result != 0) goto _output_error;
    +            if (in.pos != in.size) goto _output_error;
    +            if (out.pos != inputSize) goto _output_error;
    +            DISPLAYLEVEL(4, "OK : regenerated %u bytes \n", (U32)out.pos);
    +        }
    +
    +        ZSTD_freeCCtx(cctx);
    +    }
    +
         /* block API tests */
         {   ZSTD_CCtx* const cctx = ZSTD_createCCtx();
             static const size_t dictSize = 65 KB;
    @@ -961,8 +998,8 @@ static int basicUnitTests(U32 seed, double compressibility)
             DISPLAYLEVEL(4, "OK \n");
     
             ZSTD_freeCCtx(cctx);
    -        ZSTD_freeDCtx(dctx);
         }
    +    ZSTD_freeDCtx(dctx);
     
         /* long rle test */
         {   size_t sampleSize = 0;
    diff --git a/tests/paramgrill.c b/tests/paramgrill.c
    index 1bc48f40..317ec461 100644
    --- a/tests/paramgrill.c
    +++ b/tests/paramgrill.c
    @@ -391,8 +391,8 @@ static int BMK_seed(winnerInfo_t* winners, const ZSTD_compressionParameters para
                 double W_DMemUsed_note = W_ratioNote * ( 40 + 9*cLevel) - log((double)W_DMemUsed);
                 double O_DMemUsed_note = O_ratioNote * ( 40 + 9*cLevel) - log((double)O_DMemUsed);
     
    -            size_t W_CMemUsed = (1 << params.windowLog) + ZSTD_estimateCCtxSize_advanced_usingCParams(params);
    -            size_t O_CMemUsed = (1 << winners[cLevel].params.windowLog) + ZSTD_estimateCCtxSize_advanced_usingCParams(winners[cLevel].params);
    +            size_t W_CMemUsed = (1 << params.windowLog) + ZSTD_estimateCCtxSize_usingCParams(params);
    +            size_t O_CMemUsed = (1 << winners[cLevel].params.windowLog) + ZSTD_estimateCCtxSize_usingCParams(winners[cLevel].params);
                 double W_CMemUsed_note = W_ratioNote * ( 50 + 13*cLevel) - log((double)W_CMemUsed);
                 double O_CMemUsed_note = O_ratioNote * ( 50 + 13*cLevel) - log((double)O_CMemUsed);
     
    diff --git a/tests/playTests.sh b/tests/playTests.sh
    index a4cd4ffb..b588949c 100755
    --- a/tests/playTests.sh
    +++ b/tests/playTests.sh
    @@ -55,7 +55,6 @@ then
     fi
     
     isWindows=false
    -ECHO="echo -e"
     INTOVOID="/dev/null"
     case "$OS" in
       Windows*)
    @@ -76,6 +75,11 @@ case "$UNAME" in
       SunOS) DIFF="gdiff" ;;
     esac
     
    +ECHO="echo -e"
    +case "$UNAME" in
    +  Darwin) ECHO="echo" ;;
    +esac
    +
     $ECHO "\nStarting playTests.sh isWindows=$isWindows ZSTD='$ZSTD'"
     
     [ -n "$ZSTD" ] || die "ZSTD variable must be defined!"
    diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c
    index f69cdd64..6ae4ef96 100644
    --- a/tests/zstreamtest.c
    +++ b/tests/zstreamtest.c
    @@ -206,11 +206,11 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
         /* context size functions */
         DISPLAYLEVEL(3, "test%3i : estimate CStream size : ", testNb++);
         {   ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictSize);
    -        size_t const s = ZSTD_estimateCStreamSize_advanced_usingCParams(cParams)
    -                        /* uses ZSTD_initCStream_usingDict() */
    -                       + ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy);
    -            if (ZSTD_isError(s)) goto _output_error;
    -            DISPLAYLEVEL(3, "OK (%u bytes) \n", (U32)s);
    +        size_t const cstreamSize = ZSTD_estimateCStreamSize_usingCParams(cParams);
    +        size_t const cdictSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); /* uses ZSTD_initCStream_usingDict() */
    +        if (ZSTD_isError(cstreamSize)) goto _output_error;
    +        if (ZSTD_isError(cdictSize)) goto _output_error;
    +        DISPLAYLEVEL(3, "OK (%u bytes) \n", (U32)(cstreamSize + cdictSize));
         }
     
         DISPLAYLEVEL(3, "test%3i : check actual CStream size : ", testNb++);
    @@ -894,7 +894,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres
                     size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
                     size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
                     inBuff.size = inBuff.pos + readCSrcSize;
    -                outBuff.size = inBuff.pos + dstBuffSize;
    +                outBuff.size = outBuff.pos + dstBuffSize;
                     decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
                     if (ZSTD_getErrorCode(decompressionResult) == ZSTD_error_checksum_wrong) {
                         DISPLAY("checksum error : \n");
    @@ -1160,7 +1160,7 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
                     size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
                     size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
                     inBuff.size = inBuff.pos + readCSrcSize;
    -                outBuff.size = inBuff.pos + dstBuffSize;
    +                outBuff.size = outBuff.pos + dstBuffSize;
                     DISPLAYLEVEL(5, "ZSTD_decompressStream input %u bytes \n", (U32)readCSrcSize);
                     decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
                     CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult));
    @@ -1505,7 +1505,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
                     size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
                     size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
                     inBuff.size = inBuff.pos + readCSrcSize;
    -                outBuff.size = inBuff.pos + dstBuffSize;
    +                outBuff.size = outBuff.pos + dstBuffSize;
                     DISPLAYLEVEL(6, "ZSTD_decompressStream input %u bytes (pos:%u/%u)\n",
                                 (U32)readCSrcSize, (U32)inBuff.pos, (U32)cSize);
                     decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);