lz4hc.cc (26563B)
1 /* 2 LZ4 HC - High Compression Mode of LZ4 3 Copyright (C) 2011-2016, 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 /*! 42 * HEAPMODE : 43 * Select how default compression function will allocate workplace memory, 44 * in stack (0:fastest), or in heap (1:requires malloc()). 45 * Since workplace is rather large, heap mode is recommended. 46 */ 47 #ifndef LZ4HC_HEAPMODE 48 # define LZ4HC_HEAPMODE 1 49 #endif 50 51 52 /* ************************************* 53 * Dependency 54 ***************************************/ 55 #include "lz4hc.h" 56 57 58 /* ************************************* 59 * Local Compiler Options 60 ***************************************/ 61 #if defined(__GNUC__) 62 # pragma GCC diagnostic ignored "-Wunused-function" 63 #endif 64 65 #if defined (__clang__) 66 # pragma clang diagnostic ignored "-Wunused-function" 67 #endif 68 69 70 /* ************************************* 71 * Common LZ4 definition 72 ***************************************/ 73 #define LZ4_COMMONDEFS_ONLY 74 #include "lz4.cc" 75 76 77 /* ************************************* 78 * Local Constants 79 ***************************************/ 80 #define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH) 81 82 83 /************************************** 84 * Local Macros 85 **************************************/ 86 #define HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG)) 87 /* #define DELTANEXTU16(p) chainTable[(p) & LZ4HC_MAXD_MASK] */ /* flexible, LZ4HC_MAXD dependent */ 88 #define DELTANEXTU16(p) chainTable[(U16)(p)] /* faster */ 89 90 static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); } 91 92 93 94 /************************************** 95 * HC Compression 96 **************************************/ 97 static void LZ4HC_init (LZ4HC_CCtx_internal* hc4, const BYTE* start) 98 { 99 MEM_INIT((void*)hc4->hashTable, 0, sizeof(hc4->hashTable)); 100 MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable)); 101 hc4->nextToUpdate = 64 KB; 102 hc4->base = start - 64 KB; 103 hc4->end = start; 104 hc4->dictBase = start - 64 KB; 105 hc4->dictLimit = 64 KB; 106 hc4->lowLimit = 64 KB; 107 } 108 109 110 /* Update chains up to ip (excluded) */ 111 FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip) 112 { 113 U16* const chainTable = hc4->chainTable; 114 U32* const hashTable = hc4->hashTable; 115 const BYTE* const base = hc4->base; 116 U32 const target = (U32)(ip - base); 117 U32 idx = hc4->nextToUpdate; 118 119 while (idx < target) { 120 U32 const h = LZ4HC_hashPtr(base+idx); 121 size_t delta = idx - hashTable[h]; 122 if (delta>MAX_DISTANCE) delta = MAX_DISTANCE; 123 DELTANEXTU16(idx) = (U16)delta; 124 hashTable[h] = idx; 125 idx++; 126 } 127 128 hc4->nextToUpdate = target; 129 } 130 131 132 FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_CCtx_internal* hc4, /* Index table will be updated */ 133 const BYTE* ip, const BYTE* const iLimit, 134 const BYTE** matchpos, 135 const int maxNbAttempts) 136 { 137 U16* const chainTable = hc4->chainTable; 138 U32* const HashTable = hc4->hashTable; 139 const BYTE* const base = hc4->base; 140 const BYTE* const dictBase = hc4->dictBase; 141 const U32 dictLimit = hc4->dictLimit; 142 const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - (64 KB - 1); 143 U32 matchIndex; 144 int nbAttempts=maxNbAttempts; 145 size_t ml=0; 146 147 /* HC4 match finder */ 148 LZ4HC_Insert(hc4, ip); 149 matchIndex = HashTable[LZ4HC_hashPtr(ip)]; 150 151 while ((matchIndex>=lowLimit) && (nbAttempts)) { 152 nbAttempts--; 153 if (matchIndex >= dictLimit) { 154 const BYTE* const match = base + matchIndex; 155 if (*(match+ml) == *(ip+ml) 156 && (LZ4_read32(match) == LZ4_read32(ip))) 157 { 158 size_t const mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, iLimit) + MINMATCH; 159 if (mlt > ml) { ml = mlt; *matchpos = match; } 160 } 161 } else { 162 const BYTE* const match = dictBase + matchIndex; 163 if (LZ4_read32(match) == LZ4_read32(ip)) { 164 size_t mlt; 165 const BYTE* vLimit = ip + (dictLimit - matchIndex); 166 if (vLimit > iLimit) vLimit = iLimit; 167 mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, vLimit) + MINMATCH; 168 if ((ip+mlt == vLimit) && (vLimit < iLimit)) 169 mlt += LZ4_count(ip+mlt, base+dictLimit, iLimit); 170 if (mlt > ml) { ml = mlt; *matchpos = base + matchIndex; } /* virtual matchpos */ 171 } 172 } 173 matchIndex -= DELTANEXTU16(matchIndex); 174 } 175 176 return (int)ml; 177 } 178 179 180 FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch ( 181 LZ4HC_CCtx_internal* hc4, 182 const BYTE* const ip, 183 const BYTE* const iLowLimit, 184 const BYTE* const iHighLimit, 185 int longest, 186 const BYTE** matchpos, 187 const BYTE** startpos, 188 const int maxNbAttempts) 189 { 190 U16* const chainTable = hc4->chainTable; 191 U32* const HashTable = hc4->hashTable; 192 const BYTE* const base = hc4->base; 193 const U32 dictLimit = hc4->dictLimit; 194 const BYTE* const lowPrefixPtr = base + dictLimit; 195 const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - (64 KB - 1); 196 const BYTE* const dictBase = hc4->dictBase; 197 U32 matchIndex; 198 int nbAttempts = maxNbAttempts; 199 int delta = (int)(ip-iLowLimit); 200 201 202 /* First Match */ 203 LZ4HC_Insert(hc4, ip); 204 matchIndex = HashTable[LZ4HC_hashPtr(ip)]; 205 206 while ((matchIndex>=lowLimit) && (nbAttempts)) { 207 nbAttempts--; 208 if (matchIndex >= dictLimit) { 209 const BYTE* matchPtr = base + matchIndex; 210 if (*(iLowLimit + longest) == *(matchPtr - delta + longest)) { 211 if (LZ4_read32(matchPtr) == LZ4_read32(ip)) { 212 int mlt = MINMATCH + LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit); 213 int back = 0; 214 215 while ((ip+back > iLowLimit) 216 && (matchPtr+back > lowPrefixPtr) 217 && (ip[back-1] == matchPtr[back-1])) 218 back--; 219 220 mlt -= back; 221 222 if (mlt > longest) { 223 longest = (int)mlt; 224 *matchpos = matchPtr+back; 225 *startpos = ip+back; 226 } 227 } 228 } 229 } else { 230 const BYTE* const matchPtr = dictBase + matchIndex; 231 if (LZ4_read32(matchPtr) == LZ4_read32(ip)) { 232 size_t mlt; 233 int back=0; 234 const BYTE* vLimit = ip + (dictLimit - matchIndex); 235 if (vLimit > iHighLimit) vLimit = iHighLimit; 236 mlt = LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH; 237 if ((ip+mlt == vLimit) && (vLimit < iHighLimit)) 238 mlt += LZ4_count(ip+mlt, base+dictLimit, iHighLimit); 239 while ((ip+back > iLowLimit) && (matchIndex+back > lowLimit) && (ip[back-1] == matchPtr[back-1])) back--; 240 mlt -= back; 241 if ((int)mlt > longest) { longest = (int)mlt; *matchpos = base + matchIndex + back; *startpos = ip+back; } 242 } 243 } 244 matchIndex -= DELTANEXTU16(matchIndex); 245 } 246 247 return longest; 248 } 249 250 251 typedef enum { noLimit = 0, limitedOutput = 1 } limitedOutput_directive; 252 253 #define LZ4HC_DEBUG 0 254 #if LZ4HC_DEBUG 255 static unsigned debug = 0; 256 #endif 257 258 FORCE_INLINE int LZ4HC_encodeSequence ( 259 const BYTE** ip, 260 BYTE** op, 261 const BYTE** anchor, 262 int matchLength, 263 const BYTE* const match, 264 limitedOutput_directive limitedOutputBuffer, 265 BYTE* oend) 266 { 267 int length; 268 BYTE* token; 269 270 #if LZ4HC_DEBUG 271 if (debug) printf("literal : %u -- match : %u -- offset : %u\n", (U32)(*ip - *anchor), (U32)matchLength, (U32)(*ip-match)); 272 #endif 273 274 /* Encode Literal length */ 275 length = (int)(*ip - *anchor); 276 token = (*op)++; 277 if ((limitedOutputBuffer) && ((*op + (length>>8) + length + (2 + 1 + LASTLITERALS)) > oend)) return 1; /* Check output limit */ 278 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; } 279 else *token = (BYTE)(length<<ML_BITS); 280 281 /* Copy Literals */ 282 LZ4_wildCopy(*op, *anchor, (*op) + length); 283 *op += length; 284 285 /* Encode Offset */ 286 LZ4_writeLE16(*op, (U16)(*ip-match)); *op += 2; 287 288 /* Encode MatchLength */ 289 length = (int)(matchLength-MINMATCH); 290 if ((limitedOutputBuffer) && (*op + (length>>8) + (1 + LASTLITERALS) > oend)) return 1; /* Check output limit */ 291 if (length>=(int)ML_MASK) { 292 *token += ML_MASK; 293 length -= ML_MASK; 294 for(; length > 509 ; length-=510) { *(*op)++ = 255; *(*op)++ = 255; } 295 if (length > 254) { length-=255; *(*op)++ = 255; } 296 *(*op)++ = (BYTE)length; 297 } else { 298 *token += (BYTE)(length); 299 } 300 301 /* Prepare next loop */ 302 *ip += matchLength; 303 *anchor = *ip; 304 305 return 0; 306 } 307 308 309 static int LZ4HC_compress_generic ( 310 LZ4HC_CCtx_internal* const ctx, 311 const char* const source, 312 char* const dest, 313 int const inputSize, 314 int const maxOutputSize, 315 int compressionLevel, 316 limitedOutput_directive limit 317 ) 318 { 319 const BYTE* ip = (const BYTE*) source; 320 const BYTE* anchor = ip; 321 const BYTE* const iend = ip + inputSize; 322 const BYTE* const mflimit = iend - MFLIMIT; 323 const BYTE* const matchlimit = (iend - LASTLITERALS); 324 325 BYTE* op = (BYTE*) dest; 326 BYTE* const oend = op + maxOutputSize; 327 328 unsigned maxNbAttempts; 329 int ml, ml2, ml3, ml0; 330 const BYTE* ref = NULL; 331 const BYTE* start2 = NULL; 332 const BYTE* ref2 = NULL; 333 const BYTE* start3 = NULL; 334 const BYTE* ref3 = NULL; 335 const BYTE* start0; 336 const BYTE* ref0; 337 338 /* init */ 339 if (compressionLevel > LZ4HC_MAX_CLEVEL) compressionLevel = LZ4HC_MAX_CLEVEL; 340 if (compressionLevel < 1) compressionLevel = LZ4HC_DEFAULT_CLEVEL; 341 maxNbAttempts = 1 << (compressionLevel-1); 342 ctx->end += inputSize; 343 344 ip++; 345 346 /* Main Loop */ 347 while (ip < mflimit) { 348 ml = LZ4HC_InsertAndFindBestMatch (ctx, ip, matchlimit, (&ref), maxNbAttempts); 349 if (!ml) { ip++; continue; } 350 351 /* saved, in case we would skip too much */ 352 start0 = ip; 353 ref0 = ref; 354 ml0 = ml; 355 356 _Search2: 357 if (ip+ml < mflimit) 358 ml2 = LZ4HC_InsertAndGetWiderMatch(ctx, ip + ml - 2, ip + 0, matchlimit, ml, &ref2, &start2, maxNbAttempts); 359 else ml2 = ml; 360 361 if (ml2 == ml) { /* No better match */ 362 if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0; 363 continue; 364 } 365 366 if (start0 < ip) { 367 if (start2 < ip + ml0) { /* empirical */ 368 ip = start0; 369 ref = ref0; 370 ml = ml0; 371 } 372 } 373 374 /* Here, start0==ip */ 375 if ((start2 - ip) < 3) { /* First Match too small : removed */ 376 ml = ml2; 377 ip = start2; 378 ref =ref2; 379 goto _Search2; 380 } 381 382 _Search3: 383 /* 384 * Currently we have : 385 * ml2 > ml1, and 386 * ip1+3 <= ip2 (usually < ip1+ml1) 387 */ 388 if ((start2 - ip) < OPTIMAL_ML) { 389 int correction; 390 int new_ml = ml; 391 if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML; 392 if (ip+new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - ip) + ml2 - MINMATCH; 393 correction = new_ml - (int)(start2 - ip); 394 if (correction > 0) { 395 start2 += correction; 396 ref2 += correction; 397 ml2 -= correction; 398 } 399 } 400 /* Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) */ 401 402 if (start2 + ml2 < mflimit) 403 ml3 = LZ4HC_InsertAndGetWiderMatch(ctx, start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3, maxNbAttempts); 404 else ml3 = ml2; 405 406 if (ml3 == ml2) { /* No better match : 2 sequences to encode */ 407 /* ip & ref are known; Now for ml */ 408 if (start2 < ip+ml) ml = (int)(start2 - ip); 409 /* Now, encode 2 sequences */ 410 if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0; 411 ip = start2; 412 if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml2, ref2, limit, oend)) return 0; 413 continue; 414 } 415 416 if (start3 < ip+ml+3) { /* Not enough space for match 2 : remove it */ 417 if (start3 >= (ip+ml)) { /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */ 418 if (start2 < ip+ml) { 419 int correction = (int)(ip+ml - start2); 420 start2 += correction; 421 ref2 += correction; 422 ml2 -= correction; 423 if (ml2 < MINMATCH) { 424 start2 = start3; 425 ref2 = ref3; 426 ml2 = ml3; 427 } 428 } 429 430 if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0; 431 ip = start3; 432 ref = ref3; 433 ml = ml3; 434 435 start0 = start2; 436 ref0 = ref2; 437 ml0 = ml2; 438 goto _Search2; 439 } 440 441 start2 = start3; 442 ref2 = ref3; 443 ml2 = ml3; 444 goto _Search3; 445 } 446 447 /* 448 * OK, now we have 3 ascending matches; let's write at least the first one 449 * ip & ref are known; Now for ml 450 */ 451 if (start2 < ip+ml) { 452 if ((start2 - ip) < (int)ML_MASK) { 453 int correction; 454 if (ml > OPTIMAL_ML) ml = OPTIMAL_ML; 455 if (ip + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - ip) + ml2 - MINMATCH; 456 correction = ml - (int)(start2 - ip); 457 if (correction > 0) { 458 start2 += correction; 459 ref2 += correction; 460 ml2 -= correction; 461 } 462 } else { 463 ml = (int)(start2 - ip); 464 } 465 } 466 if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0; 467 468 ip = start2; 469 ref = ref2; 470 ml = ml2; 471 472 start2 = start3; 473 ref2 = ref3; 474 ml2 = ml3; 475 476 goto _Search3; 477 } 478 479 /* Encode Last Literals */ 480 { int lastRun = (int)(iend - anchor); 481 if ((limit) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) return 0; /* Check output limit */ 482 if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK<<ML_BITS); lastRun-=RUN_MASK; for(; lastRun > 254 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; } 483 else *op++ = (BYTE)(lastRun<<ML_BITS); 484 memcpy(op, anchor, iend - anchor); 485 op += iend-anchor; 486 } 487 488 /* End */ 489 return (int) (((char*)op)-dest); 490 } 491 492 493 int LZ4_sizeofStateHC(void) { return sizeof(LZ4_streamHC_t); } 494 495 int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel) 496 { 497 LZ4HC_CCtx_internal* ctx = &((LZ4_streamHC_t*)state)->internal_donotuse; 498 if (((size_t)(state)&(sizeof(void*)-1)) != 0) return 0; /* Error : state is not aligned for pointers (32 or 64 bits) */ 499 LZ4HC_init (ctx, (const BYTE*)src); 500 if (maxDstSize < LZ4_compressBound(srcSize)) 501 return LZ4HC_compress_generic (ctx, src, dst, srcSize, maxDstSize, compressionLevel, limitedOutput); 502 else 503 return LZ4HC_compress_generic (ctx, src, dst, srcSize, maxDstSize, compressionLevel, noLimit); 504 } 505 506 int LZ4_compress_HC(const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel) 507 { 508 #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 509 LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)malloc(sizeof(LZ4_streamHC_t)); 510 #else 511 LZ4_streamHC_t state; 512 LZ4_streamHC_t* const statePtr = &state; 513 #endif 514 int const cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, maxDstSize, compressionLevel); 515 #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 516 free(statePtr); 517 #endif 518 return cSize; 519 } 520 521 522 523 /************************************** 524 * Streaming Functions 525 **************************************/ 526 /* allocation */ 527 LZ4_streamHC_t* LZ4_createStreamHC(void) { return (LZ4_streamHC_t*)malloc(sizeof(LZ4_streamHC_t)); } 528 int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr) { free(LZ4_streamHCPtr); return 0; } 529 530 531 /* initialization */ 532 void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel) 533 { 534 LZ4_STATIC_ASSERT(sizeof(LZ4HC_CCtx_internal) <= sizeof(size_t) * LZ4_STREAMHCSIZE_SIZET); /* if compilation fails here, LZ4_STREAMHCSIZE must be increased */ 535 LZ4_streamHCPtr->internal_donotuse.base = NULL; 536 LZ4_streamHCPtr->internal_donotuse.compressionLevel = (unsigned)compressionLevel; 537 } 538 539 int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, const char* dictionary, int dictSize) 540 { 541 LZ4HC_CCtx_internal* ctxPtr = &LZ4_streamHCPtr->internal_donotuse; 542 if (dictSize > 64 KB) { 543 dictionary += dictSize - 64 KB; 544 dictSize = 64 KB; 545 } 546 LZ4HC_init (ctxPtr, (const BYTE*)dictionary); 547 if (dictSize >= 4) LZ4HC_Insert (ctxPtr, (const BYTE*)dictionary +(dictSize-3)); 548 ctxPtr->end = (const BYTE*)dictionary + dictSize; 549 return dictSize; 550 } 551 552 553 /* compression */ 554 555 static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock) 556 { 557 if (ctxPtr->end >= ctxPtr->base + 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3); /* Referencing remaining dictionary content */ 558 /* Only one memory segment for extDict, so any previous extDict is lost at this stage */ 559 ctxPtr->lowLimit = ctxPtr->dictLimit; 560 ctxPtr->dictLimit = (U32)(ctxPtr->end - ctxPtr->base); 561 ctxPtr->dictBase = ctxPtr->base; 562 ctxPtr->base = newBlock - ctxPtr->dictLimit; 563 ctxPtr->end = newBlock; 564 ctxPtr->nextToUpdate = ctxPtr->dictLimit; /* match referencing will resume from there */ 565 } 566 567 static int LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr, 568 const char* source, char* dest, 569 int inputSize, int maxOutputSize, limitedOutput_directive limit) 570 { 571 LZ4HC_CCtx_internal* ctxPtr = &LZ4_streamHCPtr->internal_donotuse; 572 /* auto-init if forgotten */ 573 if (ctxPtr->base == NULL) LZ4HC_init (ctxPtr, (const BYTE*) source); 574 575 /* Check overflow */ 576 if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 GB) { 577 size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->base) - ctxPtr->dictLimit; 578 if (dictSize > 64 KB) dictSize = 64 KB; 579 LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize); 580 } 581 582 /* Check if blocks follow each other */ 583 if ((const BYTE*)source != ctxPtr->end) LZ4HC_setExternalDict(ctxPtr, (const BYTE*)source); 584 585 /* Check overlapping input/dictionary space */ 586 { const BYTE* sourceEnd = (const BYTE*) source + inputSize; 587 const BYTE* const dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit; 588 const BYTE* const dictEnd = ctxPtr->dictBase + ctxPtr->dictLimit; 589 if ((sourceEnd > dictBegin) && ((const BYTE*)source < dictEnd)) { 590 if (sourceEnd > dictEnd) sourceEnd = dictEnd; 591 ctxPtr->lowLimit = (U32)(sourceEnd - ctxPtr->dictBase); 592 if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) ctxPtr->lowLimit = ctxPtr->dictLimit; 593 } 594 } 595 596 return LZ4HC_compress_generic (ctxPtr, source, dest, inputSize, maxOutputSize, ctxPtr->compressionLevel, limit); 597 } 598 599 int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize, int maxOutputSize) 600 { 601 if (maxOutputSize < LZ4_compressBound(inputSize)) 602 return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, source, dest, inputSize, maxOutputSize, limitedOutput); 603 else 604 return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, source, dest, inputSize, maxOutputSize, noLimit); 605 } 606 607 608 /* dictionary saving */ 609 610 int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize) 611 { 612 LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse; 613 int const prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit)); 614 if (dictSize > 64 KB) dictSize = 64 KB; 615 if (dictSize < 4) dictSize = 0; 616 if (dictSize > prefixSize) dictSize = prefixSize; 617 memmove(safeBuffer, streamPtr->end - dictSize, dictSize); 618 { U32 const endIndex = (U32)(streamPtr->end - streamPtr->base); 619 streamPtr->end = (const BYTE*)safeBuffer + dictSize; 620 streamPtr->base = streamPtr->end - endIndex; 621 streamPtr->dictLimit = endIndex - dictSize; 622 streamPtr->lowLimit = endIndex - dictSize; 623 if (streamPtr->nextToUpdate < streamPtr->dictLimit) streamPtr->nextToUpdate = streamPtr->dictLimit; 624 } 625 return dictSize; 626 } 627 628 629 /*********************************** 630 * Deprecated Functions 631 ***********************************/ 632 /* These functions currently generate deprecation warnings */ 633 /* Deprecated compression functions */ 634 int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); } 635 int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); } 636 int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); } 637 int LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); } 638 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); } 639 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); } 640 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); } 641 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); } 642 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)); } 643 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); } 644 645 646 /* Deprecated streaming functions */ 647 int LZ4_sizeofStreamStateHC(void) { return LZ4_STREAMHCSIZE; } 648 649 int LZ4_resetStreamStateHC(void* state, char* inputBuffer) 650 { 651 LZ4HC_CCtx_internal *ctx = &((LZ4_streamHC_t*)state)->internal_donotuse; 652 if ((((size_t)state) & (sizeof(void*)-1)) != 0) return 1; /* Error : pointer is not aligned for pointer (32 or 64 bits) */ 653 LZ4HC_init(ctx, (const BYTE*)inputBuffer); 654 ctx->inputBuffer = (BYTE*)inputBuffer; 655 return 0; 656 } 657 658 void* LZ4_createHC (char* inputBuffer) 659 { 660 LZ4_streamHC_t* hc4 = (LZ4_streamHC_t*)ALLOCATOR(1, sizeof(LZ4_streamHC_t)); 661 if (hc4 == NULL) return NULL; /* not enough memory */ 662 LZ4HC_init (&hc4->internal_donotuse, (const BYTE*)inputBuffer); 663 hc4->internal_donotuse.inputBuffer = (BYTE*)inputBuffer; 664 return hc4; 665 } 666 667 int LZ4_freeHC (void* LZ4HC_Data) { FREEMEM(LZ4HC_Data); return 0; } 668 669 int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel) 670 { 671 return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, source, dest, inputSize, 0, compressionLevel, noLimit); 672 } 673 674 int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel) 675 { 676 return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, source, dest, inputSize, maxOutputSize, compressionLevel, limitedOutput); 677 } 678 679 char* LZ4_slideInputBufferHC(void* LZ4HC_Data) 680 { 681 LZ4HC_CCtx_internal* const hc4 = &((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse; 682 int const dictSize = LZ4_saveDictHC((LZ4_streamHC_t*)LZ4HC_Data, (char*)(hc4->inputBuffer), 64 KB); 683 return (char*)(hc4->inputBuffer + dictSize); 684 }