Coverage Report

Created: 2025-11-11 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/lz4/lib/lz4hc.c
Line
Count
Source
1
/*
2
    LZ4 HC - High Compression Mode of LZ4
3
    Copyright (c) Yann Collet. All rights reserved.
4
5
    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6
7
    Redistribution and use in source and binary forms, with or without
8
    modification, are permitted provided that the following conditions are
9
    met:
10
11
    * Redistributions of source code must retain the above copyright
12
    notice, this list of conditions and the following disclaimer.
13
    * Redistributions in binary form must reproduce the above
14
    copyright notice, this list of conditions and the following disclaimer
15
    in the documentation and/or other materials provided with the
16
    distribution.
17
18
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30
    You can contact the author at :
31
       - LZ4 source repository : https://github.com/lz4/lz4
32
       - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
33
*/
34
/* note : lz4hc is not an independent module, it requires lz4.h/lz4.c for proper compilation */
35
36
37
/* *************************************
38
*  Tuning Parameter
39
***************************************/
40
41
/*! HEAPMODE :
42
 *  Select how stateless HC compression functions like `LZ4_compress_HC()`
43
 *  allocate memory for their workspace:
44
 *  in stack (0:fastest), or in heap (1:default, requires malloc()).
45
 *  Since workspace is rather large, heap mode is recommended.
46
**/
47
#ifndef LZ4HC_HEAPMODE
48
#  define LZ4HC_HEAPMODE 1
49
#endif
50
51
52
/*===    Dependency    ===*/
53
#define LZ4_HC_STATIC_LINKING_ONLY
54
#include "lz4hc.h"
55
#include <limits.h>
56
57
58
/*===   Shared lz4.c code   ===*/
59
#ifndef LZ4_SRC_INCLUDED
60
# if defined(__GNUC__)
61
#  pragma GCC diagnostic ignored "-Wunused-function"
62
# endif
63
# if defined (__clang__)
64
#  pragma clang diagnostic ignored "-Wunused-function"
65
# endif
66
# define LZ4_COMMONDEFS_ONLY
67
# include "lz4.c"   /* LZ4_count, constants, mem */
68
#endif
69
70
71
/*===   Enums   ===*/
72
typedef enum { noDictCtx, usingDictCtxHc } dictCtx_directive;
73
74
75
/*===   Constants   ===*/
76
17.7k
#define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH)
77
73.8k
#define LZ4_OPT_NUM   (1<<12)
78
79
80
/*===   Macros   ===*/
81
920k
#define MIN(a,b)   ( (a) < (b) ? (a) : (b) )
82
1.79M
#define MAX(a,b)   ( (a) > (b) ? (a) : (b) )
83
84
85
/*===   Levels definition   ===*/
86
typedef enum { lz4mid, lz4hc, lz4opt } lz4hc_strat_e;
87
typedef struct {
88
    lz4hc_strat_e strat;
89
    int nbSearches;
90
    U32 targetLength;
91
} cParams_t;
92
static const cParams_t k_clTable[LZ4HC_CLEVEL_MAX+1] = {
93
    { lz4mid,    2, 16 },  /* 0, unused */
94
    { lz4mid,    2, 16 },  /* 1, unused */
95
    { lz4mid,    2, 16 },  /* 2 */
96
    { lz4hc,     4, 16 },  /* 3 */
97
    { lz4hc,     8, 16 },  /* 4 */
98
    { lz4hc,    16, 16 },  /* 5 */
99
    { lz4hc,    32, 16 },  /* 6 */
100
    { lz4hc,    64, 16 },  /* 7 */
101
    { lz4hc,   128, 16 },  /* 8 */
102
    { lz4hc,   256, 16 },  /* 9 */
103
    { lz4opt,   96, 64 },  /*10==LZ4HC_CLEVEL_OPT_MIN*/
104
    { lz4opt,  512,128 },  /*11 */
105
    { lz4opt,16384,LZ4_OPT_NUM },  /* 12==LZ4HC_CLEVEL_MAX */
106
};
107
108
static cParams_t LZ4HC_getCLevelParams(int cLevel)
109
16.2k
{
110
    /* note : clevel convention is a bit different from lz4frame,
111
     * possibly something worth revisiting for consistency */
112
16.2k
    if (cLevel < 1)
113
0
        cLevel = LZ4HC_CLEVEL_DEFAULT;
114
16.2k
    cLevel = MIN(LZ4HC_CLEVEL_MAX, cLevel);
115
16.2k
    return k_clTable[cLevel];
116
16.2k
}
117
118
119
/*===   Hashing   ===*/
120
0
#define LZ4HC_HASHSIZE 4
121
320M
#define HASH_FUNCTION(i)      (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG))
122
320M
static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }
123
124
#if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2)
125
/* lie to the compiler about data alignment; use with caution */
126
static U64 LZ4_read64(const void* memPtr) { return *(const U64*) memPtr; }
127
128
#elif defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==1)
129
/* __pack instructions are safer, but compiler specific */
130
LZ4_PACK(typedef struct { U64 u64; }) LZ4_unalign64;
131
485k
static U64 LZ4_read64(const void* ptr) { return ((const LZ4_unalign64*)ptr)->u64; }
132
133
#else  /* safe and portable access using memcpy() */
134
static U64 LZ4_read64(const void* memPtr)
135
{
136
    U64 val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val;
137
}
138
139
#endif /* LZ4_FORCE_MEMORY_ACCESS */
140
141
2.62k
#define LZ4MID_HASHSIZE 8
142
929k
#define LZ4MID_HASHLOG (LZ4HC_HASH_LOG-1)
143
2.62k
#define LZ4MID_HASHTABLESIZE (1 << LZ4MID_HASHLOG)
144
145
440k
static U32 LZ4MID_hash4(U32 v) { return (v * 2654435761U) >> (32-LZ4MID_HASHLOG); }
146
440k
static U32 LZ4MID_hash4Ptr(const void* ptr) { return LZ4MID_hash4(LZ4_read32(ptr)); }
147
/* note: hash7 hashes the lower 56-bits.
148
 * It presumes input was read using little endian.*/
149
485k
static U32 LZ4MID_hash7(U64 v) { return (U32)(((v  << (64-56)) * 58295818150454627ULL) >> (64-LZ4MID_HASHLOG)) ; }
150
static U64 LZ4_readLE64(const void* memPtr);
151
485k
static U32 LZ4MID_hash8Ptr(const void* ptr) { return LZ4MID_hash7(LZ4_readLE64(ptr)); }
152
153
static U64 LZ4_readLE64(const void* memPtr)
154
485k
{
155
485k
    if (LZ4_isLittleEndian()) {
156
485k
        return LZ4_read64(memPtr);
157
485k
    } else {
158
0
        const BYTE* p = (const BYTE*)memPtr;
159
        /* note: relies on the compiler to simplify this expression */
160
0
        return (U64)p[0] | ((U64)p[1]<<8) | ((U64)p[2]<<16) | ((U64)p[3]<<24)
161
0
            | ((U64)p[4]<<32) | ((U64)p[5]<<40) | ((U64)p[6]<<48) | ((U64)p[7]<<56);
162
0
    }
163
485k
}
164
165
166
/*===   Count match length   ===*/
167
LZ4_FORCE_INLINE
168
unsigned LZ4HC_NbCommonBytes32(U32 val)
169
339k
{
170
339k
    assert(val != 0);
171
339k
    if (LZ4_isLittleEndian()) {
172
#     if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(LZ4_FORCE_SW_BITCOUNT)
173
        unsigned long r;
174
        _BitScanReverse(&r, val);
175
        return (unsigned)((31 - r) >> 3);
176
#     elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \
177
                            ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \
178
                                        !defined(LZ4_FORCE_SW_BITCOUNT)
179
        return (unsigned)__builtin_clz(val) >> 3;
180
#     else
181
        val >>= 8;
182
        val = ((((val + 0x00FFFF00) | 0x00FFFFFF) + val) |
183
              (val + 0x00FF0000)) >> 24;
184
        return (unsigned)val ^ 3;
185
#     endif
186
339k
    } else {
187
#     if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(LZ4_FORCE_SW_BITCOUNT)
188
        unsigned long r;
189
        _BitScanForward(&r, val);
190
        return (unsigned)(r >> 3);
191
#     elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \
192
                            ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \
193
                                        !defined(LZ4_FORCE_SW_BITCOUNT)
194
        return (unsigned)__builtin_ctz(val) >> 3;
195
#     else
196
        const U32 m = 0x01010101;
197
        return (unsigned)((((val - 1) ^ val) & (m - 1)) * m) >> 24;
198
#     endif
199
0
    }
200
339k
}
201
202
/** LZ4HC_countBack() :
203
 * @return : negative value, nb of common bytes before ip/match */
204
LZ4_FORCE_INLINE
205
int LZ4HC_countBack(const BYTE* const ip, const BYTE* const match,
206
                    const BYTE* const iMin, const BYTE* const mMin)
207
381k
{
208
381k
    int back = 0;
209
381k
    int const min = (int)MAX(iMin - ip, mMin - match);
210
381k
    assert(min <= 0);
211
381k
    assert(ip >= iMin); assert((size_t)(ip-iMin) < (1U<<31));
212
381k
    assert(match >= mMin); assert((size_t)(match - mMin) < (1U<<31));
213
214
11.2M
    while ((back - min) > 3) {
215
11.2M
        U32 const v = LZ4_read32(ip + back - 4) ^ LZ4_read32(match + back - 4);
216
11.2M
        if (v) {
217
339k
            return (back - (int)LZ4HC_NbCommonBytes32(v));
218
10.8M
        } else back -= 4; /* 4-byte step */
219
11.2M
    }
220
    /* check remainder if any */
221
71.4k
    while ( (back > min)
222
59.2k
         && (ip[back-1] == match[back-1]) )
223
29.8k
            back--;
224
41.5k
    return back;
225
381k
}
226
227
/*===   Chain table updates   ===*/
228
661M
#define DELTANEXTU16(table, pos) table[(U16)(pos)]   /* faster */
229
/* Make fields passed to, and updated by LZ4HC_encodeSequence explicit */
230
97.7k
#define UPDATABLE(ip, op, anchor) &ip, &op, &anchor
231
232
233
/**************************************
234
*  Init
235
**************************************/
236
static void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4)
237
0
{
238
0
    MEM_INIT(hc4->hashTable, 0, sizeof(hc4->hashTable));
239
0
    MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));
240
0
}
241
242
static void LZ4HC_init_internal (LZ4HC_CCtx_internal* hc4, const BYTE* start)
243
16.2k
{
244
16.2k
    size_t const bufferSize = (size_t)(hc4->end - hc4->prefixStart);
245
16.2k
    size_t newStartingOffset = bufferSize + hc4->dictLimit;
246
16.2k
    DEBUGLOG(5, "LZ4HC_init_internal");
247
16.2k
    assert(newStartingOffset >= bufferSize);  /* check overflow */
248
16.2k
    if (newStartingOffset > 1 GB) {
249
0
        LZ4HC_clearTables(hc4);
250
0
        newStartingOffset = 0;
251
0
    }
252
16.2k
    newStartingOffset += 64 KB;
253
16.2k
    hc4->nextToUpdate = (U32)newStartingOffset;
254
16.2k
    hc4->prefixStart = start;
255
16.2k
    hc4->end = start;
256
16.2k
    hc4->dictStart = start;
257
16.2k
    hc4->dictLimit = (U32)newStartingOffset;
258
16.2k
    hc4->lowLimit = (U32)newStartingOffset;
259
16.2k
}
260
261
262
/**************************************
263
*  Encode
264
**************************************/
265
#if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 2)
266
# define RAWLOG(...) fprintf(stderr, __VA_ARGS__)
267
void LZ4HC_hexOut(const void* src, size_t len)
268
{
269
    const BYTE* p = (const BYTE*)src;
270
    size_t n;
271
    for (n=0; n<len; n++) {
272
        RAWLOG("%02X ", p[n]);
273
    }
274
    RAWLOG(" \n");
275
}
276
277
# define HEX_CMP(_lev, _ptr, _ref, _len) \
278
    if (LZ4_DEBUG >= _lev) {            \
279
        RAWLOG("match bytes: ");        \
280
        LZ4HC_hexOut(_ptr, _len);       \
281
        RAWLOG("ref bytes: ");          \
282
        LZ4HC_hexOut(_ref, _len);       \
283
    }
284
285
#else
286
# define HEX_CMP(l,p,r,_l)
287
#endif
288
289
/* LZ4HC_encodeSequence() :
290
 * @return : 0 if ok,
291
 *           1 if buffer issue detected */
292
LZ4_FORCE_INLINE int LZ4HC_encodeSequence (
293
    const BYTE** _ip,
294
    BYTE** _op,
295
    const BYTE** _anchor,
296
    int matchLength,
297
    int offset,
298
    limitedOutput_directive limit,
299
    BYTE* oend)
