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