127b27ec6Sopenharmony_ci/*
227b27ec6Sopenharmony_ci    LZ4 HC - High Compression Mode of LZ4
327b27ec6Sopenharmony_ci    Copyright (C) 2011-2020, Yann Collet.
427b27ec6Sopenharmony_ci
527b27ec6Sopenharmony_ci    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
627b27ec6Sopenharmony_ci
727b27ec6Sopenharmony_ci    Redistribution and use in source and binary forms, with or without
827b27ec6Sopenharmony_ci    modification, are permitted provided that the following conditions are
927b27ec6Sopenharmony_ci    met:
1027b27ec6Sopenharmony_ci
1127b27ec6Sopenharmony_ci    * Redistributions of source code must retain the above copyright
1227b27ec6Sopenharmony_ci    notice, this list of conditions and the following disclaimer.
1327b27ec6Sopenharmony_ci    * Redistributions in binary form must reproduce the above
1427b27ec6Sopenharmony_ci    copyright notice, this list of conditions and the following disclaimer
1527b27ec6Sopenharmony_ci    in the documentation and/or other materials provided with the
1627b27ec6Sopenharmony_ci    distribution.
1727b27ec6Sopenharmony_ci
1827b27ec6Sopenharmony_ci    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1927b27ec6Sopenharmony_ci    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2027b27ec6Sopenharmony_ci    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2127b27ec6Sopenharmony_ci    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2227b27ec6Sopenharmony_ci    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2327b27ec6Sopenharmony_ci    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2427b27ec6Sopenharmony_ci    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2527b27ec6Sopenharmony_ci    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2627b27ec6Sopenharmony_ci    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2727b27ec6Sopenharmony_ci    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2827b27ec6Sopenharmony_ci    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2927b27ec6Sopenharmony_ci
3027b27ec6Sopenharmony_ci    You can contact the author at :
3127b27ec6Sopenharmony_ci       - LZ4 source repository : https://github.com/lz4/lz4
3227b27ec6Sopenharmony_ci       - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
3327b27ec6Sopenharmony_ci*/
3427b27ec6Sopenharmony_ci/* note : lz4hc is not an independent module, it requires lz4.h/lz4.c for proper compilation */
3527b27ec6Sopenharmony_ci
3627b27ec6Sopenharmony_ci
3727b27ec6Sopenharmony_ci/* *************************************
3827b27ec6Sopenharmony_ci*  Tuning Parameter
3927b27ec6Sopenharmony_ci***************************************/
4027b27ec6Sopenharmony_ci
4127b27ec6Sopenharmony_ci/*! HEAPMODE :
4227b27ec6Sopenharmony_ci *  Select how default compression function will allocate workplace memory,
4327b27ec6Sopenharmony_ci *  in stack (0:fastest), or in heap (1:requires malloc()).
4427b27ec6Sopenharmony_ci *  Since workplace is rather large, heap mode is recommended.
4527b27ec6Sopenharmony_ci**/
4627b27ec6Sopenharmony_ci#ifndef LZ4HC_HEAPMODE
4727b27ec6Sopenharmony_ci#  define LZ4HC_HEAPMODE 1
4827b27ec6Sopenharmony_ci#endif
4927b27ec6Sopenharmony_ci
5027b27ec6Sopenharmony_ci
5127b27ec6Sopenharmony_ci/*===    Dependency    ===*/
5227b27ec6Sopenharmony_ci#define LZ4_HC_STATIC_LINKING_ONLY
5327b27ec6Sopenharmony_ci#include "lz4hc.h"
5427b27ec6Sopenharmony_ci
5527b27ec6Sopenharmony_ci
5627b27ec6Sopenharmony_ci/*===   Common definitions   ===*/
5727b27ec6Sopenharmony_ci#if defined(__GNUC__)
5827b27ec6Sopenharmony_ci#  pragma GCC diagnostic ignored "-Wunused-function"
5927b27ec6Sopenharmony_ci#endif
6027b27ec6Sopenharmony_ci#if defined (__clang__)
6127b27ec6Sopenharmony_ci#  pragma clang diagnostic ignored "-Wunused-function"
6227b27ec6Sopenharmony_ci#endif
6327b27ec6Sopenharmony_ci
6427b27ec6Sopenharmony_ci#define LZ4_COMMONDEFS_ONLY
6527b27ec6Sopenharmony_ci#ifndef LZ4_SRC_INCLUDED
6627b27ec6Sopenharmony_ci#include "lz4.c"   /* LZ4_count, constants, mem */
6727b27ec6Sopenharmony_ci#endif
6827b27ec6Sopenharmony_ci
6927b27ec6Sopenharmony_ci
7027b27ec6Sopenharmony_ci/*===   Enums   ===*/
7127b27ec6Sopenharmony_citypedef enum { noDictCtx, usingDictCtxHc } dictCtx_directive;
7227b27ec6Sopenharmony_ci
7327b27ec6Sopenharmony_ci
7427b27ec6Sopenharmony_ci/*===   Constants   ===*/
7527b27ec6Sopenharmony_ci#define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH)
7627b27ec6Sopenharmony_ci#define LZ4_OPT_NUM   (1<<12)
7727b27ec6Sopenharmony_ci
7827b27ec6Sopenharmony_ci
7927b27ec6Sopenharmony_ci/*===   Macros   ===*/
8027b27ec6Sopenharmony_ci#define MIN(a,b)   ( (a) < (b) ? (a) : (b) )
8127b27ec6Sopenharmony_ci#define MAX(a,b)   ( (a) > (b) ? (a) : (b) )
8227b27ec6Sopenharmony_ci#define HASH_FUNCTION(i)         (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG))
8327b27ec6Sopenharmony_ci#define DELTANEXTMAXD(p)         chainTable[(p) & LZ4HC_MAXD_MASK]    /* flexible, LZ4HC_MAXD dependent */
8427b27ec6Sopenharmony_ci#define DELTANEXTU16(table, pos) table[(U16)(pos)]   /* faster */
8527b27ec6Sopenharmony_ci/* Make fields passed to, and updated by LZ4HC_encodeSequence explicit */
8627b27ec6Sopenharmony_ci#define UPDATABLE(ip, op, anchor) &ip, &op, &anchor
8727b27ec6Sopenharmony_ci
8827b27ec6Sopenharmony_cistatic U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }
8927b27ec6Sopenharmony_ci
9027b27ec6Sopenharmony_ci
9127b27ec6Sopenharmony_ci/**************************************
9227b27ec6Sopenharmony_ci*  HC Compression
9327b27ec6Sopenharmony_ci**************************************/
9427b27ec6Sopenharmony_cistatic void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4)
9527b27ec6Sopenharmony_ci{
9627b27ec6Sopenharmony_ci    MEM_INIT(hc4->hashTable, 0, sizeof(hc4->hashTable));
9727b27ec6Sopenharmony_ci    MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));
9827b27ec6Sopenharmony_ci}
9927b27ec6Sopenharmony_ci
10027b27ec6Sopenharmony_cistatic void LZ4HC_init_internal (LZ4HC_CCtx_internal* hc4, const BYTE* start)
10127b27ec6Sopenharmony_ci{
10227b27ec6Sopenharmony_ci    size_t const bufferSize = (size_t)(hc4->end - hc4->prefixStart);
10327b27ec6Sopenharmony_ci    size_t newStartingOffset = bufferSize + hc4->dictLimit;
10427b27ec6Sopenharmony_ci    assert(newStartingOffset >= bufferSize);  /* check overflow */
10527b27ec6Sopenharmony_ci    if (newStartingOffset > 1 GB) {
10627b27ec6Sopenharmony_ci        LZ4HC_clearTables(hc4);
10727b27ec6Sopenharmony_ci        newStartingOffset = 0;
10827b27ec6Sopenharmony_ci    }
10927b27ec6Sopenharmony_ci    newStartingOffset += 64 KB;
11027b27ec6Sopenharmony_ci    hc4->nextToUpdate = (U32)newStartingOffset;
11127b27ec6Sopenharmony_ci    hc4->prefixStart = start;
11227b27ec6Sopenharmony_ci    hc4->end = start;
11327b27ec6Sopenharmony_ci    hc4->dictStart = start;
11427b27ec6Sopenharmony_ci    hc4->dictLimit = (U32)newStartingOffset;
11527b27ec6Sopenharmony_ci    hc4->lowLimit = (U32)newStartingOffset;
11627b27ec6Sopenharmony_ci}
11727b27ec6Sopenharmony_ci
11827b27ec6Sopenharmony_ci
11927b27ec6Sopenharmony_ci/* Update chains up to ip (excluded) */
12027b27ec6Sopenharmony_ciLZ4_FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip)
12127b27ec6Sopenharmony_ci{
12227b27ec6Sopenharmony_ci    U16* const chainTable = hc4->chainTable;
12327b27ec6Sopenharmony_ci    U32* const hashTable  = hc4->hashTable;
12427b27ec6Sopenharmony_ci    const BYTE* const prefixPtr = hc4->prefixStart;
12527b27ec6Sopenharmony_ci    U32 const prefixIdx = hc4->dictLimit;
12627b27ec6Sopenharmony_ci    U32 const target = (U32)(ip - prefixPtr) + prefixIdx;
12727b27ec6Sopenharmony_ci    U32 idx = hc4->nextToUpdate;
12827b27ec6Sopenharmony_ci    assert(ip >= prefixPtr);
12927b27ec6Sopenharmony_ci    assert(target >= prefixIdx);
13027b27ec6Sopenharmony_ci
13127b27ec6Sopenharmony_ci    while (idx < target) {
13227b27ec6Sopenharmony_ci        U32 const h = LZ4HC_hashPtr(prefixPtr+idx-prefixIdx);
13327b27ec6Sopenharmony_ci        size_t delta = idx - hashTable[h];
13427b27ec6Sopenharmony_ci        if (delta>LZ4_DISTANCE_MAX) delta = LZ4_DISTANCE_MAX;
13527b27ec6Sopenharmony_ci        DELTANEXTU16(chainTable, idx) = (U16)delta;
13627b27ec6Sopenharmony_ci        hashTable[h] = idx;
13727b27ec6Sopenharmony_ci        idx++;
13827b27ec6Sopenharmony_ci    }
13927b27ec6Sopenharmony_ci
14027b27ec6Sopenharmony_ci    hc4->nextToUpdate = target;
14127b27ec6Sopenharmony_ci}
14227b27ec6Sopenharmony_ci
14327b27ec6Sopenharmony_ci/** LZ4HC_countBack() :
14427b27ec6Sopenharmony_ci * @return : negative value, nb of common bytes before ip/match */
14527b27ec6Sopenharmony_ciLZ4_FORCE_INLINE
14627b27ec6Sopenharmony_ciint LZ4HC_countBack(const BYTE* const ip, const BYTE* const match,
14727b27ec6Sopenharmony_ci                    const BYTE* const iMin, const BYTE* const mMin)
14827b27ec6Sopenharmony_ci{
14927b27ec6Sopenharmony_ci    int back = 0;
15027b27ec6Sopenharmony_ci    int const min = (int)MAX(iMin - ip, mMin - match);
15127b27ec6Sopenharmony_ci    assert(min <= 0);
15227b27ec6Sopenharmony_ci    assert(ip >= iMin); assert((size_t)(ip-iMin) < (1U<<31));
15327b27ec6Sopenharmony_ci    assert(match >= mMin); assert((size_t)(match - mMin) < (1U<<31));
15427b27ec6Sopenharmony_ci    while ( (back > min)
15527b27ec6Sopenharmony_ci         && (ip[back-1] == match[back-1]) )
15627b27ec6Sopenharmony_ci            back--;
15727b27ec6Sopenharmony_ci    return back;
15827b27ec6Sopenharmony_ci}
15927b27ec6Sopenharmony_ci
16027b27ec6Sopenharmony_ci#if defined(_MSC_VER)
16127b27ec6Sopenharmony_ci#  define LZ4HC_rotl32(x,r) _rotl(x,r)
16227b27ec6Sopenharmony_ci#else
16327b27ec6Sopenharmony_ci#  define LZ4HC_rotl32(x,r) ((x << r) | (x >> (32 - r)))
16427b27ec6Sopenharmony_ci#endif
16527b27ec6Sopenharmony_ci
16627b27ec6Sopenharmony_ci
16727b27ec6Sopenharmony_cistatic U32 LZ4HC_rotatePattern(size_t const rotate, U32 const pattern)
16827b27ec6Sopenharmony_ci{
16927b27ec6Sopenharmony_ci    size_t const bitsToRotate = (rotate & (sizeof(pattern) - 1)) << 3;
17027b27ec6Sopenharmony_ci    if (bitsToRotate == 0) return pattern;
17127b27ec6Sopenharmony_ci    return LZ4HC_rotl32(pattern, (int)bitsToRotate);
17227b27ec6Sopenharmony_ci}
17327b27ec6Sopenharmony_ci
17427b27ec6Sopenharmony_ci/* LZ4HC_countPattern() :
17527b27ec6Sopenharmony_ci * pattern32 must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!) */
17627b27ec6Sopenharmony_cistatic unsigned
17727b27ec6Sopenharmony_ciLZ4HC_countPattern(const BYTE* ip, const BYTE* const iEnd, U32 const pattern32)
17827b27ec6Sopenharmony_ci{
17927b27ec6Sopenharmony_ci    const BYTE* const iStart = ip;
18027b27ec6Sopenharmony_ci    reg_t const pattern = (sizeof(pattern)==8) ?
18127b27ec6Sopenharmony_ci        (reg_t)pattern32 + (((reg_t)pattern32) << (sizeof(pattern)*4)) : pattern32;
18227b27ec6Sopenharmony_ci
18327b27ec6Sopenharmony_ci    while (likely(ip < iEnd-(sizeof(pattern)-1))) {
18427b27ec6Sopenharmony_ci        reg_t const diff = LZ4_read_ARCH(ip) ^ pattern;
18527b27ec6Sopenharmony_ci        if (!diff) { ip+=sizeof(pattern); continue; }
18627b27ec6Sopenharmony_ci        ip += LZ4_NbCommonBytes(diff);
18727b27ec6Sopenharmony_ci        return (unsigned)(ip - iStart);
18827b27ec6Sopenharmony_ci    }
18927b27ec6Sopenharmony_ci
19027b27ec6Sopenharmony_ci    if (LZ4_isLittleEndian()) {
19127b27ec6Sopenharmony_ci        reg_t patternByte = pattern;
19227b27ec6Sopenharmony_ci        while ((ip<iEnd) && (*ip == (BYTE)patternByte)) {
19327b27ec6Sopenharmony_ci            ip++; patternByte >>= 8;
19427b27ec6Sopenharmony_ci        }
19527b27ec6Sopenharmony_ci    } else {  /* big endian */
19627b27ec6Sopenharmony_ci        U32 bitOffset = (sizeof(pattern)*8) - 8;
19727b27ec6Sopenharmony_ci        while (ip < iEnd) {
19827b27ec6Sopenharmony_ci            BYTE const byte = (BYTE)(pattern >> bitOffset);
19927b27ec6Sopenharmony_ci            if (*ip != byte) break;
20027b27ec6Sopenharmony_ci            ip ++; bitOffset -= 8;
20127b27ec6Sopenharmony_ci    }   }
20227b27ec6Sopenharmony_ci
20327b27ec6Sopenharmony_ci    return (unsigned)(ip - iStart);
20427b27ec6Sopenharmony_ci}
20527b27ec6Sopenharmony_ci
20627b27ec6Sopenharmony_ci/* LZ4HC_reverseCountPattern() :
20727b27ec6Sopenharmony_ci * pattern must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!)
20827b27ec6Sopenharmony_ci * read using natural platform endianness */
20927b27ec6Sopenharmony_cistatic unsigned
21027b27ec6Sopenharmony_ciLZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern)
21127b27ec6Sopenharmony_ci{
21227b27ec6Sopenharmony_ci    const BYTE* const iStart = ip;
21327b27ec6Sopenharmony_ci
21427b27ec6Sopenharmony_ci    while (likely(ip >= iLow+4)) {
21527b27ec6Sopenharmony_ci        if (LZ4_read32(ip-4) != pattern) break;
21627b27ec6Sopenharmony_ci        ip -= 4;
21727b27ec6Sopenharmony_ci    }
21827b27ec6Sopenharmony_ci    {   const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianness */
21927b27ec6Sopenharmony_ci        while (likely(ip>iLow)) {
22027b27ec6Sopenharmony_ci            if (ip[-1] != *bytePtr) break;
22127b27ec6Sopenharmony_ci            ip--; bytePtr--;
22227b27ec6Sopenharmony_ci    }   }
22327b27ec6Sopenharmony_ci    return (unsigned)(iStart - ip);
22427b27ec6Sopenharmony_ci}
22527b27ec6Sopenharmony_ci
22627b27ec6Sopenharmony_ci/* LZ4HC_protectDictEnd() :
22727b27ec6Sopenharmony_ci * Checks if the match is in the last 3 bytes of the dictionary, so reading the
22827b27ec6Sopenharmony_ci * 4 byte MINMATCH would overflow.
22927b27ec6Sopenharmony_ci * @returns true if the match index is okay.
23027b27ec6Sopenharmony_ci */
23127b27ec6Sopenharmony_cistatic int LZ4HC_protectDictEnd(U32 const dictLimit, U32 const matchIndex)
23227b27ec6Sopenharmony_ci{
23327b27ec6Sopenharmony_ci    return ((U32)((dictLimit - 1) - matchIndex) >= 3);
23427b27ec6Sopenharmony_ci}
23527b27ec6Sopenharmony_ci
23627b27ec6Sopenharmony_citypedef enum { rep_untested, rep_not, rep_confirmed } repeat_state_e;
23727b27ec6Sopenharmony_citypedef enum { favorCompressionRatio=0, favorDecompressionSpeed } HCfavor_e;
23827b27ec6Sopenharmony_ci
23927b27ec6Sopenharmony_ciLZ4_FORCE_INLINE int
24027b27ec6Sopenharmony_ciLZ4HC_InsertAndGetWiderMatch (
24127b27ec6Sopenharmony_ci        LZ4HC_CCtx_internal* const hc4,
24227b27ec6Sopenharmony_ci        const BYTE* const ip,
24327b27ec6Sopenharmony_ci        const BYTE* const iLowLimit, const BYTE* const iHighLimit,
24427b27ec6Sopenharmony_ci        int longest,
24527b27ec6Sopenharmony_ci        const BYTE** matchpos,
24627b27ec6Sopenharmony_ci        const BYTE** startpos,
24727b27ec6Sopenharmony_ci        const int maxNbAttempts,
24827b27ec6Sopenharmony_ci        const int patternAnalysis, const int chainSwap,
24927b27ec6Sopenharmony_ci        const dictCtx_directive dict,
25027b27ec6Sopenharmony_ci        const HCfavor_e favorDecSpeed)
25127b27ec6Sopenharmony_ci{
25227b27ec6Sopenharmony_ci    U16* const chainTable = hc4->chainTable;
25327b27ec6Sopenharmony_ci    U32* const HashTable = hc4->hashTable;
25427b27ec6Sopenharmony_ci    const LZ4HC_CCtx_internal * const dictCtx = hc4->dictCtx;
25527b27ec6Sopenharmony_ci    const BYTE* const prefixPtr = hc4->prefixStart;
25627b27ec6Sopenharmony_ci    const U32 prefixIdx = hc4->dictLimit;
25727b27ec6Sopenharmony_ci    const U32 ipIndex = (U32)(ip - prefixPtr) + prefixIdx;
25827b27ec6Sopenharmony_ci    const int withinStartDistance = (hc4->lowLimit + (LZ4_DISTANCE_MAX + 1) > ipIndex);
25927b27ec6Sopenharmony_ci    const U32 lowestMatchIndex = (withinStartDistance) ? hc4->lowLimit : ipIndex - LZ4_DISTANCE_MAX;
26027b27ec6Sopenharmony_ci    const BYTE* const dictStart = hc4->dictStart;
26127b27ec6Sopenharmony_ci    const U32 dictIdx = hc4->lowLimit;
26227b27ec6Sopenharmony_ci    const BYTE* const dictEnd = dictStart + prefixIdx - dictIdx;
26327b27ec6Sopenharmony_ci    int const lookBackLength = (int)(ip-iLowLimit);
26427b27ec6Sopenharmony_ci    int nbAttempts = maxNbAttempts;
26527b27ec6Sopenharmony_ci    U32 matchChainPos = 0;
26627b27ec6Sopenharmony_ci    U32 const pattern = LZ4_read32(ip);
26727b27ec6Sopenharmony_ci    U32 matchIndex;
26827b27ec6Sopenharmony_ci    repeat_state_e repeat = rep_untested;
26927b27ec6Sopenharmony_ci    size_t srcPatternLength = 0;
27027b27ec6Sopenharmony_ci
27127b27ec6Sopenharmony_ci    DEBUGLOG(7, "LZ4HC_InsertAndGetWiderMatch");
27227b27ec6Sopenharmony_ci    /* First Match */
27327b27ec6Sopenharmony_ci    LZ4HC_Insert(hc4, ip);
27427b27ec6Sopenharmony_ci    matchIndex = HashTable[LZ4HC_hashPtr(ip)];
27527b27ec6Sopenharmony_ci    DEBUGLOG(7, "First match at index %u / %u (lowestMatchIndex)",
27627b27ec6Sopenharmony_ci                matchIndex, lowestMatchIndex);
27727b27ec6Sopenharmony_ci
27827b27ec6Sopenharmony_ci    while ((matchIndex>=lowestMatchIndex) && (nbAttempts>0)) {
27927b27ec6Sopenharmony_ci        int matchLength=0;
28027b27ec6Sopenharmony_ci        nbAttempts--;
28127b27ec6Sopenharmony_ci        assert(matchIndex < ipIndex);
28227b27ec6Sopenharmony_ci        if (favorDecSpeed && (ipIndex - matchIndex < 8)) {
28327b27ec6Sopenharmony_ci            /* do nothing */
28427b27ec6Sopenharmony_ci        } else if (matchIndex >= prefixIdx) {   /* within current Prefix */
28527b27ec6Sopenharmony_ci            const BYTE* const matchPtr = prefixPtr + matchIndex - prefixIdx;
28627b27ec6Sopenharmony_ci            assert(matchPtr < ip);
28727b27ec6Sopenharmony_ci            assert(longest >= 1);
28827b27ec6Sopenharmony_ci            if (LZ4_read16(iLowLimit + longest - 1) == LZ4_read16(matchPtr - lookBackLength + longest - 1)) {
28927b27ec6Sopenharmony_ci                if (LZ4_read32(matchPtr) == pattern) {
29027b27ec6Sopenharmony_ci                    int const back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, prefixPtr) : 0;
29127b27ec6Sopenharmony_ci                    matchLength = MINMATCH + (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit);
29227b27ec6Sopenharmony_ci                    matchLength -= back;
29327b27ec6Sopenharmony_ci                    if (matchLength > longest) {
29427b27ec6Sopenharmony_ci                        longest = matchLength;
29527b27ec6Sopenharmony_ci                        *matchpos = matchPtr + back;
29627b27ec6Sopenharmony_ci                        *startpos = ip + back;
29727b27ec6Sopenharmony_ci            }   }   }
29827b27ec6Sopenharmony_ci        } else {   /* lowestMatchIndex <= matchIndex < dictLimit */
29927b27ec6Sopenharmony_ci            const BYTE* const matchPtr = dictStart + (matchIndex - dictIdx);
30027b27ec6Sopenharmony_ci            assert(matchIndex >= dictIdx);
30127b27ec6Sopenharmony_ci            if ( likely(matchIndex <= prefixIdx - 4)
30227b27ec6Sopenharmony_ci              && (LZ4_read32(matchPtr) == pattern) ) {
30327b27ec6Sopenharmony_ci                int back = 0;
30427b27ec6Sopenharmony_ci                const BYTE* vLimit = ip + (prefixIdx - matchIndex);
30527b27ec6Sopenharmony_ci                if (vLimit > iHighLimit) vLimit = iHighLimit;
30627b27ec6Sopenharmony_ci                matchLength = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
30727b27ec6Sopenharmony_ci                if ((ip+matchLength == vLimit) && (vLimit < iHighLimit))
30827b27ec6Sopenharmony_ci                    matchLength += LZ4_count(ip+matchLength, prefixPtr, iHighLimit);
30927b27ec6Sopenharmony_ci                back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictStart) : 0;
31027b27ec6Sopenharmony_ci                matchLength -= back;
31127b27ec6Sopenharmony_ci                if (matchLength > longest) {
31227b27ec6Sopenharmony_ci                    longest = matchLength;
31327b27ec6Sopenharmony_ci                    *matchpos = prefixPtr - prefixIdx + matchIndex + back;   /* virtual pos, relative to ip, to retrieve offset */
31427b27ec6Sopenharmony_ci                    *startpos = ip + back;
31527b27ec6Sopenharmony_ci        }   }   }
31627b27ec6Sopenharmony_ci
31727b27ec6Sopenharmony_ci        if (chainSwap && matchLength==longest) {   /* better match => select a better chain */
31827b27ec6Sopenharmony_ci            assert(lookBackLength==0);   /* search forward only */
31927b27ec6Sopenharmony_ci            if (matchIndex + (U32)longest <= ipIndex) {
32027b27ec6Sopenharmony_ci                int const kTrigger = 4;
32127b27ec6Sopenharmony_ci                U32 distanceToNextMatch = 1;
32227b27ec6Sopenharmony_ci                int const end = longest - MINMATCH + 1;
32327b27ec6Sopenharmony_ci                int step = 1;
32427b27ec6Sopenharmony_ci                int accel = 1 << kTrigger;
32527b27ec6Sopenharmony_ci                int pos;
32627b27ec6Sopenharmony_ci                for (pos = 0; pos < end; pos += step) {
32727b27ec6Sopenharmony_ci                    U32 const candidateDist = DELTANEXTU16(chainTable, matchIndex + (U32)pos);
32827b27ec6Sopenharmony_ci                    step = (accel++ >> kTrigger);
32927b27ec6Sopenharmony_ci                    if (candidateDist > distanceToNextMatch) {
33027b27ec6Sopenharmony_ci                        distanceToNextMatch = candidateDist;
33127b27ec6Sopenharmony_ci                        matchChainPos = (U32)pos;
33227b27ec6Sopenharmony_ci                        accel = 1 << kTrigger;
33327b27ec6Sopenharmony_ci                }   }
33427b27ec6Sopenharmony_ci                if (distanceToNextMatch > 1) {
33527b27ec6Sopenharmony_ci                    if (distanceToNextMatch > matchIndex) break;   /* avoid overflow */
33627b27ec6Sopenharmony_ci                    matchIndex -= distanceToNextMatch;
33727b27ec6Sopenharmony_ci                    continue;
33827b27ec6Sopenharmony_ci        }   }   }
33927b27ec6Sopenharmony_ci
34027b27ec6Sopenharmony_ci        {   U32 const distNextMatch = DELTANEXTU16(chainTable, matchIndex);
34127b27ec6Sopenharmony_ci            if (patternAnalysis && distNextMatch==1 && matchChainPos==0) {
34227b27ec6Sopenharmony_ci                U32 const matchCandidateIdx = matchIndex-1;
34327b27ec6Sopenharmony_ci                /* may be a repeated pattern */
34427b27ec6Sopenharmony_ci                if (repeat == rep_untested) {
34527b27ec6Sopenharmony_ci                    if ( ((pattern & 0xFFFF) == (pattern >> 16))
34627b27ec6Sopenharmony_ci                      &  ((pattern & 0xFF)   == (pattern >> 24)) ) {
34727b27ec6Sopenharmony_ci                        repeat = rep_confirmed;
34827b27ec6Sopenharmony_ci                        srcPatternLength = LZ4HC_countPattern(ip+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern);
34927b27ec6Sopenharmony_ci                    } else {
35027b27ec6Sopenharmony_ci                        repeat = rep_not;
35127b27ec6Sopenharmony_ci                }   }
35227b27ec6Sopenharmony_ci                if ( (repeat == rep_confirmed) && (matchCandidateIdx >= lowestMatchIndex)
35327b27ec6Sopenharmony_ci                  && LZ4HC_protectDictEnd(prefixIdx, matchCandidateIdx) ) {
35427b27ec6Sopenharmony_ci                    const int extDict = matchCandidateIdx < prefixIdx;
35527b27ec6Sopenharmony_ci                    const BYTE* const matchPtr = (extDict ? dictStart - dictIdx : prefixPtr - prefixIdx) + matchCandidateIdx;
35627b27ec6Sopenharmony_ci                    if (LZ4_read32(matchPtr) == pattern) {  /* good candidate */
35727b27ec6Sopenharmony_ci                        const BYTE* const iLimit = extDict ? dictEnd : iHighLimit;
35827b27ec6Sopenharmony_ci                        size_t forwardPatternLength = LZ4HC_countPattern(matchPtr+sizeof(pattern), iLimit, pattern) + sizeof(pattern);
35927b27ec6Sopenharmony_ci                        if (extDict && matchPtr + forwardPatternLength == iLimit) {
36027b27ec6Sopenharmony_ci                            U32 const rotatedPattern = LZ4HC_rotatePattern(forwardPatternLength, pattern);
36127b27ec6Sopenharmony_ci                            forwardPatternLength += LZ4HC_countPattern(prefixPtr, iHighLimit, rotatedPattern);
36227b27ec6Sopenharmony_ci                        }
36327b27ec6Sopenharmony_ci                        {   const BYTE* const lowestMatchPtr = extDict ? dictStart : prefixPtr;
36427b27ec6Sopenharmony_ci                            size_t backLength = LZ4HC_reverseCountPattern(matchPtr, lowestMatchPtr, pattern);
36527b27ec6Sopenharmony_ci                            size_t currentSegmentLength;
36627b27ec6Sopenharmony_ci                            if (!extDict
36727b27ec6Sopenharmony_ci                              && matchPtr - backLength == prefixPtr
36827b27ec6Sopenharmony_ci                              && dictIdx < prefixIdx) {
36927b27ec6Sopenharmony_ci                                U32 const rotatedPattern = LZ4HC_rotatePattern((U32)(-(int)backLength), pattern);
37027b27ec6Sopenharmony_ci                                backLength += LZ4HC_reverseCountPattern(dictEnd, dictStart, rotatedPattern);
37127b27ec6Sopenharmony_ci                            }
37227b27ec6Sopenharmony_ci                            /* Limit backLength not go further than lowestMatchIndex */
37327b27ec6Sopenharmony_ci                            backLength = matchCandidateIdx - MAX(matchCandidateIdx - (U32)backLength, lowestMatchIndex);
37427b27ec6Sopenharmony_ci                            assert(matchCandidateIdx - backLength >= lowestMatchIndex);
37527b27ec6Sopenharmony_ci                            currentSegmentLength = backLength + forwardPatternLength;
37627b27ec6Sopenharmony_ci                            /* Adjust to end of pattern if the source pattern fits, otherwise the beginning of the pattern */
37727b27ec6Sopenharmony_ci                            if ( (currentSegmentLength >= srcPatternLength)   /* current pattern segment large enough to contain full srcPatternLength */
37827b27ec6Sopenharmony_ci                              && (forwardPatternLength <= srcPatternLength) ) { /* haven't reached this position yet */
37927b27ec6Sopenharmony_ci                                U32 const newMatchIndex = matchCandidateIdx + (U32)forwardPatternLength - (U32)srcPatternLength;  /* best position, full pattern, might be followed by more match */
38027b27ec6Sopenharmony_ci                                if (LZ4HC_protectDictEnd(prefixIdx, newMatchIndex))
38127b27ec6Sopenharmony_ci                                    matchIndex = newMatchIndex;
38227b27ec6Sopenharmony_ci                                else {
38327b27ec6Sopenharmony_ci                                    /* Can only happen if started in the prefix */
38427b27ec6Sopenharmony_ci                                    assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);
38527b27ec6Sopenharmony_ci                                    matchIndex = prefixIdx;
38627b27ec6Sopenharmony_ci                                }
38727b27ec6Sopenharmony_ci                            } else {
38827b27ec6Sopenharmony_ci                                U32 const newMatchIndex = matchCandidateIdx - (U32)backLength;   /* farthest position in current segment, will find a match of length currentSegmentLength + maybe some back */
38927b27ec6Sopenharmony_ci                                if (!LZ4HC_protectDictEnd(prefixIdx, newMatchIndex)) {
39027b27ec6Sopenharmony_ci                                    assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);
39127b27ec6Sopenharmony_ci                                    matchIndex = prefixIdx;
39227b27ec6Sopenharmony_ci                                } else {
39327b27ec6Sopenharmony_ci                                    matchIndex = newMatchIndex;
39427b27ec6Sopenharmony_ci                                    if (lookBackLength==0) {  /* no back possible */
39527b27ec6Sopenharmony_ci                                        size_t const maxML = MIN(currentSegmentLength, srcPatternLength);
39627b27ec6Sopenharmony_ci                                        if ((size_t)longest < maxML) {
39727b27ec6Sopenharmony_ci                                            assert(prefixPtr - prefixIdx + matchIndex != ip);
39827b27ec6Sopenharmony_ci                                            if ((size_t)(ip - prefixPtr) + prefixIdx - matchIndex > LZ4_DISTANCE_MAX) break;
39927b27ec6Sopenharmony_ci                                            assert(maxML < 2 GB);
40027b27ec6Sopenharmony_ci                                            longest = (int)maxML;
40127b27ec6Sopenharmony_ci                                            *matchpos = prefixPtr - prefixIdx + matchIndex;   /* virtual pos, relative to ip, to retrieve offset */
40227b27ec6Sopenharmony_ci                                            *startpos = ip;
40327b27ec6Sopenharmony_ci                                        }
40427b27ec6Sopenharmony_ci                                        {   U32 const distToNextPattern = DELTANEXTU16(chainTable, matchIndex);
40527b27ec6Sopenharmony_ci                                            if (distToNextPattern > matchIndex) break;  /* avoid overflow */
40627b27ec6Sopenharmony_ci                                            matchIndex -= distToNextPattern;
40727b27ec6Sopenharmony_ci                        }   }   }   }   }
40827b27ec6Sopenharmony_ci                        continue;
40927b27ec6Sopenharmony_ci                }   }
41027b27ec6Sopenharmony_ci        }   }   /* PA optimization */
41127b27ec6Sopenharmony_ci
41227b27ec6Sopenharmony_ci        /* follow current chain */
41327b27ec6Sopenharmony_ci        matchIndex -= DELTANEXTU16(chainTable, matchIndex + matchChainPos);
41427b27ec6Sopenharmony_ci
41527b27ec6Sopenharmony_ci    }  /* while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) */
41627b27ec6Sopenharmony_ci
41727b27ec6Sopenharmony_ci    if ( dict == usingDictCtxHc
41827b27ec6Sopenharmony_ci      && nbAttempts > 0
41927b27ec6Sopenharmony_ci      && ipIndex - lowestMatchIndex < LZ4_DISTANCE_MAX) {
42027b27ec6Sopenharmony_ci        size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit;
42127b27ec6Sopenharmony_ci        U32 dictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)];
42227b27ec6Sopenharmony_ci        assert(dictEndOffset <= 1 GB);
42327b27ec6Sopenharmony_ci        matchIndex = dictMatchIndex + lowestMatchIndex - (U32)dictEndOffset;
42427b27ec6Sopenharmony_ci        while (ipIndex - matchIndex <= LZ4_DISTANCE_MAX && nbAttempts--) {
42527b27ec6Sopenharmony_ci            const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + dictMatchIndex;
42627b27ec6Sopenharmony_ci
42727b27ec6Sopenharmony_ci            if (LZ4_read32(matchPtr) == pattern) {
42827b27ec6Sopenharmony_ci                int mlt;
42927b27ec6Sopenharmony_ci                int back = 0;
43027b27ec6Sopenharmony_ci                const BYTE* vLimit = ip + (dictEndOffset - dictMatchIndex);
43127b27ec6Sopenharmony_ci                if (vLimit > iHighLimit) vLimit = iHighLimit;
43227b27ec6Sopenharmony_ci                mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
43327b27ec6Sopenharmony_ci                back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->prefixStart) : 0;
43427b27ec6Sopenharmony_ci                mlt -= back;
43527b27ec6Sopenharmony_ci                if (mlt > longest) {
43627b27ec6Sopenharmony_ci                    longest = mlt;
43727b27ec6Sopenharmony_ci                    *matchpos = prefixPtr - prefixIdx + matchIndex + back;
43827b27ec6Sopenharmony_ci                    *startpos = ip + back;
43927b27ec6Sopenharmony_ci            }   }
44027b27ec6Sopenharmony_ci
44127b27ec6Sopenharmony_ci            {   U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, dictMatchIndex);
44227b27ec6Sopenharmony_ci                dictMatchIndex -= nextOffset;
44327b27ec6Sopenharmony_ci                matchIndex -= nextOffset;
44427b27ec6Sopenharmony_ci    }   }   }
44527b27ec6Sopenharmony_ci
44627b27ec6Sopenharmony_ci    return longest;
44727b27ec6Sopenharmony_ci}
44827b27ec6Sopenharmony_ci
44927b27ec6Sopenharmony_ciLZ4_FORCE_INLINE int
45027b27ec6Sopenharmony_ciLZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4,   /* Index table will be updated */
45127b27ec6Sopenharmony_ci                       const BYTE* const ip, const BYTE* const iLimit,
45227b27ec6Sopenharmony_ci                       const BYTE** matchpos,
45327b27ec6Sopenharmony_ci                       const int maxNbAttempts,
45427b27ec6Sopenharmony_ci                       const int patternAnalysis,
45527b27ec6Sopenharmony_ci                       const dictCtx_directive dict)
45627b27ec6Sopenharmony_ci{
45727b27ec6Sopenharmony_ci    const BYTE* uselessPtr = ip;
45827b27ec6Sopenharmony_ci    /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),
45927b27ec6Sopenharmony_ci     * but this won't be the case here, as we define iLowLimit==ip,
46027b27ec6Sopenharmony_ci     * so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */
46127b27ec6Sopenharmony_ci    return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, matchpos, &uselessPtr, maxNbAttempts, patternAnalysis, 0 /*chainSwap*/, dict, favorCompressionRatio);
46227b27ec6Sopenharmony_ci}
46327b27ec6Sopenharmony_ci
46427b27ec6Sopenharmony_ci/* LZ4HC_encodeSequence() :
46527b27ec6Sopenharmony_ci * @return : 0 if ok,
46627b27ec6Sopenharmony_ci *           1 if buffer issue detected */
46727b27ec6Sopenharmony_ciLZ4_FORCE_INLINE int LZ4HC_encodeSequence (
46827b27ec6Sopenharmony_ci    const BYTE** _ip,
46927b27ec6Sopenharmony_ci    BYTE** _op,
47027b27ec6Sopenharmony_ci    const BYTE** _anchor,
47127b27ec6Sopenharmony_ci    int matchLength,
47227b27ec6Sopenharmony_ci    const BYTE* const match,
47327b27ec6Sopenharmony_ci    limitedOutput_directive limit,
47427b27ec6Sopenharmony_ci    BYTE* oend)
47527b27ec6Sopenharmony_ci{
47627b27ec6Sopenharmony_ci#define ip      (*_ip)
47727b27ec6Sopenharmony_ci#define op      (*_op)
47827b27ec6Sopenharmony_ci#define anchor  (*_anchor)
47927b27ec6Sopenharmony_ci
48027b27ec6Sopenharmony_ci    size_t length;
48127b27ec6Sopenharmony_ci    BYTE* const token = op++;
48227b27ec6Sopenharmony_ci
48327b27ec6Sopenharmony_ci#if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 6)
48427b27ec6Sopenharmony_ci    static const BYTE* start = NULL;
48527b27ec6Sopenharmony_ci    static U32 totalCost = 0;
48627b27ec6Sopenharmony_ci    U32 const pos = (start==NULL) ? 0 : (U32)(anchor - start);
48727b27ec6Sopenharmony_ci    U32 const ll = (U32)(ip - anchor);
48827b27ec6Sopenharmony_ci    U32 const llAdd = (ll>=15) ? ((ll-15) / 255) + 1 : 0;
48927b27ec6Sopenharmony_ci    U32 const mlAdd = (matchLength>=19) ? ((matchLength-19) / 255) + 1 : 0;
49027b27ec6Sopenharmony_ci    U32 const cost = 1 + llAdd + ll + 2 + mlAdd;
49127b27ec6Sopenharmony_ci    if (start==NULL) start = anchor;  /* only works for single segment */
49227b27ec6Sopenharmony_ci    /* g_debuglog_enable = (pos >= 2228) & (pos <= 2262); */
49327b27ec6Sopenharmony_ci    DEBUGLOG(6, "pos:%7u -- literals:%4u, match:%4i, offset:%5u, cost:%4u + %5u",
49427b27ec6Sopenharmony_ci                pos,
49527b27ec6Sopenharmony_ci                (U32)(ip - anchor), matchLength, (U32)(ip-match),
49627b27ec6Sopenharmony_ci                cost, totalCost);
49727b27ec6Sopenharmony_ci    totalCost += cost;
49827b27ec6Sopenharmony_ci#endif
49927b27ec6Sopenharmony_ci
50027b27ec6Sopenharmony_ci    /* Encode Literal length */
50127b27ec6Sopenharmony_ci    length = (size_t)(ip - anchor);
50227b27ec6Sopenharmony_ci    LZ4_STATIC_ASSERT(notLimited == 0);
50327b27ec6Sopenharmony_ci    /* Check output limit */
50427b27ec6Sopenharmony_ci    if (limit && ((op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) {
50527b27ec6Sopenharmony_ci        DEBUGLOG(6, "Not enough room to write %i literals (%i bytes remaining)",
50627b27ec6Sopenharmony_ci                (int)length, (int)(oend - op));
50727b27ec6Sopenharmony_ci        return 1;
50827b27ec6Sopenharmony_ci    }
50927b27ec6Sopenharmony_ci    if (length >= RUN_MASK) {
51027b27ec6Sopenharmony_ci        size_t len = length - RUN_MASK;
51127b27ec6Sopenharmony_ci        *token = (RUN_MASK << ML_BITS);
51227b27ec6Sopenharmony_ci        for(; len >= 255 ; len -= 255) *op++ = 255;
51327b27ec6Sopenharmony_ci        *op++ = (BYTE)len;
51427b27ec6Sopenharmony_ci    } else {
51527b27ec6Sopenharmony_ci        *token = (BYTE)(length << ML_BITS);
51627b27ec6Sopenharmony_ci    }
51727b27ec6Sopenharmony_ci
51827b27ec6Sopenharmony_ci    /* Copy Literals */
51927b27ec6Sopenharmony_ci    LZ4_wildCopy8(op, anchor, op + length);
52027b27ec6Sopenharmony_ci    op += length;
52127b27ec6Sopenharmony_ci
52227b27ec6Sopenharmony_ci    /* Encode Offset */
52327b27ec6Sopenharmony_ci    assert( (ip - match) <= LZ4_DISTANCE_MAX );   /* note : consider providing offset as a value, rather than as a pointer difference */
52427b27ec6Sopenharmony_ci    LZ4_writeLE16(op, (U16)(ip - match)); op += 2;
52527b27ec6Sopenharmony_ci
52627b27ec6Sopenharmony_ci    /* Encode MatchLength */
52727b27ec6Sopenharmony_ci    assert(matchLength >= MINMATCH);
52827b27ec6Sopenharmony_ci    length = (size_t)matchLength - MINMATCH;
52927b27ec6Sopenharmony_ci    if (limit && (op + (length / 255) + (1 + LASTLITERALS) > oend)) {
53027b27ec6Sopenharmony_ci        DEBUGLOG(6, "Not enough room to write match length");
53127b27ec6Sopenharmony_ci        return 1;   /* Check output limit */
53227b27ec6Sopenharmony_ci    }
53327b27ec6Sopenharmony_ci    if (length >= ML_MASK) {
53427b27ec6Sopenharmony_ci        *token += ML_MASK;
53527b27ec6Sopenharmony_ci        length -= ML_MASK;
53627b27ec6Sopenharmony_ci        for(; length >= 510 ; length -= 510) { *op++ = 255; *op++ = 255; }
53727b27ec6Sopenharmony_ci        if (length >= 255) { length -= 255; *op++ = 255; }
53827b27ec6Sopenharmony_ci        *op++ = (BYTE)length;
53927b27ec6Sopenharmony_ci    } else {
54027b27ec6Sopenharmony_ci        *token += (BYTE)(length);
54127b27ec6Sopenharmony_ci    }
54227b27ec6Sopenharmony_ci
54327b27ec6Sopenharmony_ci    /* Prepare next loop */
54427b27ec6Sopenharmony_ci    ip += matchLength;
54527b27ec6Sopenharmony_ci    anchor = ip;
54627b27ec6Sopenharmony_ci
54727b27ec6Sopenharmony_ci    return 0;
54827b27ec6Sopenharmony_ci}
54927b27ec6Sopenharmony_ci#undef ip
55027b27ec6Sopenharmony_ci#undef op
55127b27ec6Sopenharmony_ci#undef anchor
55227b27ec6Sopenharmony_ci
55327b27ec6Sopenharmony_ciLZ4_FORCE_INLINE int LZ4HC_compress_hashChain (
55427b27ec6Sopenharmony_ci    LZ4HC_CCtx_internal* const ctx,
55527b27ec6Sopenharmony_ci    const char* const source,
55627b27ec6Sopenharmony_ci    char* const dest,
55727b27ec6Sopenharmony_ci    int* srcSizePtr,
55827b27ec6Sopenharmony_ci    int const maxOutputSize,
55927b27ec6Sopenharmony_ci    int maxNbAttempts,
56027b27ec6Sopenharmony_ci    const limitedOutput_directive limit,
56127b27ec6Sopenharmony_ci    const dictCtx_directive dict
56227b27ec6Sopenharmony_ci    )
56327b27ec6Sopenharmony_ci{
56427b27ec6Sopenharmony_ci    const int inputSize = *srcSizePtr;
56527b27ec6Sopenharmony_ci    const int patternAnalysis = (maxNbAttempts > 128);   /* levels 9+ */
56627b27ec6Sopenharmony_ci
56727b27ec6Sopenharmony_ci    const BYTE* ip = (const BYTE*) source;
56827b27ec6Sopenharmony_ci    const BYTE* anchor = ip;
56927b27ec6Sopenharmony_ci    const BYTE* const iend = ip + inputSize;
57027b27ec6Sopenharmony_ci    const BYTE* const mflimit = iend - MFLIMIT;
57127b27ec6Sopenharmony_ci    const BYTE* const matchlimit = (iend - LASTLITERALS);
57227b27ec6Sopenharmony_ci
57327b27ec6Sopenharmony_ci    BYTE* optr = (BYTE*) dest;
57427b27ec6Sopenharmony_ci    BYTE* op = (BYTE*) dest;
57527b27ec6Sopenharmony_ci    BYTE* oend = op + maxOutputSize;
57627b27ec6Sopenharmony_ci
57727b27ec6Sopenharmony_ci    int   ml0, ml, ml2, ml3;
57827b27ec6Sopenharmony_ci    const BYTE* start0;
57927b27ec6Sopenharmony_ci    const BYTE* ref0;
58027b27ec6Sopenharmony_ci    const BYTE* ref = NULL;
58127b27ec6Sopenharmony_ci    const BYTE* start2 = NULL;
58227b27ec6Sopenharmony_ci    const BYTE* ref2 = NULL;
58327b27ec6Sopenharmony_ci    const BYTE* start3 = NULL;
58427b27ec6Sopenharmony_ci    const BYTE* ref3 = NULL;
58527b27ec6Sopenharmony_ci
58627b27ec6Sopenharmony_ci    /* init */
58727b27ec6Sopenharmony_ci    *srcSizePtr = 0;
58827b27ec6Sopenharmony_ci    if (limit == fillOutput) oend -= LASTLITERALS;                  /* Hack for support LZ4 format restriction */
58927b27ec6Sopenharmony_ci    if (inputSize < LZ4_minLength) goto _last_literals;             /* Input too small, no compression (all literals) */
59027b27ec6Sopenharmony_ci
59127b27ec6Sopenharmony_ci    /* Main Loop */
59227b27ec6Sopenharmony_ci    while (ip <= mflimit) {
59327b27ec6Sopenharmony_ci        ml = LZ4HC_InsertAndFindBestMatch(ctx, ip, matchlimit, &ref, maxNbAttempts, patternAnalysis, dict);
59427b27ec6Sopenharmony_ci        if (ml<MINMATCH) { ip++; continue; }
59527b27ec6Sopenharmony_ci
59627b27ec6Sopenharmony_ci        /* saved, in case we would skip too much */
59727b27ec6Sopenharmony_ci        start0 = ip; ref0 = ref; ml0 = ml;
59827b27ec6Sopenharmony_ci
59927b27ec6Sopenharmony_ci_Search2:
60027b27ec6Sopenharmony_ci        if (ip+ml <= mflimit) {
60127b27ec6Sopenharmony_ci            ml2 = LZ4HC_InsertAndGetWiderMatch(ctx,
60227b27ec6Sopenharmony_ci                            ip + ml - 2, ip + 0, matchlimit, ml, &ref2, &start2,
60327b27ec6Sopenharmony_ci                            maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);
60427b27ec6Sopenharmony_ci        } else {
60527b27ec6Sopenharmony_ci            ml2 = ml;
60627b27ec6Sopenharmony_ci        }
60727b27ec6Sopenharmony_ci
60827b27ec6Sopenharmony_ci        if (ml2 == ml) { /* No better match => encode ML1 */
60927b27ec6Sopenharmony_ci            optr = op;
61027b27ec6Sopenharmony_ci            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
61127b27ec6Sopenharmony_ci            continue;
61227b27ec6Sopenharmony_ci        }
61327b27ec6Sopenharmony_ci
61427b27ec6Sopenharmony_ci        if (start0 < ip) {   /* first match was skipped at least once */
61527b27ec6Sopenharmony_ci            if (start2 < ip + ml0) {  /* squeezing ML1 between ML0(original ML1) and ML2 */
61627b27ec6Sopenharmony_ci                ip = start0; ref = ref0; ml = ml0;  /* restore initial ML1 */
61727b27ec6Sopenharmony_ci        }   }
61827b27ec6Sopenharmony_ci
61927b27ec6Sopenharmony_ci        /* Here, start0==ip */
62027b27ec6Sopenharmony_ci        if ((start2 - ip) < 3) {  /* First Match too small : removed */
62127b27ec6Sopenharmony_ci            ml = ml2;
62227b27ec6Sopenharmony_ci            ip = start2;
62327b27ec6Sopenharmony_ci            ref =ref2;
62427b27ec6Sopenharmony_ci            goto _Search2;
62527b27ec6Sopenharmony_ci        }
62627b27ec6Sopenharmony_ci
62727b27ec6Sopenharmony_ci_Search3:
62827b27ec6Sopenharmony_ci        /* At this stage, we have :
62927b27ec6Sopenharmony_ci        *  ml2 > ml1, and
63027b27ec6Sopenharmony_ci        *  ip1+3 <= ip2 (usually < ip1+ml1) */
63127b27ec6Sopenharmony_ci        if ((start2 - ip) < OPTIMAL_ML) {
63227b27ec6Sopenharmony_ci            int correction;
63327b27ec6Sopenharmony_ci            int new_ml = ml;
63427b27ec6Sopenharmony_ci            if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;
63527b27ec6Sopenharmony_ci            if (ip+new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - ip) + ml2 - MINMATCH;
63627b27ec6Sopenharmony_ci            correction = new_ml - (int)(start2 - ip);
63727b27ec6Sopenharmony_ci            if (correction > 0) {
63827b27ec6Sopenharmony_ci                start2 += correction;
63927b27ec6Sopenharmony_ci                ref2 += correction;
64027b27ec6Sopenharmony_ci                ml2 -= correction;
64127b27ec6Sopenharmony_ci            }
64227b27ec6Sopenharmony_ci        }
64327b27ec6Sopenharmony_ci        /* Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) */
64427b27ec6Sopenharmony_ci
64527b27ec6Sopenharmony_ci        if (start2 + ml2 <= mflimit) {
64627b27ec6Sopenharmony_ci            ml3 = LZ4HC_InsertAndGetWiderMatch(ctx,
64727b27ec6Sopenharmony_ci                            start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3,
64827b27ec6Sopenharmony_ci                            maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);
64927b27ec6Sopenharmony_ci        } else {
65027b27ec6Sopenharmony_ci            ml3 = ml2;
65127b27ec6Sopenharmony_ci        }
65227b27ec6Sopenharmony_ci
65327b27ec6Sopenharmony_ci        if (ml3 == ml2) {  /* No better match => encode ML1 and ML2 */
65427b27ec6Sopenharmony_ci            /* ip & ref are known; Now for ml */
65527b27ec6Sopenharmony_ci            if (start2 < ip+ml)  ml = (int)(start2 - ip);
65627b27ec6Sopenharmony_ci            /* Now, encode 2 sequences */
65727b27ec6Sopenharmony_ci            optr = op;
65827b27ec6Sopenharmony_ci            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
65927b27ec6Sopenharmony_ci            ip = start2;
66027b27ec6Sopenharmony_ci            optr = op;
66127b27ec6Sopenharmony_ci            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml2, ref2, limit, oend)) {
66227b27ec6Sopenharmony_ci                ml  = ml2;
66327b27ec6Sopenharmony_ci                ref = ref2;
66427b27ec6Sopenharmony_ci                goto _dest_overflow;
66527b27ec6Sopenharmony_ci            }
66627b27ec6Sopenharmony_ci            continue;
66727b27ec6Sopenharmony_ci        }
66827b27ec6Sopenharmony_ci
66927b27ec6Sopenharmony_ci        if (start3 < ip+ml+3) {  /* Not enough space for match 2 : remove it */
67027b27ec6Sopenharmony_ci            if (start3 >= (ip+ml)) {  /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */
67127b27ec6Sopenharmony_ci                if (start2 < ip+ml) {
67227b27ec6Sopenharmony_ci                    int correction = (int)(ip+ml - start2);
67327b27ec6Sopenharmony_ci                    start2 += correction;
67427b27ec6Sopenharmony_ci                    ref2 += correction;
67527b27ec6Sopenharmony_ci                    ml2 -= correction;
67627b27ec6Sopenharmony_ci                    if (ml2 < MINMATCH) {
67727b27ec6Sopenharmony_ci                        start2 = start3;
67827b27ec6Sopenharmony_ci                        ref2 = ref3;
67927b27ec6Sopenharmony_ci                        ml2 = ml3;
68027b27ec6Sopenharmony_ci                    }
68127b27ec6Sopenharmony_ci                }
68227b27ec6Sopenharmony_ci
68327b27ec6Sopenharmony_ci                optr = op;
68427b27ec6Sopenharmony_ci                if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
68527b27ec6Sopenharmony_ci                ip  = start3;
68627b27ec6Sopenharmony_ci                ref = ref3;
68727b27ec6Sopenharmony_ci                ml  = ml3;
68827b27ec6Sopenharmony_ci
68927b27ec6Sopenharmony_ci                start0 = start2;
69027b27ec6Sopenharmony_ci                ref0 = ref2;
69127b27ec6Sopenharmony_ci                ml0 = ml2;
69227b27ec6Sopenharmony_ci                goto _Search2;
69327b27ec6Sopenharmony_ci            }
69427b27ec6Sopenharmony_ci
69527b27ec6Sopenharmony_ci            start2 = start3;
69627b27ec6Sopenharmony_ci            ref2 = ref3;
69727b27ec6Sopenharmony_ci            ml2 = ml3;
69827b27ec6Sopenharmony_ci            goto _Search3;
69927b27ec6Sopenharmony_ci        }
70027b27ec6Sopenharmony_ci
70127b27ec6Sopenharmony_ci        /*
70227b27ec6Sopenharmony_ci        * OK, now we have 3 ascending matches;
70327b27ec6Sopenharmony_ci        * let's write the first one ML1.
70427b27ec6Sopenharmony_ci        * ip & ref are known; Now decide ml.
70527b27ec6Sopenharmony_ci        */
70627b27ec6Sopenharmony_ci        if (start2 < ip+ml) {
70727b27ec6Sopenharmony_ci            if ((start2 - ip) < OPTIMAL_ML) {
70827b27ec6Sopenharmony_ci                int correction;
70927b27ec6Sopenharmony_ci                if (ml > OPTIMAL_ML) ml = OPTIMAL_ML;
71027b27ec6Sopenharmony_ci                if (ip + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - ip) + ml2 - MINMATCH;
71127b27ec6Sopenharmony_ci                correction = ml - (int)(start2 - ip);
71227b27ec6Sopenharmony_ci                if (correction > 0) {
71327b27ec6Sopenharmony_ci                    start2 += correction;
71427b27ec6Sopenharmony_ci                    ref2 += correction;
71527b27ec6Sopenharmony_ci                    ml2 -= correction;
71627b27ec6Sopenharmony_ci                }
71727b27ec6Sopenharmony_ci            } else {
71827b27ec6Sopenharmony_ci                ml = (int)(start2 - ip);
71927b27ec6Sopenharmony_ci            }
72027b27ec6Sopenharmony_ci        }
72127b27ec6Sopenharmony_ci        optr = op;
72227b27ec6Sopenharmony_ci        if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
72327b27ec6Sopenharmony_ci
72427b27ec6Sopenharmony_ci        /* ML2 becomes ML1 */
72527b27ec6Sopenharmony_ci        ip = start2; ref = ref2; ml = ml2;
72627b27ec6Sopenharmony_ci
72727b27ec6Sopenharmony_ci        /* ML3 becomes ML2 */
72827b27ec6Sopenharmony_ci        start2 = start3; ref2 = ref3; ml2 = ml3;
72927b27ec6Sopenharmony_ci
73027b27ec6Sopenharmony_ci        /* let's find a new ML3 */
73127b27ec6Sopenharmony_ci        goto _Search3;
73227b27ec6Sopenharmony_ci    }
73327b27ec6Sopenharmony_ci
73427b27ec6Sopenharmony_ci_last_literals:
73527b27ec6Sopenharmony_ci    /* Encode Last Literals */
73627b27ec6Sopenharmony_ci    {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */
73727b27ec6Sopenharmony_ci        size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;
73827b27ec6Sopenharmony_ci        size_t const totalSize = 1 + llAdd + lastRunSize;
73927b27ec6Sopenharmony_ci        if (limit == fillOutput) oend += LASTLITERALS;  /* restore correct value */
74027b27ec6Sopenharmony_ci        if (limit && (op + totalSize > oend)) {
74127b27ec6Sopenharmony_ci            if (limit == limitedOutput) return 0;
74227b27ec6Sopenharmony_ci            /* adapt lastRunSize to fill 'dest' */
74327b27ec6Sopenharmony_ci            lastRunSize  = (size_t)(oend - op) - 1 /*token*/;
74427b27ec6Sopenharmony_ci            llAdd = (lastRunSize + 256 - RUN_MASK) / 256;
74527b27ec6Sopenharmony_ci            lastRunSize -= llAdd;
74627b27ec6Sopenharmony_ci        }
74727b27ec6Sopenharmony_ci        DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);
74827b27ec6Sopenharmony_ci        ip = anchor + lastRunSize;  /* can be != iend if limit==fillOutput */
74927b27ec6Sopenharmony_ci
75027b27ec6Sopenharmony_ci        if (lastRunSize >= RUN_MASK) {
75127b27ec6Sopenharmony_ci            size_t accumulator = lastRunSize - RUN_MASK;
75227b27ec6Sopenharmony_ci            *op++ = (RUN_MASK << ML_BITS);
75327b27ec6Sopenharmony_ci            for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;
75427b27ec6Sopenharmony_ci            *op++ = (BYTE) accumulator;
75527b27ec6Sopenharmony_ci        } else {
75627b27ec6Sopenharmony_ci            *op++ = (BYTE)(lastRunSize << ML_BITS);
75727b27ec6Sopenharmony_ci        }
75827b27ec6Sopenharmony_ci        LZ4_memcpy(op, anchor, lastRunSize);
75927b27ec6Sopenharmony_ci        op += lastRunSize;
76027b27ec6Sopenharmony_ci    }
76127b27ec6Sopenharmony_ci
76227b27ec6Sopenharmony_ci    /* End */
76327b27ec6Sopenharmony_ci    *srcSizePtr = (int) (((const char*)ip) - source);
76427b27ec6Sopenharmony_ci    return (int) (((char*)op)-dest);
76527b27ec6Sopenharmony_ci
76627b27ec6Sopenharmony_ci_dest_overflow:
76727b27ec6Sopenharmony_ci    if (limit == fillOutput) {
76827b27ec6Sopenharmony_ci        /* Assumption : ip, anchor, ml and ref must be set correctly */
76927b27ec6Sopenharmony_ci        size_t const ll = (size_t)(ip - anchor);
77027b27ec6Sopenharmony_ci        size_t const ll_addbytes = (ll + 240) / 255;
77127b27ec6Sopenharmony_ci        size_t const ll_totalCost = 1 + ll_addbytes + ll;
77227b27ec6Sopenharmony_ci        BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */
77327b27ec6Sopenharmony_ci        DEBUGLOG(6, "Last sequence overflowing");
77427b27ec6Sopenharmony_ci        op = optr;  /* restore correct out pointer */
77527b27ec6Sopenharmony_ci        if (op + ll_totalCost <= maxLitPos) {
77627b27ec6Sopenharmony_ci            /* ll validated; now adjust match length */
77727b27ec6Sopenharmony_ci            size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));
77827b27ec6Sopenharmony_ci            size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);
77927b27ec6Sopenharmony_ci            assert(maxMlSize < INT_MAX); assert(ml >= 0);
78027b27ec6Sopenharmony_ci            if ((size_t)ml > maxMlSize) ml = (int)maxMlSize;
78127b27ec6Sopenharmony_ci            if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ml >= MFLIMIT) {
78227b27ec6Sopenharmony_ci                LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, notLimited, oend);
78327b27ec6Sopenharmony_ci        }   }
78427b27ec6Sopenharmony_ci        goto _last_literals;
78527b27ec6Sopenharmony_ci    }
78627b27ec6Sopenharmony_ci    /* compression failed */
78727b27ec6Sopenharmony_ci    return 0;
78827b27ec6Sopenharmony_ci}
78927b27ec6Sopenharmony_ci
79027b27ec6Sopenharmony_ci
79127b27ec6Sopenharmony_cistatic int LZ4HC_compress_optimal( LZ4HC_CCtx_internal* ctx,
79227b27ec6Sopenharmony_ci    const char* const source, char* dst,
79327b27ec6Sopenharmony_ci    int* srcSizePtr, int dstCapacity,
79427b27ec6Sopenharmony_ci    int const nbSearches, size_t sufficient_len,
79527b27ec6Sopenharmony_ci    const limitedOutput_directive limit, int const fullUpdate,
79627b27ec6Sopenharmony_ci    const dictCtx_directive dict,
79727b27ec6Sopenharmony_ci    const HCfavor_e favorDecSpeed);
79827b27ec6Sopenharmony_ci
79927b27ec6Sopenharmony_ci
80027b27ec6Sopenharmony_ciLZ4_FORCE_INLINE int LZ4HC_compress_generic_internal (
80127b27ec6Sopenharmony_ci    LZ4HC_CCtx_internal* const ctx,
80227b27ec6Sopenharmony_ci    const char* const src,
80327b27ec6Sopenharmony_ci    char* const dst,
80427b27ec6Sopenharmony_ci    int* const srcSizePtr,
80527b27ec6Sopenharmony_ci    int const dstCapacity,
80627b27ec6Sopenharmony_ci    int cLevel,
80727b27ec6Sopenharmony_ci    const limitedOutput_directive limit,
80827b27ec6Sopenharmony_ci    const dictCtx_directive dict
80927b27ec6Sopenharmony_ci    )
81027b27ec6Sopenharmony_ci{
81127b27ec6Sopenharmony_ci    typedef enum { lz4hc, lz4opt } lz4hc_strat_e;
81227b27ec6Sopenharmony_ci    typedef struct {
81327b27ec6Sopenharmony_ci        lz4hc_strat_e strat;
81427b27ec6Sopenharmony_ci        int nbSearches;
81527b27ec6Sopenharmony_ci        U32 targetLength;
81627b27ec6Sopenharmony_ci    } cParams_t;
81727b27ec6Sopenharmony_ci    static const cParams_t clTable[LZ4HC_CLEVEL_MAX+1] = {
81827b27ec6Sopenharmony_ci        { lz4hc,     2, 16 },  /* 0, unused */
81927b27ec6Sopenharmony_ci        { lz4hc,     2, 16 },  /* 1, unused */
82027b27ec6Sopenharmony_ci        { lz4hc,     2, 16 },  /* 2, unused */
82127b27ec6Sopenharmony_ci        { lz4hc,     4, 16 },  /* 3 */
82227b27ec6Sopenharmony_ci        { lz4hc,     8, 16 },  /* 4 */
82327b27ec6Sopenharmony_ci        { lz4hc,    16, 16 },  /* 5 */
82427b27ec6Sopenharmony_ci        { lz4hc,    32, 16 },  /* 6 */
82527b27ec6Sopenharmony_ci        { lz4hc,    64, 16 },  /* 7 */
82627b27ec6Sopenharmony_ci        { lz4hc,   128, 16 },  /* 8 */
82727b27ec6Sopenharmony_ci        { lz4hc,   256, 16 },  /* 9 */
82827b27ec6Sopenharmony_ci        { lz4opt,   96, 64 },  /*10==LZ4HC_CLEVEL_OPT_MIN*/
82927b27ec6Sopenharmony_ci        { lz4opt,  512,128 },  /*11 */
83027b27ec6Sopenharmony_ci        { lz4opt,16384,LZ4_OPT_NUM },  /* 12==LZ4HC_CLEVEL_MAX */
83127b27ec6Sopenharmony_ci    };
83227b27ec6Sopenharmony_ci
83327b27ec6Sopenharmony_ci    DEBUGLOG(4, "LZ4HC_compress_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)",
83427b27ec6Sopenharmony_ci                ctx, src, *srcSizePtr, limit);
83527b27ec6Sopenharmony_ci
83627b27ec6Sopenharmony_ci    if (limit == fillOutput && dstCapacity < 1) return 0;   /* Impossible to store anything */
83727b27ec6Sopenharmony_ci    if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0;    /* Unsupported input size (too large or negative) */
83827b27ec6Sopenharmony_ci
83927b27ec6Sopenharmony_ci    ctx->end += *srcSizePtr;
84027b27ec6Sopenharmony_ci    if (cLevel < 1) cLevel = LZ4HC_CLEVEL_DEFAULT;   /* note : convention is different from lz4frame, maybe something to review */
84127b27ec6Sopenharmony_ci    cLevel = MIN(LZ4HC_CLEVEL_MAX, cLevel);
84227b27ec6Sopenharmony_ci    {   cParams_t const cParam = clTable[cLevel];
84327b27ec6Sopenharmony_ci        HCfavor_e const favor = ctx->favorDecSpeed ? favorDecompressionSpeed : favorCompressionRatio;
84427b27ec6Sopenharmony_ci        int result;
84527b27ec6Sopenharmony_ci
84627b27ec6Sopenharmony_ci        if (cParam.strat == lz4hc) {
84727b27ec6Sopenharmony_ci            result = LZ4HC_compress_hashChain(ctx,
84827b27ec6Sopenharmony_ci                                src, dst, srcSizePtr, dstCapacity,
84927b27ec6Sopenharmony_ci                                cParam.nbSearches, limit, dict);
85027b27ec6Sopenharmony_ci        } else {
85127b27ec6Sopenharmony_ci            assert(cParam.strat == lz4opt);
85227b27ec6Sopenharmony_ci            result = LZ4HC_compress_optimal(ctx,
85327b27ec6Sopenharmony_ci                                src, dst, srcSizePtr, dstCapacity,
85427b27ec6Sopenharmony_ci                                cParam.nbSearches, cParam.targetLength, limit,
85527b27ec6Sopenharmony_ci                                cLevel == LZ4HC_CLEVEL_MAX,   /* ultra mode */
85627b27ec6Sopenharmony_ci                                dict, favor);
85727b27ec6Sopenharmony_ci        }
85827b27ec6Sopenharmony_ci        if (result <= 0) ctx->dirty = 1;
85927b27ec6Sopenharmony_ci        return result;
86027b27ec6Sopenharmony_ci    }
86127b27ec6Sopenharmony_ci}
86227b27ec6Sopenharmony_ci
86327b27ec6Sopenharmony_cistatic void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock);
86427b27ec6Sopenharmony_ci
86527b27ec6Sopenharmony_cistatic int
86627b27ec6Sopenharmony_ciLZ4HC_compress_generic_noDictCtx (
86727b27ec6Sopenharmony_ci        LZ4HC_CCtx_internal* const ctx,
86827b27ec6Sopenharmony_ci        const char* const src,
86927b27ec6Sopenharmony_ci        char* const dst,
87027b27ec6Sopenharmony_ci        int* const srcSizePtr,
87127b27ec6Sopenharmony_ci        int const dstCapacity,
87227b27ec6Sopenharmony_ci        int cLevel,
87327b27ec6Sopenharmony_ci        limitedOutput_directive limit
87427b27ec6Sopenharmony_ci        )
87527b27ec6Sopenharmony_ci{
87627b27ec6Sopenharmony_ci    assert(ctx->dictCtx == NULL);
87727b27ec6Sopenharmony_ci    return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, noDictCtx);
87827b27ec6Sopenharmony_ci}
87927b27ec6Sopenharmony_ci
88027b27ec6Sopenharmony_cistatic int
88127b27ec6Sopenharmony_ciLZ4HC_compress_generic_dictCtx (
88227b27ec6Sopenharmony_ci        LZ4HC_CCtx_internal* const ctx,
88327b27ec6Sopenharmony_ci        const char* const src,
88427b27ec6Sopenharmony_ci        char* const dst,
88527b27ec6Sopenharmony_ci        int* const srcSizePtr,
88627b27ec6Sopenharmony_ci        int const dstCapacity,
88727b27ec6Sopenharmony_ci        int cLevel,
88827b27ec6Sopenharmony_ci        limitedOutput_directive limit
88927b27ec6Sopenharmony_ci        )
89027b27ec6Sopenharmony_ci{
89127b27ec6Sopenharmony_ci    const size_t position = (size_t)(ctx->end - ctx->prefixStart) + (ctx->dictLimit - ctx->lowLimit);
89227b27ec6Sopenharmony_ci    assert(ctx->dictCtx != NULL);
89327b27ec6Sopenharmony_ci    if (position >= 64 KB) {
89427b27ec6Sopenharmony_ci        ctx->dictCtx = NULL;
89527b27ec6Sopenharmony_ci        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
89627b27ec6Sopenharmony_ci    } else if (position == 0 && *srcSizePtr > 4 KB) {
89727b27ec6Sopenharmony_ci        LZ4_memcpy(ctx, ctx->dictCtx, sizeof(LZ4HC_CCtx_internal));
89827b27ec6Sopenharmony_ci        LZ4HC_setExternalDict(ctx, (const BYTE *)src);
89927b27ec6Sopenharmony_ci        ctx->compressionLevel = (short)cLevel;
90027b27ec6Sopenharmony_ci        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
90127b27ec6Sopenharmony_ci    } else {
90227b27ec6Sopenharmony_ci        return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, usingDictCtxHc);
90327b27ec6Sopenharmony_ci    }
90427b27ec6Sopenharmony_ci}
90527b27ec6Sopenharmony_ci
90627b27ec6Sopenharmony_cistatic int
90727b27ec6Sopenharmony_ciLZ4HC_compress_generic (
90827b27ec6Sopenharmony_ci        LZ4HC_CCtx_internal* const ctx,
90927b27ec6Sopenharmony_ci        const char* const src,
91027b27ec6Sopenharmony_ci        char* const dst,
91127b27ec6Sopenharmony_ci        int* const srcSizePtr,
91227b27ec6Sopenharmony_ci        int const dstCapacity,
91327b27ec6Sopenharmony_ci        int cLevel,
91427b27ec6Sopenharmony_ci        limitedOutput_directive limit
91527b27ec6Sopenharmony_ci        )
91627b27ec6Sopenharmony_ci{
91727b27ec6Sopenharmony_ci    if (ctx->dictCtx == NULL) {
91827b27ec6Sopenharmony_ci        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
91927b27ec6Sopenharmony_ci    } else {
92027b27ec6Sopenharmony_ci        return LZ4HC_compress_generic_dictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
92127b27ec6Sopenharmony_ci    }
92227b27ec6Sopenharmony_ci}
92327b27ec6Sopenharmony_ci
92427b27ec6Sopenharmony_ci
92527b27ec6Sopenharmony_ciint LZ4_sizeofStateHC(void) { return (int)sizeof(LZ4_streamHC_t); }
92627b27ec6Sopenharmony_ci
92727b27ec6Sopenharmony_cistatic size_t LZ4_streamHC_t_alignment(void)
92827b27ec6Sopenharmony_ci{
92927b27ec6Sopenharmony_ci#if LZ4_ALIGN_TEST
93027b27ec6Sopenharmony_ci    typedef struct { char c; LZ4_streamHC_t t; } t_a;
93127b27ec6Sopenharmony_ci    return sizeof(t_a) - sizeof(LZ4_streamHC_t);
93227b27ec6Sopenharmony_ci#else
93327b27ec6Sopenharmony_ci    return 1;  /* effectively disabled */
93427b27ec6Sopenharmony_ci#endif
93527b27ec6Sopenharmony_ci}
93627b27ec6Sopenharmony_ci
93727b27ec6Sopenharmony_ci/* state is presumed correctly initialized,
93827b27ec6Sopenharmony_ci * in which case its size and alignment have already been validate */
93927b27ec6Sopenharmony_ciint LZ4_compress_HC_extStateHC_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
94027b27ec6Sopenharmony_ci{
94127b27ec6Sopenharmony_ci    LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse;
94227b27ec6Sopenharmony_ci    if (!LZ4_isAligned(state, LZ4_streamHC_t_alignment())) return 0;
94327b27ec6Sopenharmony_ci    LZ4_resetStreamHC_fast((LZ4_streamHC_t*)state, compressionLevel);
94427b27ec6Sopenharmony_ci    LZ4HC_init_internal (ctx, (const BYTE*)src);
94527b27ec6Sopenharmony_ci    if (dstCapacity < LZ4_compressBound(srcSize))
94627b27ec6Sopenharmony_ci        return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, limitedOutput);
94727b27ec6Sopenharmony_ci    else
94827b27ec6Sopenharmony_ci        return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, notLimited);
94927b27ec6Sopenharmony_ci}
95027b27ec6Sopenharmony_ci
95127b27ec6Sopenharmony_ciint LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
95227b27ec6Sopenharmony_ci{
95327b27ec6Sopenharmony_ci    LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));
95427b27ec6Sopenharmony_ci    if (ctx==NULL) return 0;   /* init failure */
95527b27ec6Sopenharmony_ci    return LZ4_compress_HC_extStateHC_fastReset(state, src, dst, srcSize, dstCapacity, compressionLevel);
95627b27ec6Sopenharmony_ci}
95727b27ec6Sopenharmony_ci
95827b27ec6Sopenharmony_ciint LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
95927b27ec6Sopenharmony_ci{
96027b27ec6Sopenharmony_ci    int cSize;
96127b27ec6Sopenharmony_ci#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
96227b27ec6Sopenharmony_ci    LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));
96327b27ec6Sopenharmony_ci    if (statePtr==NULL) return 0;
96427b27ec6Sopenharmony_ci#else
96527b27ec6Sopenharmony_ci    LZ4_streamHC_t state;
96627b27ec6Sopenharmony_ci    LZ4_streamHC_t* const statePtr = &state;
96727b27ec6Sopenharmony_ci#endif
96827b27ec6Sopenharmony_ci    cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel);
96927b27ec6Sopenharmony_ci#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
97027b27ec6Sopenharmony_ci    FREEMEM(statePtr);
97127b27ec6Sopenharmony_ci#endif
97227b27ec6Sopenharmony_ci    return cSize;
97327b27ec6Sopenharmony_ci}
97427b27ec6Sopenharmony_ci
97527b27ec6Sopenharmony_ci/* state is presumed sized correctly (>= sizeof(LZ4_streamHC_t)) */
97627b27ec6Sopenharmony_ciint LZ4_compress_HC_destSize(void* state, const char* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel)
97727b27ec6Sopenharmony_ci{
97827b27ec6Sopenharmony_ci    LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));
97927b27ec6Sopenharmony_ci    if (ctx==NULL) return 0;   /* init failure */
98027b27ec6Sopenharmony_ci    LZ4HC_init_internal(&ctx->internal_donotuse, (const BYTE*) source);
98127b27ec6Sopenharmony_ci    LZ4_setCompressionLevel(ctx, cLevel);
98227b27ec6Sopenharmony_ci    return LZ4HC_compress_generic(&ctx->internal_donotuse, source, dest, sourceSizePtr, targetDestSize, cLevel, fillOutput);
98327b27ec6Sopenharmony_ci}
98427b27ec6Sopenharmony_ci
98527b27ec6Sopenharmony_ci
98627b27ec6Sopenharmony_ci
98727b27ec6Sopenharmony_ci/**************************************
98827b27ec6Sopenharmony_ci*  Streaming Functions
98927b27ec6Sopenharmony_ci**************************************/
99027b27ec6Sopenharmony_ci/* allocation */
99127b27ec6Sopenharmony_ci#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)
99227b27ec6Sopenharmony_ciLZ4_streamHC_t* LZ4_createStreamHC(void)
99327b27ec6Sopenharmony_ci{
99427b27ec6Sopenharmony_ci    LZ4_streamHC_t* const state =
99527b27ec6Sopenharmony_ci        (LZ4_streamHC_t*)ALLOC_AND_ZERO(sizeof(LZ4_streamHC_t));
99627b27ec6Sopenharmony_ci    if (state == NULL) return NULL;
99727b27ec6Sopenharmony_ci    LZ4_setCompressionLevel(state, LZ4HC_CLEVEL_DEFAULT);
99827b27ec6Sopenharmony_ci    return state;
99927b27ec6Sopenharmony_ci}
100027b27ec6Sopenharmony_ci
100127b27ec6Sopenharmony_ciint LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr)
100227b27ec6Sopenharmony_ci{
100327b27ec6Sopenharmony_ci    DEBUGLOG(4, "LZ4_freeStreamHC(%p)", LZ4_streamHCPtr);
100427b27ec6Sopenharmony_ci    if (!LZ4_streamHCPtr) return 0;  /* support free on NULL */
100527b27ec6Sopenharmony_ci    FREEMEM(LZ4_streamHCPtr);
100627b27ec6Sopenharmony_ci    return 0;
100727b27ec6Sopenharmony_ci}
100827b27ec6Sopenharmony_ci#endif
100927b27ec6Sopenharmony_ci
101027b27ec6Sopenharmony_ci
101127b27ec6Sopenharmony_ciLZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size)
101227b27ec6Sopenharmony_ci{
101327b27ec6Sopenharmony_ci    LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)buffer;
101427b27ec6Sopenharmony_ci    DEBUGLOG(4, "LZ4_initStreamHC(%p, %u)", buffer, (unsigned)size);
101527b27ec6Sopenharmony_ci    /* check conditions */
101627b27ec6Sopenharmony_ci    if (buffer == NULL) return NULL;
101727b27ec6Sopenharmony_ci    if (size < sizeof(LZ4_streamHC_t)) return NULL;
101827b27ec6Sopenharmony_ci    if (!LZ4_isAligned(buffer, LZ4_streamHC_t_alignment())) return NULL;
101927b27ec6Sopenharmony_ci    /* init */
102027b27ec6Sopenharmony_ci    { LZ4HC_CCtx_internal* const hcstate = &(LZ4_streamHCPtr->internal_donotuse);
102127b27ec6Sopenharmony_ci      MEM_INIT(hcstate, 0, sizeof(*hcstate)); }
102227b27ec6Sopenharmony_ci    LZ4_setCompressionLevel(LZ4_streamHCPtr, LZ4HC_CLEVEL_DEFAULT);
102327b27ec6Sopenharmony_ci    return LZ4_streamHCPtr;
102427b27ec6Sopenharmony_ci}
102527b27ec6Sopenharmony_ci
102627b27ec6Sopenharmony_ci/* just a stub */
102727b27ec6Sopenharmony_civoid LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
102827b27ec6Sopenharmony_ci{
102927b27ec6Sopenharmony_ci    LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
103027b27ec6Sopenharmony_ci    LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);
103127b27ec6Sopenharmony_ci}
103227b27ec6Sopenharmony_ci
103327b27ec6Sopenharmony_civoid LZ4_resetStreamHC_fast (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
103427b27ec6Sopenharmony_ci{
103527b27ec6Sopenharmony_ci    DEBUGLOG(4, "LZ4_resetStreamHC_fast(%p, %d)", LZ4_streamHCPtr, compressionLevel);
103627b27ec6Sopenharmony_ci    if (LZ4_streamHCPtr->internal_donotuse.dirty) {
103727b27ec6Sopenharmony_ci        LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
103827b27ec6Sopenharmony_ci    } else {
103927b27ec6Sopenharmony_ci        /* preserve end - prefixStart : can trigger clearTable's threshold */
104027b27ec6Sopenharmony_ci        if (LZ4_streamHCPtr->internal_donotuse.end != NULL) {
104127b27ec6Sopenharmony_ci            LZ4_streamHCPtr->internal_donotuse.end -= (uptrval)LZ4_streamHCPtr->internal_donotuse.prefixStart;
104227b27ec6Sopenharmony_ci        } else {
104327b27ec6Sopenharmony_ci            assert(LZ4_streamHCPtr->internal_donotuse.prefixStart == NULL);
104427b27ec6Sopenharmony_ci        }
104527b27ec6Sopenharmony_ci        LZ4_streamHCPtr->internal_donotuse.prefixStart = NULL;
104627b27ec6Sopenharmony_ci        LZ4_streamHCPtr->internal_donotuse.dictCtx = NULL;
104727b27ec6Sopenharmony_ci    }
104827b27ec6Sopenharmony_ci    LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);
104927b27ec6Sopenharmony_ci}
105027b27ec6Sopenharmony_ci
105127b27ec6Sopenharmony_civoid LZ4_setCompressionLevel(LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
105227b27ec6Sopenharmony_ci{
105327b27ec6Sopenharmony_ci    DEBUGLOG(5, "LZ4_setCompressionLevel(%p, %d)", LZ4_streamHCPtr, compressionLevel);
105427b27ec6Sopenharmony_ci    if (compressionLevel < 1) compressionLevel = LZ4HC_CLEVEL_DEFAULT;
105527b27ec6Sopenharmony_ci    if (compressionLevel > LZ4HC_CLEVEL_MAX) compressionLevel = LZ4HC_CLEVEL_MAX;
105627b27ec6Sopenharmony_ci    LZ4_streamHCPtr->internal_donotuse.compressionLevel = (short)compressionLevel;
105727b27ec6Sopenharmony_ci}
105827b27ec6Sopenharmony_ci
105927b27ec6Sopenharmony_civoid LZ4_favorDecompressionSpeed(LZ4_streamHC_t* LZ4_streamHCPtr, int favor)
106027b27ec6Sopenharmony_ci{
106127b27ec6Sopenharmony_ci    LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = (favor!=0);
106227b27ec6Sopenharmony_ci}
106327b27ec6Sopenharmony_ci
106427b27ec6Sopenharmony_ci/* LZ4_loadDictHC() :
106527b27ec6Sopenharmony_ci * LZ4_streamHCPtr is presumed properly initialized */
106627b27ec6Sopenharmony_ciint LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr,
106727b27ec6Sopenharmony_ci              const char* dictionary, int dictSize)
106827b27ec6Sopenharmony_ci{
106927b27ec6Sopenharmony_ci    LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
107027b27ec6Sopenharmony_ci    DEBUGLOG(4, "LZ4_loadDictHC(ctx:%p, dict:%p, dictSize:%d)", LZ4_streamHCPtr, dictionary, dictSize);
107127b27ec6Sopenharmony_ci    assert(LZ4_streamHCPtr != NULL);
107227b27ec6Sopenharmony_ci    if (dictSize > 64 KB) {
107327b27ec6Sopenharmony_ci        dictionary += (size_t)dictSize - 64 KB;
107427b27ec6Sopenharmony_ci        dictSize = 64 KB;
107527b27ec6Sopenharmony_ci    }
107627b27ec6Sopenharmony_ci    /* need a full initialization, there are bad side-effects when using resetFast() */
107727b27ec6Sopenharmony_ci    {   int const cLevel = ctxPtr->compressionLevel;
107827b27ec6Sopenharmony_ci        LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
107927b27ec6Sopenharmony_ci        LZ4_setCompressionLevel(LZ4_streamHCPtr, cLevel);
108027b27ec6Sopenharmony_ci    }
108127b27ec6Sopenharmony_ci    LZ4HC_init_internal (ctxPtr, (const BYTE*)dictionary);
108227b27ec6Sopenharmony_ci    ctxPtr->end = (const BYTE*)dictionary + dictSize;
108327b27ec6Sopenharmony_ci    if (dictSize >= 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3);
108427b27ec6Sopenharmony_ci    return dictSize;
108527b27ec6Sopenharmony_ci}
108627b27ec6Sopenharmony_ci
108727b27ec6Sopenharmony_civoid LZ4_attach_HC_dictionary(LZ4_streamHC_t *working_stream, const LZ4_streamHC_t *dictionary_stream) {
108827b27ec6Sopenharmony_ci    working_stream->internal_donotuse.dictCtx = dictionary_stream != NULL ? &(dictionary_stream->internal_donotuse) : NULL;
108927b27ec6Sopenharmony_ci}
109027b27ec6Sopenharmony_ci
109127b27ec6Sopenharmony_ci/* compression */
109227b27ec6Sopenharmony_ci
109327b27ec6Sopenharmony_cistatic void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock)
109427b27ec6Sopenharmony_ci{
109527b27ec6Sopenharmony_ci    DEBUGLOG(4, "LZ4HC_setExternalDict(%p, %p)", ctxPtr, newBlock);
109627b27ec6Sopenharmony_ci    if (ctxPtr->end >= ctxPtr->prefixStart + 4)
109727b27ec6Sopenharmony_ci        LZ4HC_Insert (ctxPtr, ctxPtr->end-3);   /* Referencing remaining dictionary content */
109827b27ec6Sopenharmony_ci
109927b27ec6Sopenharmony_ci    /* Only one memory segment for extDict, so any previous extDict is lost at this stage */
110027b27ec6Sopenharmony_ci    ctxPtr->lowLimit  = ctxPtr->dictLimit;
110127b27ec6Sopenharmony_ci    ctxPtr->dictStart  = ctxPtr->prefixStart;
110227b27ec6Sopenharmony_ci    ctxPtr->dictLimit += (U32)(ctxPtr->end - ctxPtr->prefixStart);
110327b27ec6Sopenharmony_ci    ctxPtr->prefixStart = newBlock;
110427b27ec6Sopenharmony_ci    ctxPtr->end  = newBlock;
110527b27ec6Sopenharmony_ci    ctxPtr->nextToUpdate = ctxPtr->dictLimit;   /* match referencing will resume from there */
110627b27ec6Sopenharmony_ci
110727b27ec6Sopenharmony_ci    /* cannot reference an extDict and a dictCtx at the same time */
110827b27ec6Sopenharmony_ci    ctxPtr->dictCtx = NULL;
110927b27ec6Sopenharmony_ci}
111027b27ec6Sopenharmony_ci
111127b27ec6Sopenharmony_cistatic int
111227b27ec6Sopenharmony_ciLZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,
111327b27ec6Sopenharmony_ci                                 const char* src, char* dst,
111427b27ec6Sopenharmony_ci                                 int* srcSizePtr, int dstCapacity,
111527b27ec6Sopenharmony_ci                                 limitedOutput_directive limit)
111627b27ec6Sopenharmony_ci{
111727b27ec6Sopenharmony_ci    LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
111827b27ec6Sopenharmony_ci    DEBUGLOG(5, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)",
111927b27ec6Sopenharmony_ci                LZ4_streamHCPtr, src, *srcSizePtr, limit);
112027b27ec6Sopenharmony_ci    assert(ctxPtr != NULL);
112127b27ec6Sopenharmony_ci    /* auto-init if forgotten */
112227b27ec6Sopenharmony_ci    if (ctxPtr->prefixStart == NULL) LZ4HC_init_internal (ctxPtr, (const BYTE*) src);
112327b27ec6Sopenharmony_ci
112427b27ec6Sopenharmony_ci    /* Check overflow */
112527b27ec6Sopenharmony_ci    if ((size_t)(ctxPtr->end - ctxPtr->prefixStart) + ctxPtr->dictLimit > 2 GB) {
112627b27ec6Sopenharmony_ci        size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->prefixStart);
112727b27ec6Sopenharmony_ci        if (dictSize > 64 KB) dictSize = 64 KB;
112827b27ec6Sopenharmony_ci        LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize);
112927b27ec6Sopenharmony_ci    }
113027b27ec6Sopenharmony_ci
113127b27ec6Sopenharmony_ci    /* Check if blocks follow each other */
113227b27ec6Sopenharmony_ci    if ((const BYTE*)src != ctxPtr->end)
113327b27ec6Sopenharmony_ci        LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src);
113427b27ec6Sopenharmony_ci
113527b27ec6Sopenharmony_ci    /* Check overlapping input/dictionary space */
113627b27ec6Sopenharmony_ci    {   const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr;
113727b27ec6Sopenharmony_ci        const BYTE* const dictBegin = ctxPtr->dictStart;
113827b27ec6Sopenharmony_ci        const BYTE* const dictEnd   = ctxPtr->dictStart + (ctxPtr->dictLimit - ctxPtr->lowLimit);
113927b27ec6Sopenharmony_ci        if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) {
114027b27ec6Sopenharmony_ci            if (sourceEnd > dictEnd) sourceEnd = dictEnd;
114127b27ec6Sopenharmony_ci            ctxPtr->lowLimit += (U32)(sourceEnd - ctxPtr->dictStart);
114227b27ec6Sopenharmony_ci            ctxPtr->dictStart += (U32)(sourceEnd - ctxPtr->dictStart);
114327b27ec6Sopenharmony_ci            if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) {
114427b27ec6Sopenharmony_ci                ctxPtr->lowLimit = ctxPtr->dictLimit;
114527b27ec6Sopenharmony_ci                ctxPtr->dictStart = ctxPtr->prefixStart;
114627b27ec6Sopenharmony_ci    }   }   }
114727b27ec6Sopenharmony_ci
114827b27ec6Sopenharmony_ci    return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit);
114927b27ec6Sopenharmony_ci}
115027b27ec6Sopenharmony_ci
115127b27ec6Sopenharmony_ciint LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int srcSize, int dstCapacity)
115227b27ec6Sopenharmony_ci{
115327b27ec6Sopenharmony_ci    if (dstCapacity < LZ4_compressBound(srcSize))
115427b27ec6Sopenharmony_ci        return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput);
115527b27ec6Sopenharmony_ci    else
115627b27ec6Sopenharmony_ci        return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, notLimited);
115727b27ec6Sopenharmony_ci}
115827b27ec6Sopenharmony_ci
115927b27ec6Sopenharmony_ciint LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int targetDestSize)
116027b27ec6Sopenharmony_ci{
116127b27ec6Sopenharmony_ci    return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, fillOutput);
116227b27ec6Sopenharmony_ci}
116327b27ec6Sopenharmony_ci
116427b27ec6Sopenharmony_ci
116527b27ec6Sopenharmony_ci
116627b27ec6Sopenharmony_ci/* LZ4_saveDictHC :
116727b27ec6Sopenharmony_ci * save history content
116827b27ec6Sopenharmony_ci * into a user-provided buffer
116927b27ec6Sopenharmony_ci * which is then used to continue compression
117027b27ec6Sopenharmony_ci */
117127b27ec6Sopenharmony_ciint LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)
117227b27ec6Sopenharmony_ci{
117327b27ec6Sopenharmony_ci    LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse;
117427b27ec6Sopenharmony_ci    int const prefixSize = (int)(streamPtr->end - streamPtr->prefixStart);
117527b27ec6Sopenharmony_ci    DEBUGLOG(5, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize);
117627b27ec6Sopenharmony_ci    assert(prefixSize >= 0);
117727b27ec6Sopenharmony_ci    if (dictSize > 64 KB) dictSize = 64 KB;
117827b27ec6Sopenharmony_ci    if (dictSize < 4) dictSize = 0;
117927b27ec6Sopenharmony_ci    if (dictSize > prefixSize) dictSize = prefixSize;
118027b27ec6Sopenharmony_ci    if (safeBuffer == NULL) assert(dictSize == 0);
118127b27ec6Sopenharmony_ci    if (dictSize > 0)
118227b27ec6Sopenharmony_ci        LZ4_memmove(safeBuffer, streamPtr->end - dictSize, dictSize);
118327b27ec6Sopenharmony_ci    {   U32 const endIndex = (U32)(streamPtr->end - streamPtr->prefixStart) + streamPtr->dictLimit;
118427b27ec6Sopenharmony_ci        streamPtr->end = (const BYTE*)safeBuffer + dictSize;
118527b27ec6Sopenharmony_ci        streamPtr->prefixStart = streamPtr->end - dictSize;
118627b27ec6Sopenharmony_ci        streamPtr->dictLimit = endIndex - (U32)dictSize;
118727b27ec6Sopenharmony_ci        streamPtr->lowLimit = endIndex - (U32)dictSize;
118827b27ec6Sopenharmony_ci        streamPtr->dictStart = streamPtr->prefixStart;
118927b27ec6Sopenharmony_ci        if (streamPtr->nextToUpdate < streamPtr->dictLimit)
119027b27ec6Sopenharmony_ci            streamPtr->nextToUpdate = streamPtr->dictLimit;
119127b27ec6Sopenharmony_ci    }
119227b27ec6Sopenharmony_ci    return dictSize;
119327b27ec6Sopenharmony_ci}
119427b27ec6Sopenharmony_ci
119527b27ec6Sopenharmony_ci
119627b27ec6Sopenharmony_ci/***************************************************
119727b27ec6Sopenharmony_ci*  Deprecated Functions
119827b27ec6Sopenharmony_ci***************************************************/
119927b27ec6Sopenharmony_ci
120027b27ec6Sopenharmony_ci/* These functions currently generate deprecation warnings */
120127b27ec6Sopenharmony_ci
120227b27ec6Sopenharmony_ci/* Wrappers for deprecated compression functions */
120327b27ec6Sopenharmony_ciint LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
120427b27ec6Sopenharmony_ciint LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); }
120527b27ec6Sopenharmony_ciint LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
120627b27ec6Sopenharmony_ciint LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); }
120727b27ec6Sopenharmony_ciint 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); }
120827b27ec6Sopenharmony_ciint 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); }
120927b27ec6Sopenharmony_ciint 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); }
121027b27ec6Sopenharmony_ciint 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); }
121127b27ec6Sopenharmony_ciint 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)); }
121227b27ec6Sopenharmony_ciint 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); }
121327b27ec6Sopenharmony_ci
121427b27ec6Sopenharmony_ci
121527b27ec6Sopenharmony_ci/* Deprecated streaming functions */
121627b27ec6Sopenharmony_ciint LZ4_sizeofStreamStateHC(void) { return sizeof(LZ4_streamHC_t); }
121727b27ec6Sopenharmony_ci
121827b27ec6Sopenharmony_ci/* state is presumed correctly sized, aka >= sizeof(LZ4_streamHC_t)
121927b27ec6Sopenharmony_ci * @return : 0 on success, !=0 if error */
122027b27ec6Sopenharmony_ciint LZ4_resetStreamStateHC(void* state, char* inputBuffer)
122127b27ec6Sopenharmony_ci{
122227b27ec6Sopenharmony_ci    LZ4_streamHC_t* const hc4 = LZ4_initStreamHC(state, sizeof(*hc4));
122327b27ec6Sopenharmony_ci    if (hc4 == NULL) return 1;   /* init failed */
122427b27ec6Sopenharmony_ci    LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
122527b27ec6Sopenharmony_ci    return 0;
122627b27ec6Sopenharmony_ci}
122727b27ec6Sopenharmony_ci
122827b27ec6Sopenharmony_ci#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)
122927b27ec6Sopenharmony_civoid* LZ4_createHC (const char* inputBuffer)
123027b27ec6Sopenharmony_ci{
123127b27ec6Sopenharmony_ci    LZ4_streamHC_t* const hc4 = LZ4_createStreamHC();
123227b27ec6Sopenharmony_ci    if (hc4 == NULL) return NULL;   /* not enough memory */
123327b27ec6Sopenharmony_ci    LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
123427b27ec6Sopenharmony_ci    return hc4;
123527b27ec6Sopenharmony_ci}
123627b27ec6Sopenharmony_ci
123727b27ec6Sopenharmony_ciint LZ4_freeHC (void* LZ4HC_Data)
123827b27ec6Sopenharmony_ci{
123927b27ec6Sopenharmony_ci    if (!LZ4HC_Data) return 0;  /* support free on NULL */
124027b27ec6Sopenharmony_ci    FREEMEM(LZ4HC_Data);
124127b27ec6Sopenharmony_ci    return 0;
124227b27ec6Sopenharmony_ci}
124327b27ec6Sopenharmony_ci#endif
124427b27ec6Sopenharmony_ci
124527b27ec6Sopenharmony_ciint LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)
124627b27ec6Sopenharmony_ci{
124727b27ec6Sopenharmony_ci    return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited);
124827b27ec6Sopenharmony_ci}
124927b27ec6Sopenharmony_ci
125027b27ec6Sopenharmony_ciint LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel)
125127b27ec6Sopenharmony_ci{
125227b27ec6Sopenharmony_ci    return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput);
125327b27ec6Sopenharmony_ci}
125427b27ec6Sopenharmony_ci
125527b27ec6Sopenharmony_cichar* LZ4_slideInputBufferHC(void* LZ4HC_Data)
125627b27ec6Sopenharmony_ci{
125727b27ec6Sopenharmony_ci    LZ4_streamHC_t* const ctx = (LZ4_streamHC_t*)LZ4HC_Data;
125827b27ec6Sopenharmony_ci    const BYTE* bufferStart = ctx->internal_donotuse.prefixStart - ctx->internal_donotuse.dictLimit + ctx->internal_donotuse.lowLimit;
125927b27ec6Sopenharmony_ci    LZ4_resetStreamHC_fast(ctx, ctx->internal_donotuse.compressionLevel);
126027b27ec6Sopenharmony_ci    /* avoid const char * -> char * conversion warning :( */
126127b27ec6Sopenharmony_ci    return (char*)(uptrval)bufferStart;
126227b27ec6Sopenharmony_ci}
126327b27ec6Sopenharmony_ci
126427b27ec6Sopenharmony_ci
126527b27ec6Sopenharmony_ci/* ================================================
126627b27ec6Sopenharmony_ci *  LZ4 Optimal parser (levels [LZ4HC_CLEVEL_OPT_MIN - LZ4HC_CLEVEL_MAX])
126727b27ec6Sopenharmony_ci * ===============================================*/
126827b27ec6Sopenharmony_citypedef struct {
126927b27ec6Sopenharmony_ci    int price;
127027b27ec6Sopenharmony_ci    int off;
127127b27ec6Sopenharmony_ci    int mlen;
127227b27ec6Sopenharmony_ci    int litlen;
127327b27ec6Sopenharmony_ci} LZ4HC_optimal_t;
127427b27ec6Sopenharmony_ci
127527b27ec6Sopenharmony_ci/* price in bytes */
127627b27ec6Sopenharmony_ciLZ4_FORCE_INLINE int LZ4HC_literalsPrice(int const litlen)
127727b27ec6Sopenharmony_ci{
127827b27ec6Sopenharmony_ci    int price = litlen;
127927b27ec6Sopenharmony_ci    assert(litlen >= 0);
128027b27ec6Sopenharmony_ci    if (litlen >= (int)RUN_MASK)
128127b27ec6Sopenharmony_ci        price += 1 + ((litlen-(int)RUN_MASK) / 255);
128227b27ec6Sopenharmony_ci    return price;
128327b27ec6Sopenharmony_ci}
128427b27ec6Sopenharmony_ci
128527b27ec6Sopenharmony_ci
128627b27ec6Sopenharmony_ci/* requires mlen >= MINMATCH */
128727b27ec6Sopenharmony_ciLZ4_FORCE_INLINE int LZ4HC_sequencePrice(int litlen, int mlen)
128827b27ec6Sopenharmony_ci{
128927b27ec6Sopenharmony_ci    int price = 1 + 2 ; /* token + 16-bit offset */
129027b27ec6Sopenharmony_ci    assert(litlen >= 0);
129127b27ec6Sopenharmony_ci    assert(mlen >= MINMATCH);
129227b27ec6Sopenharmony_ci
129327b27ec6Sopenharmony_ci    price += LZ4HC_literalsPrice(litlen);
129427b27ec6Sopenharmony_ci
129527b27ec6Sopenharmony_ci    if (mlen >= (int)(ML_MASK+MINMATCH))
129627b27ec6Sopenharmony_ci        price += 1 + ((mlen-(int)(ML_MASK+MINMATCH)) / 255);
129727b27ec6Sopenharmony_ci
129827b27ec6Sopenharmony_ci    return price;
129927b27ec6Sopenharmony_ci}
130027b27ec6Sopenharmony_ci
130127b27ec6Sopenharmony_ci
130227b27ec6Sopenharmony_citypedef struct {
130327b27ec6Sopenharmony_ci    int off;
130427b27ec6Sopenharmony_ci    int len;
130527b27ec6Sopenharmony_ci} LZ4HC_match_t;
130627b27ec6Sopenharmony_ci
130727b27ec6Sopenharmony_ciLZ4_FORCE_INLINE LZ4HC_match_t
130827b27ec6Sopenharmony_ciLZ4HC_FindLongerMatch(LZ4HC_CCtx_internal* const ctx,
130927b27ec6Sopenharmony_ci                      const BYTE* ip, const BYTE* const iHighLimit,
131027b27ec6Sopenharmony_ci                      int minLen, int nbSearches,
131127b27ec6Sopenharmony_ci                      const dictCtx_directive dict,
131227b27ec6Sopenharmony_ci                      const HCfavor_e favorDecSpeed)
131327b27ec6Sopenharmony_ci{
131427b27ec6Sopenharmony_ci    LZ4HC_match_t match = { 0 , 0 };
131527b27ec6Sopenharmony_ci    const BYTE* matchPtr = NULL;
131627b27ec6Sopenharmony_ci    /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),
131727b27ec6Sopenharmony_ci     * but this won't be the case here, as we define iLowLimit==ip,
131827b27ec6Sopenharmony_ci     * so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */
131927b27ec6Sopenharmony_ci    int matchLength = LZ4HC_InsertAndGetWiderMatch(ctx, ip, ip, iHighLimit, minLen, &matchPtr, &ip, nbSearches, 1 /*patternAnalysis*/, 1 /*chainSwap*/, dict, favorDecSpeed);
132027b27ec6Sopenharmony_ci    if (matchLength <= minLen) return match;
132127b27ec6Sopenharmony_ci    if (favorDecSpeed) {
132227b27ec6Sopenharmony_ci        if ((matchLength>18) & (matchLength<=36)) matchLength=18;   /* favor shortcut */
132327b27ec6Sopenharmony_ci    }
132427b27ec6Sopenharmony_ci    match.len = matchLength;
132527b27ec6Sopenharmony_ci    match.off = (int)(ip-matchPtr);
132627b27ec6Sopenharmony_ci    return match;
132727b27ec6Sopenharmony_ci}
132827b27ec6Sopenharmony_ci
132927b27ec6Sopenharmony_ci
133027b27ec6Sopenharmony_cistatic int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,
133127b27ec6Sopenharmony_ci                                    const char* const source,
133227b27ec6Sopenharmony_ci                                    char* dst,
133327b27ec6Sopenharmony_ci                                    int* srcSizePtr,
133427b27ec6Sopenharmony_ci                                    int dstCapacity,
133527b27ec6Sopenharmony_ci                                    int const nbSearches,
133627b27ec6Sopenharmony_ci                                    size_t sufficient_len,
133727b27ec6Sopenharmony_ci                                    const limitedOutput_directive limit,
133827b27ec6Sopenharmony_ci                                    int const fullUpdate,
133927b27ec6Sopenharmony_ci                                    const dictCtx_directive dict,
134027b27ec6Sopenharmony_ci                                    const HCfavor_e favorDecSpeed)
134127b27ec6Sopenharmony_ci{
134227b27ec6Sopenharmony_ci    int retval = 0;
134327b27ec6Sopenharmony_ci#define TRAILING_LITERALS 3
134427b27ec6Sopenharmony_ci#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
134527b27ec6Sopenharmony_ci    LZ4HC_optimal_t* const opt = (LZ4HC_optimal_t*)ALLOC(sizeof(LZ4HC_optimal_t) * (LZ4_OPT_NUM + TRAILING_LITERALS));
134627b27ec6Sopenharmony_ci#else
134727b27ec6Sopenharmony_ci    LZ4HC_optimal_t opt[LZ4_OPT_NUM + TRAILING_LITERALS];   /* ~64 KB, which is a bit large for stack... */
134827b27ec6Sopenharmony_ci#endif
134927b27ec6Sopenharmony_ci
135027b27ec6Sopenharmony_ci    const BYTE* ip = (const BYTE*) source;
135127b27ec6Sopenharmony_ci    const BYTE* anchor = ip;
135227b27ec6Sopenharmony_ci    const BYTE* const iend = ip + *srcSizePtr;
135327b27ec6Sopenharmony_ci    const BYTE* const mflimit = iend - MFLIMIT;
135427b27ec6Sopenharmony_ci    const BYTE* const matchlimit = iend - LASTLITERALS;
135527b27ec6Sopenharmony_ci    BYTE* op = (BYTE*) dst;
135627b27ec6Sopenharmony_ci    BYTE* opSaved = (BYTE*) dst;
135727b27ec6Sopenharmony_ci    BYTE* oend = op + dstCapacity;
135827b27ec6Sopenharmony_ci    int ovml = MINMATCH;  /* overflow - last sequence */
135927b27ec6Sopenharmony_ci    const BYTE* ovref = NULL;
136027b27ec6Sopenharmony_ci
136127b27ec6Sopenharmony_ci    /* init */
136227b27ec6Sopenharmony_ci#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
136327b27ec6Sopenharmony_ci    if (opt == NULL) goto _return_label;
136427b27ec6Sopenharmony_ci#endif
136527b27ec6Sopenharmony_ci    DEBUGLOG(5, "LZ4HC_compress_optimal(dst=%p, dstCapa=%u)", dst, (unsigned)dstCapacity);
136627b27ec6Sopenharmony_ci    *srcSizePtr = 0;
136727b27ec6Sopenharmony_ci    if (limit == fillOutput) oend -= LASTLITERALS;   /* Hack for support LZ4 format restriction */
136827b27ec6Sopenharmony_ci    if (sufficient_len >= LZ4_OPT_NUM) sufficient_len = LZ4_OPT_NUM-1;
136927b27ec6Sopenharmony_ci
137027b27ec6Sopenharmony_ci    /* Main Loop */
137127b27ec6Sopenharmony_ci    while (ip <= mflimit) {
137227b27ec6Sopenharmony_ci         int const llen = (int)(ip - anchor);
137327b27ec6Sopenharmony_ci         int best_mlen, best_off;
137427b27ec6Sopenharmony_ci         int cur, last_match_pos = 0;
137527b27ec6Sopenharmony_ci
137627b27ec6Sopenharmony_ci         LZ4HC_match_t const firstMatch = LZ4HC_FindLongerMatch(ctx, ip, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);
137727b27ec6Sopenharmony_ci         if (firstMatch.len==0) { ip++; continue; }
137827b27ec6Sopenharmony_ci
137927b27ec6Sopenharmony_ci         if ((size_t)firstMatch.len > sufficient_len) {
138027b27ec6Sopenharmony_ci             /* good enough solution : immediate encoding */
138127b27ec6Sopenharmony_ci             int const firstML = firstMatch.len;
138227b27ec6Sopenharmony_ci             const BYTE* const matchPos = ip - firstMatch.off;
138327b27ec6Sopenharmony_ci             opSaved = op;
138427b27ec6Sopenharmony_ci             if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, matchPos, limit, oend) ) {  /* updates ip, op and anchor */
138527b27ec6Sopenharmony_ci                 ovml = firstML;
138627b27ec6Sopenharmony_ci                 ovref = matchPos;
138727b27ec6Sopenharmony_ci                 goto _dest_overflow;
138827b27ec6Sopenharmony_ci             }
138927b27ec6Sopenharmony_ci             continue;
139027b27ec6Sopenharmony_ci         }
139127b27ec6Sopenharmony_ci
139227b27ec6Sopenharmony_ci         /* set prices for first positions (literals) */
139327b27ec6Sopenharmony_ci         {   int rPos;
139427b27ec6Sopenharmony_ci             for (rPos = 0 ; rPos < MINMATCH ; rPos++) {
139527b27ec6Sopenharmony_ci                 int const cost = LZ4HC_literalsPrice(llen + rPos);
139627b27ec6Sopenharmony_ci                 opt[rPos].mlen = 1;
139727b27ec6Sopenharmony_ci                 opt[rPos].off = 0;
139827b27ec6Sopenharmony_ci                 opt[rPos].litlen = llen + rPos;
139927b27ec6Sopenharmony_ci                 opt[rPos].price = cost;
140027b27ec6Sopenharmony_ci                 DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup",
140127b27ec6Sopenharmony_ci                             rPos, cost, opt[rPos].litlen);
140227b27ec6Sopenharmony_ci         }   }
140327b27ec6Sopenharmony_ci         /* set prices using initial match */
140427b27ec6Sopenharmony_ci         {   int mlen = MINMATCH;
140527b27ec6Sopenharmony_ci             int const matchML = firstMatch.len;   /* necessarily < sufficient_len < LZ4_OPT_NUM */
140627b27ec6Sopenharmony_ci             int const offset = firstMatch.off;
140727b27ec6Sopenharmony_ci             assert(matchML < LZ4_OPT_NUM);
140827b27ec6Sopenharmony_ci             for ( ; mlen <= matchML ; mlen++) {
140927b27ec6Sopenharmony_ci                 int const cost = LZ4HC_sequencePrice(llen, mlen);
141027b27ec6Sopenharmony_ci                 opt[mlen].mlen = mlen;
141127b27ec6Sopenharmony_ci                 opt[mlen].off = offset;
141227b27ec6Sopenharmony_ci                 opt[mlen].litlen = llen;
141327b27ec6Sopenharmony_ci                 opt[mlen].price = cost;
141427b27ec6Sopenharmony_ci                 DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i) -- initial setup",
141527b27ec6Sopenharmony_ci                             mlen, cost, mlen);
141627b27ec6Sopenharmony_ci         }   }
141727b27ec6Sopenharmony_ci         last_match_pos = firstMatch.len;
141827b27ec6Sopenharmony_ci         {   int addLit;
141927b27ec6Sopenharmony_ci             for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {
142027b27ec6Sopenharmony_ci                 opt[last_match_pos+addLit].mlen = 1; /* literal */
142127b27ec6Sopenharmony_ci                 opt[last_match_pos+addLit].off = 0;
142227b27ec6Sopenharmony_ci                 opt[last_match_pos+addLit].litlen = addLit;
142327b27ec6Sopenharmony_ci                 opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);
142427b27ec6Sopenharmony_ci                 DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup",
142527b27ec6Sopenharmony_ci                             last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);
142627b27ec6Sopenharmony_ci         }   }
142727b27ec6Sopenharmony_ci
142827b27ec6Sopenharmony_ci         /* check further positions */
142927b27ec6Sopenharmony_ci         for (cur = 1; cur < last_match_pos; cur++) {
143027b27ec6Sopenharmony_ci             const BYTE* const curPtr = ip + cur;
143127b27ec6Sopenharmony_ci             LZ4HC_match_t newMatch;
143227b27ec6Sopenharmony_ci
143327b27ec6Sopenharmony_ci             if (curPtr > mflimit) break;
143427b27ec6Sopenharmony_ci             DEBUGLOG(7, "rPos:%u[%u] vs [%u]%u",
143527b27ec6Sopenharmony_ci                     cur, opt[cur].price, opt[cur+1].price, cur+1);
143627b27ec6Sopenharmony_ci             if (fullUpdate) {
143727b27ec6Sopenharmony_ci                 /* not useful to search here if next position has same (or lower) cost */
143827b27ec6Sopenharmony_ci                 if ( (opt[cur+1].price <= opt[cur].price)
143927b27ec6Sopenharmony_ci                   /* in some cases, next position has same cost, but cost rises sharply after, so a small match would still be beneficial */
144027b27ec6Sopenharmony_ci                   && (opt[cur+MINMATCH].price < opt[cur].price + 3/*min seq price*/) )
144127b27ec6Sopenharmony_ci                     continue;
144227b27ec6Sopenharmony_ci             } else {
144327b27ec6Sopenharmony_ci                 /* not useful to search here if next position has same (or lower) cost */
144427b27ec6Sopenharmony_ci                 if (opt[cur+1].price <= opt[cur].price) continue;
144527b27ec6Sopenharmony_ci             }
144627b27ec6Sopenharmony_ci
144727b27ec6Sopenharmony_ci             DEBUGLOG(7, "search at rPos:%u", cur);
144827b27ec6Sopenharmony_ci             if (fullUpdate)
144927b27ec6Sopenharmony_ci                 newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);
145027b27ec6Sopenharmony_ci             else
145127b27ec6Sopenharmony_ci                 /* only test matches of minimum length; slightly faster, but misses a few bytes */
145227b27ec6Sopenharmony_ci                 newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, last_match_pos - cur, nbSearches, dict, favorDecSpeed);
145327b27ec6Sopenharmony_ci             if (!newMatch.len) continue;
145427b27ec6Sopenharmony_ci
145527b27ec6Sopenharmony_ci             if ( ((size_t)newMatch.len > sufficient_len)
145627b27ec6Sopenharmony_ci               || (newMatch.len + cur >= LZ4_OPT_NUM) ) {
145727b27ec6Sopenharmony_ci                 /* immediate encoding */
145827b27ec6Sopenharmony_ci                 best_mlen = newMatch.len;
145927b27ec6Sopenharmony_ci                 best_off = newMatch.off;
146027b27ec6Sopenharmony_ci                 last_match_pos = cur + 1;
146127b27ec6Sopenharmony_ci                 goto encode;
146227b27ec6Sopenharmony_ci             }
146327b27ec6Sopenharmony_ci
146427b27ec6Sopenharmony_ci             /* before match : set price with literals at beginning */
146527b27ec6Sopenharmony_ci             {   int const baseLitlen = opt[cur].litlen;
146627b27ec6Sopenharmony_ci                 int litlen;
146727b27ec6Sopenharmony_ci                 for (litlen = 1; litlen < MINMATCH; litlen++) {
146827b27ec6Sopenharmony_ci                     int const price = opt[cur].price - LZ4HC_literalsPrice(baseLitlen) + LZ4HC_literalsPrice(baseLitlen+litlen);
146927b27ec6Sopenharmony_ci                     int const pos = cur + litlen;
147027b27ec6Sopenharmony_ci                     if (price < opt[pos].price) {
147127b27ec6Sopenharmony_ci                         opt[pos].mlen = 1; /* literal */
147227b27ec6Sopenharmony_ci                         opt[pos].off = 0;
147327b27ec6Sopenharmony_ci                         opt[pos].litlen = baseLitlen+litlen;
147427b27ec6Sopenharmony_ci                         opt[pos].price = price;
147527b27ec6Sopenharmony_ci                         DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)",
147627b27ec6Sopenharmony_ci                                     pos, price, opt[pos].litlen);
147727b27ec6Sopenharmony_ci             }   }   }
147827b27ec6Sopenharmony_ci
147927b27ec6Sopenharmony_ci             /* set prices using match at position = cur */
148027b27ec6Sopenharmony_ci             {   int const matchML = newMatch.len;
148127b27ec6Sopenharmony_ci                 int ml = MINMATCH;
148227b27ec6Sopenharmony_ci
148327b27ec6Sopenharmony_ci                 assert(cur + newMatch.len < LZ4_OPT_NUM);
148427b27ec6Sopenharmony_ci                 for ( ; ml <= matchML ; ml++) {
148527b27ec6Sopenharmony_ci                     int const pos = cur + ml;
148627b27ec6Sopenharmony_ci                     int const offset = newMatch.off;
148727b27ec6Sopenharmony_ci                     int price;
148827b27ec6Sopenharmony_ci                     int ll;
148927b27ec6Sopenharmony_ci                     DEBUGLOG(7, "testing price rPos %i (last_match_pos=%i)",
149027b27ec6Sopenharmony_ci                                 pos, last_match_pos);
149127b27ec6Sopenharmony_ci                     if (opt[cur].mlen == 1) {
149227b27ec6Sopenharmony_ci                         ll = opt[cur].litlen;
149327b27ec6Sopenharmony_ci                         price = ((cur > ll) ? opt[cur - ll].price : 0)
149427b27ec6Sopenharmony_ci                               + LZ4HC_sequencePrice(ll, ml);
149527b27ec6Sopenharmony_ci                     } else {
149627b27ec6Sopenharmony_ci                         ll = 0;
149727b27ec6Sopenharmony_ci                         price = opt[cur].price + LZ4HC_sequencePrice(0, ml);
149827b27ec6Sopenharmony_ci                     }
149927b27ec6Sopenharmony_ci
150027b27ec6Sopenharmony_ci                    assert((U32)favorDecSpeed <= 1);
150127b27ec6Sopenharmony_ci                     if (pos > last_match_pos+TRAILING_LITERALS
150227b27ec6Sopenharmony_ci                      || price <= opt[pos].price - (int)favorDecSpeed) {
150327b27ec6Sopenharmony_ci                         DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i)",
150427b27ec6Sopenharmony_ci                                     pos, price, ml);
150527b27ec6Sopenharmony_ci                         assert(pos < LZ4_OPT_NUM);
150627b27ec6Sopenharmony_ci                         if ( (ml == matchML)  /* last pos of last match */
150727b27ec6Sopenharmony_ci                           && (last_match_pos < pos) )
150827b27ec6Sopenharmony_ci                             last_match_pos = pos;
150927b27ec6Sopenharmony_ci                         opt[pos].mlen = ml;
151027b27ec6Sopenharmony_ci                         opt[pos].off = offset;
151127b27ec6Sopenharmony_ci                         opt[pos].litlen = ll;
151227b27ec6Sopenharmony_ci                         opt[pos].price = price;
151327b27ec6Sopenharmony_ci             }   }   }
151427b27ec6Sopenharmony_ci             /* complete following positions with literals */
151527b27ec6Sopenharmony_ci             {   int addLit;
151627b27ec6Sopenharmony_ci                 for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {
151727b27ec6Sopenharmony_ci                     opt[last_match_pos+addLit].mlen = 1; /* literal */
151827b27ec6Sopenharmony_ci                     opt[last_match_pos+addLit].off = 0;
151927b27ec6Sopenharmony_ci                     opt[last_match_pos+addLit].litlen = addLit;
152027b27ec6Sopenharmony_ci                     opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);
152127b27ec6Sopenharmony_ci                     DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)", last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);
152227b27ec6Sopenharmony_ci             }   }
152327b27ec6Sopenharmony_ci         }  /* for (cur = 1; cur <= last_match_pos; cur++) */
152427b27ec6Sopenharmony_ci
152527b27ec6Sopenharmony_ci         assert(last_match_pos < LZ4_OPT_NUM + TRAILING_LITERALS);
152627b27ec6Sopenharmony_ci         best_mlen = opt[last_match_pos].mlen;
152727b27ec6Sopenharmony_ci         best_off = opt[last_match_pos].off;
152827b27ec6Sopenharmony_ci         cur = last_match_pos - best_mlen;
152927b27ec6Sopenharmony_ci
153027b27ec6Sopenharmony_ciencode: /* cur, last_match_pos, best_mlen, best_off must be set */
153127b27ec6Sopenharmony_ci         assert(cur < LZ4_OPT_NUM);
153227b27ec6Sopenharmony_ci         assert(last_match_pos >= 1);  /* == 1 when only one candidate */
153327b27ec6Sopenharmony_ci         DEBUGLOG(6, "reverse traversal, looking for shortest path (last_match_pos=%i)", last_match_pos);
153427b27ec6Sopenharmony_ci         {   int candidate_pos = cur;
153527b27ec6Sopenharmony_ci             int selected_matchLength = best_mlen;
153627b27ec6Sopenharmony_ci             int selected_offset = best_off;
153727b27ec6Sopenharmony_ci             while (1) {  /* from end to beginning */
153827b27ec6Sopenharmony_ci                 int const next_matchLength = opt[candidate_pos].mlen;  /* can be 1, means literal */
153927b27ec6Sopenharmony_ci                 int const next_offset = opt[candidate_pos].off;
154027b27ec6Sopenharmony_ci                 DEBUGLOG(7, "pos %i: sequence length %i", candidate_pos, selected_matchLength);
154127b27ec6Sopenharmony_ci                 opt[candidate_pos].mlen = selected_matchLength;
154227b27ec6Sopenharmony_ci                 opt[candidate_pos].off = selected_offset;
154327b27ec6Sopenharmony_ci                 selected_matchLength = next_matchLength;
154427b27ec6Sopenharmony_ci                 selected_offset = next_offset;
154527b27ec6Sopenharmony_ci                 if (next_matchLength > candidate_pos) break; /* last match elected, first match to encode */
154627b27ec6Sopenharmony_ci                 assert(next_matchLength > 0);  /* can be 1, means literal */
154727b27ec6Sopenharmony_ci                 candidate_pos -= next_matchLength;
154827b27ec6Sopenharmony_ci         }   }
154927b27ec6Sopenharmony_ci
155027b27ec6Sopenharmony_ci         /* encode all recorded sequences in order */
155127b27ec6Sopenharmony_ci         {   int rPos = 0;  /* relative position (to ip) */
155227b27ec6Sopenharmony_ci             while (rPos < last_match_pos) {
155327b27ec6Sopenharmony_ci                 int const ml = opt[rPos].mlen;
155427b27ec6Sopenharmony_ci                 int const offset = opt[rPos].off;
155527b27ec6Sopenharmony_ci                 if (ml == 1) { ip++; rPos++; continue; }  /* literal; note: can end up with several literals, in which case, skip them */
155627b27ec6Sopenharmony_ci                 rPos += ml;
155727b27ec6Sopenharmony_ci                 assert(ml >= MINMATCH);
155827b27ec6Sopenharmony_ci                 assert((offset >= 1) && (offset <= LZ4_DISTANCE_MAX));
155927b27ec6Sopenharmony_ci                 opSaved = op;
156027b27ec6Sopenharmony_ci                 if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ip - offset, limit, oend) ) {  /* updates ip, op and anchor */
156127b27ec6Sopenharmony_ci                     ovml = ml;
156227b27ec6Sopenharmony_ci                     ovref = ip - offset;
156327b27ec6Sopenharmony_ci                     goto _dest_overflow;
156427b27ec6Sopenharmony_ci         }   }   }
156527b27ec6Sopenharmony_ci     }  /* while (ip <= mflimit) */
156627b27ec6Sopenharmony_ci
156727b27ec6Sopenharmony_ci_last_literals:
156827b27ec6Sopenharmony_ci     /* Encode Last Literals */
156927b27ec6Sopenharmony_ci     {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */
157027b27ec6Sopenharmony_ci         size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;
157127b27ec6Sopenharmony_ci         size_t const totalSize = 1 + llAdd + lastRunSize;
157227b27ec6Sopenharmony_ci         if (limit == fillOutput) oend += LASTLITERALS;  /* restore correct value */
157327b27ec6Sopenharmony_ci         if (limit && (op + totalSize > oend)) {
157427b27ec6Sopenharmony_ci             if (limit == limitedOutput) { /* Check output limit */
157527b27ec6Sopenharmony_ci                retval = 0;
157627b27ec6Sopenharmony_ci                goto _return_label;
157727b27ec6Sopenharmony_ci             }
157827b27ec6Sopenharmony_ci             /* adapt lastRunSize to fill 'dst' */
157927b27ec6Sopenharmony_ci             lastRunSize  = (size_t)(oend - op) - 1 /*token*/;
158027b27ec6Sopenharmony_ci             llAdd = (lastRunSize + 256 - RUN_MASK) / 256;
158127b27ec6Sopenharmony_ci             lastRunSize -= llAdd;
158227b27ec6Sopenharmony_ci         }
158327b27ec6Sopenharmony_ci         DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);
158427b27ec6Sopenharmony_ci         ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */
158527b27ec6Sopenharmony_ci
158627b27ec6Sopenharmony_ci         if (lastRunSize >= RUN_MASK) {
158727b27ec6Sopenharmony_ci             size_t accumulator = lastRunSize - RUN_MASK;
158827b27ec6Sopenharmony_ci             *op++ = (RUN_MASK << ML_BITS);
158927b27ec6Sopenharmony_ci             for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;
159027b27ec6Sopenharmony_ci             *op++ = (BYTE) accumulator;
159127b27ec6Sopenharmony_ci         } else {
159227b27ec6Sopenharmony_ci             *op++ = (BYTE)(lastRunSize << ML_BITS);
159327b27ec6Sopenharmony_ci         }
159427b27ec6Sopenharmony_ci         LZ4_memcpy(op, anchor, lastRunSize);
159527b27ec6Sopenharmony_ci         op += lastRunSize;
159627b27ec6Sopenharmony_ci     }
159727b27ec6Sopenharmony_ci
159827b27ec6Sopenharmony_ci     /* End */
159927b27ec6Sopenharmony_ci     *srcSizePtr = (int) (((const char*)ip) - source);
160027b27ec6Sopenharmony_ci     retval = (int) ((char*)op-dst);
160127b27ec6Sopenharmony_ci     goto _return_label;
160227b27ec6Sopenharmony_ci
160327b27ec6Sopenharmony_ci_dest_overflow:
160427b27ec6Sopenharmony_ciif (limit == fillOutput) {
160527b27ec6Sopenharmony_ci     /* Assumption : ip, anchor, ovml and ovref must be set correctly */
160627b27ec6Sopenharmony_ci     size_t const ll = (size_t)(ip - anchor);
160727b27ec6Sopenharmony_ci     size_t const ll_addbytes = (ll + 240) / 255;
160827b27ec6Sopenharmony_ci     size_t const ll_totalCost = 1 + ll_addbytes + ll;
160927b27ec6Sopenharmony_ci     BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */
161027b27ec6Sopenharmony_ci     DEBUGLOG(6, "Last sequence overflowing (only %i bytes remaining)", (int)(oend-1-opSaved));
161127b27ec6Sopenharmony_ci     op = opSaved;  /* restore correct out pointer */
161227b27ec6Sopenharmony_ci     if (op + ll_totalCost <= maxLitPos) {
161327b27ec6Sopenharmony_ci         /* ll validated; now adjust match length */
161427b27ec6Sopenharmony_ci         size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));
161527b27ec6Sopenharmony_ci         size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);
161627b27ec6Sopenharmony_ci         assert(maxMlSize < INT_MAX); assert(ovml >= 0);
161727b27ec6Sopenharmony_ci         if ((size_t)ovml > maxMlSize) ovml = (int)maxMlSize;
161827b27ec6Sopenharmony_ci         if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ovml >= MFLIMIT) {
161927b27ec6Sopenharmony_ci             DEBUGLOG(6, "Space to end : %i + ml (%i)", (int)((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1), ovml);
162027b27ec6Sopenharmony_ci             DEBUGLOG(6, "Before : ip = %p, anchor = %p", ip, anchor);
162127b27ec6Sopenharmony_ci             LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ovml, ovref, notLimited, oend);
162227b27ec6Sopenharmony_ci             DEBUGLOG(6, "After : ip = %p, anchor = %p", ip, anchor);
162327b27ec6Sopenharmony_ci     }   }
162427b27ec6Sopenharmony_ci     goto _last_literals;
162527b27ec6Sopenharmony_ci}
162627b27ec6Sopenharmony_ci_return_label:
162727b27ec6Sopenharmony_ci#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
162827b27ec6Sopenharmony_ci     FREEMEM(opt);
162927b27ec6Sopenharmony_ci#endif
163027b27ec6Sopenharmony_ci     return retval;
163127b27ec6Sopenharmony_ci}
1632