300
97.7k
{
301
277k
#define ip      (*_ip)
302
891k
#define op      (*_op)
303
278k
#define anchor  (*_anchor)
304
305
97.7k
    BYTE* const token = op++;
306
307
#if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 6)
308
    static const BYTE* start = NULL;
309
    static U32 totalCost = 0;
310
    U32 const pos = (start==NULL) ? 0 : (U32)(anchor - start); /* only works for single segment */
311
    U32 const ll = (U32)(ip - anchor);
312
    U32 const llAdd = (ll>=15) ? ((ll-15) / 255) + 1 : 0;
313
    U32 const mlAdd = (matchLength>=19) ? ((matchLength-19) / 255) + 1 : 0;
314
    U32 const cost = 1 + llAdd + ll + 2 + mlAdd;
315
    if (start==NULL) start = anchor;  /* only works for single segment */
316
    DEBUGLOG(6, "pos:%7u -- literals:%4u, match:%4i, offset:%5i, cost:%4u + %5u",
317
                pos,
318
                (U32)(ip - anchor), matchLength, offset,
319
                cost, totalCost);
320
# if 1 /* only works on single segment data */
321
    HEX_CMP(7, ip, ip-offset, matchLength);
322
# endif
323
    totalCost += cost;
324
#endif
325
326
    /* Encode Literal length */
327
97.7k
    {   size_t litLen = (size_t)(ip - anchor);
328
97.7k
        LZ4_STATIC_ASSERT(notLimited == 0);
329
        /* Check output limit */
330
97.7k
        if (limit && ((op + (litLen / 255) + litLen + (2 + 1 + LASTLITERALS)) > oend)) {
331
7.22k
            DEBUGLOG(6, "Not enough room to write %i literals (%i bytes remaining)",
332
7.22k
                    (int)litLen, (int)(oend - op));
333
7.22k
            return 1;
334
7.22k
        }
335
90.5k
        if (litLen >= RUN_MASK) {
336
1.72k
            size_t len = litLen - RUN_MASK;
337
1.72k
            *token = (RUN_MASK << ML_BITS);
338
1.72k
            for(; len >= 255 ; len -= 255) *op++ = 255;
339
1.72k
            *op++ = (BYTE)len;
340
88.8k
        } else {
341
88.8k
            *token = (BYTE)(litLen << ML_BITS);
342
88.8k
        }
343
344
        /* Copy Literals */
345
90.5k
        LZ4_wildCopy8(op, anchor, op + litLen);
346
90.5k
        op += litLen;
347
90.5k
    }
348
349
    /* Encode Offset */
350
90.5k
    assert(offset <= LZ4_DISTANCE_MAX );
351
90.5k
    assert(offset > 0);
352
90.5k
    LZ4_writeLE16(op, (U16)(offset)); op += 2;
353
354
    /* Encode MatchLength */
355
90.5k
    assert(matchLength >= MINMATCH);
356
90.5k
    {   size_t mlCode = (size_t)matchLength - MINMATCH;
357
90.5k
        if (limit && (op + (mlCode / 255) + (1 + LASTLITERALS) > oend)) {
358
813
            DEBUGLOG(6, "Not enough room to write match length");
359
813
            return 1;   /* Check output limit */
360
813
        }
361
89.7k
        if (mlCode >= ML_MASK) {
362
35.4k
            *token += ML_MASK;
363
35.4k
            mlCode -= ML_MASK;
364
91.9k
            for(; mlCode >= 510 ; mlCode -= 510) { *op++ = 255; *op++ = 255; }
365
35.4k
            if (mlCode >= 255) { mlCode -= 255; *op++ = 255; }
366
35.4k
            *op++ = (BYTE)mlCode;
367
54.3k
        } else {
368
54.3k
            *token += (BYTE)(mlCode);
369
54.3k
    }   }
370
371
    /* Prepare next loop */
372
89.7k
    ip += matchLength;
373
89.7k
    anchor = ip;
374
375
89.7k
    return 0;
376
377
90.5k
#undef ip
378
90.5k
#undef op
379
90.5k
#undef anchor
380
90.5k
}
381
382
383
typedef struct {
384
    int off;
385
    int len;
386
    int back;  /* negative value */
387
} LZ4HC_match_t;
388
389
LZ4HC_match_t LZ4HC_searchExtDict(const BYTE* ip, U32 ipIndex,
390
        const BYTE* const iLowLimit, const BYTE* const iHighLimit,
391
        const LZ4HC_CCtx_internal* dictCtx, U32 gDictEndIndex,
392
        int currentBestML, int nbAttempts)
393
0
{
394
0
    size_t const lDictEndIndex = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit;
395
0
    U32 lDictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)];
396
0
    U32 matchIndex = lDictMatchIndex + gDictEndIndex - (U32)lDictEndIndex;
397
0
    int offset = 0, sBack = 0;
398
0
    assert(lDictEndIndex <= 1 GB);
399
0
    if (lDictMatchIndex>0)
400
0
        DEBUGLOG(7, "lDictEndIndex = %zu, lDictMatchIndex = %u", lDictEndIndex, lDictMatchIndex);
401
0
    while (ipIndex - matchIndex <= LZ4_DISTANCE_MAX && nbAttempts--) {
402
0
        const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + lDictMatchIndex;
403
404
0
        if (LZ4_read32(matchPtr) == LZ4_read32(ip)) {
405
0
            int mlt;
406
0
            int back = 0;
407
0
            const BYTE* vLimit = ip + (lDictEndIndex - lDictMatchIndex);
408
0
            if (vLimit > iHighLimit) vLimit = iHighLimit;
409
0
            mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
410
0
            back = (ip > iLowLimit) ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->prefixStart) : 0;
411
0
            mlt -= back;
412
0
            if (mlt > currentBestML) {
413
0
                currentBestML = mlt;
414
0
                offset = (int)(ipIndex - matchIndex);
415
0
                sBack = back;
416
0
                DEBUGLOG(7, "found match of length %i within extDictCtx", currentBestML);
417
0
        }   }
418
419
0
        {   U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, lDictMatchIndex);
420
0
            lDictMatchIndex -= nextOffset;
421
0
            matchIndex -= nextOffset;
422
0
    }   }
423
424
0
    {   LZ4HC_match_t md;
425
0
        md.len = currentBestML;
426
0
        md.off = offset;
427
0
        md.back = sBack;
428
0
        return md;
429
0
    }
430
0
}
431
432
typedef LZ4HC_match_t (*LZ4MID_searchIntoDict_f)(const BYTE* ip, U32 ipIndex,
433
        const BYTE* const iHighLimit,
434
        const LZ4HC_CCtx_internal* dictCtx, U32 gDictEndIndex);
435
436
static LZ4HC_match_t LZ4MID_searchHCDict(const BYTE* ip, U32 ipIndex,
437
        const BYTE* const iHighLimit,
438
        const LZ4HC_CCtx_internal* dictCtx, U32 gDictEndIndex)
439
0
{
440
0
    return LZ4HC_searchExtDict(ip,ipIndex,
441
0
                            ip, iHighLimit,
442
0
                            dictCtx, gDictEndIndex,
443
0
                            MINMATCH-1, 2);
444
0
}
445
446
static LZ4HC_match_t LZ4MID_searchExtDict(const BYTE* ip, U32 ipIndex,
447
        const BYTE* const iHighLimit,
448
        const LZ4HC_CCtx_internal* dictCtx, U32 gDictEndIndex)
449
0
{
450
0
    size_t const lDictEndIndex = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit;
451
0
    const U32* const hash4Table = dictCtx->hashTable;
452
0
    const U32* const hash8Table = hash4Table + LZ4MID_HASHTABLESIZE;
453
0
    DEBUGLOG(7, "LZ4MID_searchExtDict (ipIdx=%u)", ipIndex);
454
455
    /* search long match first */
456
0
    {   U32 l8DictMatchIndex = hash8Table[LZ4MID_hash8Ptr(ip)];
457
0
        U32 m8Index = l8DictMatchIndex + gDictEndIndex - (U32)lDictEndIndex;
458
0
        assert(lDictEndIndex <= 1 GB);
459
0
        if (ipIndex - m8Index <= LZ4_DISTANCE_MAX) {
460
0
            const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + l8DictMatchIndex;
461
0
            const size_t safeLen = MIN(lDictEndIndex - l8DictMatchIndex, (size_t)(iHighLimit - ip));
462
0
            int mlt = (int)LZ4_count(ip, matchPtr, ip + safeLen);
463
0
            if (mlt >= MINMATCH) {
464
0
                LZ4HC_match_t md;
465
0
                DEBUGLOG(7, "Found long ExtDict match of len=%u", mlt);
466
0
                md.len = mlt;
467
0
                md.off = (int)(ipIndex - m8Index);
468
0
                md.back = 0;
469
0
                return md;
470
0
            }
471
0
        }
472
0
    }
473
474
    /* search for short match second */
475
0
    {   U32 l4DictMatchIndex = hash4Table[LZ4MID_hash4Ptr(ip)];
476
0
        U32 m4Index = l4DictMatchIndex + gDictEndIndex - (U32)lDictEndIndex;
477
0
        if (ipIndex - m4Index <= LZ4_DISTANCE_MAX) {
478
0
            const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + l4DictMatchIndex;
479
0
            const size_t safeLen = MIN(lDictEndIndex - l4DictMatchIndex, (size_t)(iHighLimit - ip));
480
0
            int mlt = (int)LZ4_count(ip, matchPtr, ip + safeLen);
481
0
            if (mlt >= MINMATCH) {
482
0
                LZ4HC_match_t md;
483
0
                DEBUGLOG(7, "Found short ExtDict match of len=%u", mlt);
484
0
                md.len = mlt;
485
0
                md.off = (int)(ipIndex - m4Index);
486
0
                md.back = 0;
487
0
                return md;
488
0
            }
489
0
        }
490
0
    }
491
492
    /* nothing found */
493
0
    {   LZ4HC_match_t const md = {0, 0, 0 };
494
0
        return md;
495
0
    }
496
0
}
497
498
/**************************************
499
*  Mid Compression (level 2)
500
**************************************/
501
502
LZ4_FORCE_INLINE void
503
LZ4MID_addPosition(U32* hTable, U32 hValue, U32 index)
504
921k
{
505
921k
    hTable[hValue] = index;
506
921k
}
507
508
72.5k
#define ADDPOS8(_p, _idx) LZ4MID_addPosition(hash8Table, LZ4MID_hash8Ptr(_p), _idx)
509
43.2k
#define ADDPOS4(_p, _idx) LZ4MID_addPosition(hash4Table, LZ4MID_hash4Ptr(_p), _idx)
510
511
/* Fill hash tables with references into dictionary.
512
 * The resulting table is only exploitable by LZ4MID (level 2) */
513
static void
514
LZ4MID_fillHTable (LZ4HC_CCtx_internal* cctx, const void* dict, size_t size)
515
0
{
516
0
    U32* const hash4Table = cctx->hashTable;
517
0
    U32* const hash8Table = hash4Table + LZ4MID_HASHTABLESIZE;
518
0
    const BYTE* const prefixPtr = (const BYTE*)dict;
519
0
    U32 const prefixIdx = cctx->dictLimit;
520
0
    U32 const target = prefixIdx + (U32)size - LZ4MID_HASHSIZE;
521
0
    U32 idx = cctx->nextToUpdate;
522
0
    assert(dict == cctx->prefixStart);
523
0
    DEBUGLOG(4, "LZ4MID_fillHTable (size:%zu)", size);
524
0
    if (size <= LZ4MID_HASHSIZE)
525
0
        return;
526
527
0
    for (; idx < target; idx += 3) {
528
0
        ADDPOS4(prefixPtr+idx-prefixIdx, idx);
529
0
        ADDPOS8(prefixPtr+idx+1-prefixIdx, idx+1);
530
0
    }
531
532
0
    idx = (size > 32 KB + LZ4MID_HASHSIZE) ? target - 32 KB : cctx->nextToUpdate;
533
0
    for (; idx < target; idx += 1) {
534
0
        ADDPOS8(prefixPtr+idx-prefixIdx, idx);
535
0
    }
536
537
0
    cctx->nextToUpdate = target;
538
0
}
539
540
static LZ4MID_searchIntoDict_f select_searchDict_function(const LZ4HC_CCtx_internal* dictCtx)
541
0
{
542
0
    if (dictCtx == NULL) return NULL;
543
0
    if (LZ4HC_getCLevelParams(dictCtx->compressionLevel).strat == lz4mid)
544
0
        return LZ4MID_searchExtDict;
545
0
    return LZ4MID_searchHCDict;
546
0
}
547
548
/* preconditions:
549
 * - *srcSizePtr within [1, LZ4_MAX_INPUT_SIZE]
550
 * - src is valid
551
 * - maxOutputSize >= 1
552
 * - dst is valid
553
 */
554
static int LZ4MID_compress (
555
    LZ4HC_CCtx_internal* const ctx,
556
    const char* const src,
557
    char* const dst,
558
    int* srcSizePtr,
559
    int const maxOutputSize,
560
    const limitedOutput_directive limit,
561
    const dictCtx_directive dict
562
    )
