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