kusano 7d535a
/*
kusano 7d535a
    LZ4 HC - High Compression Mode of LZ4
kusano 7d535a
    Copyright (C) 2011-2015, Yann Collet.
kusano 7d535a
kusano 7d535a
    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
kusano 7d535a
kusano 7d535a
    Redistribution and use in source and binary forms, with or without
kusano 7d535a
    modification, are permitted provided that the following conditions are
kusano 7d535a
    met:
kusano 7d535a
kusano 7d535a
    * Redistributions of source code must retain the above copyright
kusano 7d535a
    notice, this list of conditions and the following disclaimer.
kusano 7d535a
    * Redistributions in binary form must reproduce the above
kusano 7d535a
    copyright notice, this list of conditions and the following disclaimer
kusano 7d535a
    in the documentation and/or other materials provided with the
kusano 7d535a
    distribution.
kusano 7d535a
kusano 7d535a
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
kusano 7d535a
    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
kusano 7d535a
    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
kusano 7d535a
    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
kusano 7d535a
    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
kusano 7d535a
    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
kusano 7d535a
    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
kusano 7d535a
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
kusano 7d535a
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
kusano 7d535a
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
kusano 7d535a
    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
kusano 7d535a
kusano 7d535a
    You can contact the author at :
kusano 7d535a
       - LZ4 source repository : https://github.com/Cyan4973/lz4
kusano 7d535a
       - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
kusano 7d535a
*/
kusano 7d535a
kusano 7d535a
kusano 7d535a
kusano 7d535a
/**************************************
kusano 7d535a
*  Tuning Parameter
kusano 7d535a
**************************************/
kusano 7d535a
static const int LZ4HC_compressionLevel_default = 9;
kusano 7d535a
kusano 7d535a
kusano 7d535a
/**************************************
kusano 7d535a
*  Includes
kusano 7d535a
**************************************/
kusano 7d535a
#include "lz4hc.h"
kusano 7d535a
kusano 7d535a
kusano 7d535a
/**************************************
kusano 7d535a
*  Local Compiler Options
kusano 7d535a
**************************************/
kusano 7d535a
#if defined(__GNUC__)
kusano 7d535a
#  pragma GCC diagnostic ignored "-Wunused-function"
kusano 7d535a
#endif
kusano 7d535a
kusano 7d535a
#if defined (__clang__)
kusano 7d535a
#  pragma clang diagnostic ignored "-Wunused-function"
kusano 7d535a
#endif
kusano 7d535a
kusano 7d535a
kusano 7d535a
/**************************************
kusano 7d535a
*  Common LZ4 definition
kusano 7d535a
**************************************/
kusano 7d535a
#define LZ4_COMMONDEFS_ONLY
kusano 7d535a
#include "lz4.c"
kusano 7d535a
kusano 7d535a
kusano 7d535a
/**************************************
kusano 7d535a
*  Local Constants
kusano 7d535a
**************************************/
kusano 7d535a
#define DICTIONARY_LOGSIZE 16
kusano 7d535a
#define MAXD (1<
kusano 7d535a
#define MAXD_MASK (MAXD - 1)
kusano 7d535a
kusano 7d535a
#define HASH_LOG (DICTIONARY_LOGSIZE-1)
kusano 7d535a
#define HASHTABLESIZE (1 << HASH_LOG)
kusano 7d535a
#define HASH_MASK (HASHTABLESIZE - 1)
kusano 7d535a
kusano 7d535a
#define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH)
kusano 7d535a
kusano 7d535a
static const int g_maxCompressionLevel = 16;
kusano 7d535a
kusano 7d535a
kusano 7d535a
/**************************************
kusano 7d535a
*  Local Types
kusano 7d535a
**************************************/
kusano 7d535a
typedef struct
kusano 7d535a
{
kusano 7d535a
    U32   hashTable[HASHTABLESIZE];
kusano 7d535a
    U16   chainTable[MAXD];
kusano 7d535a
    const BYTE* end;        /* next block here to continue on current prefix */
kusano 7d535a
    const BYTE* base;       /* All index relative to this position */
kusano 7d535a
    const BYTE* dictBase;   /* alternate base for extDict */
kusano 7d535a
    BYTE* inputBuffer;      /* deprecated */
kusano 7d535a
    U32   dictLimit;        /* below that point, need extDict */
kusano 7d535a
    U32   lowLimit;         /* below that point, no more dict */
kusano 7d535a
    U32   nextToUpdate;     /* index from which to continue dictionary update */
kusano 7d535a
    U32   compressionLevel;
kusano 7d535a
} LZ4HC_Data_Structure;
kusano 7d535a
kusano 7d535a
kusano 7d535a
/**************************************
kusano 7d535a
*  Local Macros
kusano 7d535a
**************************************/
kusano 7d535a
#define HASH_FUNCTION(i)       (((i) * 2654435761U) >> ((MINMATCH*8)-HASH_LOG))
kusano 7d535a
//#define DELTANEXTU16(p)        chainTable[(p) & MAXD_MASK]   /* flexible, MAXD dependent */
kusano 7d535a
#define DELTANEXTU16(p)        chainTable[(U16)(p)]   /* faster */
kusano 7d535a
kusano 7d535a
static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }
kusano 7d535a
kusano 7d535a
kusano 7d535a
kusano 7d535a
/**************************************
kusano 7d535a
*  HC Compression
kusano 7d535a
**************************************/
kusano 7d535a
static void LZ4HC_init (LZ4HC_Data_Structure* hc4, const BYTE* start)
kusano 7d535a
{
kusano 7d535a
    MEM_INIT((void*)hc4->hashTable, 0, sizeof(hc4->hashTable));
kusano 7d535a
    MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));