563
2.62k
{
564
2.62k
    U32* const hash4Table = ctx->hashTable;
565
2.62k
    U32* const hash8Table = hash4Table + LZ4MID_HASHTABLESIZE;
566
2.62k
    const BYTE* ip = (const BYTE*)src;
567
2.62k
    const BYTE* anchor = ip;
568
2.62k
    const BYTE* const iend = ip + *srcSizePtr;
569
2.62k
    const BYTE* const mflimit = iend - MFLIMIT;
570
2.62k
    const BYTE* const matchlimit = (iend - LASTLITERALS);
571
2.62k
    const BYTE* const ilimit = (iend - LZ4MID_HASHSIZE);
572
2.62k
    BYTE* op = (BYTE*)dst;
573
2.62k
    BYTE* oend = op + maxOutputSize;
574
575
2.62k
    const BYTE* const prefixPtr = ctx->prefixStart;
576
2.62k
    const U32 prefixIdx = ctx->dictLimit;
577
2.62k
    const U32 ilimitIdx = (U32)(ilimit - prefixPtr) + prefixIdx;
578
2.62k
    const BYTE* const dictStart = ctx->dictStart;
579
2.62k
    const U32 dictIdx = ctx->lowLimit;
580
2.62k
    const U32 gDictEndIndex = ctx->lowLimit;
581
2.62k
    const LZ4MID_searchIntoDict_f searchIntoDict = (dict == usingDictCtxHc) ? select_searchDict_function(ctx->dictCtx) : NULL;
582
2.62k
    unsigned matchLength;
583
2.62k
    unsigned matchDistance;
584
585
2.62k
    DEBUGLOG(5, "LZ4MID_compress (%i bytes)", *srcSizePtr);
586
587
    /* preconditions verifications */
588
2.62k
    if (dict == usingDictCtxHc) DEBUGLOG(5, "usingDictCtxHc");
589
2.62k
    assert(*srcSizePtr > 0);
590
2.62k
    assert(*srcSizePtr <= LZ4_MAX_INPUT_SIZE);
591
2.62k
    assert(src != NULL);
592
2.62k
    assert(maxOutputSize >= 1);
593
2.62k
    assert(dst != NULL);
594
595
2.62k
    if (limit == fillOutput) oend -= LASTLITERALS;  /* Hack for support LZ4 format restriction */
596
2.62k
    if (*srcSizePtr < LZ4_minLength)
597
22
        goto _lz4mid_last_literals;  /* Input too small, no compression (all literals) */
598
599
    /* main loop */
600
407k
    while (ip <= mflimit) {
601
406k
        const U32 ipIndex = (U32)(ip - prefixPtr) + prefixIdx;
602
        /* search long match */
603
406k
        {   U32 const h8 = LZ4MID_hash8Ptr(ip);
604
406k
            U32 const pos8 = hash8Table[h8];
605
406k
            assert(h8 < LZ4MID_HASHTABLESIZE);
606
406k
            assert(pos8 < ipIndex);
607
406k
            LZ4MID_addPosition(hash8Table, h8, ipIndex);
608
406k
            if (ipIndex - pos8 <= LZ4_DISTANCE_MAX) {
609
                /* match candidate found */
610
36.8k
                if (pos8 >= prefixIdx) {
611
36.8k
                    const BYTE* const matchPtr = prefixPtr + pos8 - prefixIdx;
612
36.8k
                    assert(matchPtr < ip);
613
36.8k
                    matchLength = LZ4_count(ip, matchPtr, matchlimit);
614
36.8k
                    if (matchLength >= MINMATCH) {
615
8.85k
                        DEBUGLOG(7, "found long match at pos %u (len=%u)", pos8, matchLength);
616
8.85k
                        matchDistance = ipIndex - pos8;
617
8.85k
                        goto _lz4mid_encode_sequence;
618
8.85k
                    }
619
36.8k
                } else {
620
0
                    if (pos8 >= dictIdx) {
621
                        /* extDict match candidate */
622
0
                        const BYTE* const matchPtr = dictStart + (pos8 - dictIdx);
623
0
                        const size_t safeLen = MIN(prefixIdx - pos8, (size_t)(matchlimit - ip));
624
0
                        matchLength = LZ4_count(ip, matchPtr, ip + safeLen);
625
0
                        if (matchLength >= MINMATCH) {
626
0
                            DEBUGLOG(7, "found long match at ExtDict pos %u (len=%u)", pos8, matchLength);
627
0
                            matchDistance = ipIndex - pos8;
628
0
                            goto _lz4mid_encode_sequence;
629
0
                        }
630
0
                    }
631
0
                }
632
36.8k
        }   }
633
        /* search short match */
634
397k
        {   U32 const h4 = LZ4MID_hash4Ptr(ip);
635
397k
            U32 const pos4 = hash4Table[h4];
636
397k
            assert(h4 < LZ4MID_HASHTABLESIZE);
637
397k
            assert(pos4 < ipIndex);
638
397k
            LZ4MID_addPosition(hash4Table, h4, ipIndex);
639
397k
            if (ipIndex - pos4 <= LZ4_DISTANCE_MAX) {
640
                /* match candidate found */
641
32.6k
                if (pos4 >= prefixIdx) {
642
                /* only search within prefix */
643
32.6k
                    const BYTE* const matchPtr = prefixPtr + (pos4 - prefixIdx);
644
32.6k
                    assert(matchPtr < ip);
645
32.6k
                    assert(matchPtr >= prefixPtr);
646
32.6k
                    matchLength = LZ4_count(ip, matchPtr, matchlimit);
647
32.6k
                    if (matchLength >= MINMATCH) {
648
                        /* short match found, let's just check ip+1 for longer */
649
6.65k
                        U32 const h8 = LZ4MID_hash8Ptr(ip+1);
650
6.65k
                        U32 const pos8 = hash8Table[h8];
651
6.65k
                        U32 const m2Distance = ipIndex + 1 - pos8;
652
6.65k
                        matchDistance = ipIndex - pos4;
653
6.65k
                        if ( m2Distance <= LZ4_DISTANCE_MAX
654
2.09k
                        && pos8 >= prefixIdx /* only search within prefix */
655
2.09k
                        && likely(ip < mflimit)
656
6.65k
                        ) {
657
2.05k
                            const BYTE* const m2Ptr = prefixPtr + (pos8 - prefixIdx);
658
2.05k
                            unsigned ml2 = LZ4_count(ip+1, m2Ptr, matchlimit);
659
2.05k
                            if (ml2 > matchLength) {
660
1.07k
                                LZ4MID_addPosition(hash8Table, h8, ipIndex+1);
661
1.07k
                                ip++;
662
1.07k
                                matchLength = ml2;
663
1.07k
                                matchDistance = m2Distance;
664
1.07k
                        }   }
665
6.65k
                        goto _lz4mid_encode_sequence;
666
6.65k
                    }
667
32.6k
                } else {
668
0
                    if (pos4 >= dictIdx) {
669
                        /* extDict match candidate */
670
0
                        const BYTE* const matchPtr = dictStart + (pos4 - dictIdx);
671
0
                        const size_t safeLen = MIN(prefixIdx - pos4, (size_t)(matchlimit - ip));
672
0
                        matchLength = LZ4_count(ip, matchPtr, ip + safeLen);
673
0
                        if (matchLength >= MINMATCH) {
674
0
                            DEBUGLOG(7, "found match at ExtDict pos %u (len=%u)", pos4, matchLength);
675
0
                            matchDistance = ipIndex - pos4;
676
0
                            goto _lz4mid_encode_sequence;
677
0
                        }
678
0
                    }
679
0
                }
680
32.6k
        }   }
681
        /* no match found in prefix */
682
391k
        if ( (dict == usingDictCtxHc)
683
0
          && (ipIndex - gDictEndIndex < LZ4_DISTANCE_MAX - 8) ) {
684
            /* search a match into external dictionary */
685
0
            LZ4HC_match_t dMatch = searchIntoDict(ip, ipIndex,
686
0
                    matchlimit,
687
0
                    ctx->dictCtx, gDictEndIndex);
688
0
            if (dMatch.len >= MINMATCH) {
689
0
                DEBUGLOG(7, "found Dictionary match (offset=%i)", dMatch.off);
690
0
                assert(dMatch.back == 0);
691
0
                matchLength = (unsigned)dMatch.len;
692
0
                matchDistance = (unsigned)dMatch.off;
693
0
                goto _lz4mid_encode_sequence;
694
0
            }
695
0
        }
696
        /* no match found */
697
391k
        ip += 1 + ((ip-anchor) >> 9);  /* skip faster over incompressible data */
698
391k
        continue;
699
700
15.5k
_lz4mid_encode_sequence:
701
        /* catch back */
702
67.7k
        while (((ip > anchor) & ((U32)(ip-prefixPtr) > matchDistance)) && (unlikely(ip[-1] == ip[-(int)matchDistance-1]))) {
703
52.2k
            ip--;  matchLength++;
704
52.2k
        };
705
706
        /* fill table with beginning of match */
707
15.5k
        ADDPOS8(ip+1, ipIndex+1);
708
15.5k
        ADDPOS8(ip+2, ipIndex+2);
709
15.5k
        ADDPOS4(ip+1, ipIndex+1);
710
711
        /* encode */
712
15.5k
        {   BYTE* const saved_op = op;
713
            /* LZ4HC_encodeSequence always updates @op; on success, it updates @ip and @anchor */
714
15.5k
            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
715
15.5k
                    (int)matchLength, (int)matchDistance,
716
15.5k
                    limit, oend) ) {
717
1.21k
                op = saved_op;  /* restore @op value before failed LZ4HC_encodeSequence */
718
1.21k
                goto _lz4mid_dest_overflow;
719
1.21k
            }
720
15.5k
        }
721
722
        /* fill table with end of match */
723
14.2k
        {   U32 endMatchIdx = (U32)(ip-prefixPtr) + prefixIdx;
724
14.2k
            U32 pos_m2 = endMatchIdx - 2;
725
14.2k
            if (pos_m2 < ilimitIdx) {
726
13.8k
                if (likely(ip - prefixPtr > 5)) {
727
13.7k
                    ADDPOS8(ip-5, endMatchIdx - 5);
728
13.7k
                }
729
13.8k
                ADDPOS8(ip-3, endMatchIdx - 3);
730
13.8k
                ADDPOS8(ip-2, endMatchIdx - 2);
731
13.8k
                ADDPOS4(ip-2, endMatchIdx - 2);
732
13.8k
                ADDPOS4(ip-1, endMatchIdx - 1);
733
13.8k
            }
734
14.2k
        }
735
14.2k
    }
736
737
2.18k
_lz4mid_last_literals:
738
    /* Encode Last Literals */
739
2.18k
    {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */
740
2.18k
        size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;
741
2.18k
        size_t const totalSize = 1 + llAdd + lastRunSize;
742
2.18k
        if (limit == fillOutput) oend += LASTLITERALS;  /* restore correct value */
743
2.18k
        if (limit && (op + totalSize > oend)) {
744
1.12k
            if (limit == limitedOutput) return 0;  /* not enough space in @dst */
745
            /* adapt lastRunSize to fill 'dest' */
746
788
            lastRunSize  = (size_t)(oend - op) - 1 /*token*/;
747
788
            llAdd = (lastRunSize + 256 - RUN_MASK) / 256;
748
788
            lastRunSize -= llAdd;
749
788
        }
750
1.84k
        DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);
751
1.84k
        ip = anchor + lastRunSize;  /* can be != iend if limit==fillOutput */
752
753
1.84k
        if (lastRunSize >= RUN_MASK) {
754
133
            size_t accumulator = lastRunSize - RUN_MASK;
755
133
            *op++ = (RUN_MASK << ML_BITS);
756
133
            for(; accumulator >= 255 ; accumulator -= 255)
757
0
                *op++ = 255;
758
133
            *op++ = (BYTE) accumulator;
759
1.71k
        } else {
760
1.71k
            *op++ = (BYTE)(lastRunSize << ML_BITS);
761
1.71k
        }
762
1.84k
        assert(lastRunSize <= (size_t)(oend - op));
763
1.84k
        LZ4_memcpy(op, anchor, lastRunSize);
764
1.84k
        op += lastRunSize;
765
1.84k
    }
766
767
    /* End */
768
1.84k
    DEBUGLOG(5, "compressed %i bytes into %i bytes", *srcSizePtr, (int)((char*)op - dst));
769
1.84k
    assert(ip >= (const BYTE*)src);
770
1.84k
    assert(ip <= iend);
771
1.84k
    *srcSizePtr = (int)(ip - (const BYTE*)src);
772
1.84k
    assert((char*)op >= dst);
773
1.84k
    assert(op <= oend);
774
1.84k
    assert((char*)op - dst < INT_MAX);
775
1.84k
    return (int)((char*)op - dst);
776
777
1.21k
_lz4mid_dest_overflow:
778
1.21k
    if (limit == fillOutput) {
779
        /* Assumption : @ip, @anchor, @optr and @matchLength must be set correctly */
780
765
        size_t const ll = (size_t)(ip - anchor);
781
765
        size_t const ll_addbytes = (ll + 240) / 255;
782
765
        size_t const ll_totalCost = 1 + ll_addbytes + ll;
783
765
        BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */
784
765
        DEBUGLOG(6, "Last sequence is overflowing : %u literals, %u remaining space",
785
765
                (unsigned)ll, (unsigned)(oend-op));
786
765
        if (op + ll_totalCost <= maxLitPos) {
787
            /* ll validated; now adjust match length */
788
474
            size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));
789
474
            size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);
790
474
            assert(maxMlSize < INT_MAX);
791
474
            if ((size_t)matchLength > maxMlSize) matchLength= (unsigned)maxMlSize;
792
474
            if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + matchLength >= MFLIMIT) {
793
397
            DEBUGLOG(6, "Let's encode a last sequence (ll=%u, ml=%u)", (unsigned)ll, matchLength);
794
397
                LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
795
397
                        (int)matchLength, (int)matchDistance,
796
397
                        notLimited, oend);
797
397
        }   }
798
765
        DEBUGLOG(6, "Let's finish with a run of literals (%u bytes left)", (unsigned)(oend-op));
799
765
        goto _lz4mid_last_literals;
800
765
    }
801
    /* compression failed */
802
446
    return 0;
803
1.21k
}
804
805
806
/**************************************
807
*  HC Compression - Search
808
**************************************/
809
810
/* Update chains up to ip (excluded) */
811
LZ4_FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip)
812
132M
{
813
132M
    U16* const chainTable = hc4->chainTable;
814
132M
    U32* const hashTable  = hc4->hashTable;
815
132M
    const BYTE* const prefixPtr = hc4->prefixStart;
816
132M
    U32 const prefixIdx = hc4->dictLimit;
817
132M
    U32 const target = (U32)(ip - prefixPtr) + prefixIdx;
818
132M
    U32 idx = hc4->nextToUpdate;
819
132M
    assert(ip >= prefixPtr);
820
132M
    assert(target >= prefixIdx);
821
822
320M
    while (idx < target) {
823
187M
        U32 const h = LZ4HC_hashPtr(prefixPtr+idx-prefixIdx);
824
187M
        size_t delta = idx - hashTable[h];
825
187M
        if (delta>LZ4_DISTANCE_MAX) delta = LZ4_DISTANCE_MAX;
826
187M
        DELTANEXTU16(chainTable, idx) = (U16)delta;
827
187M
        hashTable[h] = idx;
828
187M
        idx++;
829
187M
    }
830
831
132M
    hc4->nextToUpdate = target;
832
132M
}
833
834
#if defined(_MSC_VER)
835
#  define LZ4HC_rotl32(x,r) _rotl(x,r)
836
#else
837
0
#  define LZ4HC_rotl32(x,r) ((x << r) | (x >> (32 - r)))
838
#endif
839
840
841
static U32 LZ4HC_rotatePattern(size_t const rotate, U32 const pattern)
842
0
{
843
0
    size_t const bitsToRotate = (rotate & (sizeof(pattern) - 1)) << 3;
844
0
    if (bitsToRotate == 0) return pattern;
845
0
    return LZ4HC_rotl32(pattern, (int)bitsToRotate);
846
0
}
847
848
/* LZ4HC_countPattern() :
849
 * pattern32 must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!) */
850
static unsigned
851
LZ4HC_countPattern(const BYTE* ip, const BYTE* const iEnd, U32 const pattern32)
852
1.52M
{
853
1.52M
    const BYTE* const iStart = ip;
854
1.52M
    reg_t const pattern = (sizeof(pattern)==8) ?
855
1.52M
        (reg_t)pattern32 + (((reg_t)pattern32) << (sizeof(pattern)*4)) : pattern32;
856
857
25.0M
    while (likely(ip < iEnd-(sizeof(pattern)-1))) {
858
25.0M
        reg_t const diff = LZ4_read_ARCH(ip) ^ pattern;
859
25.0M
        if (!diff) { ip+=sizeof(pattern); continue; }
860
1.50M
        ip += LZ4_NbCommonBytes(diff);
861
1.50M
        return (unsigned)(ip - iStart);
862
25.0M
    }
863
864
15.1k
    if (LZ4_isLittleEndian()) {
865
15.1k
        reg_t patternByte = pattern;
866
57.7k
        while ((ip<iEnd) && (*ip == (BYTE)patternByte)) {
867
42.6k
            ip++; patternByte >>= 8;
868
42.6k
        }
869
15.1k
    } else {  /* big endian */
870
0
        U32 bitOffset = (sizeof(pattern)*8) - 8;
871
0
        while (ip < iEnd) {
872
0
            BYTE const byte = (BYTE)(pattern >> bitOffset);
873
0
            if (*ip != byte) break;
874
0
            ip ++; bitOffset -= 8;
875
0
    }   }
876
877
15.1k
    return (unsigned)(ip - iStart);
878
1.52M
}
879
880
/* LZ4HC_reverseCountPattern() :
881
 * pattern must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!)
882
 * read using natural platform endianness */
