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