kusano 7d535a
    hc4->nextToUpdate = 64 KB;
kusano 7d535a
    hc4->base = start - 64 KB;
kusano 7d535a
    hc4->end = start;
kusano 7d535a
    hc4->dictBase = start - 64 KB;
kusano 7d535a
    hc4->dictLimit = 64 KB;
kusano 7d535a
    hc4->lowLimit = 64 KB;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
/* Update chains up to ip (excluded) */
kusano 7d535a
FORCE_INLINE void LZ4HC_Insert (LZ4HC_Data_Structure* hc4, const BYTE* ip)
kusano 7d535a
{
kusano 7d535a
    U16* chainTable = hc4->chainTable;
kusano 7d535a
    U32* HashTable  = hc4->hashTable;
kusano 7d535a
    const BYTE* const base = hc4->base;
kusano 7d535a
    const U32 target = (U32)(ip - base);
kusano 7d535a
    U32 idx = hc4->nextToUpdate;
kusano 7d535a
kusano 7d535a
    while(idx < target)
kusano 7d535a
    {
kusano 7d535a
        U32 h = LZ4HC_hashPtr(base+idx);
kusano 7d535a
        size_t delta = idx - HashTable[h];
kusano 7d535a
        if (delta>MAX_DISTANCE) delta = MAX_DISTANCE;
kusano 7d535a
        DELTANEXTU16(idx) = (U16)delta;
kusano 7d535a
        HashTable[h] = idx;
kusano 7d535a
        idx++;
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    hc4->nextToUpdate = target;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_Data_Structure* hc4,   /* Index table will be updated */
kusano 7d535a
                                               const BYTE* ip, const BYTE* const iLimit,
kusano 7d535a
                                               const BYTE** matchpos,
kusano 7d535a
                                               const int maxNbAttempts)
kusano 7d535a
{
kusano 7d535a
    U16* const chainTable = hc4->chainTable;
kusano 7d535a
    U32* const HashTable = hc4->hashTable;
kusano 7d535a
    const BYTE* const base = hc4->base;
kusano 7d535a
    const BYTE* const dictBase = hc4->dictBase;
kusano 7d535a
    const U32 dictLimit = hc4->dictLimit;
kusano 7d535a
    const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - (64 KB - 1);
kusano 7d535a
    U32 matchIndex;
kusano 7d535a
    const BYTE* match;
kusano 7d535a
    int nbAttempts=maxNbAttempts;
kusano 7d535a
    size_t ml=0;
kusano 7d535a
kusano 7d535a
    /* HC4 match finder */
kusano 7d535a
    LZ4HC_Insert(hc4, ip);
kusano 7d535a
    matchIndex = HashTable[LZ4HC_hashPtr(ip)];
kusano 7d535a
kusano 7d535a
    while ((matchIndex>=lowLimit) && (nbAttempts))
kusano 7d535a
    {
kusano 7d535a
        nbAttempts--;
kusano 7d535a
        if (matchIndex >= dictLimit)
kusano 7d535a
        {
kusano 7d535a
            match = base + matchIndex;
kusano 7d535a
            if (*(match+ml) == *(ip+ml)
kusano 7d535a
                && (LZ4_read32(match) == LZ4_read32(ip)))
kusano 7d535a
            {
kusano 7d535a
                size_t mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, iLimit) + MINMATCH;
kusano 7d535a
                if (mlt > ml) { ml = mlt; *matchpos = match; }
kusano 7d535a
            }
kusano 7d535a
        }
kusano 7d535a
        else
kusano 7d535a
        {
kusano 7d535a
            match = dictBase + matchIndex;
kusano 7d535a
            if (LZ4_read32(match) == LZ4_read32(ip))
kusano 7d535a
            {
kusano 7d535a
                size_t mlt;
kusano 7d535a
                const BYTE* vLimit = ip + (dictLimit - matchIndex);
kusano 7d535a
                if (vLimit > iLimit) vLimit = iLimit;
kusano 7d535a
                mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, vLimit) + MINMATCH;
kusano 7d535a
                if ((ip+mlt == vLimit) && (vLimit < iLimit))
kusano 7d535a
                    mlt += LZ4_count(ip+mlt, base+dictLimit, iLimit);
kusano 7d535a
                if (mlt > ml) { ml = mlt; *matchpos = base + matchIndex; }   /* virtual matchpos */
kusano 7d535a
            }
kusano 7d535a
        }
kusano 7d535a
        matchIndex -= DELTANEXTU16(matchIndex);
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    return (int)ml;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch (
kusano 7d535a
    LZ4HC_Data_Structure* hc4,
kusano 7d535a
    const BYTE* const ip,
kusano 7d535a
    const BYTE* const iLowLimit,
kusano 7d535a
    const BYTE* const iHighLimit,
kusano 7d535a
    int longest,
kusano 7d535a
    const BYTE** matchpos,
kusano 7d535a
    const BYTE** startpos,
kusano 7d535a
    const int maxNbAttempts)
kusano 7d535a
{
kusano 7d535a
    U16* const chainTable = hc4->chainTable;
kusano 7d535a
    U32* const HashTable = hc4->hashTable;
kusano 7d535a
    const BYTE* const base = hc4->base;
kusano 7d535a
    const U32 dictLimit = hc4->dictLimit;
kusano 7d535a
    const BYTE* const lowPrefixPtr = base + dictLimit;
kusano 7d535a
    const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - (64 KB - 1);
kusano 7d535a
    const BYTE* const dictBase = hc4->dictBase;
kusano 7d535a
    U32   matchIndex;
kusano 7d535a
    int nbAttempts = maxNbAttempts;
kusano 7d535a
    int delta = (int)(ip-iLowLimit);
kusano 7d535a
kusano 7d535a
kusano 7d535a
    /* First Match */
kusano 7d535a
    LZ4HC_Insert(hc4, ip);
kusano 7d535a
    matchIndex = HashTable[LZ4HC_hashPtr(ip)];
kusano 7d535a
kusano 7d535a
    while ((matchIndex>=lowLimit) && (nbAttempts))
kusano 7d535a
    {
kusano 7d535a
        nbAttempts--;
kusano 7d535a
        if (matchIndex >= dictLimit)
kusano 7d535a
        {
kusano 7d535a
            const BYTE* matchPtr = base + matchIndex;
kusano 7d535a
            if (*(iLowLimit + longest) == *(matchPtr - delta + longest))
kusano 7d535a
                if (LZ4_read32(matchPtr) == LZ4_read32(ip))
kusano 7d535a
                {
kusano 7d535a
                    int mlt = MINMATCH + LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit);
kusano 7d535a
                    int back = 0;
kusano 7d535a
kusano 7d535a
                    while ((ip+back>iLowLimit)
kusano 7d535a
                           && (matchPtr+back > lowPrefixPtr)
kusano 7d535a
                           && (ip[back-1] == matchPtr[back-1]))
kusano 7d535a
                            back--;
kusano 7d535a
kusano 7d535a
                    mlt -= back;
kusano 7d535a
kusano 7d535a
                    if (mlt > longest)
kusano 7d535a
                    {
kusano 7d535a
                        longest = (int)mlt;
kusano 7d535a
                        *matchpos = matchPtr+back;
kusano 7d535a
                        *startpos = ip+back;
kusano 7d535a
                    }
kusano 7d535a
                }
kusano 7d535a
        }
kusano 7d535a
        else
kusano 7d535a
        {
kusano 7d535a
            const BYTE* matchPtr = dictBase + matchIndex;
kusano 7d535a
            if (LZ4_read32(matchPtr) == LZ4_read32(ip))
kusano 7d535a
            {
kusano 7d535a
                size_t mlt;
kusano 7d535a
                int back=0;
kusano 7d535a
                const BYTE* vLimit = ip + (dictLimit - matchIndex);
kusano 7d535a
                if (vLimit > iHighLimit) vLimit = iHighLimit;
kusano 7d535a
                mlt = LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
kusano 7d535a
                if ((ip+mlt == vLimit) && (vLimit < iHighLimit))
kusano 7d535a
                    mlt += LZ4_count(ip+mlt, base+dictLimit, iHighLimit);
kusano 7d535a
                while ((ip+back > iLowLimit) && (matchIndex+back > lowLimit) && (ip[back-1] == matchPtr[back-1])) back--;
kusano 7d535a
                mlt -= back;
kusano 7d535a
                if ((int)mlt > longest) { longest = (int)mlt; *matchpos = base + matchIndex + back; *startpos = ip+back; }
kusano 7d535a
            }
kusano 7d535a
        }
kusano 7d535a
        matchIndex -= DELTANEXTU16(matchIndex);
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    return longest;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
typedef enum { noLimit = 0, limitedOutput = 1 } limitedOutput_directive;
kusano 7d535a
kusano 7d535a
#define LZ4HC_DEBUG 0
kusano 7d535a
#if LZ4HC_DEBUG
kusano 7d535a
static unsigned debug = 0;
kusano 7d535a
#endif
kusano 7d535a
kusano 7d535a
FORCE_INLINE int LZ4HC_encodeSequence (
kusano 7d535a
    const BYTE** ip,
kusano 7d535a
    BYTE** op,
kusano 7d535a
    const BYTE** anchor,
kusano 7d535a
    int matchLength,
kusano 7d535a
    const BYTE* const match,
kusano 7d535a
    limitedOutput_directive limitedOutputBuffer,
kusano 7d535a
    BYTE* oend)
kusano 7d535a
{
kusano 7d535a
    int length;
kusano 7d535a
    BYTE* token;
kusano 7d535a
kusano 7d535a
#if LZ4HC_DEBUG
kusano 7d535a
    if (debug) printf("literal : %u  --  match : %u  --  offset : %u\n", (U32)(*ip - *anchor), (U32)matchLength, (U32)(*ip-match));
kusano 7d535a
#endif
kusano 7d535a
kusano 7d535a
    /* Encode Literal length */
kusano 7d535a
    length = (int)(*ip - *anchor);
kusano 7d535a
    token = (*op)++;
kusano 7d535a
    if ((limitedOutputBuffer) && ((*op + (length>>8) + length + (2 + 1 + LASTLITERALS)) > oend)) return 1;   /* Check output limit */
kusano 7d535a
    if (length>=(int)RUN_MASK) { int len; *token=(RUN_MASK<<ml_bits); for(;="" len="length-RUN_MASK;"> 254 ; len-=255) *(*op)++ = 255;  *(*op)++ = (BYTE)len; }</ml_bits);>
kusano 7d535a
    else *token = (BYTE)(length<
kusano 7d535a
kusano 7d535a
    /* Copy Literals */
kusano 7d535a
    LZ4_wildCopy(*op, *anchor, (*op) + length);
kusano 7d535a
    *op += length;
kusano 7d535a
kusano 7d535a
    /* Encode Offset */
kusano 7d535a
    LZ4_writeLE16(*op, (U16)(*ip-match)); *op += 2;
kusano 7d535a
kusano 7d535a
    /* Encode MatchLength */
kusano 7d535a
    length = (int)(matchLength-MINMATCH);
kusano 7d535a
    if ((limitedOutputBuffer) && (*op + (length>>8) + (1 + LASTLITERALS) > oend)) return 1;   /* Check output limit */
kusano 7d535a
    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; }
kusano 7d535a
    else *token += (BYTE)(length);
kusano 7d535a
kusano 7d535a
    /* Prepare next loop */
kusano 7d535a
    *ip += matchLength;
kusano 7d535a
    *anchor = *ip;
kusano 7d535a
kusano 7d535a
    return 0;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
static int LZ4HC_compress_generic (
kusano 7d535a
    void* ctxvoid,
kusano 7d535a
    const char* source,
kusano 7d535a
    char* dest,
kusano 7d535a
    int inputSize,
kusano 7d535a
    int maxOutputSize,
kusano 7d535a
    int compressionLevel,
kusano 7d535a
    limitedOutput_directive limit
kusano 7d535a
    )
kusano 7d535a
{
kusano 7d535a
    LZ4HC_Data_Structure* ctx = (LZ4HC_Data_Structure*) ctxvoid;
kusano 7d535a
    const BYTE* ip = (const BYTE*) source;
kusano 7d535a
    const BYTE* anchor = ip;
kusano 7d535a
    const BYTE* const iend = ip + inputSize;
kusano 7d535a
    const BYTE* const mflimit = iend - MFLIMIT;
kusano 7d535a
    const BYTE* const matchlimit = (iend - LASTLITERALS);
kusano 7d535a
kusano 7d535a
    BYTE* op = (BYTE*) dest;
kusano 7d535a
    BYTE* const oend = op + maxOutputSize;
kusano 7d535a
kusano 7d535a
    unsigned maxNbAttempts;
kusano 7d535a
    int   ml, ml2, ml3, ml0;
kusano 7d535a
    const BYTE* ref=NULL;
kusano 7d535a
    const BYTE* start2=NULL;
kusano 7d535a
    const BYTE* ref2=NULL;
kusano 7d535a
    const BYTE* start3=NULL;
kusano 7d535a
    const BYTE* ref3=NULL;
kusano 7d535a
    const BYTE* start0;
kusano 7d535a
    const BYTE* ref0;
kusano 7d535a
kusano 7d535a
kusano 7d535a
    /* init */
kusano 7d535a
    if (compressionLevel > g_maxCompressionLevel) compressionLevel = g_maxCompressionLevel;
kusano 7d535a
    if (compressionLevel < 1) compressionLevel = LZ4HC_compressionLevel_default;
kusano 7d535a
    maxNbAttempts = 1 << (compressionLevel-1);
kusano 7d535a
    ctx->end += inputSize;
kusano 7d535a
kusano 7d535a
    ip++;
kusano 7d535a
kusano 7d535a
    /* Main Loop */
kusano 7d535a
    while (ip < mflimit)
kusano 7d535a
    {
kusano 7d535a
        ml = LZ4HC_InsertAndFindBestMatch (ctx, ip, matchlimit, (&ref), maxNbAttempts);
kusano 7d535a
        if (!ml) { ip++; continue; }
kusano 7d535a
kusano 7d535a
        /* saved, in case we would skip too much */
kusano 7d535a
        start0 = ip;
kusano 7d535a
        ref0 = ref;
kusano 7d535a
        ml0 = ml;
kusano 7d535a
kusano 7d535a
_Search2:
kusano 7d535a
        if (ip+ml < mflimit)
kusano 7d535a
            ml2 = LZ4HC_InsertAndGetWiderMatch(ctx, ip + ml - 2, ip + 1, matchlimit, ml, &ref2, &start2, maxNbAttempts);
kusano 7d535a
        else ml2 = ml;
kusano 7d535a
kusano 7d535a
        if (ml2 == ml)  /* No better match */
kusano 7d535a
        {
kusano 7d535a
            if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0;
kusano 7d535a
            continue;
kusano 7d535a
        }
kusano 7d535a
kusano 7d535a
        if (start0 < ip)
kusano 7d535a
        {
kusano 7d535a
            if (start2 < ip + ml0)   /* empirical */
kusano 7d535a
            {
kusano 7d535a
                ip = start0;
kusano 7d535a
                ref = ref0;
kusano 7d535a
                ml = ml0;
kusano 7d535a
            }
kusano 7d535a
        }
kusano 7d535a
kusano 7d535a
        /* Here, start0==ip */
kusano 7d535a
        if ((start2 - ip) < 3)   /* First Match too small : removed */
kusano 7d535a
        {
kusano 7d535a
            ml = ml2;
kusano 7d535a
            ip = start2;
kusano 7d535a
            ref =ref2;
kusano 7d535a
            goto _Search2;
kusano 7d535a
        }
kusano 7d535a
kusano 7d535a
_Search3:
kusano 7d535a
        /*
kusano 7d535a
        * Currently we have :
kusano 7d535a
        * ml2 > ml1, and
kusano 7d535a
        * ip1+3 <= ip2 (usually < ip1+ml1)
kusano 7d535a
        */
kusano 7d535a
        if ((start2 - ip) < OPTIMAL_ML)
kusano 7d535a
        {
kusano 7d535a
            int correction;
kusano 7d535a
            int new_ml = ml;
kusano 7d535a
            if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;
kusano 7d535a
            if (ip+new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - ip) + ml2 - MINMATCH;
kusano 7d535a
            correction = new_ml - (int)(start2 - ip);
kusano 7d535a
            if (correction > 0)
kusano 7d535a
            {
kusano 7d535a
                start2 += correction;
kusano 7d535a
                ref2 += correction;
kusano 7d535a
                ml2 -= correction;
kusano 7d535a
            }
kusano 7d535a
        }
kusano 7d535a
        /* Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) */
kusano 7d535a
kusano 7d535a
        if (start2 + ml2 < mflimit)
kusano 7d535a
            ml3 = LZ4HC_InsertAndGetWiderMatch(ctx, start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3, maxNbAttempts);
kusano 7d535a
        else ml3 = ml2;
kusano 7d535a
kusano 7d535a
        if (ml3 == ml2) /* No better match : 2 sequences to encode */
kusano 7d535a
        {
kusano 7d535a
            /* ip & ref are known; Now for ml */
kusano 7d535a
            if (start2 < ip+ml)  ml = (int)(start2 - ip);
kusano 7d535a
            /* Now, encode 2 sequences */
kusano 7d535a
            if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0;
kusano 7d535a
            ip = start2;
kusano 7d535a
            if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml2, ref2, limit, oend)) return 0;
kusano 7d535a
            continue;
kusano 7d535a
        }
kusano 7d535a
kusano 7d535a
        if (start3 < ip+ml+3) /* Not enough space for match 2 : remove it */
kusano 7d535a
        {
kusano 7d535a
            if (start3 >= (ip+ml)) /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */
kusano 7d535a
            {
kusano 7d535a
                if (start2 < ip+ml)
kusano 7d535a
                {
kusano 7d535a
                    int correction = (int)(ip+ml - start2);
kusano 7d535a
                    start2 += correction;
kusano 7d535a
                    ref2 += correction;
kusano 7d535a
                    ml2 -= correction;
kusano 7d535a
                    if (ml2 < MINMATCH)
kusano 7d535a
                    {
kusano 7d535a
                        start2 = start3;
kusano 7d535a
                        ref2 = ref3;
kusano 7d535a
                        ml2 = ml3;
kusano 7d535a
                    }
kusano 7d535a
                }
kusano 7d535a
kusano 7d535a
                if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0;
kusano 7d535a
                ip  = start3;
kusano 7d535a
                ref = ref3;
kusano 7d535a
                ml  = ml3;
kusano 7d535a
kusano 7d535a
                start0 = start2;
kusano 7d535a
                ref0 = ref2;
kusano 7d535a
                ml0 = ml2;
kusano 7d535a
                goto _Search2;
kusano 7d535a
            }
kusano 7d535a
kusano 7d535a
            start2 = start3;
kusano 7d535a
            ref2 = ref3;
kusano 7d535a
            ml2 = ml3;
kusano 7d535a
            goto _Search3;
kusano 7d535a
        }
kusano 7d535a
kusano 7d535a
        /*
kusano 7d535a
        * OK, now we have 3 ascending matches; let's write at least the first one
kusano 7d535a
        * ip & ref are known; Now for ml
kusano 7d535a
        */
kusano 7d535a
        if (start2 < ip+ml)
kusano 7d535a
        {
kusano 7d535a
            if ((start2 - ip) < (int)ML_MASK)
kusano 7d535a
            {
kusano 7d535a
                int correction;
kusano 7d535a
                if (ml > OPTIMAL_ML) ml = OPTIMAL_ML;
kusano 7d535a
                if (ip + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - ip) + ml2 - MINMATCH;
kusano 7d535a
                correction = ml - (int)(start2 - ip);
kusano 7d535a
                if (correction > 0)
kusano 7d535a
                {
kusano 7d535a
                    start2 += correction;
kusano 7d535a
                    ref2 += correction;
kusano 7d535a
                    ml2 -= correction;
kusano 7d535a
                }
kusano 7d535a
            }
kusano 7d535a
            else
kusano 7d535a
            {
kusano 7d535a
                ml = (int)(start2 - ip);
kusano 7d535a
            }
kusano 7d535a
        }
kusano 7d535a
        if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0;
kusano 7d535a
kusano 7d535a
        ip = start2;
kusano 7d535a
        ref = ref2;
kusano 7d535a
        ml = ml2;
kusano 7d535a
kusano 7d535a
        start2 = start3;
kusano 7d535a
        ref2 = ref3;
kusano 7d535a
        ml2 = ml3;
kusano 7d535a
kusano 7d535a
        goto _Search3;
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    /* Encode Last Literals */
kusano 7d535a
    {
kusano 7d535a
        int lastRun = (int)(iend - anchor);
kusano 7d535a
        if ((limit) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) return 0;  /* Check output limit */
kusano 7d535a
        if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK<<ml_bits); for(;="" lastrun="" lastrun-="RUN_MASK;"> 254 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; }</ml_bits);>
kusano 7d535a
        else *op++ = (BYTE)(lastRun<
kusano 7d535a
        memcpy(op, anchor, iend - anchor);
kusano 7d535a
        op += iend-anchor;
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    /* End */
kusano 7d535a
    return (int) (((char*)op)-dest);
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
int LZ4_sizeofStateHC(void) { return sizeof(LZ4HC_Data_Structure); }
kusano 7d535a
kusano 7d535a
int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel)
kusano 7d535a
{
kusano 7d535a
    if (((size_t)(state)&(sizeof(void*)-1)) != 0) return 0;   /* Error : state is not aligned for pointers (32 or 64 bits) */
kusano 7d535a
    LZ4HC_init ((LZ4HC_Data_Structure*)state, (const BYTE*)src);
kusano 7d535a
    if (maxDstSize < LZ4_compressBound(srcSize))
kusano 7d535a
        return LZ4HC_compress_generic (state, src, dst, srcSize, maxDstSize, compressionLevel, limitedOutput);
kusano 7d535a
    else
kusano 7d535a
        return LZ4HC_compress_generic (state, src, dst, srcSize, maxDstSize, compressionLevel, noLimit);
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
int LZ4_compress_HC(const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel)
kusano 7d535a
{
kusano 7d535a
    LZ4HC_Data_Structure state;
kusano 7d535a
    return LZ4_compress_HC_extStateHC(&state, src, dst, srcSize, maxDstSize, compressionLevel);
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
kusano 7d535a
/**************************************
kusano 7d535a
*  Streaming Functions
kusano 7d535a
**************************************/
kusano 7d535a
/* allocation */
kusano 7d535a
LZ4_streamHC_t* LZ4_createStreamHC(void) { return (LZ4_streamHC_t*)malloc(sizeof(LZ4_streamHC_t)); }
kusano 7d535a
int             LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr) { free(LZ4_streamHCPtr); return 0; }
kusano 7d535a
kusano 7d535a
kusano 7d535a
/* initialization */
kusano 7d535a
void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
kusano 7d535a
{
kusano 7d535a
    LZ4_STATIC_ASSERT(sizeof(LZ4HC_Data_Structure) <= sizeof(LZ4_streamHC_t));   /* if compilation fails here, LZ4_STREAMHCSIZE must be increased */
kusano 7d535a
    ((LZ4HC_Data_Structure*)LZ4_streamHCPtr)->base = NULL;
kusano 7d535a
    ((LZ4HC_Data_Structure*)LZ4_streamHCPtr)->compressionLevel = (unsigned)compressionLevel;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, const char* dictionary, int dictSize)
kusano 7d535a
{
kusano 7d535a
    LZ4HC_Data_Structure* ctxPtr = (LZ4HC_Data_Structure*) LZ4_streamHCPtr;
kusano 7d535a
    if (dictSize > 64 KB)
kusano 7d535a
    {
kusano 7d535a
        dictionary += dictSize - 64 KB;
kusano 7d535a
        dictSize = 64 KB;
kusano 7d535a
    }
kusano 7d535a
    LZ4HC_init (ctxPtr, (const BYTE*)dictionary);
kusano 7d535a
    if (dictSize >= 4) LZ4HC_Insert (ctxPtr, (const BYTE*)dictionary +(dictSize-3));
kusano 7d535a
    ctxPtr->end = (const BYTE*)dictionary + dictSize;
kusano 7d535a
    return dictSize;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
/* compression */
kusano 7d535a
kusano 7d535a
static void LZ4HC_setExternalDict(LZ4HC_Data_Structure* ctxPtr, const BYTE* newBlock)
kusano 7d535a
{
kusano 7d535a
    if (ctxPtr->end >= ctxPtr->base + 4)
kusano 7d535a
        LZ4HC_Insert (ctxPtr, ctxPtr->end-3);   /* Referencing remaining dictionary content */
kusano 7d535a
    /* Only one memory segment for extDict, so any previous extDict is lost at this stage */
kusano 7d535a
    ctxPtr->lowLimit  = ctxPtr->dictLimit;
kusano 7d535a
    ctxPtr->dictLimit = (U32)(ctxPtr->end - ctxPtr->base);
kusano 7d535a
    ctxPtr->dictBase  = ctxPtr->base;
kusano 7d535a
    ctxPtr->base = newBlock - ctxPtr->dictLimit;
kusano 7d535a
    ctxPtr->end  = newBlock;
kusano 7d535a
    ctxPtr->nextToUpdate = ctxPtr->dictLimit;   /* match referencing will resume from there */
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
static int LZ4_compressHC_continue_generic (LZ4HC_Data_Structure* ctxPtr,
kusano 7d535a
                                            const char* source, char* dest,
kusano 7d535a
                                            int inputSize, int maxOutputSize, limitedOutput_directive limit)
kusano 7d535a
{
kusano 7d535a
    /* auto-init if forgotten */
kusano 7d535a
    if (ctxPtr->base == NULL)
kusano 7d535a
        LZ4HC_init (ctxPtr, (const BYTE*) source);
kusano 7d535a
kusano 7d535a
    /* Check overflow */
kusano 7d535a
    if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 GB)
kusano 7d535a
    {
kusano 7d535a
        size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->base) - ctxPtr->dictLimit;
kusano 7d535a
        if (dictSize > 64 KB) dictSize = 64 KB;
kusano 7d535a
kusano 7d535a
        LZ4_loadDictHC((LZ4_streamHC_t*)ctxPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize);
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    /* Check if blocks follow each other */
kusano 7d535a
    if ((const BYTE*)source != ctxPtr->end)
kusano 7d535a
        LZ4HC_setExternalDict(ctxPtr, (const BYTE*)source);
kusano 7d535a
kusano 7d535a
    /* Check overlapping input/dictionary space */
kusano 7d535a
    {
kusano 7d535a
        const BYTE* sourceEnd = (const BYTE*) source + inputSize;
kusano 7d535a
        const BYTE* dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit;
kusano 7d535a
        const BYTE* dictEnd   = ctxPtr->dictBase + ctxPtr->dictLimit;
kusano 7d535a
        if ((sourceEnd > dictBegin) && ((const BYTE*)source < dictEnd))
kusano 7d535a
        {
kusano 7d535a
            if (sourceEnd > dictEnd) sourceEnd = dictEnd;
kusano 7d535a
            ctxPtr->lowLimit = (U32)(sourceEnd - ctxPtr->dictBase);
kusano 7d535a
            if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) ctxPtr->lowLimit = ctxPtr->dictLimit;
kusano 7d535a
        }
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    return LZ4HC_compress_generic (ctxPtr, source, dest, inputSize, maxOutputSize, ctxPtr->compressionLevel, limit);
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize, int maxOutputSize)
kusano 7d535a
{
kusano 7d535a
    if (maxOutputSize < LZ4_compressBound(inputSize))
kusano 7d535a
        return LZ4_compressHC_continue_generic ((LZ4HC_Data_Structure*)LZ4_streamHCPtr, source, dest, inputSize, maxOutputSize, limitedOutput);
kusano 7d535a
    else
kusano 7d535a
        return LZ4_compressHC_continue_generic ((LZ4HC_Data_Structure*)LZ4_streamHCPtr, source, dest, inputSize, maxOutputSize, noLimit);
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
/* dictionary saving */
kusano 7d535a
kusano 7d535a
int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)
kusano 7d535a
{
kusano 7d535a
    LZ4HC_Data_Structure* streamPtr = (LZ4HC_Data_Structure*)LZ4_streamHCPtr;
kusano 7d535a
    int prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit));
kusano 7d535a
    if (dictSize > 64 KB) dictSize = 64 KB;
kusano 7d535a
    if (dictSize < 4) dictSize = 0;
kusano 7d535a
    if (dictSize > prefixSize) dictSize = prefixSize;
kusano 7d535a
    memmove(safeBuffer, streamPtr->end - dictSize, dictSize);
kusano 7d535a
    {
kusano 7d535a
        U32 endIndex = (U32)(streamPtr->end - streamPtr->base);
kusano 7d535a
        streamPtr->end = (const BYTE*)safeBuffer + dictSize;
kusano 7d535a
        streamPtr->base = streamPtr->end - endIndex;
kusano 7d535a
        streamPtr->dictLimit = endIndex - dictSize;
kusano 7d535a
        streamPtr->lowLimit = endIndex - dictSize;
kusano 7d535a
        if (streamPtr->nextToUpdate < streamPtr->dictLimit) streamPtr->nextToUpdate = streamPtr->dictLimit;
kusano 7d535a
    }
kusano 7d535a
    return dictSize;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
/***********************************
kusano 7d535a
*  Deprecated Functions
kusano 7d535a
***********************************/
kusano 7d535a
/* Deprecated compression functions */
kusano 7d535a
/* These functions are planned to start generate warnings by r131 approximately */
kusano 7d535a
int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
kusano 7d535a
int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); }
kusano 7d535a
int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
kusano 7d535a
int LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); }
kusano 7d535a
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); }
kusano 7d535a
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); }
kusano 7d535a
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); }
kusano 7d535a
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); }
kusano 7d535a
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)); }
kusano 7d535a
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); }
kusano 7d535a
kusano 7d535a
kusano 7d535a
/* Deprecated streaming functions */
kusano 7d535a
/* These functions currently generate deprecation warnings */
kusano 7d535a
int LZ4_sizeofStreamStateHC(void) { return LZ4_STREAMHCSIZE; }
kusano 7d535a
kusano 7d535a
int LZ4_resetStreamStateHC(void* state, char* inputBuffer)
kusano 7d535a
{
kusano 7d535a
    if ((((size_t)state) & (sizeof(void*)-1)) != 0) return 1;   /* Error : pointer is not aligned for pointer (32 or 64 bits) */
kusano 7d535a
    LZ4HC_init((LZ4HC_Data_Structure*)state, (const BYTE*)inputBuffer);
kusano 7d535a
    ((LZ4HC_Data_Structure*)state)->inputBuffer = (BYTE*)inputBuffer;
kusano 7d535a
    return 0;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
void* LZ4_createHC (char* inputBuffer)
kusano 7d535a
{
kusano 7d535a
    void* hc4 = ALLOCATOR(1, sizeof(LZ4HC_Data_Structure));
kusano 7d535a
    if (hc4 == NULL) return NULL;   /* not enough memory */
kusano 7d535a
    LZ4HC_init ((LZ4HC_Data_Structure*)hc4, (const BYTE*)inputBuffer);
kusano 7d535a
    ((LZ4HC_Data_Structure*)hc4)->inputBuffer = (BYTE*)inputBuffer;
kusano 7d535a
    return hc4;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
int LZ4_freeHC (void* LZ4HC_Data)
kusano 7d535a
{
kusano 7d535a
    FREEMEM(LZ4HC_Data);
kusano 7d535a
    return (0);
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel)
kusano 7d535a
{
kusano 7d535a
    return LZ4HC_compress_generic (LZ4HC_Data, source, dest, inputSize, 0, compressionLevel, noLimit);
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel)
kusano 7d535a
{
kusano 7d535a
    return LZ4HC_compress_generic (LZ4HC_Data, source, dest, inputSize, maxOutputSize, compressionLevel, limitedOutput);
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
char* LZ4_slideInputBufferHC(void* LZ4HC_Data)
kusano 7d535a
{
kusano 7d535a
    LZ4HC_Data_Structure* hc4 = (LZ4HC_Data_Structure*)LZ4HC_Data;
kusano 7d535a
    int dictSize = LZ4_saveDictHC((LZ4_streamHC_t*)LZ4HC_Data, (char*)(hc4->inputBuffer), 64 KB);
kusano 7d535a
    return (char*)(hc4->inputBuffer + dictSize);
kusano 7d535a
}