883
static unsigned
884
LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern)
885
1.41M
{
886
1.41M
    const BYTE* const iStart = ip;
887
888
92.9M
    while (likely(ip >= iLow+4)) {
889
92.9M
        if (LZ4_read32(ip-4) != pattern) break;
890
91.5M
        ip -= 4;
891
91.5M
    }
892
1.41M
    {   const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianness */
893
3.45M
        while (likely(ip>iLow)) {
894
3.45M
            if (ip[-1] != *bytePtr) break;
895
2.06M
            ip--; bytePtr--;
896
2.06M
    }   }
897
1.41M
    return (unsigned)(iStart - ip);
898
1.41M
}
899
900
/* LZ4HC_protectDictEnd() :
901
 * Checks if the match is in the last 3 bytes of the dictionary, so reading the
902
 * 4 byte MINMATCH would overflow.
903
 * @returns true if the match index is okay.
904
 */
905
static int LZ4HC_protectDictEnd(U32 const dictLimit, U32 const matchIndex)
906
2.83M
{
907
2.83M
    return ((U32)((dictLimit - 1) - matchIndex) >= 3);
908
2.83M
}
909
910
typedef enum { rep_untested, rep_not, rep_confirmed } repeat_state_e;
911
typedef enum { favorCompressionRatio=0, favorDecompressionSpeed } HCfavor_e;
912
913
914
LZ4_FORCE_INLINE LZ4HC_match_t
915
LZ4HC_InsertAndGetWiderMatch (
916
        LZ4HC_CCtx_internal* const hc4,
917
        const BYTE* const ip,
918
        const BYTE* const iLowLimit, const BYTE* const iHighLimit,
919
        int longest,
920
        const int maxNbAttempts,
921
        const int patternAnalysis, const int chainSwap,
922
        const dictCtx_directive dict,
923
        const HCfavor_e favorDecSpeed)
924
132M
{
925
132M
    U16* const chainTable = hc4->chainTable;
926
132M
    U32* const hashTable = hc4->hashTable;
927
132M
    const LZ4HC_CCtx_internal* const dictCtx = hc4->dictCtx;
928
132M
    const BYTE* const prefixPtr = hc4->prefixStart;
929
132M
    const U32 prefixIdx = hc4->dictLimit;
930
132M
    const U32 ipIndex = (U32)(ip - prefixPtr) + prefixIdx;
931
132M
    const int withinStartDistance = (hc4->lowLimit + (LZ4_DISTANCE_MAX + 1) > ipIndex);
932
132M
    const U32 lowestMatchIndex = (withinStartDistance) ? hc4->lowLimit : ipIndex - LZ4_DISTANCE_MAX;
933
132M
    const BYTE* const dictStart = hc4->dictStart;
934
132M
    const U32 dictIdx = hc4->lowLimit;
935
132M
    const BYTE* const dictEnd = dictStart + prefixIdx - dictIdx;
936
132M
    int const lookBackLength = (int)(ip-iLowLimit);
937
132M
    int nbAttempts = maxNbAttempts;
938
132M
    U32 matchChainPos = 0;
939
132M
    U32 const pattern = LZ4_read32(ip);
940
132M
    U32 matchIndex;
941
132M
    repeat_state_e repeat = rep_untested;
942
132M
    size_t srcPatternLength = 0;
943
132M
    int offset = 0, sBack = 0;
944
945
132M
    DEBUGLOG(7, "LZ4HC_InsertAndGetWiderMatch");
946
    /* First Match */
947
132M
    LZ4HC_Insert(hc4, ip);  /* insert all prior positions up to ip (excluded) */
948
132M
    matchIndex = hashTable[LZ4HC_hashPtr(ip)];
949
132M
    DEBUGLOG(7, "First candidate match for pos %u found at index %u / %u (lowestMatchIndex)",
950
132M
                ipIndex, matchIndex, lowestMatchIndex);
951
952
365M
    while ((matchIndex>=lowestMatchIndex) && (nbAttempts>0)) {
953
233M
        int matchLength=0;
954
233M
        nbAttempts--;
955
233M
        assert(matchIndex < ipIndex);
956
233M
        if (favorDecSpeed && (ipIndex - matchIndex < 8)) {
957
            /* do nothing:
958
             * favorDecSpeed intentionally skips matches with offset < 8 */
959
233M
        } else if (matchIndex >= prefixIdx) {   /* within current Prefix */
960
233M
            const BYTE* const matchPtr = prefixPtr + (matchIndex - prefixIdx);
961
233M
            assert(matchPtr < ip);
962
233M
            assert(longest >= 1);
963
233M
            if (LZ4_read16(iLowLimit + longest - 1) == LZ4_read16(matchPtr - lookBackLength + longest - 1)) {
964
1.56M
                if (LZ4_read32(matchPtr) == pattern) {
965
1.52M
                    int const back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, prefixPtr) : 0;
966
1.52M
                    matchLength = MINMATCH + (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit);
967
1.52M
                    matchLength -= back;
968
1.52M
                    if (matchLength > longest) {
969
344k
                        longest = matchLength;
970
344k
                        offset = (int)(ipIndex - matchIndex);
971
344k
                        sBack = back;
972
344k
                        DEBUGLOG(7, "Found match of len=%i within prefix, offset=%i, back=%i", longest, offset, -back);
973
344k
                        HEX_CMP(7, ip + back, ip + back - offset, (size_t)matchLength);
974
344k
            }   }   }
975
233M
        } else {   /* lowestMatchIndex <= matchIndex < dictLimit : within Ext Dict */
976
0
            const BYTE* const matchPtr = dictStart + (matchIndex - dictIdx);
977
0
            assert(matchIndex >= dictIdx);
978
0
            if ( likely(matchIndex <= prefixIdx - 4)
979
0
              && (LZ4_read32(matchPtr) == pattern) ) {
980
0
                int back = 0;
981
0
                const BYTE* vLimit = ip + (prefixIdx - matchIndex);
982
0
                if (vLimit > iHighLimit) vLimit = iHighLimit;
983
0
                matchLength = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
984
0
                if ((ip+matchLength == vLimit) && (vLimit < iHighLimit))
985
0
                    matchLength += LZ4_count(ip+matchLength, prefixPtr, iHighLimit);
986
0
                back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictStart) : 0;
987
0
                matchLength -= back;
988
0
                if (matchLength > longest) {
989
0
                    longest = matchLength;
990
0
                    offset = (int)(ipIndex - matchIndex);
991
0
                    sBack = back;
992
0
                    DEBUGLOG(7, "Found match of len=%i within dict, offset=%i, back=%i", longest, offset, -back);
993
0
                    HEX_CMP(7, ip + back, matchPtr + back, (size_t)matchLength);
994
0
        }   }   }
995
996
233M
        if (chainSwap && matchLength==longest) {   /* better match => select a better chain */
997
210k
            assert(lookBackLength==0);   /* search forward only */
998
210k
            if (matchIndex + (U32)longest <= ipIndex) {
999
141k
                int const kTrigger = 4;
1000
141k
                U32 distanceToNextMatch = 1;
1001
141k
                int const end = longest - MINMATCH + 1;
1002
141k
                int step = 1;
1003
141k
                int accel = 1 << kTrigger;
1004
141k
                int pos;
1005
8.75M
                for (pos = 0; pos < end; pos += step) {
1006
8.61M
                    U32 const candidateDist = DELTANEXTU16(chainTable, matchIndex + (U32)pos);
1007
8.61M
                    step = (accel++ >> kTrigger);
1008
8.61M
                    if (candidateDist > distanceToNextMatch) {
1009
117k
                        distanceToNextMatch = candidateDist;
1010
117k
                        matchChainPos = (U32)pos;
1011
117k
                        accel = 1 << kTrigger;
1012
117k
                }   }
1013
141k
                if (distanceToNextMatch > 1) {
1014
108k
                    if (distanceToNextMatch > matchIndex) break;   /* avoid overflow */
1015
108k
                    matchIndex -= distanceToNextMatch;
1016
108k
                    continue;
1017
108k
        }   }   }
1018
1019
233M
        {   U32 const distNextMatch = DELTANEXTU16(chainTable, matchIndex);
1020
233M
            if (patternAnalysis && distNextMatch==1 && matchChainPos==0) {
1021
3.42M
                U32 const matchCandidateIdx = matchIndex-1;
1022
                /* may be a repeated pattern */
1023
3.42M
                if (repeat == rep_untested) {
1024
114k
                    if ( ((pattern & 0xFFFF) == (pattern >> 16))
1025
114k
                      &  ((pattern & 0xFF)   == (pattern >> 24)) ) {
1026
107k
                        DEBUGLOG(7, "Repeat pattern detected, char %02X", pattern >> 24);
1027
107k
                        repeat = rep_confirmed;
1028
107k
                        srcPatternLength = LZ4HC_countPattern(ip+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern);
1029
107k
                    } else {
1030
6.26k
                        repeat = rep_not;
1031
6.26k
                }   }
1032
3.42M
                if ( (repeat == rep_confirmed) && (matchCandidateIdx >= lowestMatchIndex)
1033
1.42M
                  && LZ4HC_protectDictEnd(prefixIdx, matchCandidateIdx) ) {
1034
1.42M
                    const int extDict = matchCandidateIdx < prefixIdx;
1035
1.42M
                    const BYTE* const matchPtr = extDict ? dictStart + (matchCandidateIdx - dictIdx) : prefixPtr + (matchCandidateIdx - prefixIdx);
1036
1.42M
                    if (LZ4_read32(matchPtr) == pattern) {  /* good candidate */
1037
1.41M
                        const BYTE* const iLimit = extDict ? dictEnd : iHighLimit;
1038
1.41M
                        size_t forwardPatternLength = LZ4HC_countPattern(matchPtr+sizeof(pattern), iLimit, pattern) + sizeof(pattern);
1039
1.41M
                        if (extDict && matchPtr + forwardPatternLength == iLimit) {
1040
0
                            U32 const rotatedPattern = LZ4HC_rotatePattern(forwardPatternLength, pattern);
1041
0
                            forwardPatternLength += LZ4HC_countPattern(prefixPtr, iHighLimit, rotatedPattern);
1042
0
                        }
1043
1.41M
                        {   const BYTE* const lowestMatchPtr = extDict ? dictStart : prefixPtr;
1044
1.41M
                            size_t backLength = LZ4HC_reverseCountPattern(matchPtr, lowestMatchPtr, pattern);
1045
1.41M
                            size_t currentSegmentLength;
1046
1.41M
                            if (!extDict
1047
1.41M
                              && matchPtr - backLength == prefixPtr
1048
25.3k
                              && dictIdx < prefixIdx) {
1049
0
                                U32 const rotatedPattern = LZ4HC_rotatePattern((U32)(-(int)backLength), pattern);
1050
0
                                backLength += LZ4HC_reverseCountPattern(dictEnd, dictStart, rotatedPattern);
1051
0
                            }
1052
                            /* Limit backLength not go further than lowestMatchIndex */
1053
1.41M
                            backLength = matchCandidateIdx - MAX(matchCandidateIdx - (U32)backLength, lowestMatchIndex);
1054
1.41M
                            assert(matchCandidateIdx - backLength >= lowestMatchIndex);
1055
1.41M
                            currentSegmentLength = backLength + forwardPatternLength;
1056
                            /* Adjust to end of pattern if the source pattern fits, otherwise the beginning of the pattern */
1057
1.41M
                            if ( (currentSegmentLength >= srcPatternLength)   /* current pattern segment large enough to contain full srcPatternLength */
1058
953k
                              && (forwardPatternLength <= srcPatternLength) ) { /* haven't reached this position yet */
1059
441k
                                U32 const newMatchIndex = matchCandidateIdx + (U32)forwardPatternLength - (U32)srcPatternLength;  /* best position, full pattern, might be followed by more match */
1060
441k
                                if (LZ4HC_protectDictEnd(prefixIdx, newMatchIndex))
1061
441k
                                    matchIndex = newMatchIndex;
1062
0
                                else {
1063
                                    /* Can only happen if started in the prefix */
1064
0
                                    assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);
1065
0
                                    matchIndex = prefixIdx;
1066
0
                                }
1067
973k
                            } else {
1068
973k
                                U32 const newMatchIndex = matchCandidateIdx - (U32)backLength;   /* farthest position in current segment, will find a match of length currentSegmentLength + maybe some back */
1069
973k
                                if (!LZ4HC_protectDictEnd(prefixIdx, newMatchIndex)) {
1070
0
                                    assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);
1071
0
                                    matchIndex = prefixIdx;
1072
973k
                                } else {
1073
973k
                                    matchIndex = newMatchIndex;
1074
973k
                                    if (lookBackLength==0) {  /* no back possible */
1075
904k
                                        size_t const maxML = MIN(currentSegmentLength, srcPatternLength);
1076
904k
                                        if ((size_t)longest < maxML) {
1077
19.0k
                                            assert(prefixPtr - prefixIdx + matchIndex != ip);
1078
19.0k
                                            if ((size_t)(ip - prefixPtr) + prefixIdx - matchIndex > LZ4_DISTANCE_MAX) break;
1079
19.0k
                                            assert(maxML < 2 GB);
1080
19.0k
                                            longest = (int)maxML;
1081
19.0k
                                            offset = (int)(ipIndex - matchIndex);
1082
19.0k
                                            assert(sBack == 0);
1083
19.0k
                                            DEBUGLOG(7, "Found repeat pattern match of len=%i, offset=%i", longest, offset);
1084
19.0k
                                        }
1085
904k
                                        {   U32 const distToNextPattern = DELTANEXTU16(chainTable, matchIndex);
1086
904k
                                            if (distToNextPattern > matchIndex) break;  /* avoid overflow */
1087
904k
                                            matchIndex -= distToNextPattern;
1088
904k
                        }   }   }   }   }
1089
1.41M
                        continue;
1090
1.41M
                }   }
1091
3.42M
        }   }   /* PA optimization */
1092
1093
        /* follow current chain */
1094
231M
        matchIndex -= DELTANEXTU16(chainTable, matchIndex + matchChainPos);
1095
1096
231M
    }  /* while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) */
1097
1098
132M
    if ( dict == usingDictCtxHc
1099
0
      && nbAttempts > 0
1100
0
      && withinStartDistance) {
1101
0
        size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit;
1102
0
        U32 dictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)];
1103
0
        assert(dictEndOffset <= 1 GB);
1104
0
        matchIndex = dictMatchIndex + lowestMatchIndex - (U32)dictEndOffset;
