Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * LZ4 HC - High Compression Mode of LZ4
0003  * Copyright (C) 2011-2015, Yann Collet.
0004  *
0005  * BSD 2 - Clause License (http://www.opensource.org/licenses/bsd - license.php)
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions are
0008  * met:
0009  *  * Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  *  * Redistributions in binary form must reproduce the above
0012  * copyright notice, this list of conditions and the following disclaimer
0013  * in the documentation and/or other materials provided with the
0014  * distribution.
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0016  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0017  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0018  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0019  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0020  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0021  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0022  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0023  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0024  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0025  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0026  * You can contact the author at :
0027  *  - LZ4 homepage : http://www.lz4.org
0028  *  - LZ4 source repository : https://github.com/lz4/lz4
0029  *
0030  *  Changed for kernel usage by:
0031  *  Sven Schmidt <4sschmid@informatik.uni-hamburg.de>
0032  */
0033 
0034 /*-************************************
0035  *  Dependencies
0036  **************************************/
0037 #include <linux/lz4.h>
0038 #include "lz4defs.h"
0039 #include <linux/module.h>
0040 #include <linux/kernel.h>
0041 #include <linux/string.h> /* memset */
0042 
0043 /* *************************************
0044  *  Local Constants and types
0045  ***************************************/
0046 
0047 #define OPTIMAL_ML (int)((ML_MASK - 1) + MINMATCH)
0048 
0049 #define HASH_FUNCTION(i)    (((i) * 2654435761U) \
0050     >> ((MINMATCH*8) - LZ4HC_HASH_LOG))
0051 #define DELTANEXTU16(p) chainTable[(U16)(p)] /* faster */
0052 
0053 static U32 LZ4HC_hashPtr(const void *ptr)
0054 {
0055     return HASH_FUNCTION(LZ4_read32(ptr));
0056 }
0057 
0058 /**************************************
0059  *  HC Compression
0060  **************************************/
0061 static void LZ4HC_init(LZ4HC_CCtx_internal *hc4, const BYTE *start)
0062 {
0063     memset((void *)hc4->hashTable, 0, sizeof(hc4->hashTable));
0064     memset(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));
0065     hc4->nextToUpdate = 64 * KB;
0066     hc4->base = start - 64 * KB;
0067     hc4->end = start;
0068     hc4->dictBase = start - 64 * KB;
0069     hc4->dictLimit = 64 * KB;
0070     hc4->lowLimit = 64 * KB;
0071 }
0072 
0073 /* Update chains up to ip (excluded) */
0074 static FORCE_INLINE void LZ4HC_Insert(LZ4HC_CCtx_internal *hc4,
0075     const BYTE *ip)
0076 {
0077     U16 * const chainTable = hc4->chainTable;
0078     U32 * const hashTable   = hc4->hashTable;
0079     const BYTE * const base = hc4->base;
0080     U32 const target = (U32)(ip - base);
0081     U32 idx = hc4->nextToUpdate;
0082 
0083     while (idx < target) {
0084         U32 const h = LZ4HC_hashPtr(base + idx);
0085         size_t delta = idx - hashTable[h];
0086 
0087         if (delta > MAX_DISTANCE)
0088             delta = MAX_DISTANCE;
0089 
0090         DELTANEXTU16(idx) = (U16)delta;
0091 
0092         hashTable[h] = idx;
0093         idx++;
0094     }
0095 
0096     hc4->nextToUpdate = target;
0097 }
0098 
0099 static FORCE_INLINE int LZ4HC_InsertAndFindBestMatch(
0100     LZ4HC_CCtx_internal *hc4, /* Index table will be updated */
0101     const BYTE *ip,
0102     const BYTE * const iLimit,
0103     const BYTE **matchpos,
0104     const int maxNbAttempts)
0105 {
0106     U16 * const chainTable = hc4->chainTable;
0107     U32 * const HashTable = hc4->hashTable;
0108     const BYTE * const base = hc4->base;
0109     const BYTE * const dictBase = hc4->dictBase;
0110     const U32 dictLimit = hc4->dictLimit;
0111     const U32 lowLimit = (hc4->lowLimit + 64 * KB > (U32)(ip - base))
0112         ? hc4->lowLimit
0113         : (U32)(ip - base) - (64 * KB - 1);
0114     U32 matchIndex;
0115     int nbAttempts = maxNbAttempts;
0116     size_t ml = 0;
0117 
0118     /* HC4 match finder */
0119     LZ4HC_Insert(hc4, ip);
0120     matchIndex = HashTable[LZ4HC_hashPtr(ip)];
0121 
0122     while ((matchIndex >= lowLimit)
0123         && (nbAttempts)) {
0124         nbAttempts--;
0125         if (matchIndex >= dictLimit) {
0126             const BYTE * const match = base + matchIndex;
0127 
0128             if (*(match + ml) == *(ip + ml)
0129                 && (LZ4_read32(match) == LZ4_read32(ip))) {
0130                 size_t const mlt = LZ4_count(ip + MINMATCH,
0131                     match + MINMATCH, iLimit) + MINMATCH;
0132 
0133                 if (mlt > ml) {
0134                     ml = mlt;
0135                     *matchpos = match;
0136                 }
0137             }
0138         } else {
0139             const BYTE * const match = dictBase + matchIndex;
0140 
0141             if (LZ4_read32(match) == LZ4_read32(ip)) {
0142                 size_t mlt;
0143                 const BYTE *vLimit = ip
0144                     + (dictLimit - matchIndex);
0145 
0146                 if (vLimit > iLimit)
0147                     vLimit = iLimit;
0148                 mlt = LZ4_count(ip + MINMATCH,
0149                     match + MINMATCH, vLimit) + MINMATCH;
0150                 if ((ip + mlt == vLimit)
0151                     && (vLimit < iLimit))
0152                     mlt += LZ4_count(ip + mlt,
0153                         base + dictLimit,
0154                         iLimit);
0155                 if (mlt > ml) {
0156                     /* virtual matchpos */
0157                     ml = mlt;
0158                     *matchpos = base + matchIndex;
0159                 }
0160             }
0161         }
0162         matchIndex -= DELTANEXTU16(matchIndex);
0163     }
0164 
0165     return (int)ml;
0166 }
0167 
0168 static FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch(
0169     LZ4HC_CCtx_internal *hc4,
0170     const BYTE * const ip,
0171     const BYTE * const iLowLimit,
0172     const BYTE * const iHighLimit,
0173     int longest,
0174     const BYTE **matchpos,
0175     const BYTE **startpos,
0176     const int maxNbAttempts)
0177 {
0178     U16 * const chainTable = hc4->chainTable;
0179     U32 * const HashTable = hc4->hashTable;
0180     const BYTE * const base = hc4->base;
0181     const U32 dictLimit = hc4->dictLimit;
0182     const BYTE * const lowPrefixPtr = base + dictLimit;
0183     const U32 lowLimit = (hc4->lowLimit + 64 * KB > (U32)(ip - base))
0184         ? hc4->lowLimit
0185         : (U32)(ip - base) - (64 * KB - 1);
0186     const BYTE * const dictBase = hc4->dictBase;
0187     U32 matchIndex;
0188     int nbAttempts = maxNbAttempts;
0189     int delta = (int)(ip - iLowLimit);
0190 
0191     /* First Match */
0192     LZ4HC_Insert(hc4, ip);
0193     matchIndex = HashTable[LZ4HC_hashPtr(ip)];
0194 
0195     while ((matchIndex >= lowLimit)
0196         && (nbAttempts)) {
0197         nbAttempts--;
0198         if (matchIndex >= dictLimit) {
0199             const BYTE *matchPtr = base + matchIndex;
0200 
0201             if (*(iLowLimit + longest)
0202                 == *(matchPtr - delta + longest)) {
0203                 if (LZ4_read32(matchPtr) == LZ4_read32(ip)) {
0204                     int mlt = MINMATCH + LZ4_count(
0205                         ip + MINMATCH,
0206                         matchPtr + MINMATCH,
0207                         iHighLimit);
0208                     int back = 0;
0209 
0210                     while ((ip + back > iLowLimit)
0211                         && (matchPtr + back > lowPrefixPtr)
0212                         && (ip[back - 1] == matchPtr[back - 1]))
0213                         back--;
0214 
0215                     mlt -= back;
0216 
0217                     if (mlt > longest) {
0218                         longest = (int)mlt;
0219                         *matchpos = matchPtr + back;
0220                         *startpos = ip + back;
0221                     }
0222                 }
0223             }
0224         } else {
0225             const BYTE * const matchPtr = dictBase + matchIndex;
0226 
0227             if (LZ4_read32(matchPtr) == LZ4_read32(ip)) {
0228                 size_t mlt;
0229                 int back = 0;
0230                 const BYTE *vLimit = ip + (dictLimit - matchIndex);
0231 
0232                 if (vLimit > iHighLimit)
0233                     vLimit = iHighLimit;
0234 
0235                 mlt = LZ4_count(ip + MINMATCH,
0236                     matchPtr + MINMATCH, vLimit) + MINMATCH;
0237 
0238                 if ((ip + mlt == vLimit) && (vLimit < iHighLimit))
0239                     mlt += LZ4_count(ip + mlt, base + dictLimit,
0240                         iHighLimit);
0241                 while ((ip + back > iLowLimit)
0242                     && (matchIndex + back > lowLimit)
0243                     && (ip[back - 1] == matchPtr[back - 1]))
0244                     back--;
0245 
0246                 mlt -= back;
0247 
0248                 if ((int)mlt > longest) {
0249                     longest = (int)mlt;
0250                     *matchpos = base + matchIndex + back;
0251                     *startpos = ip + back;
0252                 }
0253             }
0254         }
0255 
0256         matchIndex -= DELTANEXTU16(matchIndex);
0257     }
0258 
0259     return longest;
0260 }
0261 
0262 static FORCE_INLINE int LZ4HC_encodeSequence(
0263     const BYTE **ip,
0264     BYTE **op,
0265     const BYTE **anchor,
0266     int matchLength,
0267     const BYTE * const match,
0268     limitedOutput_directive limitedOutputBuffer,
0269     BYTE *oend)
0270 {
0271     int length;
0272     BYTE *token;
0273 
0274     /* Encode Literal length */
0275     length = (int)(*ip - *anchor);
0276     token = (*op)++;
0277 
0278     if ((limitedOutputBuffer)
0279         && ((*op + (length>>8)
0280             + length + (2 + 1 + LASTLITERALS)) > oend)) {
0281         /* Check output limit */
0282         return 1;
0283     }
0284     if (length >= (int)RUN_MASK) {
0285         int len;
0286 
0287         *token = (RUN_MASK<<ML_BITS);
0288         len = length - RUN_MASK;
0289         for (; len > 254 ; len -= 255)
0290             *(*op)++ = 255;
0291         *(*op)++ = (BYTE)len;
0292     } else
0293         *token = (BYTE)(length<<ML_BITS);
0294 
0295     /* Copy Literals */
0296     LZ4_wildCopy(*op, *anchor, (*op) + length);
0297     *op += length;
0298 
0299     /* Encode Offset */
0300     LZ4_writeLE16(*op, (U16)(*ip - match));
0301     *op += 2;
0302 
0303     /* Encode MatchLength */
0304     length = (int)(matchLength - MINMATCH);
0305 
0306     if ((limitedOutputBuffer)
0307         && (*op + (length>>8)
0308             + (1 + LASTLITERALS) > oend)) {
0309         /* Check output limit */
0310         return 1;
0311     }
0312 
0313     if (length >= (int)ML_MASK) {
0314         *token += ML_MASK;
0315         length -= ML_MASK;
0316 
0317         for (; length > 509 ; length -= 510) {
0318             *(*op)++ = 255;
0319             *(*op)++ = 255;
0320         }
0321 
0322         if (length > 254) {
0323             length -= 255;
0324             *(*op)++ = 255;
0325         }
0326 
0327         *(*op)++ = (BYTE)length;
0328     } else
0329         *token += (BYTE)(length);
0330 
0331     /* Prepare next loop */
0332     *ip += matchLength;
0333     *anchor = *ip;
0334 
0335     return 0;
0336 }
0337 
0338 static int LZ4HC_compress_generic(
0339     LZ4HC_CCtx_internal *const ctx,
0340     const char * const source,
0341     char * const dest,
0342     int const inputSize,
0343     int const maxOutputSize,
0344     int compressionLevel,
0345     limitedOutput_directive limit
0346     )
0347 {
0348     const BYTE *ip = (const BYTE *) source;
0349     const BYTE *anchor = ip;
0350     const BYTE * const iend = ip + inputSize;
0351     const BYTE * const mflimit = iend - MFLIMIT;
0352     const BYTE * const matchlimit = (iend - LASTLITERALS);
0353 
0354     BYTE *op = (BYTE *) dest;
0355     BYTE * const oend = op + maxOutputSize;
0356 
0357     unsigned int maxNbAttempts;
0358     int ml, ml2, ml3, ml0;
0359     const BYTE *ref = NULL;
0360     const BYTE *start2 = NULL;
0361     const BYTE *ref2 = NULL;
0362     const BYTE *start3 = NULL;
0363     const BYTE *ref3 = NULL;
0364     const BYTE *start0;
0365     const BYTE *ref0;
0366 
0367     /* init */
0368     if (compressionLevel > LZ4HC_MAX_CLEVEL)
0369         compressionLevel = LZ4HC_MAX_CLEVEL;
0370     if (compressionLevel < 1)
0371         compressionLevel = LZ4HC_DEFAULT_CLEVEL;
0372     maxNbAttempts = 1 << (compressionLevel - 1);
0373     ctx->end += inputSize;
0374 
0375     ip++;
0376 
0377     /* Main Loop */
0378     while (ip < mflimit) {
0379         ml = LZ4HC_InsertAndFindBestMatch(ctx, ip,
0380             matchlimit, (&ref), maxNbAttempts);
0381         if (!ml) {
0382             ip++;
0383             continue;
0384         }
0385 
0386         /* saved, in case we would skip too much */
0387         start0 = ip;
0388         ref0 = ref;
0389         ml0 = ml;
0390 
0391 _Search2:
0392         if (ip + ml < mflimit)
0393             ml2 = LZ4HC_InsertAndGetWiderMatch(ctx,
0394                 ip + ml - 2, ip + 0,
0395                 matchlimit, ml, &ref2,
0396                 &start2, maxNbAttempts);
0397         else
0398             ml2 = ml;
0399 
0400         if (ml2 == ml) {
0401             /* No better match */
0402             if (LZ4HC_encodeSequence(&ip, &op,
0403                 &anchor, ml, ref, limit, oend))
0404                 return 0;
0405             continue;
0406         }
0407 
0408         if (start0 < ip) {
0409             if (start2 < ip + ml0) {
0410                 /* empirical */
0411                 ip = start0;
0412                 ref = ref0;
0413                 ml = ml0;
0414             }
0415         }
0416 
0417         /* Here, start0 == ip */
0418         if ((start2 - ip) < 3) {
0419             /* First Match too small : removed */
0420             ml = ml2;
0421             ip = start2;
0422             ref = ref2;
0423             goto _Search2;
0424         }
0425 
0426 _Search3:
0427         /*
0428         * Currently we have :
0429         * ml2 > ml1, and
0430         * ip1 + 3 <= ip2 (usually < ip1 + ml1)
0431         */
0432         if ((start2 - ip) < OPTIMAL_ML) {
0433             int correction;
0434             int new_ml = ml;
0435 
0436             if (new_ml > OPTIMAL_ML)
0437                 new_ml = OPTIMAL_ML;
0438             if (ip + new_ml > start2 + ml2 - MINMATCH)
0439                 new_ml = (int)(start2 - ip) + ml2 - MINMATCH;
0440 
0441             correction = new_ml - (int)(start2 - ip);
0442 
0443             if (correction > 0) {
0444                 start2 += correction;
0445                 ref2 += correction;
0446                 ml2 -= correction;
0447             }
0448         }
0449         /*
0450          * Now, we have start2 = ip + new_ml,
0451          * with new_ml = min(ml, OPTIMAL_ML = 18)
0452          */
0453 
0454         if (start2 + ml2 < mflimit)
0455             ml3 = LZ4HC_InsertAndGetWiderMatch(ctx,
0456                 start2 + ml2 - 3, start2,
0457                 matchlimit, ml2, &ref3, &start3,
0458                 maxNbAttempts);
0459         else
0460             ml3 = ml2;
0461 
0462         if (ml3 == ml2) {
0463             /* No better match : 2 sequences to encode */
0464             /* ip & ref are known; Now for ml */
0465             if (start2 < ip + ml)
0466                 ml = (int)(start2 - ip);
0467             /* Now, encode 2 sequences */
0468             if (LZ4HC_encodeSequence(&ip, &op, &anchor,
0469                 ml, ref, limit, oend))
0470                 return 0;
0471             ip = start2;
0472             if (LZ4HC_encodeSequence(&ip, &op, &anchor,
0473                 ml2, ref2, limit, oend))
0474                 return 0;
0475             continue;
0476         }
0477 
0478         if (start3 < ip + ml + 3) {
0479             /* Not enough space for match 2 : remove it */
0480             if (start3 >= (ip + ml)) {
0481                 /* can write Seq1 immediately
0482                  * ==> Seq2 is removed,
0483                  * so Seq3 becomes Seq1
0484                  */
0485                 if (start2 < ip + ml) {
0486                     int correction = (int)(ip + ml - start2);
0487 
0488                     start2 += correction;
0489                     ref2 += correction;
0490                     ml2 -= correction;
0491                     if (ml2 < MINMATCH) {
0492                         start2 = start3;
0493                         ref2 = ref3;
0494                         ml2 = ml3;
0495                     }
0496                 }
0497 
0498                 if (LZ4HC_encodeSequence(&ip, &op, &anchor,
0499                     ml, ref, limit, oend))
0500                     return 0;
0501                 ip = start3;
0502                 ref = ref3;
0503                 ml = ml3;
0504 
0505                 start0 = start2;
0506                 ref0 = ref2;
0507                 ml0 = ml2;
0508                 goto _Search2;
0509             }
0510 
0511             start2 = start3;
0512             ref2 = ref3;
0513             ml2 = ml3;
0514             goto _Search3;
0515         }
0516 
0517         /*
0518         * OK, now we have 3 ascending matches;
0519         * let's write at least the first one
0520         * ip & ref are known; Now for ml
0521         */
0522         if (start2 < ip + ml) {
0523             if ((start2 - ip) < (int)ML_MASK) {
0524                 int correction;
0525 
0526                 if (ml > OPTIMAL_ML)
0527                     ml = OPTIMAL_ML;
0528                 if (ip + ml > start2 + ml2 - MINMATCH)
0529                     ml = (int)(start2 - ip) + ml2 - MINMATCH;
0530                 correction = ml - (int)(start2 - ip);
0531                 if (correction > 0) {
0532                     start2 += correction;
0533                     ref2 += correction;
0534                     ml2 -= correction;
0535                 }
0536             } else
0537                 ml = (int)(start2 - ip);
0538         }
0539         if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml,
0540             ref, limit, oend))
0541             return 0;
0542 
0543         ip = start2;
0544         ref = ref2;
0545         ml = ml2;
0546 
0547         start2 = start3;
0548         ref2 = ref3;
0549         ml2 = ml3;
0550 
0551         goto _Search3;
0552     }
0553 
0554     /* Encode Last Literals */
0555     {
0556         int lastRun = (int)(iend - anchor);
0557 
0558         if ((limit)
0559             && (((char *)op - dest) + lastRun + 1
0560                 + ((lastRun + 255 - RUN_MASK)/255)
0561                     > (U32)maxOutputSize)) {
0562             /* Check output limit */
0563             return 0;
0564         }
0565         if (lastRun >= (int)RUN_MASK) {
0566             *op++ = (RUN_MASK<<ML_BITS);
0567             lastRun -= RUN_MASK;
0568             for (; lastRun > 254 ; lastRun -= 255)
0569                 *op++ = 255;
0570             *op++ = (BYTE) lastRun;
0571         } else
0572             *op++ = (BYTE)(lastRun<<ML_BITS);
0573         LZ4_memcpy(op, anchor, iend - anchor);
0574         op += iend - anchor;
0575     }
0576 
0577     /* End */
0578     return (int) (((char *)op) - dest);
0579 }
0580 
0581 static int LZ4_compress_HC_extStateHC(
0582     void *state,
0583     const char *src,
0584     char *dst,
0585     int srcSize,
0586     int maxDstSize,
0587     int compressionLevel)
0588 {
0589     LZ4HC_CCtx_internal *ctx = &((LZ4_streamHC_t *)state)->internal_donotuse;
0590 
0591     if (((size_t)(state)&(sizeof(void *) - 1)) != 0) {
0592         /* Error : state is not aligned
0593          * for pointers (32 or 64 bits)
0594          */
0595         return 0;
0596     }
0597 
0598     LZ4HC_init(ctx, (const BYTE *)src);
0599 
0600     if (maxDstSize < LZ4_compressBound(srcSize))
0601         return LZ4HC_compress_generic(ctx, src, dst,
0602             srcSize, maxDstSize, compressionLevel, limitedOutput);
0603     else
0604         return LZ4HC_compress_generic(ctx, src, dst,
0605             srcSize, maxDstSize, compressionLevel, noLimit);
0606 }
0607 
0608 int LZ4_compress_HC(const char *src, char *dst, int srcSize,
0609     int maxDstSize, int compressionLevel, void *wrkmem)
0610 {
0611     return LZ4_compress_HC_extStateHC(wrkmem, src, dst,
0612         srcSize, maxDstSize, compressionLevel);
0613 }
0614 EXPORT_SYMBOL(LZ4_compress_HC);
0615 
0616 /**************************************
0617  *  Streaming Functions
0618  **************************************/
0619 void LZ4_resetStreamHC(LZ4_streamHC_t *LZ4_streamHCPtr, int compressionLevel)
0620 {
0621     LZ4_streamHCPtr->internal_donotuse.base = NULL;
0622     LZ4_streamHCPtr->internal_donotuse.compressionLevel = (unsigned int)compressionLevel;
0623 }
0624 
0625 int LZ4_loadDictHC(LZ4_streamHC_t *LZ4_streamHCPtr,
0626     const char *dictionary,
0627     int dictSize)
0628 {
0629     LZ4HC_CCtx_internal *ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
0630 
0631     if (dictSize > 64 * KB) {
0632         dictionary += dictSize - 64 * KB;
0633         dictSize = 64 * KB;
0634     }
0635     LZ4HC_init(ctxPtr, (const BYTE *)dictionary);
0636     if (dictSize >= 4)
0637         LZ4HC_Insert(ctxPtr, (const BYTE *)dictionary + (dictSize - 3));
0638     ctxPtr->end = (const BYTE *)dictionary + dictSize;
0639     return dictSize;
0640 }
0641 EXPORT_SYMBOL(LZ4_loadDictHC);
0642 
0643 /* compression */
0644 
0645 static void LZ4HC_setExternalDict(
0646     LZ4HC_CCtx_internal *ctxPtr,
0647     const BYTE *newBlock)
0648 {
0649     if (ctxPtr->end >= ctxPtr->base + 4) {
0650         /* Referencing remaining dictionary content */
0651         LZ4HC_Insert(ctxPtr, ctxPtr->end - 3);
0652     }
0653 
0654     /*
0655      * Only one memory segment for extDict,
0656      * so any previous extDict is lost at this stage
0657      */
0658     ctxPtr->lowLimit    = ctxPtr->dictLimit;
0659     ctxPtr->dictLimit = (U32)(ctxPtr->end - ctxPtr->base);
0660     ctxPtr->dictBase    = ctxPtr->base;
0661     ctxPtr->base = newBlock - ctxPtr->dictLimit;
0662     ctxPtr->end = newBlock;
0663     /* match referencing will resume from there */
0664     ctxPtr->nextToUpdate = ctxPtr->dictLimit;
0665 }
0666 
0667 static int LZ4_compressHC_continue_generic(
0668     LZ4_streamHC_t *LZ4_streamHCPtr,
0669     const char *source,
0670     char *dest,
0671     int inputSize,
0672     int maxOutputSize,
0673     limitedOutput_directive limit)
0674 {
0675     LZ4HC_CCtx_internal *ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
0676 
0677     /* auto - init if forgotten */
0678     if (ctxPtr->base == NULL)
0679         LZ4HC_init(ctxPtr, (const BYTE *) source);
0680 
0681     /* Check overflow */
0682     if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 * GB) {
0683         size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->base)
0684             - ctxPtr->dictLimit;
0685         if (dictSize > 64 * KB)
0686             dictSize = 64 * KB;
0687         LZ4_loadDictHC(LZ4_streamHCPtr,
0688             (const char *)(ctxPtr->end) - dictSize, (int)dictSize);
0689     }
0690 
0691     /* Check if blocks follow each other */
0692     if ((const BYTE *)source != ctxPtr->end)
0693         LZ4HC_setExternalDict(ctxPtr, (const BYTE *)source);
0694 
0695     /* Check overlapping input/dictionary space */
0696     {
0697         const BYTE *sourceEnd = (const BYTE *) source + inputSize;
0698         const BYTE * const dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit;
0699         const BYTE * const dictEnd = ctxPtr->dictBase + ctxPtr->dictLimit;
0700 
0701         if ((sourceEnd > dictBegin)
0702             && ((const BYTE *)source < dictEnd)) {
0703             if (sourceEnd > dictEnd)
0704                 sourceEnd = dictEnd;
0705             ctxPtr->lowLimit = (U32)(sourceEnd - ctxPtr->dictBase);
0706 
0707             if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4)
0708                 ctxPtr->lowLimit = ctxPtr->dictLimit;
0709         }
0710     }
0711 
0712     return LZ4HC_compress_generic(ctxPtr, source, dest,
0713         inputSize, maxOutputSize, ctxPtr->compressionLevel, limit);
0714 }
0715 
0716 int LZ4_compress_HC_continue(
0717     LZ4_streamHC_t *LZ4_streamHCPtr,
0718     const char *source,
0719     char *dest,
0720     int inputSize,
0721     int maxOutputSize)
0722 {
0723     if (maxOutputSize < LZ4_compressBound(inputSize))
0724         return LZ4_compressHC_continue_generic(LZ4_streamHCPtr,
0725             source, dest, inputSize, maxOutputSize, limitedOutput);
0726     else
0727         return LZ4_compressHC_continue_generic(LZ4_streamHCPtr,
0728             source, dest, inputSize, maxOutputSize, noLimit);
0729 }
0730 EXPORT_SYMBOL(LZ4_compress_HC_continue);
0731 
0732 /* dictionary saving */
0733 
0734 int LZ4_saveDictHC(
0735     LZ4_streamHC_t *LZ4_streamHCPtr,
0736     char *safeBuffer,
0737     int dictSize)
0738 {
0739     LZ4HC_CCtx_internal *const streamPtr = &LZ4_streamHCPtr->internal_donotuse;
0740     int const prefixSize = (int)(streamPtr->end
0741         - (streamPtr->base + streamPtr->dictLimit));
0742 
0743     if (dictSize > 64 * KB)
0744         dictSize = 64 * KB;
0745     if (dictSize < 4)
0746         dictSize = 0;
0747     if (dictSize > prefixSize)
0748         dictSize = prefixSize;
0749 
0750     memmove(safeBuffer, streamPtr->end - dictSize, dictSize);
0751 
0752     {
0753         U32 const endIndex = (U32)(streamPtr->end - streamPtr->base);
0754 
0755         streamPtr->end = (const BYTE *)safeBuffer + dictSize;
0756         streamPtr->base = streamPtr->end - endIndex;
0757         streamPtr->dictLimit = endIndex - dictSize;
0758         streamPtr->lowLimit = endIndex - dictSize;
0759 
0760         if (streamPtr->nextToUpdate < streamPtr->dictLimit)
0761             streamPtr->nextToUpdate = streamPtr->dictLimit;
0762     }
0763     return dictSize;
0764 }
0765 EXPORT_SYMBOL(LZ4_saveDictHC);
0766 
0767 MODULE_LICENSE("Dual BSD/GPL");
0768 MODULE_DESCRIPTION("LZ4 HC compressor");