1/*
2LZ4 auto-framing library
3Copyright (C) 2011-2016, Yann Collet.
4
5BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6
7Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are
9met:
10
11* Redistributions of source code must retain the above copyright
12notice, this list of conditions and the following disclaimer.
13* Redistributions in binary form must reproduce the above
14copyright notice, this list of conditions and the following disclaimer
15in the documentation and/or other materials provided with the
16distribution.
17
18THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30You can contact the author at :
31- LZ4 homepage : http://www.lz4.org
32- LZ4 source repository : https://github.com/lz4/lz4
33*/
34
35/* LZ4F is a stand-alone API to create LZ4-compressed Frames
36*  in full conformance with specification v1.5.0
37*  All related operations, including memory management, are handled by the library.
38* */
39
40
41/*-************************************
42*  Compiler Options
43**************************************/
44#ifdef _MSC_VER    /* Visual Studio */
45#  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */
46#endif
47
48
49/*-************************************
50*  Memory routines
51**************************************/
52#include <stdlib.h>   /* malloc, calloc, free */
53#define ALLOCATOR(s)   calloc(1,s)
54#define FREEMEM        free
55#include <string.h>   /* memset, memcpy, memmove */
56#define MEM_INIT       memset
57
58
59/*-************************************
60*  Includes
61**************************************/
62#include "lz4frame_static.h"
63#include "lz4.h"
64#include "lz4hc.h"
65#define XXH_STATIC_LINKING_ONLY
66#include "xxhash.h"
67
68
69/*-************************************
70*  Common Utils
71**************************************/
72#define LZ4_STATIC_ASSERT(c)    { enum { LZ4_static_assert = 1/(int)(!!(c)) }; }   /* use only *after* variable declarations */
73
74
75/*-************************************
76*  Basic Types
77**************************************/
78#if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
79# include <stdint.h>
80  typedef  uint8_t BYTE;
81  typedef uint16_t U16;
82  typedef uint32_t U32;
83  typedef  int32_t S32;
84  typedef uint64_t U64;
85#else
86  typedef unsigned char       BYTE;
87  typedef unsigned short      U16;
88  typedef unsigned int        U32;
89  typedef   signed int        S32;
90  typedef unsigned long long  U64;
91#endif
92
93
94/* unoptimized version; solves endianess & alignment issues */
95static U32 LZ4F_readLE32 (const void* src)
96{
97    const BYTE* const srcPtr = (const BYTE*)src;
98    U32 value32 = srcPtr[0];
99    value32 += (srcPtr[1]<<8);
100    value32 += (srcPtr[2]<<16);
101    value32 += ((U32)srcPtr[3])<<24;
102    return value32;
103}
104
105static void LZ4F_writeLE32 (void* dst, U32 value32)
106{
107    BYTE* const dstPtr = (BYTE*)dst;
108    dstPtr[0] = (BYTE)value32;
109    dstPtr[1] = (BYTE)(value32 >> 8);
110    dstPtr[2] = (BYTE)(value32 >> 16);
111    dstPtr[3] = (BYTE)(value32 >> 24);
112}
113
114static U64 LZ4F_readLE64 (const void* src)
115{
116    const BYTE* const srcPtr = (const BYTE*)src;
117    U64 value64 = srcPtr[0];
118    value64 += ((U64)srcPtr[1]<<8);
119    value64 += ((U64)srcPtr[2]<<16);
120    value64 += ((U64)srcPtr[3]<<24);
121    value64 += ((U64)srcPtr[4]<<32);
122    value64 += ((U64)srcPtr[5]<<40);
123    value64 += ((U64)srcPtr[6]<<48);
124    value64 += ((U64)srcPtr[7]<<56);
125    return value64;
126}
127
128static void LZ4F_writeLE64 (void* dst, U64 value64)
129{
130    BYTE* const dstPtr = (BYTE*)dst;
131    dstPtr[0] = (BYTE)value64;
132    dstPtr[1] = (BYTE)(value64 >> 8);
133    dstPtr[2] = (BYTE)(value64 >> 16);
134    dstPtr[3] = (BYTE)(value64 >> 24);
135    dstPtr[4] = (BYTE)(value64 >> 32);
136    dstPtr[5] = (BYTE)(value64 >> 40);
137    dstPtr[6] = (BYTE)(value64 >> 48);
138    dstPtr[7] = (BYTE)(value64 >> 56);
139}
140
141
142/*-************************************
143*  Constants
144**************************************/
145#define KB *(1<<10)
146#define MB *(1<<20)
147#define GB *(1<<30)
148
149#define _1BIT  0x01
150#define _2BITS 0x03
151#define _3BITS 0x07
152#define _4BITS 0x0F
153#define _8BITS 0xFF
154
155#define LZ4F_MAGIC_SKIPPABLE_START 0x184D2A50U
156#define LZ4F_MAGICNUMBER 0x184D2204U
157#define LZ4F_BLOCKUNCOMPRESSED_FLAG 0x80000000U
158#define LZ4F_BLOCKSIZEID_DEFAULT LZ4F_max64KB
159
160static const size_t minFHSize = 7;
161static const size_t maxFHSize = LZ4F_HEADER_SIZE_MAX;   /* 15 */
162static const size_t BHSize = 4;
163
164
165/*-************************************
166*  Structures and local types
167**************************************/
168typedef struct LZ4F_cctx_s
169{
170    LZ4F_preferences_t prefs;
171    U32    version;
172    U32    cStage;
173    size_t maxBlockSize;
174    size_t maxBufferSize;
175    BYTE*  tmpBuff;
176    BYTE*  tmpIn;
177    size_t tmpInSize;
178    U64    totalInSize;
179    XXH32_state_t xxh;
180    void*  lz4CtxPtr;
181    U32    lz4CtxLevel;     /* 0: unallocated;  1: LZ4_stream_t;  3: LZ4_streamHC_t */
182} LZ4F_cctx_t;
183
184
185/*-************************************
186*  Error management
187**************************************/
188#define LZ4F_GENERATE_STRING(STRING) #STRING,
189static const char* LZ4F_errorStrings[] = { LZ4F_LIST_ERRORS(LZ4F_GENERATE_STRING) };
190
191
192unsigned LZ4F_isError(LZ4F_errorCode_t code)
193{
194    return (code > (LZ4F_errorCode_t)(-LZ4F_ERROR_maxCode));
195}
196
197const char* LZ4F_getErrorName(LZ4F_errorCode_t code)
198{
199    static const char* codeError = "Unspecified error code";
200    if (LZ4F_isError(code)) return LZ4F_errorStrings[-(int)(code)];
201    return codeError;
202}
203
204LZ4F_errorCodes LZ4F_getErrorCode(size_t functionResult)
205{
206    if (!LZ4F_isError(functionResult)) return LZ4F_OK_NoError;
207    return (LZ4F_errorCodes)(-(ptrdiff_t)functionResult);
208}
209
210static LZ4F_errorCode_t err0r(LZ4F_errorCodes code)
211{
212    LZ4_STATIC_ASSERT(sizeof(ptrdiff_t) >= sizeof(size_t));    /* A compilation error here means sizeof(ptrdiff_t) is not large enough */
213    return (LZ4F_errorCode_t)-(ptrdiff_t)code;
214}
215
216unsigned LZ4F_getVersion(void) { return LZ4F_VERSION; }
217
218
219/*-************************************
220*  Private functions
221**************************************/
222#define MIN(a,b)   ( (a) < (b) ? (a) : (b) )
223
224static size_t LZ4F_getBlockSize(unsigned blockSizeID)
225{
226    static const size_t blockSizes[4] = { 64 KB, 256 KB, 1 MB, 4 MB };
227
228    if (blockSizeID == 0) blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT;
229    blockSizeID -= 4;
230    if (blockSizeID > 3) return err0r(LZ4F_ERROR_maxBlockSize_invalid);
231    return blockSizes[blockSizeID];
232}
233
234static BYTE LZ4F_headerChecksum (const void* header, size_t length)
235{
236    U32 const xxh = XXH32(header, length, 0);
237    return (BYTE)(xxh >> 8);
238}
239
240
241/*-************************************
242*  Simple-pass compression functions
243**************************************/
244static LZ4F_blockSizeID_t LZ4F_optimalBSID(const LZ4F_blockSizeID_t requestedBSID, const size_t srcSize)
245{
246    LZ4F_blockSizeID_t proposedBSID = LZ4F_max64KB;
247    size_t maxBlockSize = 64 KB;
248    while (requestedBSID > proposedBSID) {
249        if (srcSize <= maxBlockSize)
250            return proposedBSID;
251        proposedBSID = (LZ4F_blockSizeID_t)((int)proposedBSID + 1);
252        maxBlockSize <<= 2;
253    }
254    return requestedBSID;
255}
256
257/* LZ4F_compressBound() :
258 * Provides dstCapacity given a srcSize to guarantee operation success in worst case situations.
259 * prefsPtr is optional : you can provide NULL as argument, preferences will be set to cover worst case scenario.
260 * Result is always the same for a srcSize and prefsPtr, so it can be trusted to size reusable buffers.
261 * When srcSize==0, LZ4F_compressBound() provides an upper bound for LZ4F_flush() and LZ4F_compressEnd() operations.
262 */
263static size_t LZ4F_compressBound_internal(size_t srcSize, const LZ4F_preferences_t* preferencesPtr, size_t alreadyBuffered)
264{
265    LZ4F_preferences_t prefsNull;
266    memset(&prefsNull, 0, sizeof(prefsNull));
267    prefsNull.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;   /* worst case */
268    {   const LZ4F_preferences_t* const prefsPtr = (preferencesPtr==NULL) ? &prefsNull : preferencesPtr;
269        U32 const flush = prefsPtr->autoFlush | (srcSize==0);
270        LZ4F_blockSizeID_t const bid = prefsPtr->frameInfo.blockSizeID;
271        size_t const blockSize = LZ4F_getBlockSize(bid);
272        size_t const maxBuffered = blockSize - 1;
273        size_t const bufferedSize = MIN(alreadyBuffered, maxBuffered);
274        size_t const maxSrcSize = srcSize + bufferedSize;
275        unsigned const nbFullBlocks = (unsigned)(maxSrcSize / blockSize);
276        size_t const partialBlockSize = (srcSize - (srcSize==0)) & (blockSize-1);   /* 0 => -1 == MAX => blockSize-1 */
277        size_t const lastBlockSize = flush ? partialBlockSize : 0;
278        unsigned const nbBlocks = nbFullBlocks + (lastBlockSize>0);
279
280        size_t const blockHeaderSize = 4;   /* default, without block CRC option (which cannot be generated with current API) */
281        size_t const frameEnd = 4 + (prefsPtr->frameInfo.contentChecksumFlag*4);
282
283        return (blockHeaderSize * nbBlocks) + (blockSize * nbFullBlocks) + lastBlockSize + frameEnd;;
284    }
285}
286
287size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr)
288{
289    LZ4F_preferences_t prefs;
290    size_t const headerSize = maxFHSize;      /* max header size, including magic number and frame content size */
291
292    if (preferencesPtr!=NULL) prefs = *preferencesPtr;
293    else memset(&prefs, 0, sizeof(prefs));
294    prefs.autoFlush = 1;
295
296    return headerSize + LZ4F_compressBound_internal(srcSize, &prefs, 0);;
297}
298
299
300/*! LZ4F_compressFrame() :
301* Compress an entire srcBuffer into a valid LZ4 frame, as defined by specification v1.5.0, in a single step.
302* The most important rule is that dstBuffer MUST be large enough (dstMaxSize) to ensure compression completion even in worst case.
303* You can get the minimum value of dstMaxSize by using LZ4F_compressFrameBound()
304* If this condition is not respected, LZ4F_compressFrame() will fail (result is an errorCode)
305* The LZ4F_preferences_t structure is optional : you can provide NULL as argument. All preferences will then be set to default.
306* The result of the function is the number of bytes written into dstBuffer.
307* The function outputs an error code if it fails (can be tested using LZ4F_isError())
308*/
309size_t LZ4F_compressFrame(void* dstBuffer, size_t dstCapacity, const void* srcBuffer, size_t srcSize, const LZ4F_preferences_t* preferencesPtr)
310{
311    LZ4F_cctx_t cctxI;
312    LZ4_stream_t lz4ctx;
313    LZ4F_preferences_t prefs;
314    LZ4F_compressOptions_t options;
315    BYTE* const dstStart = (BYTE*) dstBuffer;
316    BYTE* dstPtr = dstStart;
317    BYTE* const dstEnd = dstStart + dstCapacity;
318
319    memset(&cctxI, 0, sizeof(cctxI));   /* works because no allocation */
320    memset(&options, 0, sizeof(options));
321
322    cctxI.version = LZ4F_VERSION;
323    cctxI.maxBufferSize = 5 MB;   /* mess with real buffer size to prevent allocation; works because autoflush==1 & stableSrc==1 */
324
325    if (preferencesPtr!=NULL)
326        prefs = *preferencesPtr;
327    else
328        memset(&prefs, 0, sizeof(prefs));
329    if (prefs.frameInfo.contentSize != 0)
330        prefs.frameInfo.contentSize = (U64)srcSize;   /* auto-correct content size if selected (!=0) */
331
332    if (prefs.compressionLevel < LZ4HC_CLEVEL_MIN) {
333        cctxI.lz4CtxPtr = &lz4ctx;
334        cctxI.lz4CtxLevel = 1;
335    }
336
337    prefs.frameInfo.blockSizeID = LZ4F_optimalBSID(prefs.frameInfo.blockSizeID, srcSize);
338    prefs.autoFlush = 1;
339    if (srcSize <= LZ4F_getBlockSize(prefs.frameInfo.blockSizeID))
340        prefs.frameInfo.blockMode = LZ4F_blockIndependent;   /* no need for linked blocks */
341
342    options.stableSrc = 1;
343
344    if (dstCapacity < LZ4F_compressFrameBound(srcSize, &prefs))
345        return err0r(LZ4F_ERROR_dstMaxSize_tooSmall);
346
347    { size_t const headerSize = LZ4F_compressBegin(&cctxI, dstBuffer, dstCapacity, &prefs);  /* write header */
348      if (LZ4F_isError(headerSize)) return headerSize;
349      dstPtr += headerSize;   /* header size */ }
350
351    { size_t const cSize = LZ4F_compressUpdate(&cctxI, dstPtr, dstEnd-dstPtr, srcBuffer, srcSize, &options);
352      if (LZ4F_isError(cSize)) return cSize;
353      dstPtr += cSize; }
354
355    { size_t const tailSize = LZ4F_compressEnd(&cctxI, dstPtr, dstEnd-dstPtr, &options);   /* flush last block, and generate suffix */
356      if (LZ4F_isError(tailSize)) return tailSize;
357      dstPtr += tailSize; }
358
359    if (prefs.compressionLevel >= LZ4HC_CLEVEL_MIN)   /* no allocation done with lz4 fast */
360        FREEMEM(cctxI.lz4CtxPtr);
361
362    return (dstPtr - dstStart);
363}
364
365
366/*-*********************************
367*  Advanced compression functions
368***********************************/
369
370/*! LZ4F_createCompressionContext() :
371 * The first thing to do is to create a compressionContext object, which will be used in all compression operations.
372 * This is achieved using LZ4F_createCompressionContext(), which takes as argument a version and an LZ4F_preferences_t structure.
373 * The version provided MUST be LZ4F_VERSION. It is intended to track potential version differences between different binaries.
374 * The function will provide a pointer to an allocated LZ4F_compressionContext_t object.
375 * If the result LZ4F_errorCode_t is not OK_NoError, there was an error during context creation.
376 * Object can release its memory using LZ4F_freeCompressionContext();
377 */
378LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_compressionContext_t* LZ4F_compressionContextPtr, unsigned version)
379{
380    LZ4F_cctx_t* const cctxPtr = (LZ4F_cctx_t*)ALLOCATOR(sizeof(LZ4F_cctx_t));
381    if (cctxPtr==NULL) return err0r(LZ4F_ERROR_allocation_failed);
382
383    cctxPtr->version = version;
384    cctxPtr->cStage = 0;   /* Next stage : write header */
385
386    *LZ4F_compressionContextPtr = (LZ4F_compressionContext_t)cctxPtr;
387
388    return LZ4F_OK_NoError;
389}
390
391
392LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_compressionContext_t LZ4F_compressionContext)
393{
394    LZ4F_cctx_t* const cctxPtr = (LZ4F_cctx_t*)LZ4F_compressionContext;
395
396    if (cctxPtr != NULL) {  /* null pointers can be safely provided to this function, like free() */
397       FREEMEM(cctxPtr->lz4CtxPtr);
398       FREEMEM(cctxPtr->tmpBuff);
399       FREEMEM(LZ4F_compressionContext);
400    }
401
402    return LZ4F_OK_NoError;
403}
404
405
406/*! LZ4F_compressBegin() :
407 * will write the frame header into dstBuffer.
408 * dstBuffer must be large enough to accommodate a header (dstCapacity). Maximum header size is LZ4F_HEADER_SIZE_MAX bytes.
409 * @return : number of bytes written into dstBuffer for the header
410 *           or an error code (can be tested using LZ4F_isError())
411 */
412size_t LZ4F_compressBegin(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstCapacity, const LZ4F_preferences_t* preferencesPtr)
413{
414    LZ4F_preferences_t prefNull;
415    BYTE* const dstStart = (BYTE*)dstBuffer;
416    BYTE* dstPtr = dstStart;
417    BYTE* headerStart;
418    size_t requiredBuffSize;
419
420    if (dstCapacity < maxFHSize) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall);
421    if (cctxPtr->cStage != 0) return err0r(LZ4F_ERROR_GENERIC);
422    memset(&prefNull, 0, sizeof(prefNull));
423    if (preferencesPtr == NULL) preferencesPtr = &prefNull;
424    cctxPtr->prefs = *preferencesPtr;
425
426    /* ctx Management */
427    {   U32 const tableID = (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) ? 1 : 2;  /* 0:nothing ; 1:LZ4 table ; 2:HC tables */
428        if (cctxPtr->lz4CtxLevel < tableID) {
429            FREEMEM(cctxPtr->lz4CtxPtr);
430            if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN)
431                cctxPtr->lz4CtxPtr = (void*)LZ4_createStream();
432            else
433                cctxPtr->lz4CtxPtr = (void*)LZ4_createStreamHC();
434            cctxPtr->lz4CtxLevel = tableID;
435        }
436    }
437
438    /* Buffer Management */
439    if (cctxPtr->prefs.frameInfo.blockSizeID == 0) cctxPtr->prefs.frameInfo.blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT;
440    cctxPtr->maxBlockSize = LZ4F_getBlockSize(cctxPtr->prefs.frameInfo.blockSizeID);
441
442    requiredBuffSize = cctxPtr->maxBlockSize + ((cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) * 128 KB);
443    if (preferencesPtr->autoFlush)
444        requiredBuffSize = (cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) * 64 KB;   /* just needs dict */
445
446    if (cctxPtr->maxBufferSize < requiredBuffSize) {
447        cctxPtr->maxBufferSize = requiredBuffSize;
448        FREEMEM(cctxPtr->tmpBuff);
449        cctxPtr->tmpBuff = (BYTE*)ALLOCATOR(requiredBuffSize);
450        if (cctxPtr->tmpBuff == NULL) return err0r(LZ4F_ERROR_allocation_failed);
451    }
452    cctxPtr->tmpIn = cctxPtr->tmpBuff;
453    cctxPtr->tmpInSize = 0;
454    XXH32_reset(&(cctxPtr->xxh), 0);
455    if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN)
456        LZ4_resetStream((LZ4_stream_t*)(cctxPtr->lz4CtxPtr));
457    else
458        LZ4_resetStreamHC((LZ4_streamHC_t*)(cctxPtr->lz4CtxPtr), cctxPtr->prefs.compressionLevel);
459
460    /* Magic Number */
461    LZ4F_writeLE32(dstPtr, LZ4F_MAGICNUMBER);
462    dstPtr += 4;
463    headerStart = dstPtr;
464
465    /* FLG Byte */
466    *dstPtr++ = (BYTE)(((1 & _2BITS) << 6)    /* Version('01') */
467        + ((cctxPtr->prefs.frameInfo.blockMode & _1BIT ) << 5)    /* Block mode */
468        + ((cctxPtr->prefs.frameInfo.contentChecksumFlag & _1BIT ) << 2)   /* Frame checksum */
469        + ((cctxPtr->prefs.frameInfo.contentSize > 0) << 3));   /* Frame content size */
470    /* BD Byte */
471    *dstPtr++ = (BYTE)((cctxPtr->prefs.frameInfo.blockSizeID & _3BITS) << 4);
472    /* Optional Frame content size field */
473    if (cctxPtr->prefs.frameInfo.contentSize) {
474        LZ4F_writeLE64(dstPtr, cctxPtr->prefs.frameInfo.contentSize);
475        dstPtr += 8;
476        cctxPtr->totalInSize = 0;
477    }
478    /* CRC Byte */
479    *dstPtr = LZ4F_headerChecksum(headerStart, dstPtr - headerStart);
480    dstPtr++;
481
482    cctxPtr->cStage = 1;   /* header written, now request input data block */
483
484    return (dstPtr - dstStart);
485}
486
487
488/* LZ4F_compressBound() :
489 *      @ return size of Dst buffer given a srcSize to handle worst case situations.
490 *      The LZ4F_frameInfo_t structure is optional : if NULL, preferences will be set to cover worst case situations.
491 *      This function cannot fail.
492 */
493size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr)
494{
495    return LZ4F_compressBound_internal(srcSize, preferencesPtr, (size_t)-1);
496}
497
498
499typedef int (*compressFunc_t)(void* ctx, const char* src, char* dst, int srcSize, int dstSize, int level);
500
501static size_t LZ4F_compressBlock(void* dst, const void* src, size_t srcSize, compressFunc_t compress, void* lz4ctx, int level)
502{
503    /* compress a single block */
504    BYTE* const cSizePtr = (BYTE*)dst;
505    U32 cSize = (U32)compress(lz4ctx, (const char*)src, (char*)(cSizePtr+4), (int)(srcSize), (int)(srcSize-1), level);
506    LZ4F_writeLE32(cSizePtr, cSize);
507    if (cSize == 0) {  /* compression failed */
508        cSize = (U32)srcSize;
509        LZ4F_writeLE32(cSizePtr, cSize | LZ4F_BLOCKUNCOMPRESSED_FLAG);
510        memcpy(cSizePtr+4, src, srcSize);
511    }
512    return cSize + 4;
513}
514
515
516static int LZ4F_localLZ4_compress_limitedOutput_withState(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level)
517{
518    (void) level;
519    return LZ4_compress_fast_extState(ctx, src, dst, srcSize, dstCapacity, 1);
520}
521
522static int LZ4F_localLZ4_compress_limitedOutput_continue(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level)
523{
524    (void) level;
525    return LZ4_compress_fast_continue((LZ4_stream_t*)ctx, src, dst, srcSize, dstCapacity, 1);
526}
527
528static int LZ4F_localLZ4_compressHC_limitedOutput_continue(void* ctx, const char* src, char* dst, int srcSize, int dstSize, int level)
529{
530    (void) level;
531    return LZ4_compress_HC_continue((LZ4_streamHC_t*)ctx, src, dst, srcSize, dstSize);
532}
533
534static compressFunc_t LZ4F_selectCompression(LZ4F_blockMode_t blockMode, int level)
535{
536    if (level < LZ4HC_CLEVEL_MIN) {
537        if (blockMode == LZ4F_blockIndependent) return LZ4F_localLZ4_compress_limitedOutput_withState;
538        return LZ4F_localLZ4_compress_limitedOutput_continue;
539    }
540    if (blockMode == LZ4F_blockIndependent) return LZ4_compress_HC_extStateHC;
541    return LZ4F_localLZ4_compressHC_limitedOutput_continue;
542}
543
544static int LZ4F_localSaveDict(LZ4F_cctx_t* cctxPtr)
545{
546    if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN)
547        return LZ4_saveDict ((LZ4_stream_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), 64 KB);
548    return LZ4_saveDictHC ((LZ4_streamHC_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), 64 KB);
549}
550
551typedef enum { notDone, fromTmpBuffer, fromSrcBuffer } LZ4F_lastBlockStatus;
552
553/*! LZ4F_compressUpdate() :
554* LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary.
555* The most important rule is that dstBuffer MUST be large enough (dstCapacity) to ensure compression completion even in worst case.
556* If this condition is not respected, LZ4F_compress() will fail (result is an errorCode)
557* You can get the minimum value of dstCapacity by using LZ4F_compressBound()
558* The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
559* The result of the function is the number of bytes written into dstBuffer : it can be zero, meaning input data was just buffered.
560* The function outputs an error code if it fails (can be tested using LZ4F_isError())
561*/
562size_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstCapacity, const void* srcBuffer, size_t srcSize, const LZ4F_compressOptions_t* compressOptionsPtr)
563{
564    LZ4F_compressOptions_t cOptionsNull;
565    size_t const blockSize = cctxPtr->maxBlockSize;
566    const BYTE* srcPtr = (const BYTE*)srcBuffer;
567    const BYTE* const srcEnd = srcPtr + srcSize;
568    BYTE* const dstStart = (BYTE*)dstBuffer;
569    BYTE* dstPtr = dstStart;
570    LZ4F_lastBlockStatus lastBlockCompressed = notDone;
571    compressFunc_t const compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel);
572
573
574    if (cctxPtr->cStage != 1) return err0r(LZ4F_ERROR_GENERIC);
575    if (dstCapacity < LZ4F_compressBound_internal(srcSize, &(cctxPtr->prefs), cctxPtr->tmpInSize)) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall);
576    memset(&cOptionsNull, 0, sizeof(cOptionsNull));
577    if (compressOptionsPtr == NULL) compressOptionsPtr = &cOptionsNull;
578
579    /* complete tmp buffer */
580    if (cctxPtr->tmpInSize > 0) {   /* some data already within tmp buffer */
581        size_t const sizeToCopy = blockSize - cctxPtr->tmpInSize;
582        if (sizeToCopy > srcSize) {
583            /* add src to tmpIn buffer */
584            memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, srcSize);
585            srcPtr = srcEnd;
586            cctxPtr->tmpInSize += srcSize;
587            /* still needs some CRC */
588        } else {
589            /* complete tmpIn block and then compress it */
590            lastBlockCompressed = fromTmpBuffer;
591            memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, sizeToCopy);
592            srcPtr += sizeToCopy;
593
594            dstPtr += LZ4F_compressBlock(dstPtr, cctxPtr->tmpIn, blockSize, compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel);
595
596            if (cctxPtr->prefs.frameInfo.blockMode==LZ4F_blockLinked) cctxPtr->tmpIn += blockSize;
597            cctxPtr->tmpInSize = 0;
598        }
599    }
600
601    while ((size_t)(srcEnd - srcPtr) >= blockSize) {
602        /* compress full block */
603        lastBlockCompressed = fromSrcBuffer;
604        dstPtr += LZ4F_compressBlock(dstPtr, srcPtr, blockSize, compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel);
605        srcPtr += blockSize;
606    }
607
608    if ((cctxPtr->prefs.autoFlush) && (srcPtr < srcEnd)) {
609        /* compress remaining input < blockSize */
610        lastBlockCompressed = fromSrcBuffer;
611        dstPtr += LZ4F_compressBlock(dstPtr, srcPtr, srcEnd - srcPtr, compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel);
612        srcPtr  = srcEnd;
613    }
614
615    /* preserve dictionary if necessary */
616    if ((cctxPtr->prefs.frameInfo.blockMode==LZ4F_blockLinked) && (lastBlockCompressed==fromSrcBuffer)) {
617        if (compressOptionsPtr->stableSrc) {
618            cctxPtr->tmpIn = cctxPtr->tmpBuff;
619        } else {
620            int realDictSize = LZ4F_localSaveDict(cctxPtr);
621            if (realDictSize==0) return err0r(LZ4F_ERROR_GENERIC);
622            cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize;
623        }
624    }
625
626    /* keep tmpIn within limits */
627    if ((cctxPtr->tmpIn + blockSize) > (cctxPtr->tmpBuff + cctxPtr->maxBufferSize)   /* necessarily LZ4F_blockLinked && lastBlockCompressed==fromTmpBuffer */
628        && !(cctxPtr->prefs.autoFlush))
629    {
630        int realDictSize = LZ4F_localSaveDict(cctxPtr);
631        cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize;
632    }
633
634    /* some input data left, necessarily < blockSize */
635    if (srcPtr < srcEnd) {
636        /* fill tmp buffer */
637        size_t const sizeToCopy = srcEnd - srcPtr;
638        memcpy(cctxPtr->tmpIn, srcPtr, sizeToCopy);
639        cctxPtr->tmpInSize = sizeToCopy;
640    }
641
642    if (cctxPtr->prefs.frameInfo.contentChecksumFlag == LZ4F_contentChecksumEnabled)
643        XXH32_update(&(cctxPtr->xxh), srcBuffer, srcSize);
644
645    cctxPtr->totalInSize += srcSize;
646    return dstPtr - dstStart;
647}
648
649
650/*! LZ4F_flush() :
651* Should you need to create compressed data immediately, without waiting for a block to be filled,
652* you can call LZ4_flush(), which will immediately compress any remaining data stored within compressionContext.
653* The result of the function is the number of bytes written into dstBuffer
654* (it can be zero, this means there was no data left within compressionContext)
655* The function outputs an error code if it fails (can be tested using LZ4F_isError())
656* The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
657*/
658size_t LZ4F_flush(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstCapacity, const LZ4F_compressOptions_t* compressOptionsPtr)
659{
660    BYTE* const dstStart = (BYTE*)dstBuffer;
661    BYTE* dstPtr = dstStart;
662    compressFunc_t compress;
663
664    if (cctxPtr->tmpInSize == 0) return 0;   /* nothing to flush */
665    if (cctxPtr->cStage != 1) return err0r(LZ4F_ERROR_GENERIC);
666    if (dstCapacity < (cctxPtr->tmpInSize + 4)) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall);   /* +4 : block header(4)  */
667    (void)compressOptionsPtr;   /* not yet useful */
668
669    /* select compression function */
670    compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel);
671
672    /* compress tmp buffer */
673    dstPtr += LZ4F_compressBlock(dstPtr, cctxPtr->tmpIn, cctxPtr->tmpInSize, compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel);
674    if (cctxPtr->prefs.frameInfo.blockMode==LZ4F_blockLinked) cctxPtr->tmpIn += cctxPtr->tmpInSize;
675    cctxPtr->tmpInSize = 0;
676
677    /* keep tmpIn within limits */
678    if ((cctxPtr->tmpIn + cctxPtr->maxBlockSize) > (cctxPtr->tmpBuff + cctxPtr->maxBufferSize)) {  /* necessarily LZ4F_blockLinked */
679        int realDictSize = LZ4F_localSaveDict(cctxPtr);
680        cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize;
681    }
682
683    return dstPtr - dstStart;
684}
685
686
687/*! LZ4F_compressEnd() :
688* When you want to properly finish the compressed frame, just call LZ4F_compressEnd().
689* It will flush whatever data remained within compressionContext (like LZ4_flush())
690* but also properly finalize the frame, with an endMark and a checksum.
691* The result of the function is the number of bytes written into dstBuffer (necessarily >= 4 (endMark size))
692* The function outputs an error code if it fails (can be tested using LZ4F_isError())
693* The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
694* compressionContext can then be used again, starting with LZ4F_compressBegin(). The preferences will remain the same.
695*/
696size_t LZ4F_compressEnd(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstMaxSize, const LZ4F_compressOptions_t* compressOptionsPtr)
697{
698    BYTE* const dstStart = (BYTE*)dstBuffer;
699    BYTE* dstPtr = dstStart;
700
701    size_t const flushSize = LZ4F_flush(cctxPtr, dstBuffer, dstMaxSize, compressOptionsPtr);
702    if (LZ4F_isError(flushSize)) return flushSize;
703    dstPtr += flushSize;
704
705    LZ4F_writeLE32(dstPtr, 0);
706    dstPtr+=4;   /* endMark */
707
708    if (cctxPtr->prefs.frameInfo.contentChecksumFlag == LZ4F_contentChecksumEnabled) {
709        U32 const xxh = XXH32_digest(&(cctxPtr->xxh));
710        LZ4F_writeLE32(dstPtr, xxh);
711        dstPtr+=4;   /* content Checksum */
712    }
713
714    cctxPtr->cStage = 0;   /* state is now re-usable (with identical preferences) */
715    cctxPtr->maxBufferSize = 0;  /* reuse HC context */
716
717    if (cctxPtr->prefs.frameInfo.contentSize) {
718        if (cctxPtr->prefs.frameInfo.contentSize != cctxPtr->totalInSize)
719            return err0r(LZ4F_ERROR_frameSize_wrong);
720    }
721
722    return dstPtr - dstStart;
723}
724
725
726/*-***************************************************
727*   Frame Decompression
728*****************************************************/
729
730struct LZ4F_dctx_s {
731    LZ4F_frameInfo_t frameInfo;
732    U32    version;
733    U32    dStage;
734    U64    frameRemainingSize;
735    size_t maxBlockSize;
736    size_t maxBufferSize;
737    BYTE*  tmpIn;
738    size_t tmpInSize;
739    size_t tmpInTarget;
740    BYTE*  tmpOutBuffer;
741    const BYTE*  dict;
742    size_t dictSize;
743    BYTE*  tmpOut;
744    size_t tmpOutSize;
745    size_t tmpOutStart;
746    XXH32_state_t xxh;
747    BYTE   header[16];
748};  /* typedef'd to LZ4F_dctx in lz4frame.h */
749
750
751/*! LZ4F_createDecompressionContext() :
752*   Create a decompressionContext object, which will track all decompression operations.
753*   Provides a pointer to a fully allocated and initialized LZ4F_decompressionContext object.
754*   Object can later be released using LZ4F_freeDecompressionContext().
755*   @return : if != 0, there was an error during context creation.
756*/
757LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_dctx** LZ4F_decompressionContextPtr, unsigned versionNumber)
758{
759    LZ4F_dctx* const dctxPtr = (LZ4F_dctx*)ALLOCATOR(sizeof(LZ4F_dctx));
760    if (dctxPtr==NULL) return err0r(LZ4F_ERROR_GENERIC);
761
762    dctxPtr->version = versionNumber;
763    *LZ4F_decompressionContextPtr = dctxPtr;
764    return LZ4F_OK_NoError;
765}
766
767LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* const dctxPtr)
768{
769    LZ4F_errorCode_t result = LZ4F_OK_NoError;
770    if (dctxPtr != NULL) {   /* can accept NULL input, like free() */
771      result = (LZ4F_errorCode_t)dctxPtr->dStage;
772      FREEMEM(dctxPtr->tmpIn);
773      FREEMEM(dctxPtr->tmpOutBuffer);
774      FREEMEM(dctxPtr);
775    }
776    return result;
777}
778
779
780/*==---   Streaming Decompression operations   ---==*/
781
782typedef enum { dstage_getHeader=0, dstage_storeHeader,
783    dstage_getCBlockSize, dstage_storeCBlockSize,
784    dstage_copyDirect,
785    dstage_getCBlock, dstage_storeCBlock,
786    dstage_decodeCBlock, dstage_decodeCBlock_intoDst,
787    dstage_decodeCBlock_intoTmp, dstage_flushOut,
788    dstage_getSuffix, dstage_storeSuffix,
789    dstage_getSFrameSize, dstage_storeSFrameSize,
790    dstage_skipSkippable
791} dStage_t;
792
793
794/*! LZ4F_headerSize() :
795*   @return : size of frame header
796*             or an error code, which can be tested using LZ4F_isError()
797*/
798static size_t LZ4F_headerSize(const void* src, size_t srcSize)
799{
800    /* minimal srcSize to determine header size */
801    if (srcSize < 5) return err0r(LZ4F_ERROR_frameHeader_incomplete);
802
803    /* special case : skippable frames */
804    if ((LZ4F_readLE32(src) & 0xFFFFFFF0U) == LZ4F_MAGIC_SKIPPABLE_START) return 8;
805
806    /* control magic number */
807    if (LZ4F_readLE32(src) != LZ4F_MAGICNUMBER) return err0r(LZ4F_ERROR_frameType_unknown);
808
809    /* Frame Header Size */
810    {   BYTE const FLG = ((const BYTE*)src)[4];
811        U32 const contentSizeFlag = (FLG>>3) & _1BIT;
812        return contentSizeFlag ? maxFHSize : minFHSize;
813    }
814}
815
816
817/*! LZ4F_decodeHeader() :
818   input   : `src` points at the **beginning of the frame**
819   output  : set internal values of dctx, such as
820             dctxPtr->frameInfo and dctxPtr->dStage.
821             Also allocates internal buffers.
822   @return : nb Bytes read from srcVoidPtr (necessarily <= srcSize)
823             or an error code (testable with LZ4F_isError())
824*/
825static size_t LZ4F_decodeHeader(LZ4F_dctx* dctxPtr, const void* src, size_t srcSize)
826{
827    BYTE FLG, BD;
828    unsigned version, blockMode, blockChecksumFlag, contentSizeFlag, contentChecksumFlag, blockSizeID;
829    size_t frameHeaderSize;
830    const BYTE* srcPtr = (const BYTE*)src;
831
832    /* need to decode header to get frameInfo */
833    if (srcSize < minFHSize) return err0r(LZ4F_ERROR_frameHeader_incomplete);   /* minimal frame header size */
834    memset(&(dctxPtr->frameInfo), 0, sizeof(dctxPtr->frameInfo));
835
836    /* special case : skippable frames */
837    if ((LZ4F_readLE32(srcPtr) & 0xFFFFFFF0U) == LZ4F_MAGIC_SKIPPABLE_START) {
838        dctxPtr->frameInfo.frameType = LZ4F_skippableFrame;
839        if (src == (void*)(dctxPtr->header)) {
840            dctxPtr->tmpInSize = srcSize;
841            dctxPtr->tmpInTarget = 8;
842            dctxPtr->dStage = dstage_storeSFrameSize;
843            return srcSize;
844        } else {
845            dctxPtr->dStage = dstage_getSFrameSize;
846            return 4;
847        }
848    }
849
850    /* control magic number */
851    if (LZ4F_readLE32(srcPtr) != LZ4F_MAGICNUMBER) return err0r(LZ4F_ERROR_frameType_unknown);
852    dctxPtr->frameInfo.frameType = LZ4F_frame;
853
854    /* Flags */
855    FLG = srcPtr[4];
856    version = (FLG>>6) & _2BITS;
857    blockMode = (FLG>>5) & _1BIT;
858    blockChecksumFlag = (FLG>>4) & _1BIT;
859    contentSizeFlag = (FLG>>3) & _1BIT;
860    contentChecksumFlag = (FLG>>2) & _1BIT;
861
862    /* Frame Header Size */
863    frameHeaderSize = contentSizeFlag ? maxFHSize : minFHSize;
864
865    if (srcSize < frameHeaderSize) {
866        /* not enough input to fully decode frame header */
867        if (srcPtr != dctxPtr->header)
868            memcpy(dctxPtr->header, srcPtr, srcSize);
869        dctxPtr->tmpInSize = srcSize;
870        dctxPtr->tmpInTarget = frameHeaderSize;
871        dctxPtr->dStage = dstage_storeHeader;
872        return srcSize;
873    }
874
875    BD = srcPtr[5];
876    blockSizeID = (BD>>4) & _3BITS;
877
878    /* validate */
879    if (version != 1) return err0r(LZ4F_ERROR_headerVersion_wrong);        /* Version Number, only supported value */
880    if (blockChecksumFlag != 0) return err0r(LZ4F_ERROR_blockChecksum_unsupported); /* Not supported for the time being */
881    if (((FLG>>0)&_2BITS) != 0) return err0r(LZ4F_ERROR_reservedFlag_set); /* Reserved bits */
882    if (((BD>>7)&_1BIT) != 0) return err0r(LZ4F_ERROR_reservedFlag_set);   /* Reserved bit */
883    if (blockSizeID < 4) return err0r(LZ4F_ERROR_maxBlockSize_invalid);    /* 4-7 only supported values for the time being */
884    if (((BD>>0)&_4BITS) != 0) return err0r(LZ4F_ERROR_reservedFlag_set);  /* Reserved bits */
885
886    /* check header */
887    { BYTE const HC = LZ4F_headerChecksum(srcPtr+4, frameHeaderSize-5);
888      if (HC != srcPtr[frameHeaderSize-1]) return err0r(LZ4F_ERROR_headerChecksum_invalid); }
889
890    /* save */
891    dctxPtr->frameInfo.blockMode = (LZ4F_blockMode_t)blockMode;
892    dctxPtr->frameInfo.contentChecksumFlag = (LZ4F_contentChecksum_t)contentChecksumFlag;
893    dctxPtr->frameInfo.blockSizeID = (LZ4F_blockSizeID_t)blockSizeID;
894    dctxPtr->maxBlockSize = LZ4F_getBlockSize(blockSizeID);
895    if (contentSizeFlag)
896        dctxPtr->frameRemainingSize = dctxPtr->frameInfo.contentSize = LZ4F_readLE64(srcPtr+6);
897
898    /* init */
899    if (contentChecksumFlag) XXH32_reset(&(dctxPtr->xxh), 0);
900
901    /* internal buffers allocation */
902    {   size_t const bufferNeeded = dctxPtr->maxBlockSize + ((dctxPtr->frameInfo.blockMode==LZ4F_blockLinked) * 128 KB);
903        if (bufferNeeded > dctxPtr->maxBufferSize) {   /* tmp buffers too small */
904            FREEMEM(dctxPtr->tmpIn);
905            dctxPtr->tmpIn = (BYTE*)ALLOCATOR(dctxPtr->maxBlockSize);
906            if (dctxPtr->tmpIn == NULL) return err0r(LZ4F_ERROR_allocation_failed);
907            FREEMEM(dctxPtr->tmpOutBuffer);
908            dctxPtr->maxBufferSize = 0;
909            dctxPtr->tmpOutBuffer= (BYTE*)ALLOCATOR(bufferNeeded);
910            if (dctxPtr->tmpOutBuffer== NULL) return err0r(LZ4F_ERROR_allocation_failed);
911            dctxPtr->maxBufferSize = bufferNeeded;
912    }   }
913    dctxPtr->tmpInSize = 0;
914    dctxPtr->tmpInTarget = 0;
915    dctxPtr->dict = dctxPtr->tmpOutBuffer;
916    dctxPtr->dictSize = 0;
917    dctxPtr->tmpOut = dctxPtr->tmpOutBuffer;
918    dctxPtr->tmpOutStart = 0;
919    dctxPtr->tmpOutSize = 0;
920
921    dctxPtr->dStage = dstage_getCBlockSize;
922
923    return frameHeaderSize;
924}
925
926
927/*! LZ4F_getFrameInfo() :
928*   Decodes frame header information, such as blockSize. Usage is optional.
929*   The objective is to extract header information before receiving decompressed data, typically for allocation purposes.
930*   LZ4F_getFrameInfo() can also be used *after* starting decompression, on a valid LZ4F_decompressionContext_t.
931*   The number of bytes consumed from srcBuffer will be provided within *srcSizePtr (necessarily <= original value).
932*   Decompression must resume from where it stopped (srcBuffer + *srcSizePtr)
933*   @return : hint of the better `srcSize` to use for next call to LZ4F_decompress,
934*             or an error code which can be tested using LZ4F_isError().
935*/
936LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctxPtr, LZ4F_frameInfo_t* frameInfoPtr,
937                                   const void* srcBuffer, size_t* srcSizePtr)
938{
939    if (dctxPtr->dStage > dstage_storeHeader) {  /* note : requires dstage_* header related to be at beginning of enum */
940        /* frameInfo already decoded */
941        size_t o=0, i=0;
942        *srcSizePtr = 0;
943        *frameInfoPtr = dctxPtr->frameInfo;
944        return LZ4F_decompress(dctxPtr, NULL, &o, NULL, &i, NULL);  /* returns : recommended nb of bytes for LZ4F_decompress() */
945    } else {
946        size_t nextSrcSize, o=0;
947        size_t const hSize = LZ4F_headerSize(srcBuffer, *srcSizePtr);
948        if (LZ4F_isError(hSize)) { *srcSizePtr=0; return hSize; }
949        if (*srcSizePtr < hSize) { *srcSizePtr=0; return err0r(LZ4F_ERROR_frameHeader_incomplete); }
950
951        *srcSizePtr = hSize;
952        nextSrcSize = LZ4F_decompress(dctxPtr, NULL, &o, srcBuffer, srcSizePtr, NULL);
953        if (dctxPtr->dStage <= dstage_storeHeader) return err0r(LZ4F_ERROR_frameHeader_incomplete); /* should not happen, already checked */
954        *frameInfoPtr = dctxPtr->frameInfo;
955        return nextSrcSize;
956    }
957}
958
959
960/* trivial redirector, for common prototype */
961static int LZ4F_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize)
962{
963    (void)dictStart; (void)dictSize;
964    return LZ4_decompress_safe (source, dest, compressedSize, maxDecompressedSize);
965}
966
967
968static void LZ4F_updateDict(LZ4F_dctx* dctxPtr, const BYTE* dstPtr, size_t dstSize, const BYTE* dstPtr0, unsigned withinTmp)
969{
970    if (dctxPtr->dictSize==0)
971        dctxPtr->dict = (const BYTE*)dstPtr;   /* priority to dictionary continuity */
972
973    if (dctxPtr->dict + dctxPtr->dictSize == dstPtr) {  /* dictionary continuity */
974        dctxPtr->dictSize += dstSize;
975        return;
976    }
977
978    if (dstPtr - dstPtr0 + dstSize >= 64 KB) {  /* dstBuffer large enough to become dictionary */
979        dctxPtr->dict = (const BYTE*)dstPtr0;
980        dctxPtr->dictSize = dstPtr - dstPtr0 + dstSize;
981        return;
982    }
983
984    if ((withinTmp) && (dctxPtr->dict == dctxPtr->tmpOutBuffer)) {
985        /* assumption : dctxPtr->dict + dctxPtr->dictSize == dctxPtr->tmpOut + dctxPtr->tmpOutStart */
986        dctxPtr->dictSize += dstSize;
987        return;
988    }
989
990    if (withinTmp) { /* copy relevant dict portion in front of tmpOut within tmpOutBuffer */
991        size_t const preserveSize = dctxPtr->tmpOut - dctxPtr->tmpOutBuffer;
992        size_t copySize = 64 KB - dctxPtr->tmpOutSize;
993        const BYTE* const oldDictEnd = dctxPtr->dict + dctxPtr->dictSize - dctxPtr->tmpOutStart;
994        if (dctxPtr->tmpOutSize > 64 KB) copySize = 0;
995        if (copySize > preserveSize) copySize = preserveSize;
996
997        memcpy(dctxPtr->tmpOutBuffer + preserveSize - copySize, oldDictEnd - copySize, copySize);
998
999        dctxPtr->dict = dctxPtr->tmpOutBuffer;
1000        dctxPtr->dictSize = preserveSize + dctxPtr->tmpOutStart + dstSize;
1001        return;
1002    }
1003
1004    if (dctxPtr->dict == dctxPtr->tmpOutBuffer) {    /* copy dst into tmp to complete dict */
1005        if (dctxPtr->dictSize + dstSize > dctxPtr->maxBufferSize) {  /* tmp buffer not large enough */
1006            size_t const preserveSize = 64 KB - dstSize;   /* note : dstSize < 64 KB */
1007            memcpy(dctxPtr->tmpOutBuffer, dctxPtr->dict + dctxPtr->dictSize - preserveSize, preserveSize);
1008            dctxPtr->dictSize = preserveSize;
1009        }
1010        memcpy(dctxPtr->tmpOutBuffer + dctxPtr->dictSize, dstPtr, dstSize);
1011        dctxPtr->dictSize += dstSize;
1012        return;
1013    }
1014
1015    /* join dict & dest into tmp */
1016    {   size_t preserveSize = 64 KB - dstSize;   /* note : dstSize < 64 KB */
1017        if (preserveSize > dctxPtr->dictSize) preserveSize = dctxPtr->dictSize;
1018        memcpy(dctxPtr->tmpOutBuffer, dctxPtr->dict + dctxPtr->dictSize - preserveSize, preserveSize);
1019        memcpy(dctxPtr->tmpOutBuffer + preserveSize, dstPtr, dstSize);
1020        dctxPtr->dict = dctxPtr->tmpOutBuffer;
1021        dctxPtr->dictSize = preserveSize + dstSize;
1022    }
1023}
1024
1025
1026
1027/*! LZ4F_decompress() :
1028* Call this function repetitively to regenerate data compressed within srcBuffer.
1029* The function will attempt to decode up to *srcSizePtr bytes from srcBuffer, into dstBuffer of capacity *dstSizePtr.
1030*
1031* The number of bytes regenerated into dstBuffer will be provided within *dstSizePtr (necessarily <= original value).
1032*
1033* The number of bytes effectively read from srcBuffer will be provided within *srcSizePtr (necessarily <= original value).
1034* If the number of bytes read is < number of bytes provided, then the decompression operation is not complete.
1035* Remaining data will have to be presented again in a subsequent invocation.
1036*
1037* The function result is an hint of the better srcSize to use for next call to LZ4F_decompress.
1038* Basically, it's the size of the current (or remaining) compressed block + header of next block.
1039* Respecting the hint provides some boost to performance, since it allows less buffer shuffling.
1040* Note that this is just a hint, it's always possible to any srcSize value.
1041* When a frame is fully decoded, @return will be 0.
1042* If decompression failed, @return is an error code which can be tested using LZ4F_isError().
1043*/
1044size_t LZ4F_decompress(LZ4F_dctx* dctxPtr,
1045                       void* dstBuffer, size_t* dstSizePtr,
1046                       const void* srcBuffer, size_t* srcSizePtr,
1047                       const LZ4F_decompressOptions_t* decompressOptionsPtr)
1048{
1049    LZ4F_decompressOptions_t optionsNull;
1050    const BYTE* const srcStart = (const BYTE*)srcBuffer;
1051    const BYTE* const srcEnd = srcStart + *srcSizePtr;
1052    const BYTE* srcPtr = srcStart;
1053    BYTE* const dstStart = (BYTE*)dstBuffer;
1054    BYTE* const dstEnd = dstStart + *dstSizePtr;
1055    BYTE* dstPtr = dstStart;
1056    const BYTE* selectedIn = NULL;
1057    unsigned doAnotherStage = 1;
1058    size_t nextSrcSizeHint = 1;
1059
1060
1061    memset(&optionsNull, 0, sizeof(optionsNull));
1062    if (decompressOptionsPtr==NULL) decompressOptionsPtr = &optionsNull;
1063    *srcSizePtr = 0;
1064    *dstSizePtr = 0;
1065
1066    /* programmed as a state machine */
1067
1068    while (doAnotherStage) {
1069
1070        switch(dctxPtr->dStage)
1071        {
1072
1073        case dstage_getHeader:
1074            if ((size_t)(srcEnd-srcPtr) >= maxFHSize) {  /* enough to decode - shortcut */
1075                LZ4F_errorCode_t const hSize = LZ4F_decodeHeader(dctxPtr, srcPtr, srcEnd-srcPtr);
1076                if (LZ4F_isError(hSize)) return hSize;
1077                srcPtr += hSize;
1078                break;
1079            }
1080            dctxPtr->tmpInSize = 0;
1081            dctxPtr->tmpInTarget = minFHSize;   /* minimum to attempt decode */
1082            dctxPtr->dStage = dstage_storeHeader;
1083            /* pass-through */
1084
1085        case dstage_storeHeader:
1086            {   size_t sizeToCopy = dctxPtr->tmpInTarget - dctxPtr->tmpInSize;
1087                if (sizeToCopy > (size_t)(srcEnd - srcPtr)) sizeToCopy =  srcEnd - srcPtr;
1088                memcpy(dctxPtr->header + dctxPtr->tmpInSize, srcPtr, sizeToCopy);
1089                dctxPtr->tmpInSize += sizeToCopy;
1090                srcPtr += sizeToCopy;
1091                if (dctxPtr->tmpInSize < dctxPtr->tmpInTarget) {
1092                    nextSrcSizeHint = (dctxPtr->tmpInTarget - dctxPtr->tmpInSize) + BHSize;   /* rest of header + nextBlockHeader */
1093                    doAnotherStage = 0;   /* not enough src data, ask for some more */
1094                    break;
1095                }
1096                {   LZ4F_errorCode_t const hSize = LZ4F_decodeHeader(dctxPtr, dctxPtr->header, dctxPtr->tmpInTarget);
1097                    if (LZ4F_isError(hSize)) return hSize;
1098                }
1099                break;
1100            }
1101
1102        case dstage_getCBlockSize:
1103            if ((size_t)(srcEnd - srcPtr) >= BHSize) {
1104                selectedIn = srcPtr;
1105                srcPtr += BHSize;
1106            } else {
1107                /* not enough input to read cBlockSize field */
1108                dctxPtr->tmpInSize = 0;
1109                dctxPtr->dStage = dstage_storeCBlockSize;
1110            }
1111
1112            if (dctxPtr->dStage == dstage_storeCBlockSize)   /* can be skipped */
1113        case dstage_storeCBlockSize:
1114            {   size_t sizeToCopy = BHSize - dctxPtr->tmpInSize;
1115                if (sizeToCopy > (size_t)(srcEnd - srcPtr)) sizeToCopy = srcEnd - srcPtr;
1116                memcpy(dctxPtr->tmpIn + dctxPtr->tmpInSize, srcPtr, sizeToCopy);
1117                srcPtr += sizeToCopy;
1118                dctxPtr->tmpInSize += sizeToCopy;
1119                if (dctxPtr->tmpInSize < BHSize) {   /* not enough input to get full cBlockSize; wait for more */
1120                    nextSrcSizeHint = BHSize - dctxPtr->tmpInSize;
1121                    doAnotherStage  = 0;
1122                    break;
1123                }
1124                selectedIn = dctxPtr->tmpIn;
1125            }
1126
1127        /* case dstage_decodeCBlockSize: */   /* no more direct access, to prevent scan-build warning */
1128            {   size_t const nextCBlockSize = LZ4F_readLE32(selectedIn) & 0x7FFFFFFFU;
1129                if (nextCBlockSize==0) {  /* frameEnd signal, no more CBlock */
1130                    dctxPtr->dStage = dstage_getSuffix;
1131                    break;
1132                }
1133                if (nextCBlockSize > dctxPtr->maxBlockSize) return err0r(LZ4F_ERROR_GENERIC);   /* invalid cBlockSize */
1134                dctxPtr->tmpInTarget = nextCBlockSize;
1135                if (LZ4F_readLE32(selectedIn) & LZ4F_BLOCKUNCOMPRESSED_FLAG) {
1136                    dctxPtr->dStage = dstage_copyDirect;
1137                    break;
1138                }
1139                dctxPtr->dStage = dstage_getCBlock;
1140                if (dstPtr==dstEnd) {
1141                    nextSrcSizeHint = nextCBlockSize + BHSize;
1142                    doAnotherStage = 0;
1143                }
1144                break;
1145            }
1146
1147        case dstage_copyDirect:   /* uncompressed block */
1148            {   size_t sizeToCopy = dctxPtr->tmpInTarget;
1149                if ((size_t)(srcEnd-srcPtr) < sizeToCopy) sizeToCopy = srcEnd - srcPtr;  /* not enough input to read full block */
1150                if ((size_t)(dstEnd-dstPtr) < sizeToCopy) sizeToCopy = dstEnd - dstPtr;
1151                memcpy(dstPtr, srcPtr, sizeToCopy);
1152                if (dctxPtr->frameInfo.contentChecksumFlag) XXH32_update(&(dctxPtr->xxh), srcPtr, sizeToCopy);
1153                if (dctxPtr->frameInfo.contentSize) dctxPtr->frameRemainingSize -= sizeToCopy;
1154
1155                /* dictionary management */
1156                if (dctxPtr->frameInfo.blockMode==LZ4F_blockLinked)
1157                    LZ4F_updateDict(dctxPtr, dstPtr, sizeToCopy, dstStart, 0);
1158
1159                srcPtr += sizeToCopy;
1160                dstPtr += sizeToCopy;
1161                if (sizeToCopy == dctxPtr->tmpInTarget) {  /* all copied */
1162                    dctxPtr->dStage = dstage_getCBlockSize;
1163                    break;
1164                }
1165                dctxPtr->tmpInTarget -= sizeToCopy;   /* still need to copy more */
1166                nextSrcSizeHint = dctxPtr->tmpInTarget + BHSize;
1167                doAnotherStage = 0;
1168                break;
1169            }
1170
1171        case dstage_getCBlock:   /* entry from dstage_decodeCBlockSize */
1172            if ((size_t)(srcEnd-srcPtr) < dctxPtr->tmpInTarget) {
1173                dctxPtr->tmpInSize = 0;
1174                dctxPtr->dStage = dstage_storeCBlock;
1175                break;
1176            }
1177            selectedIn = srcPtr;
1178            srcPtr += dctxPtr->tmpInTarget;
1179            dctxPtr->dStage = dstage_decodeCBlock;
1180            break;
1181
1182        case dstage_storeCBlock:
1183            {   size_t sizeToCopy = dctxPtr->tmpInTarget - dctxPtr->tmpInSize;
1184                if (sizeToCopy > (size_t)(srcEnd-srcPtr)) sizeToCopy = srcEnd-srcPtr;
1185                memcpy(dctxPtr->tmpIn + dctxPtr->tmpInSize, srcPtr, sizeToCopy);
1186                dctxPtr->tmpInSize += sizeToCopy;
1187                srcPtr += sizeToCopy;
1188                if (dctxPtr->tmpInSize < dctxPtr->tmpInTarget) { /* need more input */
1189                    nextSrcSizeHint = (dctxPtr->tmpInTarget - dctxPtr->tmpInSize) + BHSize;
1190                    doAnotherStage=0;
1191                    break;
1192                }
1193                selectedIn = dctxPtr->tmpIn;
1194                dctxPtr->dStage = dstage_decodeCBlock;
1195                /* pass-through */
1196            }
1197
1198        case dstage_decodeCBlock:
1199            if ((size_t)(dstEnd-dstPtr) < dctxPtr->maxBlockSize)   /* not enough place into dst : decode into tmpOut */
1200                dctxPtr->dStage = dstage_decodeCBlock_intoTmp;
1201            else
1202                dctxPtr->dStage = dstage_decodeCBlock_intoDst;
1203            break;
1204
1205        case dstage_decodeCBlock_intoDst:
1206            {   int (*decoder)(const char*, char*, int, int, const char*, int);
1207                int decodedSize;
1208
1209                if (dctxPtr->frameInfo.blockMode == LZ4F_blockLinked)
1210                    decoder = LZ4_decompress_safe_usingDict;
1211                else
1212                    decoder = LZ4F_decompress_safe;
1213
1214                decodedSize = decoder((const char*)selectedIn, (char*)dstPtr, (int)dctxPtr->tmpInTarget, (int)dctxPtr->maxBlockSize, (const char*)dctxPtr->dict, (int)dctxPtr->dictSize);
1215                if (decodedSize < 0) return err0r(LZ4F_ERROR_GENERIC);   /* decompression failed */
1216                if (dctxPtr->frameInfo.contentChecksumFlag) XXH32_update(&(dctxPtr->xxh), dstPtr, decodedSize);
1217                if (dctxPtr->frameInfo.contentSize) dctxPtr->frameRemainingSize -= decodedSize;
1218
1219                /* dictionary management */
1220                if (dctxPtr->frameInfo.blockMode==LZ4F_blockLinked)
1221                    LZ4F_updateDict(dctxPtr, dstPtr, decodedSize, dstStart, 0);
1222
1223                dstPtr += decodedSize;
1224                dctxPtr->dStage = dstage_getCBlockSize;
1225                break;
1226            }
1227
1228        case dstage_decodeCBlock_intoTmp:
1229            /* not enough place into dst : decode into tmpOut */
1230            {   int (*decoder)(const char*, char*, int, int, const char*, int);
1231                int decodedSize;
1232
1233                if (dctxPtr->frameInfo.blockMode == LZ4F_blockLinked)
1234                    decoder = LZ4_decompress_safe_usingDict;
1235                else
1236                    decoder = LZ4F_decompress_safe;
1237
1238                /* ensure enough place for tmpOut */
1239                if (dctxPtr->frameInfo.blockMode == LZ4F_blockLinked) {
1240                    if (dctxPtr->dict == dctxPtr->tmpOutBuffer) {
1241                        if (dctxPtr->dictSize > 128 KB) {
1242                            memcpy(dctxPtr->tmpOutBuffer, dctxPtr->dict + dctxPtr->dictSize - 64 KB, 64 KB);
1243                            dctxPtr->dictSize = 64 KB;
1244                        }
1245                        dctxPtr->tmpOut = dctxPtr->tmpOutBuffer + dctxPtr->dictSize;
1246                    } else {  /* dict not within tmp */
1247                        size_t reservedDictSpace = dctxPtr->dictSize;
1248                        if (reservedDictSpace > 64 KB) reservedDictSpace = 64 KB;
1249                        dctxPtr->tmpOut = dctxPtr->tmpOutBuffer + reservedDictSpace;
1250                    }
1251                }
1252
1253                /* Decode */
1254                decodedSize = decoder((const char*)selectedIn, (char*)dctxPtr->tmpOut, (int)dctxPtr->tmpInTarget, (int)dctxPtr->maxBlockSize, (const char*)dctxPtr->dict, (int)dctxPtr->dictSize);
1255                if (decodedSize < 0) return err0r(LZ4F_ERROR_decompressionFailed);   /* decompression failed */
1256                if (dctxPtr->frameInfo.contentChecksumFlag) XXH32_update(&(dctxPtr->xxh), dctxPtr->tmpOut, decodedSize);
1257                if (dctxPtr->frameInfo.contentSize) dctxPtr->frameRemainingSize -= decodedSize;
1258                dctxPtr->tmpOutSize = decodedSize;
1259                dctxPtr->tmpOutStart = 0;
1260                dctxPtr->dStage = dstage_flushOut;
1261                break;
1262            }
1263
1264        case dstage_flushOut:  /* flush decoded data from tmpOut to dstBuffer */
1265            {   size_t sizeToCopy = dctxPtr->tmpOutSize - dctxPtr->tmpOutStart;
1266                if (sizeToCopy > (size_t)(dstEnd-dstPtr)) sizeToCopy = dstEnd-dstPtr;
1267                memcpy(dstPtr, dctxPtr->tmpOut + dctxPtr->tmpOutStart, sizeToCopy);
1268
1269                /* dictionary management */
1270                if (dctxPtr->frameInfo.blockMode==LZ4F_blockLinked)
1271                    LZ4F_updateDict(dctxPtr, dstPtr, sizeToCopy, dstStart, 1);
1272
1273                dctxPtr->tmpOutStart += sizeToCopy;
1274                dstPtr += sizeToCopy;
1275
1276                /* end of flush ? */
1277                if (dctxPtr->tmpOutStart == dctxPtr->tmpOutSize) {
1278                    dctxPtr->dStage = dstage_getCBlockSize;
1279                    break;
1280                }
1281                nextSrcSizeHint = BHSize;
1282                doAnotherStage = 0;   /* still some data to flush */
1283                break;
1284            }
1285
1286        case dstage_getSuffix:
1287            {   size_t const suffixSize = dctxPtr->frameInfo.contentChecksumFlag * 4;
1288                if (dctxPtr->frameRemainingSize) return err0r(LZ4F_ERROR_frameSize_wrong);   /* incorrect frame size decoded */
1289                if (suffixSize == 0) {  /* frame completed */
1290                    nextSrcSizeHint = 0;
1291                    dctxPtr->dStage = dstage_getHeader;
1292                    doAnotherStage = 0;
1293                    break;
1294                }
1295                if ((srcEnd - srcPtr) < 4) {  /* not enough size for entire CRC */
1296                    dctxPtr->tmpInSize = 0;
1297                    dctxPtr->dStage = dstage_storeSuffix;
1298                } else {
1299                    selectedIn = srcPtr;
1300                    srcPtr += 4;
1301                }
1302            }
1303
1304            if (dctxPtr->dStage == dstage_storeSuffix)   /* can be skipped */
1305        case dstage_storeSuffix:
1306            {
1307                size_t sizeToCopy = 4 - dctxPtr->tmpInSize;
1308                if (sizeToCopy > (size_t)(srcEnd - srcPtr)) sizeToCopy = srcEnd - srcPtr;
1309                memcpy(dctxPtr->tmpIn + dctxPtr->tmpInSize, srcPtr, sizeToCopy);
1310                srcPtr += sizeToCopy;
1311                dctxPtr->tmpInSize += sizeToCopy;
1312                if (dctxPtr->tmpInSize < 4) { /* not enough input to read complete suffix */
1313                    nextSrcSizeHint = 4 - dctxPtr->tmpInSize;
1314                    doAnotherStage=0;
1315                    break;
1316                }
1317                selectedIn = dctxPtr->tmpIn;
1318            }
1319
1320        /* case dstage_checkSuffix: */   /* no direct call, to avoid scan-build warning */
1321            {   U32 const readCRC = LZ4F_readLE32(selectedIn);
1322                U32 const resultCRC = XXH32_digest(&(dctxPtr->xxh));
1323                if (readCRC != resultCRC) return err0r(LZ4F_ERROR_contentChecksum_invalid);
1324                nextSrcSizeHint = 0;
1325                dctxPtr->dStage = dstage_getHeader;
1326                doAnotherStage = 0;
1327                break;
1328            }
1329
1330        case dstage_getSFrameSize:
1331            if ((srcEnd - srcPtr) >= 4) {
1332                selectedIn = srcPtr;
1333                srcPtr += 4;
1334            } else {
1335                /* not enough input to read cBlockSize field */
1336                dctxPtr->tmpInSize = 4;
1337                dctxPtr->tmpInTarget = 8;
1338                dctxPtr->dStage = dstage_storeSFrameSize;
1339            }
1340
1341            if (dctxPtr->dStage == dstage_storeSFrameSize)
1342        case dstage_storeSFrameSize:
1343            {
1344                size_t sizeToCopy = dctxPtr->tmpInTarget - dctxPtr->tmpInSize;
1345                if (sizeToCopy > (size_t)(srcEnd - srcPtr)) sizeToCopy = srcEnd - srcPtr;
1346                memcpy(dctxPtr->header + dctxPtr->tmpInSize, srcPtr, sizeToCopy);
1347                srcPtr += sizeToCopy;
1348                dctxPtr->tmpInSize += sizeToCopy;
1349                if (dctxPtr->tmpInSize < dctxPtr->tmpInTarget) { /* not enough input to get full sBlockSize; wait for more */
1350                    nextSrcSizeHint = dctxPtr->tmpInTarget - dctxPtr->tmpInSize;
1351                    doAnotherStage = 0;
1352                    break;
1353                }
1354                selectedIn = dctxPtr->header + 4;
1355            }
1356
1357        /* case dstage_decodeSFrameSize: */   /* no direct access */
1358            {   size_t const SFrameSize = LZ4F_readLE32(selectedIn);
1359                dctxPtr->frameInfo.contentSize = SFrameSize;
1360                dctxPtr->tmpInTarget = SFrameSize;
1361                dctxPtr->dStage = dstage_skipSkippable;
1362                break;
1363            }
1364
1365        case dstage_skipSkippable:
1366            {   size_t skipSize = dctxPtr->tmpInTarget;
1367                if (skipSize > (size_t)(srcEnd-srcPtr)) skipSize = srcEnd-srcPtr;
1368                srcPtr += skipSize;
1369                dctxPtr->tmpInTarget -= skipSize;
1370                doAnotherStage = 0;
1371                nextSrcSizeHint = dctxPtr->tmpInTarget;
1372                if (nextSrcSizeHint) break;
1373                dctxPtr->dStage = dstage_getHeader;
1374                break;
1375            }
1376        }
1377    }
1378
1379    /* preserve dictionary within tmp if necessary */
1380    if ( (dctxPtr->frameInfo.blockMode==LZ4F_blockLinked)
1381        &&(dctxPtr->dict != dctxPtr->tmpOutBuffer)
1382        &&(!decompressOptionsPtr->stableDst)
1383        &&((unsigned)(dctxPtr->dStage-1) < (unsigned)(dstage_getSuffix-1))
1384        )
1385    {
1386        if (dctxPtr->dStage == dstage_flushOut) {
1387            size_t preserveSize = dctxPtr->tmpOut - dctxPtr->tmpOutBuffer;
1388            size_t copySize = 64 KB - dctxPtr->tmpOutSize;
1389            const BYTE* oldDictEnd = dctxPtr->dict + dctxPtr->dictSize - dctxPtr->tmpOutStart;
1390            if (dctxPtr->tmpOutSize > 64 KB) copySize = 0;
1391            if (copySize > preserveSize) copySize = preserveSize;
1392
1393            memcpy(dctxPtr->tmpOutBuffer + preserveSize - copySize, oldDictEnd - copySize, copySize);
1394
1395            dctxPtr->dict = dctxPtr->tmpOutBuffer;
1396            dctxPtr->dictSize = preserveSize + dctxPtr->tmpOutStart;
1397        } else {
1398            size_t newDictSize = dctxPtr->dictSize;
1399            const BYTE* oldDictEnd = dctxPtr->dict + dctxPtr->dictSize;
1400            if ((newDictSize) > 64 KB) newDictSize = 64 KB;
1401
1402            memcpy(dctxPtr->tmpOutBuffer, oldDictEnd - newDictSize, newDictSize);
1403
1404            dctxPtr->dict = dctxPtr->tmpOutBuffer;
1405            dctxPtr->dictSize = newDictSize;
1406            dctxPtr->tmpOut = dctxPtr->tmpOutBuffer + newDictSize;
1407        }
1408    }
1409
1410    *srcSizePtr = (srcPtr - srcStart);
1411    *dstSizePtr = (dstPtr - dstStart);
1412    return nextSrcSizeHint;
1413}
1414