File Coverage

lz4hc.c
Criterion Covered Total %
statement 0 395 0.0
branch 0 362 0.0
condition n/a
subroutine n/a
pod n/a
total 0 757 0.0


line stmt bran cond sub pod time code
1             /*
2             LZ4 HC - High Compression Mode of LZ4
3             Copyright (C) 2011-2017, Yann Collet.
4              
5             BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6              
7             Redistribution and use in source and binary forms, with or without
8             modification, are permitted provided that the following conditions are
9             met:
10              
11             * Redistributions of source code must retain the above copyright
12             notice, this list of conditions and the following disclaimer.
13             * Redistributions in binary form must reproduce the above
14             copyright notice, this list of conditions and the following disclaimer
15             in the documentation and/or other materials provided with the
16             distribution.
17              
18             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19             "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20             LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21             A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22             OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24             LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25             DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26             THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27             (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28             OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29              
30             You can contact the author at :
31             - LZ4 source repository : https://github.com/lz4/lz4
32             - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
33             */
34             /* note : lz4hc is not an independent module, it requires lz4.h/lz4.c for proper compilation */
35              
36              
37             /* *************************************
38             * Tuning Parameter
39             ***************************************/
40              
41             /*! HEAPMODE :
42             * Select how default compression function will allocate workplace memory,
43             * in stack (0:fastest), or in heap (1:requires malloc()).
44             * Since workplace is rather large, heap mode is recommended.
45             */
46             #ifndef LZ4HC_HEAPMODE
47             # define LZ4HC_HEAPMODE 1
48             #endif
49              
50              
51             /*=== Dependency ===*/
52             #include "lz4hc.h"
53              
54              
55             /*=== Common LZ4 definitions ===*/
56             #if defined(__GNUC__)
57             # pragma GCC diagnostic ignored "-Wunused-function"
58             #endif
59             #if defined (__clang__)
60             # pragma clang diagnostic ignored "-Wunused-function"
61             #endif
62              
63             #define LZ4_COMMONDEFS_ONLY
64             #include "lz4.c" /* LZ4_count, constants, mem */
65              
66              
67             /*=== Constants ===*/
68             #define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH)
69              
70              
71             /*=== Macros ===*/
72             #define MIN(a,b) ( (a) < (b) ? (a) : (b) )
73             #define MAX(a,b) ( (a) > (b) ? (a) : (b) )
74             #define HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG))
75             #define DELTANEXTMAXD(p) chainTable[(p) & LZ4HC_MAXD_MASK] /* flexible, LZ4HC_MAXD dependent */
76             #define DELTANEXTU16(table, pos) table[(U16)(pos)] /* faster */
77              
78 0           static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }
79              
80              
81              
82             /**************************************
83             * HC Compression
84             **************************************/
85 0           static void LZ4HC_init (LZ4HC_CCtx_internal* hc4, const BYTE* start)
86             {
87 0           MEM_INIT((void*)hc4->hashTable, 0, sizeof(hc4->hashTable));
88 0           MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));
89 0           hc4->nextToUpdate = 64 KB;
90 0           hc4->base = start - 64 KB;
91 0           hc4->end = start;
92 0           hc4->dictBase = start - 64 KB;
93 0           hc4->dictLimit = 64 KB;
94 0           hc4->lowLimit = 64 KB;
95 0           }
96              
97              
98             /* Update chains up to ip (excluded) */
99             LZ4_FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip)
100             {
101 0           U16* const chainTable = hc4->chainTable;
102 0           U32* const hashTable = hc4->hashTable;
103 0           const BYTE* const base = hc4->base;
104 0           U32 const target = (U32)(ip - base);
105 0           U32 idx = hc4->nextToUpdate;
106              
107 0 0         while (idx < target) {
    0          
    0          
    0          
    0          
108 0           U32 const h = LZ4HC_hashPtr(base+idx);
109 0           size_t delta = idx - hashTable[h];
110 0 0         if (delta>MAX_DISTANCE) delta = MAX_DISTANCE;
    0          
    0          
    0          
    0          
111 0           DELTANEXTU16(chainTable, idx) = (U16)delta;
112 0           hashTable[h] = idx;
113 0           idx++;
114             }
115              
116 0           hc4->nextToUpdate = target;
117             }
118              
119              
120             LZ4_FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_CCtx_internal* const hc4, /* Index table will be updated */
121             const BYTE* const ip, const BYTE* const iLimit,
122             const BYTE** matchpos,
123             const int maxNbAttempts)
124             {
125 0           U16* const chainTable = hc4->chainTable;
126 0           U32* const HashTable = hc4->hashTable;
127 0           const BYTE* const base = hc4->base;
128 0           const BYTE* const dictBase = hc4->dictBase;
129 0           const U32 dictLimit = hc4->dictLimit;
130 0 0         const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - (64 KB - 1);
131             U32 matchIndex;
132 0           int nbAttempts = maxNbAttempts;
133 0           size_t ml = 0;
134              
135             /* HC4 match finder */
136             LZ4HC_Insert(hc4, ip);
137 0           matchIndex = HashTable[LZ4HC_hashPtr(ip)];
138              
139 0 0         while ((matchIndex>=lowLimit) && (nbAttempts)) {
    0          
140 0           nbAttempts--;
141 0 0         if (matchIndex >= dictLimit) {
142 0           const BYTE* const match = base + matchIndex;
143 0 0         if ( (*(match+ml) == *(ip+ml)) /* can be longer */
144 0 0         && (LZ4_read32(match) == LZ4_read32(ip)) )
145             {
146 0           size_t const mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, iLimit) + MINMATCH;
147 0 0         if (mlt > ml) { ml = mlt; *matchpos = match; }
148             }
149             } else {
150 0           const BYTE* const match = dictBase + matchIndex;
151 0 0         if (LZ4_read32(match) == LZ4_read32(ip)) {
152             size_t mlt;
153 0           const BYTE* vLimit = ip + (dictLimit - matchIndex);
154 0 0         if (vLimit > iLimit) vLimit = iLimit;
155 0           mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, vLimit) + MINMATCH;
156 0 0         if ((ip+mlt == vLimit) && (vLimit < iLimit))
    0          
157 0           mlt += LZ4_count(ip+mlt, base+dictLimit, iLimit);
158 0 0         if (mlt > ml) { ml = mlt; *matchpos = base + matchIndex; } /* virtual matchpos */
159             }
160             }
161 0           matchIndex -= DELTANEXTU16(chainTable, matchIndex);
162             }
163              
164 0           return (int)ml;
165             }
166              
167              
168             LZ4_FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch (
169             LZ4HC_CCtx_internal* hc4,
170             const BYTE* const ip,
171             const BYTE* const iLowLimit,
172             const BYTE* const iHighLimit,
173             int longest,
174             const BYTE** matchpos,
175             const BYTE** startpos,
176             const int maxNbAttempts)
177             {
178 0           U16* const chainTable = hc4->chainTable;
179 0           U32* const HashTable = hc4->hashTable;
180 0           const BYTE* const base = hc4->base;
181 0           const U32 dictLimit = hc4->dictLimit;
182 0           const BYTE* const lowPrefixPtr = base + dictLimit;
183 0 0         const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - (64 KB - 1);
    0          
184 0           const BYTE* const dictBase = hc4->dictBase;
185 0           int const delta = (int)(ip-iLowLimit);
186 0           int nbAttempts = maxNbAttempts;
187             U32 matchIndex;
188              
189              
190             /* First Match */
191             LZ4HC_Insert(hc4, ip);
192 0           matchIndex = HashTable[LZ4HC_hashPtr(ip)];
193              
194 0 0         while ((matchIndex>=lowLimit) && (nbAttempts)) {
    0          
    0          
    0          
195 0           nbAttempts--;
196 0 0         if (matchIndex >= dictLimit) {
    0          
197 0           const BYTE* const matchPtr = base + matchIndex;
198 0 0         if (*(iLowLimit + longest) == *(matchPtr - delta + longest)) {
    0          
199 0 0         if (LZ4_read32(matchPtr) == LZ4_read32(ip)) {
    0          
200 0           int mlt = MINMATCH + LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit);
201 0           int back = 0;
202              
203 0 0         while ( (ip+back > iLowLimit)
    0          
204 0 0         && (matchPtr+back > lowPrefixPtr)
    0          
205 0 0         && (ip[back-1] == matchPtr[back-1])) {
    0          
206 0           back--;
207             }
208              
209 0           mlt -= back;
210              
211 0 0         if (mlt > longest) {
    0          
212 0           longest = mlt;
213 0           *matchpos = matchPtr+back;
214 0           *startpos = ip+back;
215             } } }
216             } else {
217 0           const BYTE* const matchPtr = dictBase + matchIndex;
218 0 0         if (LZ4_read32(matchPtr) == LZ4_read32(ip)) {
    0          
219             int mlt;
220 0           int back=0;
221 0           const BYTE* vLimit = ip + (dictLimit - matchIndex);
222 0 0         if (vLimit > iHighLimit) vLimit = iHighLimit;
    0          
223 0           mlt = LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
224 0 0         if ((ip+mlt == vLimit) && (vLimit < iHighLimit))
    0          
225 0           mlt += LZ4_count(ip+mlt, base+dictLimit, iHighLimit);
226 0 0         while ((ip+back > iLowLimit) && (matchIndex+back > lowLimit) && (ip[back-1] == matchPtr[back-1])) back--;
    0          
    0          
    0          
    0          
    0          
227 0           mlt -= back;
228 0 0         if (mlt > longest) { longest = mlt; *matchpos = base + matchIndex + back; *startpos = ip+back; }
    0          
229             }
230             }
231 0           matchIndex -= DELTANEXTU16(chainTable, matchIndex);
232             }
233              
234 0           return longest;
235             }
236              
237              
238             typedef enum {
239             noLimit = 0,
240             limitedOutput = 1,
241             limitedDestSize = 2,
242             } limitedOutput_directive;
243              
244             #ifndef LZ4HC_DEBUG
245             # define LZ4HC_DEBUG 0
246             #endif
247              
248             /* LZ4HC_encodeSequence() :
249             * @return : 0 if ok,
250             * 1 if buffer issue detected */
251             LZ4_FORCE_INLINE int LZ4HC_encodeSequence (
252             const BYTE** ip,
253             BYTE** op,
254             const BYTE** anchor,
255             int matchLength,
256             const BYTE* const match,
257             limitedOutput_directive limit,
258             BYTE* oend)
259             {
260             size_t length;
261 0           BYTE* const token = (*op)++;
262              
263             #if LZ4HC_DEBUG
264             printf("literal : %u -- match : %u -- offset : %u\n",
265             (U32)(*ip - *anchor), (U32)matchLength, (U32)(*ip-match));
266             #endif
267              
268             /* Encode Literal length */
269 0           length = (size_t)(*ip - *anchor);
270 0 0         if ((limit) && ((*op + (length >> 8) + length + (2 + 1 + LASTLITERALS)) > oend)) return 1; /* Check output limit */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
271 0 0         if (length >= RUN_MASK) {
    0          
    0          
    0          
    0          
    0          
272 0           size_t len = length - RUN_MASK;
273 0           *token = (RUN_MASK << ML_BITS);
274 0 0         for(; len >= 255 ; len -= 255) *(*op)++ = 255;
    0          
    0          
    0          
    0          
    0          
275 0           *(*op)++ = (BYTE)len;
276             } else {
277 0           *token = (BYTE)(length << ML_BITS);
278             }
279              
280             /* Copy Literals */
281 0           LZ4_wildCopy(*op, *anchor, (*op) + length);
282 0           *op += length;
283              
284             /* Encode Offset */
285 0           LZ4_writeLE16(*op, (U16)(*ip-match)); *op += 2;
286              
287             /* Encode MatchLength */
288 0           length = (size_t)(matchLength - MINMATCH);
289 0 0         if ((limit) && (*op + (length >> 8) + (1 + LASTLITERALS) > oend)) return 1; /* Check output limit */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
290 0 0         if (length >= ML_MASK) {
    0          
    0          
    0          
    0          
    0          
291 0           *token += ML_MASK;
292 0           length -= ML_MASK;
293 0 0         for(; length >= 510 ; length -= 510) { *(*op)++ = 255; *(*op)++ = 255; }
    0          
    0          
    0          
    0          
    0          
294 0 0         if (length >= 255) { length -= 255; *(*op)++ = 255; }
    0          
    0          
    0          
    0          
    0          
295 0           *(*op)++ = (BYTE)length;
296             } else {
297 0           *token += (BYTE)(length);
298             }
299              
300             /* Prepare next loop */
301 0           *ip += matchLength;
302 0           *anchor = *ip;
303              
304 0           return 0;
305             }
306              
307             /* btopt */
308             #include "lz4opt.h"
309              
310              
311 0           static int LZ4HC_compress_hashChain (
312             LZ4HC_CCtx_internal* const ctx,
313             const char* const source,
314             char* const dest,
315             int* srcSizePtr,
316             int const maxOutputSize,
317             unsigned maxNbAttempts,
318             limitedOutput_directive limit
319             )
320             {
321 0           const int inputSize = *srcSizePtr;
322              
323 0           const BYTE* ip = (const BYTE*) source;
324 0           const BYTE* anchor = ip;
325 0           const BYTE* const iend = ip + inputSize;
326 0           const BYTE* const mflimit = iend - MFLIMIT;
327 0           const BYTE* const matchlimit = (iend - LASTLITERALS);
328              
329 0           BYTE* optr = (BYTE*) dest;
330 0           BYTE* op = (BYTE*) dest;
331 0           BYTE* oend = op + maxOutputSize;
332              
333             int ml, ml2, ml3, ml0;
334 0           const BYTE* ref = NULL;
335 0           const BYTE* start2 = NULL;
336 0           const BYTE* ref2 = NULL;
337 0           const BYTE* start3 = NULL;
338 0           const BYTE* ref3 = NULL;
339             const BYTE* start0;
340             const BYTE* ref0;
341              
342             /* init */
343 0           *srcSizePtr = 0;
344 0 0         if (limit == limitedDestSize && maxOutputSize < 1) return 0; /* Impossible to store anything */
    0          
345 0 0         if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */
346              
347 0           ctx->end += inputSize;
348 0 0         if (limit == limitedDestSize) oend -= LASTLITERALS; /* Hack for support limitations LZ4 decompressor */
349 0 0         if (inputSize < LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
350              
351 0           ip++;
352              
353             /* Main Loop */
354 0 0         while (ip < mflimit) {
355 0           ml = LZ4HC_InsertAndFindBestMatch (ctx, ip, matchlimit, (&ref), maxNbAttempts);
356 0 0         if (!ml) { ip++; continue; }
357              
358             /* saved, in case we would skip too much */
359 0           start0 = ip;
360 0           ref0 = ref;
361 0           ml0 = ml;
362              
363             _Search2:
364 0 0         if (ip+ml < mflimit)
365 0           ml2 = LZ4HC_InsertAndGetWiderMatch(ctx, ip + ml - 2, ip + 0, matchlimit, ml, &ref2, &start2, maxNbAttempts);
366             else
367 0           ml2 = ml;
368              
369 0 0         if (ml2 == ml) { /* No better match */
370 0           optr = op;
371 0 0         if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) goto _dest_overflow;
372 0           continue;
373             }
374              
375 0 0         if (start0 < ip) {
376 0 0         if (start2 < ip + ml0) { /* empirical */
377 0           ip = start0;
378 0           ref = ref0;
379 0           ml = ml0;
380             }
381             }
382              
383             /* Here, start0==ip */
384 0 0         if ((start2 - ip) < 3) { /* First Match too small : removed */
385 0           ml = ml2;
386 0           ip = start2;
387 0           ref =ref2;
388 0           goto _Search2;
389             }
390              
391             _Search3:
392             /* At this stage, we have :
393             * ml2 > ml1, and
394             * ip1+3 <= ip2 (usually < ip1+ml1) */
395 0 0         if ((start2 - ip) < OPTIMAL_ML) {
396             int correction;
397 0           int new_ml = ml;
398 0 0         if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;
399 0 0         if (ip+new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - ip) + ml2 - MINMATCH;
400 0           correction = new_ml - (int)(start2 - ip);
401 0 0         if (correction > 0) {
402 0           start2 += correction;
403 0           ref2 += correction;
404 0           ml2 -= correction;
405             }
406             }
407             /* Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) */
408              
409 0 0         if (start2 + ml2 < mflimit)
410 0           ml3 = LZ4HC_InsertAndGetWiderMatch(ctx, start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3, maxNbAttempts);
411             else
412 0           ml3 = ml2;
413              
414 0 0         if (ml3 == ml2) { /* No better match : 2 sequences to encode */
415             /* ip & ref are known; Now for ml */
416 0 0         if (start2 < ip+ml) ml = (int)(start2 - ip);
417             /* Now, encode 2 sequences */
418 0           optr = op;
419 0 0         if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) goto _dest_overflow;
420 0           ip = start2;
421 0           optr = op;
422 0 0         if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml2, ref2, limit, oend)) goto _dest_overflow;
423 0           continue;
424             }
425              
426 0 0         if (start3 < ip+ml+3) { /* Not enough space for match 2 : remove it */
427 0 0         if (start3 >= (ip+ml)) { /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */
428 0 0         if (start2 < ip+ml) {
429 0           int correction = (int)(ip+ml - start2);
430 0           start2 += correction;
431 0           ref2 += correction;
432 0           ml2 -= correction;
433 0 0         if (ml2 < MINMATCH) {
434 0           start2 = start3;
435 0           ref2 = ref3;
436 0           ml2 = ml3;
437             }
438             }
439              
440 0           optr = op;
441 0 0         if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) goto _dest_overflow;
442 0           ip = start3;
443 0           ref = ref3;
444 0           ml = ml3;
445              
446 0           start0 = start2;
447 0           ref0 = ref2;
448 0           ml0 = ml2;
449 0           goto _Search2;
450             }
451              
452 0           start2 = start3;
453 0           ref2 = ref3;
454 0           ml2 = ml3;
455 0           goto _Search3;
456             }
457              
458             /*
459             * OK, now we have 3 ascending matches; let's write at least the first one
460             * ip & ref are known; Now for ml
461             */
462 0 0         if (start2 < ip+ml) {
463 0 0         if ((start2 - ip) < (int)ML_MASK) {
464             int correction;
465 0 0         if (ml > OPTIMAL_ML) ml = OPTIMAL_ML;
466 0 0         if (ip + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - ip) + ml2 - MINMATCH;
467 0           correction = ml - (int)(start2 - ip);
468 0 0         if (correction > 0) {
469 0           start2 += correction;
470 0           ref2 += correction;
471 0           ml2 -= correction;
472             }
473             } else {
474 0           ml = (int)(start2 - ip);
475             }
476             }
477 0           optr = op;
478 0 0         if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) goto _dest_overflow;
479              
480 0           ip = start2;
481 0           ref = ref2;
482 0           ml = ml2;
483              
484 0           start2 = start3;
485 0           ref2 = ref3;
486 0           ml2 = ml3;
487              
488 0           goto _Search3;
489             }
490              
491             _last_literals:
492             /* Encode Last Literals */
493 0           { size_t lastRunSize = (size_t)(iend - anchor); /* literals */
494 0           size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255;
495 0           size_t const totalSize = 1 + litLength + lastRunSize;
496 0 0         if (limit == limitedDestSize) oend += LASTLITERALS; /* restore correct value */
497 0 0         if (limit && (op + totalSize > oend)) {
    0          
498 0 0         if (limit == limitedOutput) return 0; /* Check output limit */
499             /* adapt lastRunSize to fill 'dest' */
500 0           lastRunSize = (size_t)(oend - op) - 1;
501 0           litLength = (lastRunSize + 255 - RUN_MASK) / 255;
502 0           lastRunSize -= litLength;
503             }
504 0           ip = anchor + lastRunSize;
505              
506 0 0         if (lastRunSize >= RUN_MASK) {
507 0           size_t accumulator = lastRunSize - RUN_MASK;
508 0           *op++ = (RUN_MASK << ML_BITS);
509 0 0         for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;
510 0           *op++ = (BYTE) accumulator;
511             } else {
512 0           *op++ = (BYTE)(lastRunSize << ML_BITS);
513             }
514 0           memcpy(op, anchor, lastRunSize);
515 0           op += lastRunSize;
516             }
517              
518             /* End */
519 0           *srcSizePtr = (int) (((const char*)ip) - source);
520 0           return (int) (((char*)op)-dest);
521              
522             _dest_overflow:
523 0 0         if (limit == limitedDestSize) {
524 0           op = optr; /* restore correct out pointer */
525 0           goto _last_literals;
526             }
527 0           return 0;
528             }
529              
530 0           static int LZ4HC_getSearchNum(int compressionLevel)
531             {
532 0           switch (compressionLevel) {
533 0           default: return 0; /* unused */
534 0           case 11: return 128;
535 0           case 12: return 1<<10;
536             }
537             }
538              
539 0           static int LZ4HC_compress_generic (
540             LZ4HC_CCtx_internal* const ctx,
541             const char* const src,
542             char* const dst,
543             int* const srcSizePtr,
544             int const dstCapacity,
545             int cLevel,
546             limitedOutput_directive limit
547             )
548             {
549 0 0         if (cLevel < 1) cLevel = LZ4HC_CLEVEL_DEFAULT; /* note : convention is different from lz4frame, maybe to reconsider */
550 0 0         if (cLevel > 9) {
551 0 0         if (limit == limitedDestSize) cLevel = 10;
552 0           switch (cLevel) {
553             case 10:
554 0           return LZ4HC_compress_hashChain(ctx, src, dst, srcSizePtr, dstCapacity, 1 << 12, limit);
555             case 11:
556 0           ctx->searchNum = LZ4HC_getSearchNum(cLevel);
557 0           return LZ4HC_compress_optimal(ctx, src, dst, *srcSizePtr, dstCapacity, limit, 128, 0);
558             default:
559 0           cLevel = 12;
560             /* fall-through */
561             case 12:
562 0           ctx->searchNum = LZ4HC_getSearchNum(cLevel);
563 0           return LZ4HC_compress_optimal(ctx, src, dst, *srcSizePtr, dstCapacity, limit, LZ4_OPT_NUM, 1);
564             }
565             }
566 0           return LZ4HC_compress_hashChain(ctx, src, dst, srcSizePtr, dstCapacity, 1 << (cLevel-1), limit); /* levels 1-9 */
567             }
568              
569              
570 0           int LZ4_sizeofStateHC(void) { return sizeof(LZ4_streamHC_t); }
571              
572 0           int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
573             {
574 0           LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse;
575 0 0         if (((size_t)(state)&(sizeof(void*)-1)) != 0) return 0; /* Error : state is not aligned for pointers (32 or 64 bits) */
576 0           LZ4HC_init (ctx, (const BYTE*)src);
577 0 0         if (dstCapacity < LZ4_compressBound(srcSize))
578 0           return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, limitedOutput);
579             else
580 0           return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, noLimit);
581             }
582              
583 0           int LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
584             {
585             #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
586 0           LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)malloc(sizeof(LZ4_streamHC_t));
587             #else
588             LZ4_streamHC_t state;
589             LZ4_streamHC_t* const statePtr = &state;
590             #endif
591 0           int const cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel);
592             #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
593 0           free(statePtr);
594             #endif
595 0           return cSize;
596             }
597              
598             /* LZ4_compress_HC_destSize() :
599             * currently, only compatible with Hash Chain implementation,
600             * hence limit compression level to LZ4HC_CLEVEL_OPT_MIN-1*/
601 0           int LZ4_compress_HC_destSize(void* LZ4HC_Data, const char* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel)
602             {
603 0           LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse;
604 0           LZ4HC_init(ctx, (const BYTE*) source);
605 0           return LZ4HC_compress_generic(ctx, source, dest, sourceSizePtr, targetDestSize, cLevel, limitedDestSize);
606             }
607              
608              
609              
610             /**************************************
611             * Streaming Functions
612             **************************************/
613             /* allocation */
614 0           LZ4_streamHC_t* LZ4_createStreamHC(void) { return (LZ4_streamHC_t*)malloc(sizeof(LZ4_streamHC_t)); }
615 0           int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr) {
616 0 0         if (!LZ4_streamHCPtr) return 0; /* support free on NULL */
617 0           free(LZ4_streamHCPtr);
618 0           return 0;
619             }
620              
621              
622             /* initialization */
623 0           void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
624             {
625             LZ4_STATIC_ASSERT(sizeof(LZ4HC_CCtx_internal) <= sizeof(size_t) * LZ4_STREAMHCSIZE_SIZET); /* if compilation fails here, LZ4_STREAMHCSIZE must be increased */
626 0           LZ4_streamHCPtr->internal_donotuse.base = NULL;
627 0 0         if (compressionLevel > LZ4HC_CLEVEL_MAX) compressionLevel = LZ4HC_CLEVEL_MAX; /* cap compression level */
628 0           LZ4_streamHCPtr->internal_donotuse.compressionLevel = compressionLevel;
629 0           LZ4_streamHCPtr->internal_donotuse.searchNum = LZ4HC_getSearchNum(compressionLevel);
630 0           }
631              
632 0           void LZ4_setCompressionLevel(LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
633             {
634 0           int const currentCLevel = LZ4_streamHCPtr->internal_donotuse.compressionLevel;
635 0 0         int const minCLevel = currentCLevel < LZ4HC_CLEVEL_OPT_MIN ? 1 : LZ4HC_CLEVEL_OPT_MIN;
636 0 0         int const maxCLevel = currentCLevel < LZ4HC_CLEVEL_OPT_MIN ? LZ4HC_CLEVEL_OPT_MIN-1 : LZ4HC_CLEVEL_MAX;
637 0           compressionLevel = MIN(compressionLevel, minCLevel);
638 0           compressionLevel = MAX(compressionLevel, maxCLevel);
639 0           LZ4_streamHCPtr->internal_donotuse.compressionLevel = compressionLevel;
640 0           }
641              
642 0           int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, const char* dictionary, int dictSize)
643             {
644 0           LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
645 0 0         if (dictSize > 64 KB) {
646 0           dictionary += dictSize - 64 KB;
647 0           dictSize = 64 KB;
648             }
649 0           LZ4HC_init (ctxPtr, (const BYTE*)dictionary);
650 0           ctxPtr->end = (const BYTE*)dictionary + dictSize;
651 0 0         if (ctxPtr->compressionLevel >= LZ4HC_CLEVEL_OPT_MIN)
652 0           LZ4HC_updateBinTree(ctxPtr, ctxPtr->end - MFLIMIT, ctxPtr->end - LASTLITERALS);
653             else
654 0 0         if (dictSize >= 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3);
655 0           return dictSize;
656             }
657              
658              
659             /* compression */
660              
661 0           static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock)
662             {
663 0 0         if (ctxPtr->compressionLevel >= LZ4HC_CLEVEL_OPT_MIN)
664 0           LZ4HC_updateBinTree(ctxPtr, ctxPtr->end - MFLIMIT, ctxPtr->end - LASTLITERALS);
665             else
666 0 0         if (ctxPtr->end >= ctxPtr->base + 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3); /* Referencing remaining dictionary content */
667              
668             /* Only one memory segment for extDict, so any previous extDict is lost at this stage */
669 0           ctxPtr->lowLimit = ctxPtr->dictLimit;
670 0           ctxPtr->dictLimit = (U32)(ctxPtr->end - ctxPtr->base);
671 0           ctxPtr->dictBase = ctxPtr->base;
672 0           ctxPtr->base = newBlock - ctxPtr->dictLimit;
673 0           ctxPtr->end = newBlock;
674 0           ctxPtr->nextToUpdate = ctxPtr->dictLimit; /* match referencing will resume from there */
675 0           }
676              
677 0           static int LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,
678             const char* src, char* dst,
679             int* srcSizePtr, int dstCapacity,
680             limitedOutput_directive limit)
681             {
682 0           LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
683             /* auto-init if forgotten */
684 0 0         if (ctxPtr->base == NULL) LZ4HC_init (ctxPtr, (const BYTE*) src);
685              
686             /* Check overflow */
687 0 0         if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 GB) {
688 0           size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->base) - ctxPtr->dictLimit;
689 0 0         if (dictSize > 64 KB) dictSize = 64 KB;
690 0           LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize);
691             }
692              
693             /* Check if blocks follow each other */
694 0 0         if ((const BYTE*)src != ctxPtr->end) LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src);
695              
696             /* Check overlapping input/dictionary space */
697 0           { const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr;
698 0           const BYTE* const dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit;
699 0           const BYTE* const dictEnd = ctxPtr->dictBase + ctxPtr->dictLimit;
700 0 0         if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) {
    0          
701 0 0         if (sourceEnd > dictEnd) sourceEnd = dictEnd;
702 0           ctxPtr->lowLimit = (U32)(sourceEnd - ctxPtr->dictBase);
703 0 0         if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) ctxPtr->lowLimit = ctxPtr->dictLimit;
704             }
705             }
706              
707 0           return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit);
708             }
709              
710 0           int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int srcSize, int dstCapacity)
711             {
712 0 0         if (dstCapacity < LZ4_compressBound(srcSize))
713 0           return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput);
714             else
715 0           return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, noLimit);
716             }
717              
718 0           int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int targetDestSize)
719             {
720 0           LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
721 0 0         if (ctxPtr->compressionLevel >= LZ4HC_CLEVEL_OPT_MIN) LZ4HC_init(ctxPtr, (const BYTE*)src); /* not compatible with btopt implementation */
722 0           return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, limitedDestSize);
723             }
724              
725              
726              
727             /* dictionary saving */
728              
729 0           int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)
730             {
731 0           LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse;
732 0           int const prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit));
733 0 0         if (dictSize > 64 KB) dictSize = 64 KB;
734 0 0         if (dictSize < 4) dictSize = 0;
735 0 0         if (dictSize > prefixSize) dictSize = prefixSize;
736 0           memmove(safeBuffer, streamPtr->end - dictSize, dictSize);
737 0           { U32 const endIndex = (U32)(streamPtr->end - streamPtr->base);
738 0           streamPtr->end = (const BYTE*)safeBuffer + dictSize;
739 0           streamPtr->base = streamPtr->end - endIndex;
740 0           streamPtr->dictLimit = endIndex - dictSize;
741 0           streamPtr->lowLimit = endIndex - dictSize;
742 0 0         if (streamPtr->nextToUpdate < streamPtr->dictLimit) streamPtr->nextToUpdate = streamPtr->dictLimit;
743             }
744 0           return dictSize;
745             }
746              
747              
748             /***********************************
749             * Deprecated Functions
750             ***********************************/
751             /* These functions currently generate deprecation warnings */
752             /* Deprecated compression functions */
753 0           int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
754 0           int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); }
755 0           int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
756 0           int LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); }
757 0           int LZ4_compressHC_withStateHC (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
758 0           int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, maxDstSize, 0); }
759 0           int LZ4_compressHC2_withStateHC (void* state, const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
760 0           int LZ4_compressHC2_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, maxDstSize, cLevel); }
761 0           int LZ4_compressHC_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, LZ4_compressBound(srcSize)); }
762 0           int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, maxDstSize); }
763              
764              
765             /* Deprecated streaming functions */
766 0           int LZ4_sizeofStreamStateHC(void) { return LZ4_STREAMHCSIZE; }
767              
768 0           int LZ4_resetStreamStateHC(void* state, char* inputBuffer)
769             {
770 0           LZ4HC_CCtx_internal *ctx = &((LZ4_streamHC_t*)state)->internal_donotuse;
771 0 0         if ((((size_t)state) & (sizeof(void*)-1)) != 0) return 1; /* Error : pointer is not aligned for pointer (32 or 64 bits) */
772 0           LZ4HC_init(ctx, (const BYTE*)inputBuffer);
773 0           ctx->inputBuffer = (BYTE*)inputBuffer;
774 0           return 0;
775             }
776              
777 0           void* LZ4_createHC (char* inputBuffer)
778             {
779 0           LZ4_streamHC_t* hc4 = (LZ4_streamHC_t*)ALLOCATOR(1, sizeof(LZ4_streamHC_t));
780 0 0         if (hc4 == NULL) return NULL; /* not enough memory */
781 0           LZ4HC_init (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
782 0           hc4->internal_donotuse.inputBuffer = (BYTE*)inputBuffer;
783 0           return hc4;
784             }
785              
786 0           int LZ4_freeHC (void* LZ4HC_Data) {
787 0 0         if (!LZ4HC_Data) return 0; /* support free on NULL */
788 0           FREEMEM(LZ4HC_Data);
789 0           return 0;
790             }
791              
792 0           int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)
793             {
794 0           return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, noLimit);
795             }
796              
797 0           int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel)
798             {
799 0           return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput);
800             }
801              
802 0           char* LZ4_slideInputBufferHC(void* LZ4HC_Data)
803             {
804 0           LZ4HC_CCtx_internal* const hc4 = &((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse;
805 0           int const dictSize = LZ4_saveDictHC((LZ4_streamHC_t*)LZ4HC_Data, (char*)(hc4->inputBuffer), 64 KB);
806 0           return (char*)(hc4->inputBuffer + dictSize);
807             }