1105
0
        if (dictMatchIndex>0) DEBUGLOG(7, "dictEndOffset = %zu, dictMatchIndex = %u => relative matchIndex = %i", dictEndOffset, dictMatchIndex, (int)dictMatchIndex - (int)dictEndOffset);
1106
0
        while (ipIndex - matchIndex <= LZ4_DISTANCE_MAX && nbAttempts--) {
1107
0
            const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + dictMatchIndex;
1108
1109
0
            if (LZ4_read32(matchPtr) == pattern) {
1110
0
                int mlt;
1111
0
                int back = 0;
1112
0
                const BYTE* vLimit = ip + (dictEndOffset - dictMatchIndex);
1113
0
                if (vLimit > iHighLimit) vLimit = iHighLimit;
1114
0
                mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
1115
0
                back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->prefixStart) : 0;
1116
0
                mlt -= back;
1117
0
                if (mlt > longest) {
1118
0
                    longest = mlt;
1119
0
                    offset = (int)(ipIndex - matchIndex);
1120
0
                    sBack = back;
1121
0
                    DEBUGLOG(7, "found match of length %i within extDictCtx", longest);
1122
0
            }   }
1123
1124
0
            {   U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, dictMatchIndex);
1125
0
                dictMatchIndex -= nextOffset;
1126
0
                matchIndex -= nextOffset;
1127
0
    }   }   }
1128
1129
132M
    {   LZ4HC_match_t md;
1130
132M
        assert(longest >= 0);
1131
132M
        md.len = longest;
1132
132M
        md.off = offset;
1133
132M
        md.back = sBack;
1134
132M
        return md;
1135
132M
    }
1136
132M
}
1137
1138
LZ4_FORCE_INLINE LZ4HC_match_t
1139
LZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4,   /* Index table will be updated */
1140
                       const BYTE* const ip, const BYTE* const iLimit,
1141
                       const int maxNbAttempts,
1142
                       const int patternAnalysis,
1143
                       const dictCtx_directive dict)
1144
45.9M
{
1145
45.9M
    DEBUGLOG(7, "LZ4HC_InsertAndFindBestMatch");
1146
    /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),
1147
     * but this won't be the case here, as we define iLowLimit==ip,
1148
     * so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */
1149
45.9M
    return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, maxNbAttempts, patternAnalysis, 0 /*chainSwap*/, dict, favorCompressionRatio);
1150
45.9M
}
1151
1152
1153
/* preconditions:
1154
 * - *srcSizePtr within [1, LZ4_MAX_INPUT_SIZE]
1155
 * - src is valid
1156
 * - maxOutputSize >= 1
1157
 * - dst is valid
1158
 */
1159
LZ4_FORCE_INLINE int LZ4HC_compress_hashChain (
1160
    LZ4HC_CCtx_internal* const ctx,
1161
    const char* const src,
1162
    char* const dst,
1163
    int* srcSizePtr,
1164
    int const maxOutputSize,
1165
    int maxNbAttempts,
1166
    const limitedOutput_directive limit,
1167
    const dictCtx_directive dict
1168
    )
1169
6.50k
{
1170
6.50k
    const int inputSize = *srcSizePtr;
1171
6.50k
    const int patternAnalysis = (maxNbAttempts > 128);   /* levels 9+ */
1172
1173
6.50k
    const BYTE* ip = (const BYTE*)src;
1174
6.50k
    const BYTE* anchor = ip;
1175
6.50k
    const BYTE* const iend = ip + inputSize;
1176
6.50k
    const BYTE* const mflimit = iend - MFLIMIT;
1177
6.50k
    const BYTE* const matchlimit = (iend - LASTLITERALS);
1178
1179
6.50k
    BYTE* optr = (BYTE*) dst;
1180
6.50k
    BYTE* op = (BYTE*) dst;
1181
6.50k
    BYTE* oend = op + maxOutputSize;
1182
1183
6.50k
    const BYTE* start0;
1184
6.50k
    const BYTE* start2 = NULL;
1185
6.50k
    const BYTE* start3 = NULL;
1186
6.50k
    LZ4HC_match_t m0, m1, m2, m3;
1187
6.50k
    const LZ4HC_match_t nomatch = {0, 0, 0};
1188
1189
    /* init */
1190
6.50k
    DEBUGLOG(5, "LZ4HC_compress_hashChain (dict?=>%i)", dict);
1191
1192
    /* preconditions verifications */
1193
6.50k
    assert(*srcSizePtr >= 1);
1194
6.50k
    assert(src != NULL);
1195
6.50k
    assert(maxOutputSize >= 1);
1196
6.50k
    assert(dst != NULL);
1197
1198
6.50k
    *srcSizePtr = 0;
1199
6.50k
    if (limit == fillOutput) oend -= LASTLITERALS;                  /* Hack for support LZ4 format restriction */
1200
6.50k
    if (inputSize < LZ4_minLength) goto _last_literals;             /* Input too small, no compression (all literals) */
1201
1202
    /* Main Loop */
1203
45.9M
    while (ip <= mflimit) {
1204
45.9M
        m1 = LZ4HC_InsertAndFindBestMatch(ctx, ip, matchlimit, maxNbAttempts, patternAnalysis, dict);
1205
45.9M
        if (m1.len<MINMATCH) { ip++; continue; }
1206
1207
        /* saved, in case we would skip too much */
1208
31.8k
        start0 = ip; m0 = m1;
1209
1210
41.3k
_Search2:
1211
41.3k
        DEBUGLOG(7, "_Search2 (currently found match of size %i)", m1.len);
1212
41.3k
        if (ip+m1.len <= mflimit) {
1213
38.2k
            start2 = ip + m1.len - 2;
1214
38.2k
            m2 = LZ4HC_InsertAndGetWiderMatch(ctx,
1215
38.2k
                            start2, ip + 0, matchlimit, m1.len,
1216
38.2k
                            maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);
1217
38.2k
            start2 += m2.back;
1218
38.2k
        } else {
1219
3.08k
            m2 = nomatch;  /* do not search further */
1220
3.08k
        }
1221
1222
41.3k
        if (m2.len <= m1.len) { /* No better match => encode ML1 immediately */
1223
27.1k
            optr = op;
1224
27.1k
            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
1225
27.1k
                    m1.len, m1.off,
1226
27.1k
                    limit, oend) )
1227
2.09k
                goto _dest_overflow;
1228
25.0k
            continue;
1229
27.1k
        }
1230
1231
14.1k
        if (start0 < ip) {   /* first match was skipped at least once */
1232
1.90k
            if (start2 < ip + m0.len) {  /* squeezing ML1 between ML0(original ML1) and ML2 */
1233
985
                ip = start0; m1 = m0;  /* restore initial Match1 */
1234
985
        }   }
1235
1236
        /* Here, start0==ip */
1237
14.1k
        if ((start2 - ip) < 3) {  /* First Match too small : removed */
1238
7.80k
            ip = start2;
1239
7.80k
            m1 = m2;
1240
7.80k
            goto _Search2;
1241
7.80k
        }
1242
1243
8.72k
_Search3:
1244
8.72k
        if ((start2 - ip) < OPTIMAL_ML) {
1245
6.54k
            int correction;
1246
6.54k
            int new_ml = m1.len;
1247
6.54k
            if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;
1248
6.54k
            if (ip+new_ml > start2 + m2.len - MINMATCH)
1249
56
                new_ml = (int)(start2 - ip) + m2.len - MINMATCH;
1250
6.54k
            correction = new_ml - (int)(start2 - ip);
1251
6.54k
            if (correction > 0) {
1252
6.16k
                start2 += correction;
1253
6.16k
                m2.len -= correction;
1254
6.16k
            }
1255
6.54k
        }
1256
1257
8.72k
        if (start2 + m2.len <= mflimit) {
1258
8.07k
            start3 = start2 + m2.len - 3;
1259
8.07k
            m3 = LZ4HC_InsertAndGetWiderMatch(ctx,
1260
8.07k
                            start3, start2, matchlimit, m2.len,
1261
8.07k
                            maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);
1262
8.07k
            start3 += m3.back;
1263
8.07k
        } else {
1264
646
            m3 = nomatch;  /* do not search further */
1265
646
        }
1266
1267
8.72k
        if (m3.len <= m2.len) {  /* No better match => encode ML1 and ML2 */
1268
            /* ip & ref are known; Now for ml */
1269
4.27k
            if (start2 < ip+m1.len) m1.len = (int)(start2 - ip);
1270
            /* Now, encode 2 sequences */
1271
4.27k
            optr = op;
1272
4.27k
            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
1273
4.27k
                    m1.len, m1.off,
1274
4.27k
                    limit, oend) )
1275
440
                goto _dest_overflow;
1276
3.83k
            ip = start2;
1277
3.83k
            optr = op;
1278
3.83k
            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
1279
3.83k
                    m2.len, m2.off,
1280
3.83k
                    limit, oend) ) {
1281
241
                m1 = m2;
1282
241
                goto _dest_overflow;
1283
241
            }
1284
3.59k
            continue;
1285
3.83k
        }
1286
1287
4.44k
        if (start3 < ip+m1.len+3) {  /* Not enough space for match 2 : remove it */
1288
2.35k
            if (start3 >= (ip+m1.len)) {  /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */
1289
1.97k
                if (start2 < ip+m1.len) {
1290
506
                    int correction = (int)(ip+m1.len - start2);
1291
506
                    start2 += correction;
1292
506
                    m2.len -= correction;
1293
506
                    if (m2.len < MINMATCH) {
1294
18
                        start2 = start3;
1295
18
                        m2 = m3;
1296
18
                    }
1297
506
                }
1298
1299
1.97k
                optr = op;
1300
1.97k
                if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
1301
1.97k
                        m1.len, m1.off,
1302
1.97k
                        limit, oend) )
1303
310
                    goto _dest_overflow;
1304
1.66k
                ip  = start3;
1305
1.66k
                m1 = m3;
1306
1307
1.66k
                start0 = start2;
1308
1.66k
                m0 = m2;
1309
1.66k
                goto _Search2;
1310
1.97k
            }
1311
1312
378
            start2 = start3;
1313
378
            m2 = m3;
1314
378
            goto _Search3;
1315
2.35k
        }
1316
1317
        /*
1318
        * OK, now we have 3 ascending matches;
1319
        * let's write the first one ML1.
1320
        * ip & ref are known; Now decide ml.
1321
        */
1322
2.08k
        if (start2 < ip+m1.len) {
1323
926
            if ((start2 - ip) < OPTIMAL_ML) {
1324
0
                int correction;
1325
0
                if (m1.len > OPTIMAL_ML) m1.len = OPTIMAL_ML;
1326
0
                if (ip + m1.len > start2 + m2.len - MINMATCH)
1327
0
                    m1.len = (int)(start2 - ip) + m2.len - MINMATCH;
1328
0
                correction = m1.len - (int)(start2 - ip);
1329
0
                if (correction > 0) {
1330
0
                    start2 += correction;
1331
0
                    m2.len -= correction;
1332
0
                }
1333
926
            } else {
1334
926
                m1.len = (int)(start2 - ip);
1335
926
            }
1336
926
        }
1337
2.08k
        optr = op;
1338
2.08k
        if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
1339
2.08k
                m1.len, m1.off,
1340
2.08k
                limit, oend) )
1341
99
            goto _dest_overflow;
1342
1343
        /* ML2 becomes ML1 */
1344
1.98k
        ip = start2; m1 = m2;
1345
1346
        /* ML3 becomes ML2 */
1347
1.98k
        start2 = start3; m2 = m3;
1348
1349
        /* let's find a new ML3 */
1350
1.98k
        goto _Search3;
1351
2.08k
    }
1352
1353
5.22k
_last_literals:
1354
    /* Encode Last Literals */
1355
5.22k
    {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */
1356
5.22k
        size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;
1357
5.22k
        size_t const totalSize = 1 + llAdd + lastRunSize;
1358
5.22k
        if (limit == fillOutput) oend += LASTLITERALS;  /* restore correct value */
1359
5.22k
        if (limit && (op + totalSize > oend)) {
1360
2.33k
            if (limit == limitedOutput) return 0;
1361
            /* adapt lastRunSize to fill 'dest' */
1362
1.81k
            lastRunSize  = (size_t)(oend - op) - 1 /*token*/;
1363
1.81k
            llAdd = (lastRunSize + 256 - RUN_MASK) / 256;
1364
1.81k
            lastRunSize -= llAdd;
1365
1.81k
        }
1366
4.71k
        DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);
1367
4.71k
        ip = anchor + lastRunSize;  /* can be != iend if limit==fillOutput */
1368
1369
4.71k
        if (lastRunSize >= RUN_MASK) {
1370
215
            size_t accumulator = lastRunSize - RUN_MASK;
1371
215
            *op++ = (RUN_MASK << ML_BITS);
1372
215
            for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;
1373
215
            *op++ = (BYTE) accumulator;
1374
4.49k
        } else {
1375
4.49k
            *op++ = (BYTE)(lastRunSize << ML_BITS);
1376
4.49k
        }
1377
4.71k
        LZ4_memcpy(op, anchor, lastRunSize);
1378
4.71k
        op += lastRunSize;
1379
4.71k
    }
1380
1381
    /* End */
1382
0
    *srcSizePtr = (int) (((const char*)ip) - src);
1383
4.71k
    return (int) (((char*)op)-dst);
1384
1385
3.18k
_dest_overflow:
1386
3.18k
    if (limit == fillOutput) {
1387
        /* Assumption : @ip, @anchor, @optr and @m1 must be set correctly */
1388
1.90k
        size_t const ll = (size_t)(ip - anchor);
1389
1.90k
        size_t const ll_addbytes = (ll + 240) / 255;
1390
1.90k
        size_t const ll_totalCost = 1 + ll_addbytes + ll;
1391
1.90k
        BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */
1392
1.90k
        DEBUGLOG(6, "Last sequence overflowing");
1393
1.90k
        op = optr;  /* restore correct out pointer */
1394
1.90k
        if (op + ll_totalCost <= maxLitPos) {
1395
            /* ll validated; now adjust match length */
1396
1.26k
            size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));
1397
1.26k
            size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);
1398
1.26k
            assert(maxMlSize < INT_MAX); assert(m1.len >= 0);
1399
1.26k
            if ((size_t)m1.len > maxMlSize) m1.len = (int)maxMlSize;
1400
1.26k
            if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + m1.len >= MFLIMIT) {
1401
1.05k
                LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), m1.len, m1.off, notLimited, oend);
1402
1.05k
        }   }
1403
1.90k
        goto _last_literals;
1404
1.90k
    }
1405
    /* compression failed */
1406
1.28k
    return 0;
