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