1407
3.18k
}
1408
1409
1410
static int LZ4HC_compress_optimal( LZ4HC_CCtx_internal* ctx,
1411
    const char* const source, char* dst,
1412
    int* srcSizePtr, int dstCapacity,
1413
    int const nbSearches, size_t sufficient_len,
1414
    const limitedOutput_directive limit, int const fullUpdate,
1415
    const dictCtx_directive dict,
1416
    const HCfavor_e favorDecSpeed);
1417
1418
static int
1419
LZ4HC_compress_generic_internal (
1420
            LZ4HC_CCtx_internal* const ctx,
1421
            const char* const src,
1422
            char* const dst,
1423
            int* const srcSizePtr,
1424
            int const dstCapacity,
1425
            int cLevel,
1426
            const limitedOutput_directive limit,
1427
            const dictCtx_directive dict
1428
            )
1429
16.2k
{
1430
16.2k
    DEBUGLOG(5, "LZ4HC_compress_generic_internal(src=%p, srcSize=%d, dstCapacity=%d)",
1431
16.2k
                src, *srcSizePtr, dstCapacity);
1432
1433
    /* input sanitization */
1434
16.2k
    if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0;  /* Unsupported input size (too large or negative) */
1435
16.2k
    if (dstCapacity < 1) return 0;   /* Invalid: impossible to store anything */
1436
16.2k
    assert(dst); /* since dstCapacity >= 1, dst must be valid */
1437
16.2k
    if (*srcSizePtr == 0) { *dst = 0; return 1; }
1438
16.2k
    assert(src != NULL); /* since *srcSizePtr >= 1, src must be valid */
1439
1440
16.2k
    ctx->end += *srcSizePtr;
1441
16.2k
    {   cParams_t const cParam = LZ4HC_getCLevelParams(cLevel);
1442
16.2k
        HCfavor_e const favor = ctx->favorDecSpeed ? favorDecompressionSpeed : favorCompressionRatio;
1443
16.2k
        int result;
1444
1445
16.2k
        if (cParam.strat == lz4mid) {
1446
2.62k
            result = LZ4MID_compress(ctx,
1447
2.62k
                                src, dst, srcSizePtr, dstCapacity,
1448
2.62k
                                limit, dict);
1449
13.5k
        } else if (cParam.strat == lz4hc) {
1450
6.50k
            result = LZ4HC_compress_hashChain(ctx,
1451
6.50k
                                src, dst, srcSizePtr, dstCapacity,
1452
6.50k
                                cParam.nbSearches, limit, dict);
1453
7.06k
        } else {
1454
7.06k
            assert(cParam.strat == lz4opt);
1455
7.06k
            result = LZ4HC_compress_optimal(ctx,
1456
7.06k
                                src, dst, srcSizePtr, dstCapacity,
1457
7.06k
                                cParam.nbSearches, cParam.targetLength, limit,
1458
7.06k
                                cLevel >= LZ4HC_CLEVEL_MAX,   /* ultra mode */
1459
7.06k
                                dict, favor);
1460
7.06k
        }
1461
16.2k
        if (result <= 0) ctx->dirty = 1;
1462
16.2k
        return result;
1463
16.2k
    }
1464
16.2k
}
1465
1466
static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock);
1467
1468
static int
1469
LZ4HC_compress_generic_noDictCtx (
1470
        LZ4HC_CCtx_internal* const ctx,
1471
        const char* const src,
1472
        char* const dst,
1473
        int* const srcSizePtr,
1474
        int const dstCapacity,
1475
        int cLevel,
1476
        limitedOutput_directive limit
1477
        )
1478
16.2k
{
1479
16.2k
    assert(ctx->dictCtx == NULL);
1480
16.2k
    return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, noDictCtx);
1481
16.2k
}
1482
1483
static int isStateCompatible(const LZ4HC_CCtx_internal* ctx1, const LZ4HC_CCtx_internal* ctx2)
1484
0
{
1485
0
    int const isMid1 = LZ4HC_getCLevelParams(ctx1->compressionLevel).strat == lz4mid;
1486
0
    int const isMid2 = LZ4HC_getCLevelParams(ctx2->compressionLevel).strat == lz4mid;
1487
0
    return !(isMid1 ^ isMid2);
1488
0
}
1489
1490
static int
1491
LZ4HC_compress_generic_dictCtx (
1492
        LZ4HC_CCtx_internal* const ctx,
1493
        const char* const src,
1494
        char* const dst,
1495
        int* const srcSizePtr,
1496
        int const dstCapacity,
1497
        int cLevel,
1498
        limitedOutput_directive limit
1499
        )
1500
0
{
1501
0
    const size_t position = (size_t)(ctx->end - ctx->prefixStart) + (ctx->dictLimit - ctx->lowLimit);
1502
0
    assert(ctx->dictCtx != NULL);
1503
0
    if (position >= 64 KB) {
1504
0
        ctx->dictCtx = NULL;
1505
0
        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
1506
0
    } else if (position == 0 && *srcSizePtr > 4 KB && isStateCompatible(ctx, ctx->dictCtx)) {
1507
0
        LZ4_memcpy(ctx, ctx->dictCtx, sizeof(LZ4HC_CCtx_internal));
1508
0
        LZ4HC_setExternalDict(ctx, (const BYTE *)src);
1509
0
        ctx->compressionLevel = (short)cLevel;
1510
0
        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
1511
0
    } else {
1512
0
        return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, usingDictCtxHc);
1513
0
    }
1514
0
}
1515
1516
static int
1517
LZ4HC_compress_generic (
1518
        LZ4HC_CCtx_internal* const ctx,
1519
        const char* const src,
1520
        char* const dst,
1521
        int* const srcSizePtr,
1522
        int const dstCapacity,
1523
        int cLevel,
1524
        limitedOutput_directive limit
1525
        )
1526
16.2k
{
1527
16.2k
    if (ctx->dictCtx == NULL) {
1528
16.2k
        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
1529
16.2k
    } else {
1530
0
        return LZ4HC_compress_generic_dictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
1531
0
    }
1532
16.2k
}
1533
1534
1535
8.10k
int LZ4_sizeofStateHC(void) { return (int)sizeof(LZ4_streamHC_t); }
1536
1537
static size_t LZ4_streamHC_t_alignment(void)
1538
24.3k
{
1539
24.3k
#if LZ4_ALIGN_TEST
1540
24.3k
    typedef struct { char c; LZ4_streamHC_t t; } t_a;
1541
24.3k
    return sizeof(t_a) - sizeof(LZ4_streamHC_t);
1542
#else
1543
    return 1;  /* effectively disabled */
1544
#endif
1545
24.3k
}
1546
1547
/* state is presumed correctly initialized,
1548
 * in which case its size and alignment have already been validate */
1549
int LZ4_compress_HC_extStateHC_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
1550
8.11k
{
1551
8.11k
    LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse;
1552
8.11k
    if (!LZ4_isAligned(state, LZ4_streamHC_t_alignment())) return 0;
1553
8.11k
    LZ4_resetStreamHC_fast((LZ4_streamHC_t*)state, compressionLevel);
1554
8.11k
    LZ4HC_init_internal (ctx, (const BYTE*)src);
1555
8.11k
    if (dstCapacity < LZ4_compressBound(srcSize))
1556
8.11k
        return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, limitedOutput);
1557
0
    else
1558
0
        return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, notLimited);
1559
8.11k
}
1560
1561
int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
1562
8.11k
{
1563
8.11k
    LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));
1564
8.11k
    if (ctx==NULL) return 0;   /* init failure */
1565
8.11k
    return LZ4_compress_HC_extStateHC_fastReset(state, src, dst, srcSize, dstCapacity, compressionLevel);
1566
8.11k
}
1567
1568
int LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
1569
8.11k
{
1570
8.11k
    int cSize;
1571
8.11k
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
1572
8.11k
    LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));
1573
8.11k
    if (statePtr==NULL) return 0;
1574
#else
1575
    LZ4_streamHC_t state;
1576
    LZ4_streamHC_t* const statePtr = &state;
1577
#endif
1578
8.11k
    DEBUGLOG(5, "LZ4_compress_HC")
1579
8.11k
    cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel);
1580
8.11k
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
1581
8.11k
    FREEMEM(statePtr);
1582
8.11k
#endif
1583
8.11k
    return cSize;
1584
8.11k
}
1585
1586
/* state is presumed sized correctly (>= sizeof(LZ4_streamHC_t)) */
1587
int LZ4_compress_HC_destSize(void* state, const char* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel)
1588
8.10k
{
1589
8.10k
    LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));
1590
8.10k
    if (ctx==NULL) return 0;   /* init failure */
1591
8.10k
    LZ4HC_init_internal(&ctx->internal_donotuse, (const BYTE*) source);
1592
8.10k
    LZ4_setCompressionLevel(ctx, cLevel);
1593
8.10k
    return LZ4HC_compress_generic(&ctx->internal_donotuse, source, dest, sourceSizePtr, targetDestSize, cLevel, fillOutput);
1594
8.10k
}
1595
1596
1597
1598
/**************************************
1599
*  Streaming Functions
1600
**************************************/
1601
/* allocation */
1602
#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)
1603
LZ4_streamHC_t* LZ4_createStreamHC(void)
1604
0
{
1605
0
    LZ4_streamHC_t* const state =
1606
0
        (LZ4_streamHC_t*)ALLOC_AND_ZERO(sizeof(LZ4_streamHC_t));
1607
0
    if (state == NULL) return NULL;
1608
0
    LZ4_setCompressionLevel(state, LZ4HC_CLEVEL_DEFAULT);
1609
0
    return state;
1610
0
}
1611
1612
int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr)
1613
0
{
1614
0
    DEBUGLOG(4, "LZ4_freeStreamHC(%p)", LZ4_streamHCPtr);
1615
0
    if (!LZ4_streamHCPtr) return 0;  /* support free on NULL */
1616
0
    FREEMEM(LZ4_streamHCPtr);
1617
0
    return 0;
1618
0
}
1619
#endif
1620
1621
1622
LZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size)
1623
16.2k
{
1624
16.2k
    LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)buffer;
1625
16.2k
    DEBUGLOG(4, "LZ4_initStreamHC(%p, %u)", buffer, (unsigned)size);
1626
    /* check conditions */
1627
16.2k
    if (buffer == NULL) return NULL;
1628
16.2k
    if (size < sizeof(LZ4_streamHC_t)) return NULL;
1629
16.2k
    if (!LZ4_isAligned(buffer, LZ4_streamHC_t_alignment())) return NULL;
1630
    /* init */
1631
16.2k
    { LZ4HC_CCtx_internal* const hcstate = &(LZ4_streamHCPtr->internal_donotuse);
1632
16.2k
      MEM_INIT(hcstate, 0, sizeof(*hcstate)); }
1633
16.2k
    LZ4_setCompressionLevel(LZ4_streamHCPtr, LZ4HC_CLEVEL_DEFAULT);
1634
16.2k
    return LZ4_streamHCPtr;
1635
16.2k
}
1636
1637
/* just a stub */
1638
void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
1639
0
{
1640
0
    LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
1641
0
    LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);
1642
0
}
1643
1644
void LZ4_resetStreamHC_fast (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
1645
8.11k
{
1646
8.11k
    LZ4HC_CCtx_internal* const s = &LZ4_streamHCPtr->internal_donotuse;
1647
8.11k
    DEBUGLOG(5, "LZ4_resetStreamHC_fast(%p, %d)", LZ4_streamHCPtr, compressionLevel);
1648
8.11k
    if (s->dirty) {
1649
0
        LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
1650
8.11k
    } else {
1651
8.11k
        assert(s->end >= s->prefixStart);
1652
8.11k
        s->dictLimit += (U32)(s->end - s->prefixStart);
1653
8.11k
        s->prefixStart = NULL;
1654
8.11k
        s->end = NULL;
1655
8.11k
        s->dictCtx = NULL;
1656
8.11k
    }
1657
8.11k
    LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);
1658
8.11k
}
1659
1660
void LZ4_setCompressionLevel(LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
1661
32.4k
{
1662
32.4k
    DEBUGLOG(5, "LZ4_setCompressionLevel(%p, %d)", LZ4_streamHCPtr, compressionLevel);
1663
32.4k
    if (compressionLevel < 1) compressionLevel = LZ4HC_CLEVEL_DEFAULT;
1664
32.4k
    if (compressionLevel > LZ4HC_CLEVEL_MAX) compressionLevel = LZ4HC_CLEVEL_MAX;
1665
32.4k
    LZ4_streamHCPtr->internal_donotuse.compressionLevel = (short)compressionLevel;
1666
32.4k
}
1667
1668
void LZ4_favorDecompressionSpeed(LZ4_streamHC_t* LZ4_streamHCPtr, int favor)
1669
0
{
1670
0
    LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = (favor!=0);
1671
0
}
1672
1673
/* LZ4_loadDictHC() :
1674
 * LZ4_streamHCPtr is presumed properly initialized */
1675
int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr,
1676
              const char* dictionary, int dictSize)
1677
0
{
1678
0
    LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
1679
0
    cParams_t cp;
1680
0
    DEBUGLOG(4, "LZ4_loadDictHC(ctx:%p, dict:%p, dictSize:%d, clevel=%d)", LZ4_streamHCPtr, dictionary, dictSize, ctxPtr->compressionLevel);
1681
0
    assert(dictSize >= 0);
1682
0
    assert(LZ4_streamHCPtr != NULL);
1683
0
    if (dictSize > 64 KB) {
1684
0
        dictionary += (size_t)dictSize - 64 KB;
1685
0
        dictSize = 64 KB;
1686
0
    }
1687
    /* need a full initialization, there are bad side-effects when using resetFast() */
1688
0
    {   int const cLevel = ctxPtr->compressionLevel;
1689
0
        LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
1690
0
        LZ4_setCompressionLevel(LZ4_streamHCPtr, cLevel);
1691
0
        cp = LZ4HC_getCLevelParams(cLevel);
1692
0
    }
1693
0
    LZ4HC_init_internal (ctxPtr, (const BYTE*)dictionary);
1694
0
    ctxPtr->end = (const BYTE*)dictionary + dictSize;
1695
0
    if (cp.strat == lz4mid) {
1696
0
        LZ4MID_fillHTable (ctxPtr, dictionary, (size_t)dictSize);
1697
0
    } else {
1698
0
        if (dictSize >= LZ4HC_HASHSIZE) LZ4HC_Insert (ctxPtr, ctxPtr->end-3);
1699
0
    }
1700
0
    return dictSize;
1701
0
}
1702
1703
0
void LZ4_attach_HC_dictionary(LZ4_streamHC_t *working_stream, const LZ4_streamHC_t *dictionary_stream) {
1704
0
    working_stream->internal_donotuse.dictCtx = dictionary_stream != NULL ? &(dictionary_stream->internal_donotuse) : NULL;
1705
0
}
1706
1707
/* compression */
1708
1709
static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock)
1710
0
{
1711
0
    DEBUGLOG(4, "LZ4HC_setExternalDict(%p, %p)", ctxPtr, newBlock);
1712
0
    if ( (ctxPtr->end >= ctxPtr->prefixStart + 4)
1713
0
      && (LZ4HC_getCLevelParams(ctxPtr->compressionLevel).strat != lz4mid) ) {
1714
0
        LZ4HC_Insert (ctxPtr, ctxPtr->end-3);  /* Referencing remaining dictionary content */
1715
0
    }
1716
1717
    /* Only one memory segment for extDict, so any previous extDict is lost at this stage */
1718
0
    ctxPtr->lowLimit  = ctxPtr->dictLimit;
1719
0
    ctxPtr->dictStart  = ctxPtr->prefixStart;
1720
0
    ctxPtr->dictLimit += (U32)(ctxPtr->end - ctxPtr->prefixStart);
1721
0
    ctxPtr->prefixStart = newBlock;
1722
0
    ctxPtr->end  = newBlock;
1723
0
    ctxPtr->nextToUpdate = ctxPtr->dictLimit;   /* match referencing will resume from there */
1724
1725
    /* cannot reference an extDict and a dictCtx at the same time */
1726
0
    ctxPtr->dictCtx = NULL;
1727
0
}
1728
1729
static int
1730
LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,
1731
                                 const char* src, char* dst,
1732
                                 int* srcSizePtr, int dstCapacity,
1733
                                 limitedOutput_directive limit)
1734
0
{
1735
0
    LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
1736
0
    DEBUGLOG(5, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)",
1737
0
                LZ4_streamHCPtr, src, *srcSizePtr, limit);
1738
0
    assert(ctxPtr != NULL);
1739
    /* auto-init if forgotten */
1740
0
    if (ctxPtr->prefixStart == NULL)
1741
0
        LZ4HC_init_internal (ctxPtr, (const BYTE*) src);
1742
1743
    /* Check overflow */
1744
0
    if ((size_t)(ctxPtr->end - ctxPtr->prefixStart) + ctxPtr->dictLimit > 2 GB) {
1745
0
        size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->prefixStart);
1746
0
        if (dictSize > 64 KB) dictSize = 64 KB;
1747
0
        LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize);
1748
0
    }
1749
1750
    /* Check if blocks follow each other */
1751
0
    if ((const BYTE*)src != ctxPtr->end)
1752
0
        LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src);
1753
1754
    /* Check overlapping input/dictionary space */
1755
0
    {   const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr;
1756
0
        const BYTE* const dictBegin = ctxPtr->dictStart;
1757
0
        const BYTE* const dictEnd   = ctxPtr->dictStart + (ctxPtr->dictLimit - ctxPtr->lowLimit);
1758
0
        if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) {
1759
0
            if (sourceEnd > dictEnd) sourceEnd = dictEnd;
1760
0
            ctxPtr->lowLimit += (U32)(sourceEnd - ctxPtr->dictStart);
1761
0
            ctxPtr->dictStart += (U32)(sourceEnd - ctxPtr->dictStart);
1762
            /* invalidate dictionary is it's too small */
1763
0
            if (ctxPtr->dictLimit - ctxPtr->lowLimit < LZ4HC_HASHSIZE) {
1764
0
                ctxPtr->lowLimit = ctxPtr->dictLimit;
1765
0
                ctxPtr->dictStart = ctxPtr->prefixStart;
1766
0
    }   }   }
1767
1768
0
    return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit);
1769
0
}
1770
1771
int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int srcSize, int dstCapacity)
1772
0
{
1773
0
    DEBUGLOG(5, "LZ4_compress_HC_continue");
1774
0
    if (dstCapacity < LZ4_compressBound(srcSize))
1775
0
        return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput);
1776
0
    else
1777
0
        return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, notLimited);
1778
0
}
1779
1780
int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int targetDestSize)
1781
0
{
1782
0
    return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, fillOutput);
1783
0
}
1784
1785
1786
/* LZ4_saveDictHC :
1787
 * save history content
1788
 * into a user-provided buffer
1789
 * which is then used to continue compression
1790
 */
1791
int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)
1792
0
{
1793
0
    LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse;
1794
0
    int const prefixSize = (int)(streamPtr->end - streamPtr->prefixStart);
1795
0
    DEBUGLOG(5, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize);
1796
0
    assert(prefixSize >= 0);
1797
0
    if (dictSize > 64 KB) dictSize = 64 KB;
1798
0
    if (dictSize < 4) dictSize = 0;
1799
0
    if (dictSize > prefixSize) dictSize = prefixSize;
1800
0
    if (safeBuffer == NULL) assert(dictSize == 0);
1801
0
    if (dictSize > 0)
1802
0
        LZ4_memmove(safeBuffer, streamPtr->end - dictSize, (size_t)dictSize);
1803
0
    {   U32 const endIndex = (U32)(streamPtr->end - streamPtr->prefixStart) + streamPtr->dictLimit;
1804
0
        streamPtr->end = (safeBuffer == NULL) ? NULL : (const BYTE*)safeBuffer + dictSize;
1805
0
        streamPtr->prefixStart = (const BYTE*)safeBuffer;
1806
0
        streamPtr->dictLimit = endIndex - (U32)dictSize;
1807
0
        streamPtr->lowLimit = endIndex - (U32)dictSize;
1808
0
        streamPtr->dictStart = streamPtr->prefixStart;
1809
0
        if (streamPtr->nextToUpdate < streamPtr->dictLimit)
1810
0
            streamPtr->nextToUpdate = streamPtr->dictLimit;
1811
0
    }
1812
0
    return dictSize;
1813
0
}
1814
1815
1816
/* ================================================
1817
 *  LZ4 Optimal parser (levels [LZ4HC_CLEVEL_OPT_MIN - LZ4HC_CLEVEL_MAX])
1818
 * ===============================================*/
1819
typedef struct {
1820
    int price;
1821
    int off;
1822
    int mlen;
1823
    int litlen;
1824
} LZ4HC_optimal_t;
1825
1826
/* price in bytes */
1827
LZ4_FORCE_INLINE int LZ4HC_literalsPrice(int const litlen)
1828
25.6M
{
1829
25.6M
    int price = litlen;
1830
25.6M
    assert(litlen >= 0);
1831
25.6M
    if (litlen >= (int)RUN_MASK)
1832
137k
        price += 1 + ((litlen-(int)RUN_MASK) / 255);
1833
25.6M
    return price;
1834
25.6M
}
1835
1836
/* requires mlen >= MINMATCH */
1837
LZ4_FORCE_INLINE int LZ4HC_sequencePrice(int litlen, int mlen)
1838
24.9M
{
1839
24.9M
    int price = 1 + 2 ; /* token + 16-bit offset */
1840
24.9M
    assert(litlen >= 0);
1841
24.9M
    assert(mlen >= MINMATCH);
1842
1843
24.9M
    price += LZ4HC_literalsPrice(litlen);
1844
1845
24.9M
    if (mlen >= (int)(ML_MASK+MINMATCH))
1846
24.0M
        price += 1 + ((mlen-(int)(ML_MASK+MINMATCH)) / 255);
1847
1848
24.9M
    return price;
1849
24.9M
}
1850
1851
LZ4_FORCE_INLINE LZ4HC_match_t
1852
LZ4HC_FindLongerMatch(LZ4HC_CCtx_internal* const ctx,
1853
                      const BYTE* ip, const BYTE* const iHighLimit,
1854
                      int minLen, int nbSearches,
1855
                      const dictCtx_directive dict,
1856
                      const HCfavor_e favorDecSpeed)
1857
86.4M
{
1858
86.4M
    LZ4HC_match_t const match0 = { 0 , 0, 0 };
1859
    /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),
1860
     * but this won't be the case here, as we define iLowLimit==ip,
1861
    ** so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */
1862
86.4M
    LZ4HC_match_t md = LZ4HC_InsertAndGetWiderMatch(ctx, ip, ip, iHighLimit, minLen, nbSearches, 1 /*patternAnalysis*/, 1 /*chainSwap*/, dict, favorDecSpeed);
1863
86.4M
    assert(md.back == 0);
1864
86.4M
    if (md.len <= minLen) return match0;
1865
99.3k
    if (favorDecSpeed) {
1866
0
        if ((md.len>18) & (md.len<=36)) md.len=18;   /* favor dec.speed (shortcut) */
1867
0
    }
1868
99.3k
    return md;
1869
86.4M
}
1870
1871
1872
1873
/* preconditions:
1874
 * - *srcSizePtr within [1, LZ4_MAX_INPUT_SIZE]
1875
 * - src is valid
1876
 * - maxOutputSize >= 1
1877
 * - dst is valid
1878
 */
1879
static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,
1880
                                    const char* const source,
1881
                                    char* dst,
1882
                                    int* srcSizePtr,
1883
                                    int dstCapacity,
1884
                                    int const nbSearches,
1885
                                    size_t sufficient_len,
1886
                                    const limitedOutput_directive limit,
1887
                                    int const fullUpdate,
1888
                                    const dictCtx_directive dict,
1889
                                    const HCfavor_e favorDecSpeed)
1890
7.06k
{
1891
7.06k
    int retval = 0;
1892
45.1M
#define TRAILING_LITERALS 3
1893
7.06k
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
1894
7.06k
    LZ4HC_optimal_t* const opt = (LZ4HC_optimal_t*)ALLOC(sizeof(LZ4HC_optimal_t) * (LZ4_OPT_NUM + TRAILING_LITERALS));
1895
#else
1896
    LZ4HC_optimal_t opt[LZ4_OPT_NUM + TRAILING_LITERALS];   /* ~64 KB, which can be a bit large for some stacks... */
1897
#endif
1898
1899
7.06k
    const BYTE* ip = (const BYTE*) source;
1900
7.06k
    const BYTE* anchor = ip;
1901
7.06k
    const BYTE* const iend = ip + *srcSizePtr;
1902
7.06k
    const BYTE* const mflimit = iend - MFLIMIT;
1903
7.06k
    const BYTE* const matchlimit = iend - LASTLITERALS;
1904
7.06k
    BYTE* op = (BYTE*) dst;
1905
7.06k
    BYTE* opSaved = (BYTE*) dst;
1906
7.06k
    BYTE* oend = op + dstCapacity;
1907
7.06k
    int ovml = MINMATCH;  /* overflow - last sequence */
1908
7.06k
    int ovoff = 0;
1909
1910
    /* init */
1911
7.06k
    DEBUGLOG(5, "LZ4HC_compress_optimal(dst=%p, dstCapa=%u)", dst, (unsigned)dstCapacity);
1912
7.06k
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
1913
7.06k
    if (opt == NULL) goto _return_label;
1914
7.06k
#endif
1915
1916
    /* preconditions verifications */
1917
7.06k
    assert(dstCapacity > 0);
1918
7.06k
    assert(dst != NULL);
1919
7.06k
    assert(*srcSizePtr > 0);
1920
7.06k
    assert(source != NULL);
1921
1922
7.06k
    *srcSizePtr = 0;
1923
7.06k
    if (limit == fillOutput) oend -= LASTLITERALS;   /* Hack for support LZ4 format restriction */
1924
7.06k
    if (sufficient_len >= LZ4_OPT_NUM) sufficient_len = LZ4_OPT_NUM-1;
1925
1926
    /* Main Loop */
1927
86.3M
    while (ip <= mflimit) {
1928
86.3M
         int const llen = (int)(ip - anchor);
1929
86.3M
         int best_mlen, best_off;
1930
86.3M
         int cur, last_match_pos = 0;
1931
1932
86.3M
         LZ4HC_match_t const firstMatch = LZ4HC_FindLongerMatch(ctx, ip, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);
1933
86.3M
         if (firstMatch.len==0) { ip++; continue; }
1934
1935
35.0k
         if ((size_t)firstMatch.len > sufficient_len) {
1936
             /* good enough solution : immediate encoding */
1937
4.53k
             int const firstML = firstMatch.len;
1938
4.53k
             opSaved = op;
1939
4.53k
             if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, firstMatch.off, limit, oend) ) {  /* updates ip, op and anchor */
1940
199
                 ovml = firstML;
1941
199
                 ovoff = firstMatch.off;
1942
199
                 goto _dest_overflow;
1943
199
             }
1944
4.33k
             continue;
1945
4.53k
         }
1946
1947
         /* set prices for first positions (literals) */
1948
30.5k
         {   int rPos;
1949
152k
             for (rPos = 0 ; rPos < MINMATCH ; rPos++) {
1950
122k
                 int const cost = LZ4HC_literalsPrice(llen + rPos);
1951
122k
                 opt[rPos].mlen = 1;
1952
122k
                 opt[rPos].off = 0;
1953
122k
                 opt[rPos].litlen = llen + rPos;
1954
122k
                 opt[rPos].price = cost;
1955
122k
                 DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup",
1956
122k
                             rPos, cost, opt[rPos].litlen);
1957
122k
         }   }
1958
         /* set prices using initial match */
1959
30.5k
         {   int const matchML = firstMatch.len;   /* necessarily < sufficient_len < LZ4_OPT_NUM */
1960
30.5k
             int const offset = firstMatch.off;
1961
30.5k
             int mlen;
1962
30.5k
             assert(matchML < LZ4_OPT_NUM);
1963
2.56M
             for (mlen = MINMATCH ; mlen <= matchML ; mlen++) {
1964
2.53M
                 int const cost = LZ4HC_sequencePrice(llen, mlen);
1965
2.53M
                 opt[mlen].mlen = mlen;
1966
2.53M
                 opt[mlen].off = offset;
1967
2.53M
                 opt[mlen].litlen = llen;
1968
2.53M
                 opt[mlen].price = cost;
1969
2.53M
                 DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i) -- initial setup",
1970
2.53M
                             mlen, cost, mlen);
1971
2.53M
         }   }
1972
30.5k
         last_match_pos = firstMatch.len;
1973
30.5k
         {   int addLit;
1974
122k
             for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {
1975
91.7k
                 opt[last_match_pos+addLit].mlen = 1; /* literal */
1976
91.7k
                 opt[last_match_pos+addLit].off = 0;
1977
91.7k
                 opt[last_match_pos+addLit].litlen = addLit;
1978
91.7k
                 opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);
1979
91.7k
                 DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup",
1980
91.7k
                             last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);
1981
91.7k
         }   }
1982
1983
         /* check further positions */
1984
3.75M
         for (cur = 1; cur < last_match_pos; cur++) {
1985
3.72M
             const BYTE* const curPtr = ip + cur;
1986
3.72M
             LZ4HC_match_t newMatch;
1987
1988
3.72M
             if (curPtr > mflimit) break;
1989
3.72M
             DEBUGLOG(7, "rPos:%u[%u] vs [%u]%u",
1990
3.72M
                     cur, opt[cur].price, opt[cur+1].price, cur+1);
1991
3.72M
             if (fullUpdate) {
1992
                 /* not useful to search here if next position has same (or lower) cost */
1993
3.43M
                 if ( (opt[cur+1].price <= opt[cur].price)
1994
                   /* in some cases, next position has same cost, but cost rises sharply after, so a small match would still be beneficial */
1995
3.37M
                   && (opt[cur+MINMATCH].price < opt[cur].price + 3/*min seq price*/) )
1996
3.36M
                     continue;
1997
3.43M
             } else {
1998
                 /* not useful to search here if next position has same (or lower) cost */
1999
281k
                 if (opt[cur+1].price <= opt[cur].price) continue;
2000
281k
             }
2001
2002
118k
             DEBUGLOG(7, "search at rPos:%u", cur);
2003
118k
             if (fullUpdate)
2004
78.1k
                 newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);
2005
40.4k
             else
2006
                 /* only test matches of minimum length; slightly faster, but misses a few bytes */
2007
40.4k
                 newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, last_match_pos - cur, nbSearches, dict, favorDecSpeed);
2008
118k
             if (!newMatch.len) continue;
2009
2010
64.2k
             if ( ((size_t)newMatch.len > sufficient_len)
2011
63.3k
               || (newMatch.len + cur >= LZ4_OPT_NUM) ) {
2012
                 /* immediate encoding */
2013
1.06k
                 best_mlen = newMatch.len;
2014
1.06k
                 best_off = newMatch.off;
2015
1.06k
                 last_match_pos = cur + 1;
2016
1.06k
                 goto encode;
2017
1.06k
             }
2018
2019
             /* before match : set price with literals at beginning */
2020
63.1k
             {   int const baseLitlen = opt[cur].litlen;
2021
63.1k
                 int litlen;
2022
252k
                 for (litlen = 1; litlen < MINMATCH; litlen++) {
2023
189k
                     int const price = opt[cur].price - LZ4HC_literalsPrice(baseLitlen) + LZ4HC_literalsPrice(baseLitlen+litlen);
2024
189k
                     int const pos = cur + litlen;
2025
189k
                     if (price < opt[pos].price) {
2026
0
                         opt[pos].mlen = 1; /* literal */
2027
0
                         opt[pos].off = 0;
2028
0
                         opt[pos].litlen = baseLitlen+litlen;
2029
0
                         opt[pos].price = price;
2030
0
                         DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)",
2031
0
                                     pos, price, opt[pos].litlen);
2032
0
             }   }   }
2033
2034
             /* set prices using match at position = cur */
2035
63.1k
             {   int const matchML = newMatch.len;
2036
63.1k
                 int ml = MINMATCH;
2037
2038
63.1k
                 assert(cur + newMatch.len < LZ4_OPT_NUM);
2039
22.4M
                 for ( ; ml <= matchML ; ml++) {
2040
22.3M
                     int const pos = cur + ml;
2041
22.3M
                     int const offset = newMatch.off;
2042
22.3M
                     int price;
2043
22.3M
                     int ll;
2044
22.3M
                     DEBUGLOG(7, "testing price rPos %i (last_match_pos=%i)",
2045
22.3M
                                 pos, last_match_pos);
2046
22.3M
                     if (opt[cur].mlen == 1) {
2047
6.93M
                         ll = opt[cur].litlen;
2048
6.93M
                         price = ((cur > ll) ? opt[cur - ll].price : 0)
2049
6.93M
                               + LZ4HC_sequencePrice(ll, ml);
2050
15.4M
                     } else {
2051
15.4M
                         ll = 0;
2052
15.4M
                         price = opt[cur].price + LZ4HC_sequencePrice(0, ml);
2053
15.4M
                     }
2054
2055
22.3M
                    assert((U32)favorDecSpeed <= 1);
2056
22.3M
                     if (pos > last_match_pos+TRAILING_LITERALS
2057
20.9M
                      || price <= opt[pos].price - (int)favorDecSpeed) {
2058
2.41M
                         DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i)",
2059
2.41M
                                     pos, price, ml);
2060
2.41M
                         assert(pos < LZ4_OPT_NUM);
2061
2.41M
                         if ( (ml == matchML)  /* last pos of last match */
2062
18.6k
                           && (last_match_pos < pos) )
2063
14.7k
                             last_match_pos = pos;
2064
2.41M
                         opt[pos].mlen = ml;
2065
2.41M
                         opt[pos].off = offset;
2066
2.41M
                         opt[pos].litlen = ll;
2067
2.41M
                         opt[pos].price = price;
2068
2.41M
             }   }   }
2069
             /* complete following positions with literals */
2070
63.1k
             {   int addLit;
2071
252k
                 for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {
2072
189k
                     opt[last_match_pos+addLit].mlen = 1; /* literal */
2073
189k
                     opt[last_match_pos+addLit].off = 0;
2074
189k
                     opt[last_match_pos+addLit].litlen = addLit;
2075
189k
                     opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);
2076
189k
                     DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)", last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);
2077
189k
             }   }
2078
63.1k
         }  /* for (cur = 1; cur <= last_match_pos; cur++) */
2079
2080
30.5k
         assert(last_match_pos < LZ4_OPT_NUM + TRAILING_LITERALS);
2081
29.5k
         best_mlen = opt[last_match_pos].mlen;
2082
29.5k
         best_off = opt[last_match_pos].off;
2083
29.5k
         cur = last_match_pos - best_mlen;
2084
2085
30.5k
encode: /* cur, last_match_pos, best_mlen, best_off must be set */
2086
30.5k
         assert(cur < LZ4_OPT_NUM);
2087
30.5k
         assert(last_match_pos >= 1);  /* == 1 when only one candidate */
2088
30.5k
         DEBUGLOG(6, "reverse traversal, looking for shortest path (last_match_pos=%i)", last_match_pos);
2089
30.5k
         {   int candidate_pos = cur;
2090
30.5k
             int selected_matchLength = best_mlen;
2091
30.5k
             int selected_offset = best_off;
2092
44.6k
             while (1) {  /* from end to beginning */
2093
44.6k
                 int const next_matchLength = opt[candidate_pos].mlen;  /* can be 1, means literal */
2094
44.6k
                 int const next_offset = opt[candidate_pos].off;
2095
44.6k
                 DEBUGLOG(7, "pos %i: sequence length %i", candidate_pos, selected_matchLength);
2096
44.6k
                 opt[candidate_pos].mlen = selected_matchLength;
2097
44.6k
                 opt[candidate_pos].off = selected_offset;
2098
44.6k
                 selected_matchLength = next_matchLength;
2099
44.6k
                 selected_offset = next_offset;
2100
44.6k
                 if (next_matchLength > candidate_pos) break; /* last match elected, first match to encode */
2101
44.6k
                 assert(next_matchLength > 0);  /* can be 1, means literal */
2102
14.0k
                 candidate_pos -= next_matchLength;
2103
14.0k
         }   }
2104
2105
         /* encode all recorded sequences in order */
2106
30.5k
         {   int rPos = 0;  /* relative position (to ip) */
2107
70.7k
             while (rPos < last_match_pos) {
2108
43.6k
                 int const ml = opt[rPos].mlen;
2109
43.6k
                 int const offset = opt[rPos].off;
2110
43.6k
                 if (ml == 1) { ip++; rPos++; continue; }  /* literal; note: can end up with several literals, in which case, skip them */
2111
35.8k
                 rPos += ml;
2112
35.8k
                 assert(ml >= MINMATCH);
2113
35.8k
                 assert((offset >= 1) && (offset <= LZ4_DISTANCE_MAX));
2114
35.8k
                 opSaved = op;
2115
35.8k
                 if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, offset, limit, oend) ) {  /* updates ip, op and anchor */
2116
3.43k
                     ovml = ml;
2117
3.43k
                     ovoff = offset;
2118
3.43k
                     goto _dest_overflow;
2119
3.43k
         }   }   }
2120
30.5k
     }  /* while (ip <= mflimit) */
2121
2122
5.62k
_last_literals:
2123
     /* Encode Last Literals */
2124
5.62k
     {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */
2125
5.62k
         size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;
2126
5.62k
         size_t const totalSize = 1 + llAdd + lastRunSize;
2127
5.62k
         if (limit == fillOutput) oend += LASTLITERALS;  /* restore correct value */
2128
5.62k
         if (limit && (op + totalSize > oend)) {
2129
2.53k
             if (limit == limitedOutput) { /* Check output limit */
2130
526
                retval = 0;
2131
526
                goto _return_label;
2132
526
             }
2133
             /* adapt lastRunSize to fill 'dst' */
2134
2.00k
             lastRunSize  = (size_t)(oend - op) - 1 /*token*/;
2135
2.00k
             llAdd = (lastRunSize + 256 - RUN_MASK) / 256;
2136
2.00k
             lastRunSize -= llAdd;
2137
2.00k
         }
2138
5.09k
         DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);
2139
5.09k
         ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */
2140
2141
5.09k
         if (lastRunSize >= RUN_MASK) {
2142
349
             size_t accumulator = lastRunSize - RUN_MASK;
2143
349
             *op++ = (RUN_MASK << ML_BITS);
2144
349
             for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;
2145
349
             *op++ = (BYTE) accumulator;
2146
4.74k
         } else {
2147
4.74k
             *op++ = (BYTE)(lastRunSize << ML_BITS);
2148
4.74k
         }
2149
5.09k
         LZ4_memcpy(op, anchor, lastRunSize);
2150
5.09k
         op += lastRunSize;
2151
5.09k
     }
2152
2153
     /* End */
2154
0
     *srcSizePtr = (int) (((const char*)ip) - source);
2155
5.09k
     retval = (int) ((char*)op-dst);
2156
5.09k
     goto _return_label;
2157
2158
3.63k
_dest_overflow:
2159
3.63k
if (limit == fillOutput) {
2160
     /* Assumption : ip, anchor, ovml and ovref must be set correctly */
2161
2.19k
     size_t const ll = (size_t)(ip - anchor);
2162
2.19k
     size_t const ll_addbytes = (ll + 240) / 255;
2163
2.19k
     size_t const ll_totalCost = 1 + ll_addbytes + ll;
2164
2.19k
     BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */
2165
2.19k
     DEBUGLOG(6, "Last sequence overflowing (only %i bytes remaining)", (int)(oend-1-opSaved));
2166
2.19k
     op = opSaved;  /* restore correct out pointer */
2167
2.19k
     if (op + ll_totalCost <= maxLitPos) {
2168
         /* ll validated; now adjust match length */
2169
1.34k
         size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));
2170
1.34k
         size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);
2171
1.34k
         assert(maxMlSize < INT_MAX); assert(ovml >= 0);
2172
1.34k
         if ((size_t)ovml > maxMlSize) ovml = (int)maxMlSize;
2173
1.34k
         if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ovml >= MFLIMIT) {
2174
1.08k
             DEBUGLOG(6, "Space to end : %i + ml (%i)", (int)((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1), ovml);
2175
1.08k
             DEBUGLOG(6, "Before : ip = %p, anchor = %p", ip, anchor);
2176
1.08k
             LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ovml, ovoff, notLimited, oend);
2177
1.08k
             DEBUGLOG(6, "After : ip = %p, anchor = %p", ip, anchor);
2178
1.08k
     }   }
2179
2.19k
     goto _last_literals;
2180
2.19k
}
2181
7.06k
_return_label:
2182
7.06k
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
2183
7.06k
     if (opt) FREEMEM(opt);
2184
7.06k
#endif
2185
7.06k
     return retval;
2186
3.63k
}
2187
2188
2189
/***************************************************
2190
*  Deprecated Functions
2191
***************************************************/
2192
2193
/* These functions currently generate deprecation warnings */
2194
2195
/* Wrappers for deprecated compression functions */
2196
0
int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
2197
0
int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); }
2198
0
int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
2199
0
int LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); }
2200
0
int LZ4_compressHC_withStateHC (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
2201
0
int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, maxDstSize, 0); }
2202
0
int LZ4_compressHC2_withStateHC (void* state, const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
2203
0
int LZ4_compressHC2_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, maxDstSize, cLevel); }
2204
0
int LZ4_compressHC_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, LZ4_compressBound(srcSize)); }
2205
0
int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, maxDstSize); }
2206
2207
2208
/* Deprecated streaming functions */
2209
0
int LZ4_sizeofStreamStateHC(void) { return sizeof(LZ4_streamHC_t); }
2210
2211
/* state is presumed correctly sized, aka >= sizeof(LZ4_streamHC_t)
2212
 * @return : 0 on success, !=0 if error */
2213
int LZ4_resetStreamStateHC(void* state, char* inputBuffer)
2214
0
{
2215
0
    LZ4_streamHC_t* const hc4 = LZ4_initStreamHC(state, sizeof(*hc4));
2216
0
    if (hc4 == NULL) return 1;   /* init failed */
2217
0
    LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
2218
0
    return 0;
2219
0
}
2220
2221
#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)
2222
void* LZ4_createHC (const char* inputBuffer)
2223
0
{
2224
0
    LZ4_streamHC_t* const hc4 = LZ4_createStreamHC();
2225
0
    if (hc4 == NULL) return NULL;   /* not enough memory */
2226
0
    LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
2227
0
    return hc4;
2228
0
}
2229
2230
int LZ4_freeHC (void* LZ4HC_Data)
2231
0
{
2232
0
    if (!LZ4HC_Data) return 0;  /* support free on NULL */
2233
0
    FREEMEM(LZ4HC_Data);
2234
0
    return 0;
2235
0
}
2236
#endif
2237
2238
int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)
2239
0
{
2240
0
    return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited);
2241
0
}
2242
2243
int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel)
2244
0
{
2245
0
    return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput);
2246
0
}
2247
2248
char* LZ4_slideInputBufferHC(void* LZ4HC_Data)
2249
0
{
2250
0
    LZ4HC_CCtx_internal* const s = &((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse;
2251
0
    const BYTE* const bufferStart = s->prefixStart - s->dictLimit + s->lowLimit;
2252
0
    LZ4_resetStreamHC_fast((LZ4_streamHC_t*)LZ4HC_Data, s->compressionLevel);
2253
    /* ugly conversion trick, required to evade (const char*) -> (char*) cast-qual warning :( */
2254
0
    return (char*)(uptrval)bufferStart;
2255
0
}