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
2.87M
#define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH)
77
5.62M
#define LZ4_OPT_NUM   (1<<12)
78
79
80
/*===   Macros   ===*/
81
259M
#define MIN(a,b)   ( (a) < (b) ? (a) : (b) )
82
522M
#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
397k
{
110
    /* note : clevel convention is a bit different from lz4frame,
111
     * possibly something worth revisiting for consistency */
112
397k
    if (cLevel < 1)
113
0
        cLevel = LZ4HC_CLEVEL_DEFAULT;
114
397k
    cLevel = MIN(LZ4HC_CLEVEL_MAX, cLevel);
115
397k
    return k_clTable[cLevel];
116
397k
}
117
118
119
/*===   Hashing   ===*/
120
23.2k
#define LZ4HC_HASHSIZE 4
121
1.86G
#define HASH_FUNCTION(i)      (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG))
122
1.86G
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
65.0M
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
59.6k
#define LZ4MID_HASHSIZE 8
142
102M
#define LZ4MID_HASHLOG (LZ4HC_HASH_LOG-1)
143
333k
#define LZ4MID_HASHTABLESIZE (1 << LZ4MID_HASHLOG)
144
145
37.3M
static U32 LZ4MID_hash4(U32 v) { return (v * 2654435761U) >> (32-LZ4MID_HASHLOG); }
146
37.3M
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
65.0M
static U32 LZ4MID_hash7(U64 v) { return (U32)(((v  << (64-56)) * 58295818150454627ULL) >> (64-LZ4MID_HASHLOG)) ; }
150
static U64 LZ4_readLE64(const void* memPtr);
151
65.0M
static U32 LZ4MID_hash8Ptr(const void* ptr) { return LZ4MID_hash7(LZ4_readLE64(ptr)); }
152
153
static U64 LZ4_readLE64(const void* memPtr)
154
65.0M
{
155
65.0M
    if (LZ4_isLittleEndian()) {
156
65.0M
        return LZ4_read64(memPtr);
157
65.0M
    } 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
65.0M
}
164
165
166
/*===   Count match length   ===*/
167
LZ4_FORCE_INLINE
168
unsigned LZ4HC_NbCommonBytes32(U32 val)
169
131M
{
170
131M
    assert(val != 0);
171
131M
    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
131M
    } 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
131M
}
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
159M
{
208
159M
    int back = 0;
209
159M
    int const min = (int)MAX(iMin - ip, mMin - match);
210
159M
    assert(min <= 0);
211
159M
    assert(ip >= iMin); assert((size_t)(ip-iMin) < (1U<<31));
212
159M
    assert(match >= mMin); assert((size_t)(match - mMin) < (1U<<31));
213
214
721M
    while ((back - min) > 3) {
215
693M
        U32 const v = LZ4_read32(ip + back - 4) ^ LZ4_read32(match + back - 4);
216
693M
        if (v) {
217
131M
            return (back - (int)LZ4HC_NbCommonBytes32(v));
218
561M
        } else back -= 4; /* 4-byte step */
219
693M
    }
220
    /* check remainder if any */
221
45.1M
    while ( (back > min)
222
44.1M
         && (ip[back-1] == match[back-1]) )
223
16.7M
            back--;
224
28.3M
    return back;
225
159M
}
226
227
/*===   Chain table updates   ===*/
228
6.46G
#define DELTANEXTU16(table, pos) table[(U16)(pos)]   /* faster */
229
/* Make fields passed to, and updated by LZ4HC_encodeSequence explicit */
230
22.6M
#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
68.3k
{
244
68.3k
    size_t const bufferSize = (size_t)(hc4->end - hc4->prefixStart);
245
68.3k
    size_t newStartingOffset = bufferSize + hc4->dictLimit;
246
68.3k
    DEBUGLOG(5, "LZ4HC_init_internal");
247
68.3k
    assert(newStartingOffset >= bufferSize);  /* check overflow */
248
68.3k
    if (newStartingOffset > 1 GB) {
249
0
        LZ4HC_clearTables(hc4);
250
0
        newStartingOffset = 0;
251
0
    }
252
68.3k
    newStartingOffset += 64 KB;
253
68.3k
    hc4->nextToUpdate = (U32)newStartingOffset;
254
68.3k
    hc4->prefixStart = start;
255
68.3k
    hc4->end = start;
256
68.3k
    hc4->dictStart = start;
257
68.3k
    hc4->dictLimit = (U32)newStartingOffset;
258
68.3k
    hc4->lowLimit = (U32)newStartingOffset;
259
68.3k
}
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
22.6M
{
301
67.8M
#define ip      (*_ip)
302
147M
#define op      (*_op)
303
67.8M
#define anchor  (*_anchor)
304
305
22.6M
    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
22.6M
    {   size_t litLen = (size_t)(ip - anchor);
328
22.6M
        LZ4_STATIC_ASSERT(notLimited == 0);
329
        /* Check output limit */
330
22.6M
        if (limit && ((op + (litLen / 255) + litLen + (2 + 1 + LASTLITERALS)) > oend)) {
331
0
            DEBUGLOG(6, "Not enough room to write %i literals (%i bytes remaining)",
332
0
                    (int)litLen, (int)(oend - op));
333
0
            return 1;
334
0
        }
335
22.6M
        if (litLen >= RUN_MASK) {
336
791k
            size_t len = litLen - RUN_MASK;
337
791k
            *token = (RUN_MASK << ML_BITS);
338
1.39M
            for(; len >= 255 ; len -= 255) *op++ = 255;
339
791k
            *op++ = (BYTE)len;
340
21.8M
        } else {
341
21.8M
            *token = (BYTE)(litLen << ML_BITS);
342
21.8M
        }
343
344
        /* Copy Literals */
345
22.6M
        LZ4_wildCopy8(op, anchor, op + litLen);
346
22.6M
        op += litLen;
347
22.6M
    }
348
349
    /* Encode Offset */
350
22.6M
    assert(offset <= LZ4_DISTANCE_MAX );
351
22.6M
    assert(offset > 0);
352
22.6M
    LZ4_writeLE16(op, (U16)(offset)); op += 2;
353
354
    /* Encode MatchLength */
355
22.6M
    assert(matchLength >= MINMATCH);
356
22.6M
    {   size_t mlCode = (size_t)matchLength - MINMATCH;
357
22.6M
        if (limit && (op + (mlCode / 255) + (1 + LASTLITERALS) > oend)) {
358
0
            DEBUGLOG(6, "Not enough room to write match length");
359
0
            return 1;   /* Check output limit */
360
0
        }
361
22.6M
        if (mlCode >= ML_MASK) {
362
6.77M
            *token += ML_MASK;
363
6.77M
            mlCode -= ML_MASK;
364
8.61M
            for(; mlCode >= 510 ; mlCode -= 510) { *op++ = 255; *op++ = 255; }
365
6.77M
            if (mlCode >= 255) { mlCode -= 255; *op++ = 255; }
366
6.77M
            *op++ = (BYTE)mlCode;
367
15.8M
        } else {
368
15.8M
            *token += (BYTE)(mlCode);
369
15.8M
    }   }
370
371
    /* Prepare next loop */
372
22.6M
    ip += matchLength;
373
22.6M
    anchor = ip;
374
375
22.6M
    return 0;
376
377
22.6M
#undef ip
378
22.6M
#undef op
379
22.6M
#undef anchor
380
22.6M
}
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
281k
{
450
281k
    size_t const lDictEndIndex = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit;
451
281k
    const U32* const hash4Table = dictCtx->hashTable;
452
281k
    const U32* const hash8Table = hash4Table + LZ4MID_HASHTABLESIZE;
453
281k
    DEBUGLOG(7, "LZ4MID_searchExtDict (ipIdx=%u)", ipIndex);
454
455
    /* search long match first */
456
281k
    {   U32 l8DictMatchIndex = hash8Table[LZ4MID_hash8Ptr(ip)];
457
281k
        U32 m8Index = l8DictMatchIndex + gDictEndIndex - (U32)lDictEndIndex;
458
281k
        assert(lDictEndIndex <= 1 GB);
459
281k
        if (ipIndex - m8Index <= LZ4_DISTANCE_MAX) {
460
82.2k
            const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + l8DictMatchIndex;
461
82.2k
            const size_t safeLen = MIN(lDictEndIndex - l8DictMatchIndex, (size_t)(iHighLimit - ip));
462
82.2k
            int mlt = (int)LZ4_count(ip, matchPtr, ip + safeLen);
463
82.2k
            if (mlt >= MINMATCH) {
464
6.09k
                LZ4HC_match_t md;
465
6.09k
                DEBUGLOG(7, "Found long ExtDict match of len=%u", mlt);
466
6.09k
                md.len = mlt;
467
6.09k
                md.off = (int)(ipIndex - m8Index);
468
6.09k
                md.back = 0;
469
6.09k
                return md;
470
6.09k
            }
471
82.2k
        }
472
281k
    }
473
474
    /* search for short match second */
475
275k
    {   U32 l4DictMatchIndex = hash4Table[LZ4MID_hash4Ptr(ip)];
476
275k
        U32 m4Index = l4DictMatchIndex + gDictEndIndex - (U32)lDictEndIndex;
477
275k
        if (ipIndex - m4Index <= LZ4_DISTANCE_MAX) {
478
43.0k
            const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + l4DictMatchIndex;
479
43.0k
            const size_t safeLen = MIN(lDictEndIndex - l4DictMatchIndex, (size_t)(iHighLimit - ip));
480
43.0k
            int mlt = (int)LZ4_count(ip, matchPtr, ip + safeLen);
481
43.0k
            if (mlt >= MINMATCH) {
482
4.40k
                LZ4HC_match_t md;
483
4.40k
                DEBUGLOG(7, "Found short ExtDict match of len=%u", mlt);
484
4.40k
                md.len = mlt;
485
4.40k
                md.off = (int)(ipIndex - m4Index);
486
4.40k
                md.back = 0;
487
4.40k
                return md;
488
4.40k
            }
489
43.0k
        }
490
275k
    }
491
492
    /* nothing found */
493
270k
    {   LZ4HC_match_t const md = {0, 0, 0 };
494
270k
        return md;
495
275k
    }
496
275k
}
497
498
/**************************************
499
*  Mid Compression (level 2)
500
**************************************/
501
502
LZ4_FORCE_INLINE void
503
LZ4MID_addPosition(U32* hTable, U32 hValue, U32 index)
504
100M
{
505
100M
    hTable[hValue] = index;
506
100M
}
507
508
43.8M
#define ADDPOS8(_p, _idx) LZ4MID_addPosition(hash8Table, LZ4MID_hash8Ptr(_p), _idx)
509
20.7M
#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
4.41k
{
516
4.41k
    U32* const hash4Table = cctx->hashTable;
517
4.41k
    U32* const hash8Table = hash4Table + LZ4MID_HASHTABLESIZE;
518
4.41k
    const BYTE* const prefixPtr = (const BYTE*)dict;
519
4.41k
    U32 const prefixIdx = cctx->dictLimit;
520
4.41k
    U32 const target = prefixIdx + (U32)size - LZ4MID_HASHSIZE;
521
4.41k
    U32 idx = cctx->nextToUpdate;
522
4.41k
    assert(dict == cctx->prefixStart);
523
4.41k
    DEBUGLOG(4, "LZ4MID_fillHTable (size:%zu)", size);
524
4.41k
    if (size <= LZ4MID_HASHSIZE)
525
830
        return;
526
527
6.70M
    for (; idx < target; idx += 3) {
528
6.70M
        ADDPOS4(prefixPtr+idx-prefixIdx, idx);
529
6.70M
        ADDPOS8(prefixPtr+idx+1-prefixIdx, idx+1);
530
6.70M
    }
531
532
3.58k
    idx = (size > 32 KB + LZ4MID_HASHSIZE) ? target - 32 KB : cctx->nextToUpdate;
533
13.7M
    for (; idx < target; idx += 1) {
534
13.7M
        ADDPOS8(prefixPtr+idx-prefixIdx, idx);
535
13.7M
    }
536
537
3.58k
    cctx->nextToUpdate = target;
538
3.58k
}
539
540
static LZ4MID_searchIntoDict_f select_searchDict_function(const LZ4HC_CCtx_internal* dictCtx)
541
5.06k
{
542
5.06k
    if (dictCtx == NULL) return NULL;
543
5.06k
    if (LZ4HC_getCLevelParams(dictCtx->compressionLevel).strat == lz4mid)
544
5.06k
        return LZ4MID_searchExtDict;
545
0
    return LZ4MID_searchHCDict;
546
5.06k
}
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
47.2k
{
564
47.2k
    U32* const hash4Table = ctx->hashTable;
565
47.2k
    U32* const hash8Table = hash4Table + LZ4MID_HASHTABLESIZE;
566
47.2k
    const BYTE* ip = (const BYTE*)src;
567
47.2k
    const BYTE* anchor = ip;
568
47.2k
    const BYTE* const iend = ip + *srcSizePtr;
569
47.2k
    const BYTE* const mflimit = iend - MFLIMIT;
570
47.2k
    const BYTE* const matchlimit = (iend - LASTLITERALS);
571
47.2k
    const BYTE* const ilimit = (iend - LZ4MID_HASHSIZE);
572
47.2k
    BYTE* op = (BYTE*)dst;
573
47.2k
    BYTE* oend = op + maxOutputSize;
574
575
47.2k
    const BYTE* const prefixPtr = ctx->prefixStart;
576
47.2k
    const U32 prefixIdx = ctx->dictLimit;
577
47.2k
    const U32 ilimitIdx = (U32)(ilimit - prefixPtr) + prefixIdx;
578
47.2k
    const BYTE* const dictStart = ctx->dictStart;
579
47.2k
    const U32 dictIdx = ctx->lowLimit;
580
47.2k
    const U32 gDictEndIndex = ctx->lowLimit;
581
47.2k
    const LZ4MID_searchIntoDict_f searchIntoDict = (dict == usingDictCtxHc) ? select_searchDict_function(ctx->dictCtx) : NULL;
582
47.2k
    unsigned matchLength;
583
47.2k
    unsigned matchDistance;
584
585
47.2k
    DEBUGLOG(5, "LZ4MID_compress (%i bytes)", *srcSizePtr);
586
587
    /* preconditions verifications */
588
47.2k
    if (dict == usingDictCtxHc) DEBUGLOG(5, "usingDictCtxHc");
589
47.2k
    assert(*srcSizePtr > 0);
590
47.2k
    assert(*srcSizePtr <= LZ4_MAX_INPUT_SIZE);
591
47.2k
    assert(src != NULL);
592
47.2k
    assert(maxOutputSize >= 1);
593
47.2k
    assert(dst != NULL);
594
595
47.2k
    if (limit == fillOutput) oend -= LASTLITERALS;  /* Hack for support LZ4 format restriction */
596
47.2k
    if (*srcSizePtr < LZ4_minLength)
597
20.8k
        goto _lz4mid_last_literals;  /* Input too small, no compression (all literals) */
598
599
    /* main loop */
600
19.8M
    while (ip <= mflimit) {
601
19.7M
        const U32 ipIndex = (U32)(ip - prefixPtr) + prefixIdx;
602
        /* search long match */
603
19.7M
        {   U32 const h8 = LZ4MID_hash8Ptr(ip);
604
19.7M
            U32 const pos8 = hash8Table[h8];
605
19.7M
            assert(h8 < LZ4MID_HASHTABLESIZE);
606
19.7M
            assert(pos8 < ipIndex);
607
19.7M
            LZ4MID_addPosition(hash8Table, h8, ipIndex);
608
19.7M
            if (ipIndex - pos8 <= LZ4_DISTANCE_MAX) {
609
                /* match candidate found */
610
11.9M
                if (pos8 >= prefixIdx) {
611
10.7M
                    const BYTE* const matchPtr = prefixPtr + pos8 - prefixIdx;
612
10.7M
                    assert(matchPtr < ip);
613
10.7M
                    matchLength = LZ4_count(ip, matchPtr, matchlimit);
614
10.7M
                    if (matchLength >= MINMATCH) {
615
3.25M
                        DEBUGLOG(7, "found long match at pos %u (len=%u)", pos8, matchLength);
616
3.25M
                        matchDistance = ipIndex - pos8;
617
3.25M
                        goto _lz4mid_encode_sequence;
618
3.25M
                    }
619
10.7M
                } else {
620
1.22M
                    if (pos8 >= dictIdx) {
621
                        /* extDict match candidate */
622
718k
                        const BYTE* const matchPtr = dictStart + (pos8 - dictIdx);
623
718k
                        const size_t safeLen = MIN(prefixIdx - pos8, (size_t)(matchlimit - ip));
624
718k
                        matchLength = LZ4_count(ip, matchPtr, ip + safeLen);
625
718k
                        if (matchLength >= MINMATCH) {
626
195k
                            DEBUGLOG(7, "found long match at ExtDict pos %u (len=%u)", pos8, matchLength);
627
195k
                            matchDistance = ipIndex - pos8;
628
195k
                            goto _lz4mid_encode_sequence;
629
195k
                        }
630
718k
                    }
631
1.22M
                }
632
11.9M
        }   }
633
        /* search short match */
634
16.3M
        {   U32 const h4 = LZ4MID_hash4Ptr(ip);
635
16.3M
            U32 const pos4 = hash4Table[h4];
636
16.3M
            assert(h4 < LZ4MID_HASHTABLESIZE);
637
16.3M
            assert(pos4 < ipIndex);
638
16.3M
            LZ4MID_addPosition(hash4Table, h4, ipIndex);
639
16.3M
            if (ipIndex - pos4 <= LZ4_DISTANCE_MAX) {
640
                /* match candidate found */
641
7.82M
                if (pos4 >= prefixIdx) {
642
                /* only search within prefix */
643
6.96M
                    const BYTE* const matchPtr = prefixPtr + (pos4 - prefixIdx);
644
6.96M
                    assert(matchPtr < ip);
645
6.96M
                    assert(matchPtr >= prefixPtr);
646
6.96M
                    matchLength = LZ4_count(ip, matchPtr, matchlimit);
647
6.96M
                    if (matchLength >= MINMATCH) {
648
                        /* short match found, let's just check ip+1 for longer */
649
1.15M
                        U32 const h8 = LZ4MID_hash8Ptr(ip+1);
650
1.15M
                        U32 const pos8 = hash8Table[h8];
651
1.15M
                        U32 const m2Distance = ipIndex + 1 - pos8;
652
1.15M
                        matchDistance = ipIndex - pos4;
653
1.15M
                        if ( m2Distance <= LZ4_DISTANCE_MAX
654
819k
                        && pos8 >= prefixIdx /* only search within prefix */
655
774k
                        && likely(ip < mflimit)
656
1.15M
                        ) {
657
773k
                            const BYTE* const m2Ptr = prefixPtr + (pos8 - prefixIdx);
658
773k
                            unsigned ml2 = LZ4_count(ip+1, m2Ptr, matchlimit);
659
773k
                            if (ml2 > matchLength) {
660
124k
                                LZ4MID_addPosition(hash8Table, h8, ipIndex+1);
661
124k
                                ip++;
662
124k
                                matchLength = ml2;
663
124k
                                matchDistance = m2Distance;
664
124k
                        }   }
665
1.15M
                        goto _lz4mid_encode_sequence;
666
1.15M
                    }
667
6.96M
                } else {
668
857k
                    if (pos4 >= dictIdx) {
669
                        /* extDict match candidate */
670
406k
                        const BYTE* const matchPtr = dictStart + (pos4 - dictIdx);
671
406k
                        const size_t safeLen = MIN(prefixIdx - pos4, (size_t)(matchlimit - ip));
672
406k
                        matchLength = LZ4_count(ip, matchPtr, ip + safeLen);
673
406k
                        if (matchLength >= MINMATCH) {
674
66.4k
                            DEBUGLOG(7, "found match at ExtDict pos %u (len=%u)", pos4, matchLength);
675
66.4k
                            matchDistance = ipIndex - pos4;
676
66.4k
                            goto _lz4mid_encode_sequence;
677
66.4k
                        }
678
406k
                    }
679
857k
                }
680
7.82M
        }   }
681
        /* no match found in prefix */
682
15.1M
        if ( (dict == usingDictCtxHc)
683
296k
          && (ipIndex - gDictEndIndex < LZ4_DISTANCE_MAX - 8) ) {
684
            /* search a match into external dictionary */
685
281k
            LZ4HC_match_t dMatch = searchIntoDict(ip, ipIndex,
686
281k
                    matchlimit,
687
281k
                    ctx->dictCtx, gDictEndIndex);
688
281k
            if (dMatch.len >= MINMATCH) {
689
10.5k
                DEBUGLOG(7, "found Dictionary match (offset=%i)", dMatch.off);
690
10.5k
                assert(dMatch.back == 0);
691
10.5k
                matchLength = (unsigned)dMatch.len;
692
10.5k
                matchDistance = (unsigned)dMatch.off;
693
10.5k
                goto _lz4mid_encode_sequence;
694
10.5k
            }
695
281k
        }
696
        /* no match found */
697
15.1M
        ip += 1 + ((ip-anchor) >> 9);  /* skip faster over incompressible data */
698
15.1M
        continue;
699
700
4.67M
_lz4mid_encode_sequence:
701
        /* catch back */
702
5.05M
        while (((ip > anchor) & ((U32)(ip-prefixPtr) > matchDistance)) && (unlikely(ip[-1] == ip[-(int)matchDistance-1]))) {
703
372k
            ip--;  matchLength++;
704
372k
        };
705
706
        /* fill table with beginning of match */
707
4.67M
        ADDPOS8(ip+1, ipIndex+1);
708
4.67M
        ADDPOS8(ip+2, ipIndex+2);
709
4.67M
        ADDPOS4(ip+1, ipIndex+1);
710
711
        /* encode */
712
4.67M
        {   BYTE* const saved_op = op;
713
            /* LZ4HC_encodeSequence always updates @op; on success, it updates @ip and @anchor */
714
4.67M
            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
715
4.67M
                    (int)matchLength, (int)matchDistance,
716
4.67M
                    limit, oend) ) {
717
0
                op = saved_op;  /* restore @op value before failed LZ4HC_encodeSequence */
718
0
                goto _lz4mid_dest_overflow;
719
0
            }
720
4.67M
        }
721
722
        /* fill table with end of match */
723
4.67M
        {   U32 endMatchIdx = (U32)(ip-prefixPtr) + prefixIdx;
724
4.67M
            U32 pos_m2 = endMatchIdx - 2;
725
4.67M
            if (pos_m2 < ilimitIdx) {
726
4.66M
                if (likely(ip - prefixPtr > 5)) {
727
4.66M
                    ADDPOS8(ip-5, endMatchIdx - 5);
728
4.66M
                }
729
4.66M
                ADDPOS8(ip-3, endMatchIdx - 3);
730
4.66M
                ADDPOS8(ip-2, endMatchIdx - 2);
731
4.66M
                ADDPOS4(ip-2, endMatchIdx - 2);
732
4.66M
                ADDPOS4(ip-1, endMatchIdx - 1);
733
4.66M
            }
734
4.67M
        }
735
4.67M
    }
736
737
47.2k
_lz4mid_last_literals:
738
    /* Encode Last Literals */
739
47.2k
    {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */
740
47.2k
        size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;
741
47.2k
        size_t const totalSize = 1 + llAdd + lastRunSize;
742
47.2k
        if (limit == fillOutput) oend += LASTLITERALS;  /* restore correct value */
743
47.2k
        if (limit && (op + totalSize > oend)) {
744
0
            if (limit == limitedOutput) return 0;  /* not enough space in @dst */
745
            /* adapt lastRunSize to fill 'dest' */
746
0
            lastRunSize  = (size_t)(oend - op) - 1 /*token*/;
747
0
            llAdd = (lastRunSize + 256 - RUN_MASK) / 256;
748
0
            lastRunSize -= llAdd;
749
0
        }
750
47.2k
        DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);
751
47.2k
        ip = anchor + lastRunSize;  /* can be != iend if limit==fillOutput */
752
753
47.2k
        if (lastRunSize >= RUN_MASK) {
754
4.57k
            size_t accumulator = lastRunSize - RUN_MASK;
755
4.57k
            *op++ = (RUN_MASK << ML_BITS);
756
20.1k
            for(; accumulator >= 255 ; accumulator -= 255)
757
15.6k
                *op++ = 255;
758
4.57k
            *op++ = (BYTE) accumulator;
759
42.6k
        } else {
760
42.6k
            *op++ = (BYTE)(lastRunSize << ML_BITS);
761
42.6k
        }
762
47.2k
        assert(lastRunSize <= (size_t)(oend - op));
763
47.2k
        LZ4_memcpy(op, anchor, lastRunSize);
764
47.2k
        op += lastRunSize;
765
47.2k
    }
766
767
    /* End */
768
47.2k
    DEBUGLOG(5, "compressed %i bytes into %i bytes", *srcSizePtr, (int)((char*)op - dst));
769
47.2k
    assert(ip >= (const BYTE*)src);
770
47.2k
    assert(ip <= iend);
771
47.2k
    *srcSizePtr = (int)(ip - (const BYTE*)src);
772
47.2k
    assert((char*)op >= dst);
773
47.2k
    assert(op <= oend);
774
47.2k
    assert((char*)op - dst < INT_MAX);
775
47.2k
    return (int)((char*)op - dst);
776
777
0
_lz4mid_dest_overflow:
778
0
    if (limit == fillOutput) {
779
        /* Assumption : @ip, @anchor, @optr and @matchLength must be set correctly */
780
0
        size_t const ll = (size_t)(ip - anchor);
781
0
        size_t const ll_addbytes = (ll + 240) / 255;
782
0
        size_t const ll_totalCost = 1 + ll_addbytes + ll;
783
0
        BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */
784
0
        DEBUGLOG(6, "Last sequence is overflowing : %u literals, %u remaining space",
785
0
                (unsigned)ll, (unsigned)(oend-op));
786
0
        if (op + ll_totalCost <= maxLitPos) {
787
            /* ll validated; now adjust match length */
788
0
            size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));
789
0
            size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);
790
0
            assert(maxMlSize < INT_MAX);
791
0
            if ((size_t)matchLength > maxMlSize) matchLength= (unsigned)maxMlSize;
792
0
            if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + matchLength >= MFLIMIT) {
793
0
            DEBUGLOG(6, "Let's encode a last sequence (ll=%u, ml=%u)", (unsigned)ll, matchLength);
794
0
                LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
795
0
                        (int)matchLength, (int)matchDistance,
796
0
                        notLimited, oend);
797
0
        }   }
798
0
        DEBUGLOG(6, "Let's finish with a run of literals (%u bytes left)", (unsigned)(oend-op));
799
0
        goto _lz4mid_last_literals;
800
0
    }
801
    /* compression failed */
802
0
    return 0;
803
0
}
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
260M
{
813
260M
    U16* const chainTable = hc4->chainTable;
814
260M
    U32* const hashTable  = hc4->hashTable;
815
260M
    const BYTE* const prefixPtr = hc4->prefixStart;
816
260M
    U32 const prefixIdx = hc4->dictLimit;
817
260M
    U32 const target = (U32)(ip - prefixPtr) + prefixIdx;
818
260M
    U32 idx = hc4->nextToUpdate;
819
260M
    assert(ip >= prefixPtr);
820
260M
    assert(target >= prefixIdx);
821
822
1.86G
    while (idx < target) {
823
1.60G
        U32 const h = LZ4HC_hashPtr(prefixPtr+idx-prefixIdx);
824
1.60G
        size_t delta = idx - hashTable[h];
825
1.60G
        if (delta>LZ4_DISTANCE_MAX) delta = LZ4_DISTANCE_MAX;
826
1.60G
        DELTANEXTU16(chainTable, idx) = (U16)delta;
827
1.60G
        hashTable[h] = idx;
828
1.60G
        idx++;
829
1.60G
    }
830
831
260M
    hc4->nextToUpdate = target;
832
260M
}
833
834
#if defined(_MSC_VER)
835
#  define LZ4HC_rotl32(x,r) _rotl(x,r)
836
#else
837
218k
#  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
293k
{
843
293k
    size_t const bitsToRotate = (rotate & (sizeof(pattern) - 1)) << 3;
844
293k
    if (bitsToRotate == 0) return pattern;
845
218k
    return LZ4HC_rotl32(pattern, (int)bitsToRotate);
846
293k
}
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
366M
{
853
366M
    const BYTE* const iStart = ip;
854
366M
    reg_t const pattern = (sizeof(pattern)==8) ?
855
366M
        (reg_t)pattern32 + (((reg_t)pattern32) << (sizeof(pattern)*4)) : pattern32;
856
857
664M
    while (likely(ip < iEnd-(sizeof(pattern)-1))) {
858
664M
        reg_t const diff = LZ4_read_ARCH(ip) ^ pattern;
859
664M
        if (!diff) { ip+=sizeof(pattern); continue; }
860
366M
        ip += LZ4_NbCommonBytes(diff);
861
366M
        return (unsigned)(ip - iStart);
862
664M
    }
863
864
227k
    if (LZ4_isLittleEndian()) {
865
227k
        reg_t patternByte = pattern;
866
758k
        while ((ip<iEnd) && (*ip == (BYTE)patternByte)) {
867
531k
            ip++; patternByte >>= 8;
868
531k
        }
869
227k
    } 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
227k
    return (unsigned)(ip - iStart);
878
366M
}
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
363M
{
886
363M
    const BYTE* const iStart = ip;
887
888
6.61G
    while (likely(ip >= iLow+4)) {
889
6.61G
        if (LZ4_read32(ip-4) != pattern) break;
890
6.25G
        ip -= 4;
891
6.25G
    }
892
363M
    {   const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianness */
893
832M
        while (likely(ip>iLow)) {
894
832M
            if (ip[-1] != *bytePtr) break;
895
469M
            ip--; bytePtr--;
896
469M
    }   }
897
363M
    return (unsigned)(iStart - ip);
898
363M
}
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
726M
{
907
726M
    return ((U32)((dictLimit - 1) - matchIndex) >= 3);
908
726M
}
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
260M
{
925
260M
    U16* const chainTable = hc4->chainTable;
926
260M
    U32* const hashTable = hc4->hashTable;
927
260M
    const LZ4HC_CCtx_internal* const dictCtx = hc4->dictCtx;
928
260M
    const BYTE* const prefixPtr = hc4->prefixStart;
929
260M
    const U32 prefixIdx = hc4->dictLimit;
930
260M
    const U32 ipIndex = (U32)(ip - prefixPtr) + prefixIdx;
931
260M
    const int withinStartDistance = (hc4->lowLimit + (LZ4_DISTANCE_MAX + 1) > ipIndex);
932
260M
    const U32 lowestMatchIndex = (withinStartDistance) ? hc4->lowLimit : ipIndex - LZ4_DISTANCE_MAX;
933
260M
    const BYTE* const dictStart = hc4->dictStart;
934
260M
    const U32 dictIdx = hc4->lowLimit;
935
260M
    const BYTE* const dictEnd = dictStart + prefixIdx - dictIdx;
936
260M
    int const lookBackLength = (int)(ip-iLowLimit);
937
260M
    int nbAttempts = maxNbAttempts;
938
260M
    U32 matchChainPos = 0;
939
260M
    U32 const pattern = LZ4_read32(ip);
940
260M
    U32 matchIndex;
941
260M
    repeat_state_e repeat = rep_untested;
942
260M
    size_t srcPatternLength = 0;
943
260M
    int offset = 0, sBack = 0;
944
945
260M
    DEBUGLOG(7, "LZ4HC_InsertAndGetWiderMatch");
946
    /* First Match */
947
260M
    LZ4HC_Insert(hc4, ip);  /* insert all prior positions up to ip (excluded) */
948
260M
    matchIndex = hashTable[LZ4HC_hashPtr(ip)];
949
260M
    DEBUGLOG(7, "First candidate match for pos %u found at index %u / %u (lowestMatchIndex)",
950
260M
                ipIndex, matchIndex, lowestMatchIndex);
951
952
2.10G
    while ((matchIndex>=lowestMatchIndex) && (nbAttempts>0)) {
953
1.84G
        int matchLength=0;
954
1.84G
        nbAttempts--;
955
1.84G
        assert(matchIndex < ipIndex);
956
1.84G
        if (favorDecSpeed && (ipIndex - matchIndex < 8)) {
957
            /* do nothing:
958
             * favorDecSpeed intentionally skips matches with offset < 8 */
959
1.84G
        } else if (matchIndex >= prefixIdx) {   /* within current Prefix */
960
1.69G
            const BYTE* const matchPtr = prefixPtr + (matchIndex - prefixIdx);
961
1.69G
            assert(matchPtr < ip);
962
1.69G
            assert(longest >= 1);
963
1.69G
            if (LZ4_read16(iLowLimit + longest - 1) == LZ4_read16(matchPtr - lookBackLength + longest - 1)) {
964
254M
                if (LZ4_read32(matchPtr) == pattern) {
965
218M
                    int const back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, prefixPtr) : 0;
966
218M
                    matchLength = MINMATCH + (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit);
967
218M
                    matchLength -= back;
968
218M
                    if (matchLength > longest) {
969
36.8M
                        longest = matchLength;
970
36.8M
                        offset = (int)(ipIndex - matchIndex);
971
36.8M
                        sBack = back;
972
36.8M
                        DEBUGLOG(7, "Found match of len=%i within prefix, offset=%i, back=%i", longest, offset, -back);
973
36.8M
                        HEX_CMP(7, ip + back, ip + back - offset, (size_t)matchLength);
974
36.8M
            }   }   }
975
1.69G
        } else {   /* lowestMatchIndex <= matchIndex < dictLimit : within Ext Dict */
976
154M
            const BYTE* const matchPtr = dictStart + (matchIndex - dictIdx);
977
154M
            assert(matchIndex >= dictIdx);
978
154M
            if ( likely(matchIndex <= prefixIdx - 4)
979
154M
              && (LZ4_read32(matchPtr) == pattern) ) {
980
102M
                int back = 0;
981
102M
                const BYTE* vLimit = ip + (prefixIdx - matchIndex);
982
102M
                if (vLimit > iHighLimit) vLimit = iHighLimit;
983
102M
                matchLength = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
984
102M
                if ((ip+matchLength == vLimit) && (vLimit < iHighLimit))
985
772k
                    matchLength += LZ4_count(ip+matchLength, prefixPtr, iHighLimit);
986
102M
                back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictStart) : 0;
987
102M
                matchLength -= back;
988
102M
                if (matchLength > longest) {
989
1.31M
                    longest = matchLength;
990
1.31M
                    offset = (int)(ipIndex - matchIndex);
991
1.31M
                    sBack = back;
992
1.31M
                    DEBUGLOG(7, "Found match of len=%i within dict, offset=%i, back=%i", longest, offset, -back);
993
1.31M
                    HEX_CMP(7, ip + back, matchPtr + back, (size_t)matchLength);
994
1.31M
        }   }   }
995
996
1.84G
        if (chainSwap && matchLength==longest) {   /* better match => select a better chain */
997
37.6M
            assert(lookBackLength==0);   /* search forward only */
998
37.6M
            if (matchIndex + (U32)longest <= ipIndex) {
999
35.8M
                int const kTrigger = 4;
1000
35.8M
                U32 distanceToNextMatch = 1;
1001
35.8M
                int const end = longest - MINMATCH + 1;
1002
35.8M
                int step = 1;
1003
35.8M
                int accel = 1 << kTrigger;
1004
35.8M
                int pos;
1005
1.33G
                for (pos = 0; pos < end; pos += step) {
1006
1.29G
                    U32 const candidateDist = DELTANEXTU16(chainTable, matchIndex + (U32)pos);
1007
1.29G
                    step = (accel++ >> kTrigger);
1008
1.29G
                    if (candidateDist > distanceToNextMatch) {
1009
32.7M
                        distanceToNextMatch = candidateDist;
1010
32.7M
                        matchChainPos = (U32)pos;
1011
32.7M
                        accel = 1 << kTrigger;
1012
32.7M
                }   }
1013
35.8M
                if (distanceToNextMatch > 1) {
1014
26.3M
                    if (distanceToNextMatch > matchIndex) break;   /* avoid overflow */
1015
26.3M
                    matchIndex -= distanceToNextMatch;
1016
26.3M
                    continue;
1017
26.3M
        }   }   }
1018
1019
1.81G
        {   U32 const distNextMatch = DELTANEXTU16(chainTable, matchIndex);
1020
1.81G
            if (patternAnalysis && distNextMatch==1 && matchChainPos==0) {
1021
374M
                U32 const matchCandidateIdx = matchIndex-1;
1022
                /* may be a repeated pattern */
1023
374M
                if (repeat == rep_untested) {
1024
3.22M
                    if ( ((pattern & 0xFFFF) == (pattern >> 16))
1025
3.22M
                      &  ((pattern & 0xFF)   == (pattern >> 24)) ) {
1026
3.16M
                        DEBUGLOG(7, "Repeat pattern detected, char %02X", pattern >> 24);
1027
3.16M
                        repeat = rep_confirmed;
1028
3.16M
                        srcPatternLength = LZ4HC_countPattern(ip+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern);
1029
3.16M
                    } else {
1030
58.4k
                        repeat = rep_not;
1031
58.4k
                }   }
1032
374M
                if ( (repeat == rep_confirmed) && (matchCandidateIdx >= lowestMatchIndex)
1033
363M
                  && LZ4HC_protectDictEnd(prefixIdx, matchCandidateIdx) ) {
1034
363M
                    const int extDict = matchCandidateIdx < prefixIdx;
1035
363M
                    const BYTE* const matchPtr = extDict ? dictStart + (matchCandidateIdx - dictIdx) : prefixPtr + (matchCandidateIdx - prefixIdx);
1036
363M
                    if (LZ4_read32(matchPtr) == pattern) {  /* good candidate */
1037
363M
                        const BYTE* const iLimit = extDict ? dictEnd : iHighLimit;
1038
363M
                        size_t forwardPatternLength = LZ4HC_countPattern(matchPtr+sizeof(pattern), iLimit, pattern) + sizeof(pattern);
1039
363M
                        if (extDict && matchPtr + forwardPatternLength == iLimit) {
1040
65.5k
                            U32 const rotatedPattern = LZ4HC_rotatePattern(forwardPatternLength, pattern);
1041
65.5k
                            forwardPatternLength += LZ4HC_countPattern(prefixPtr, iHighLimit, rotatedPattern);
1042
65.5k
                        }
1043
363M
                        {   const BYTE* const lowestMatchPtr = extDict ? dictStart : prefixPtr;
1044
363M
                            size_t backLength = LZ4HC_reverseCountPattern(matchPtr, lowestMatchPtr, pattern);
1045
363M
                            size_t currentSegmentLength;
1046
363M
                            if (!extDict
1047
326M
                              && matchPtr - backLength == prefixPtr
1048
329k
                              && dictIdx < prefixIdx) {
1049
228k
                                U32 const rotatedPattern = LZ4HC_rotatePattern((U32)(-(int)backLength), pattern);
1050
228k
                                backLength += LZ4HC_reverseCountPattern(dictEnd, dictStart, rotatedPattern);
1051
228k
                            }
1052
                            /* Limit backLength not go further than lowestMatchIndex */
1053
363M
                            backLength = matchCandidateIdx - MAX(matchCandidateIdx - (U32)backLength, lowestMatchIndex);
1054
363M
                            assert(matchCandidateIdx - backLength >= lowestMatchIndex);
1055
363M
                            currentSegmentLength = backLength + forwardPatternLength;
1056
                            /* Adjust to end of pattern if the source pattern fits, otherwise the beginning of the pattern */
1057
363M
                            if ( (currentSegmentLength >= srcPatternLength)   /* current pattern segment large enough to contain full srcPatternLength */
1058
196M
                              && (forwardPatternLength <= srcPatternLength) ) { /* haven't reached this position yet */
1059
89.4M
                                U32 const newMatchIndex = matchCandidateIdx + (U32)forwardPatternLength - (U32)srcPatternLength;  /* best position, full pattern, might be followed by more match */
1060
89.4M
                                if (LZ4HC_protectDictEnd(prefixIdx, newMatchIndex))
1061
89.4M
                                    matchIndex = newMatchIndex;
1062
6.39k
                                else {
1063
                                    /* Can only happen if started in the prefix */
1064
6.39k
                                    assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);
1065
6.39k
                                    matchIndex = prefixIdx;
1066
6.39k
                                }
1067
273M
                            } else {
1068
273M
                                U32 const newMatchIndex = matchCandidateIdx - (U32)backLength;   /* farthest position in current segment, will find a match of length currentSegmentLength + maybe some back */
1069
273M
                                if (!LZ4HC_protectDictEnd(prefixIdx, newMatchIndex)) {
1070
16.8k
                                    assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);
1071
16.8k
                                    matchIndex = prefixIdx;
1072
273M
                                } else {
1073
273M
                                    matchIndex = newMatchIndex;
1074
273M
                                    if (lookBackLength==0) {  /* no back possible */
1075
258M
                                        size_t const maxML = MIN(currentSegmentLength, srcPatternLength);
1076
258M
                                        if ((size_t)longest < maxML) {
1077
609k
                                            assert(prefixPtr - prefixIdx + matchIndex != ip);
1078
609k
                                            if ((size_t)(ip - prefixPtr) + prefixIdx - matchIndex > LZ4_DISTANCE_MAX) break;
1079
609k
                                            assert(maxML < 2 GB);
1080
609k
                                            longest = (int)maxML;
1081
609k
                                            offset = (int)(ipIndex - matchIndex);
1082
609k
                                            assert(sBack == 0);
1083
609k
                                            DEBUGLOG(7, "Found repeat pattern match of len=%i, offset=%i", longest, offset);
1084
609k
                                        }
1085
258M
                                        {   U32 const distToNextPattern = DELTANEXTU16(chainTable, matchIndex);
1086
258M
                                            if (distToNextPattern > matchIndex) break;  /* avoid overflow */
1087
258M
                                            matchIndex -= distToNextPattern;
1088
258M
                        }   }   }   }   }
1089
363M
                        continue;
1090
363M
                }   }
1091
374M
        }   }   /* PA optimization */
1092
1093
        /* follow current chain */
1094
1.45G
        matchIndex -= DELTANEXTU16(chainTable, matchIndex + matchChainPos);
1095
1096
1.45G
    }  /* while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) */
1097
1098
260M
    if ( dict == usingDictCtxHc
1099
1.56M
      && nbAttempts > 0
1100
1.54M
      && withinStartDistance) {
1101
1.36M
        size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit;
1102
1.36M
        U32 dictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)];
1103
1.36M
        assert(dictEndOffset <= 1 GB);
1104
1.36M
        matchIndex = dictMatchIndex + lowestMatchIndex - (U32)dictEndOffset;
1105
1.36M
        if (dictMatchIndex>0) DEBUGLOG(7, "dictEndOffset = %zu, dictMatchIndex = %u => relative matchIndex = %i", dictEndOffset, dictMatchIndex, (int)dictMatchIndex - (int)dictEndOffset);
1106
30.6M
        while (ipIndex - matchIndex <= LZ4_DISTANCE_MAX && nbAttempts--) {
1107
29.2M
            const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + dictMatchIndex;
1108
1109
29.2M
            if (LZ4_read32(matchPtr) == pattern) {
1110
28.9M
                int mlt;
1111
28.9M
                int back = 0;
1112
28.9M
                const BYTE* vLimit = ip + (dictEndOffset - dictMatchIndex);
1113
28.9M
                if (vLimit > iHighLimit) vLimit = iHighLimit;
1114
28.9M
                mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
1115
28.9M
                back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->prefixStart) : 0;
1116
28.9M
                mlt -= back;
1117
28.9M
                if (mlt > longest) {
1118
122k
                    longest = mlt;
1119
122k
                    offset = (int)(ipIndex - matchIndex);
1120
122k
                    sBack = back;
1121
122k
                    DEBUGLOG(7, "found match of length %i within extDictCtx", longest);
1122
122k
            }   }
1123
1124
29.2M
            {   U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, dictMatchIndex);
1125
29.2M
                dictMatchIndex -= nextOffset;
1126
29.2M
                matchIndex -= nextOffset;
1127
29.2M
    }   }   }
1128
1129
260M
    {   LZ4HC_match_t md;
1130
260M
        assert(longest >= 0);
1131
260M
        md.len = longest;
1132
260M
        md.off = offset;
1133
260M
        md.back = sBack;
1134
260M
        return md;
1135
260M
    }
1136
260M
}
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
140M
{
1145
140M
    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
140M
    return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, maxNbAttempts, patternAnalysis, 0 /*chainSwap*/, dict, favorCompressionRatio);
1150
140M
}
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
121k
{
1170
121k
    const int inputSize = *srcSizePtr;
1171
121k
    const int patternAnalysis = (maxNbAttempts > 128);   /* levels 9+ */
1172
1173
121k
    const BYTE* ip = (const BYTE*)src;
1174
121k
    const BYTE* anchor = ip;
1175
121k
    const BYTE* const iend = ip + inputSize;
1176
121k
    const BYTE* const mflimit = iend - MFLIMIT;
1177
121k
    const BYTE* const matchlimit = (iend - LASTLITERALS);
1178
1179
121k
    BYTE* optr = (BYTE*) dst;
1180
121k
    BYTE* op = (BYTE*) dst;
1181
121k
    BYTE* oend = op + maxOutputSize;
1182
1183
121k
    const BYTE* start0;
1184
121k
    const BYTE* start2 = NULL;
1185
121k
    const BYTE* start3 = NULL;
1186
121k
    LZ4HC_match_t m0, m1, m2, m3;
1187
121k
    const LZ4HC_match_t nomatch = {0, 0, 0};
1188
1189
    /* init */
1190
121k
    DEBUGLOG(5, "LZ4HC_compress_hashChain (dict?=>%i)", dict);
1191
1192
    /* preconditions verifications */
1193
121k
    assert(*srcSizePtr >= 1);
1194
121k
    assert(src != NULL);
1195
121k
    assert(maxOutputSize >= 1);
1196
121k
    assert(dst != NULL);
1197
1198
121k
    *srcSizePtr = 0;
1199
121k
    if (limit == fillOutput) oend -= LASTLITERALS;                  /* Hack for support LZ4 format restriction */
1200
121k
    if (inputSize < LZ4_minLength) goto _last_literals;             /* Input too small, no compression (all literals) */
1201
1202
    /* Main Loop */
1203
140M
    while (ip <= mflimit) {
1204
140M
        m1 = LZ4HC_InsertAndFindBestMatch(ctx, ip, matchlimit, maxNbAttempts, patternAnalysis, dict);
1205
140M
        if (m1.len<MINMATCH) { ip++; continue; }
1206
1207
        /* saved, in case we would skip too much */
1208
12.9M
        start0 = ip; m0 = m1;
1209
1210
15.4M
_Search2:
1211
15.4M
        DEBUGLOG(7, "_Search2 (currently found match of size %i)", m1.len);
1212
15.4M
        if (ip+m1.len <= mflimit) {
1213
15.3M
            start2 = ip + m1.len - 2;
1214
15.3M
            m2 = LZ4HC_InsertAndGetWiderMatch(ctx,
1215
15.3M
                            start2, ip + 0, matchlimit, m1.len,
1216
15.3M
                            maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);
1217
15.3M
            start2 += m2.back;
1218
15.3M
        } else {
1219
47.7k
            m2 = nomatch;  /* do not search further */
1220
47.7k
        }
1221
1222
15.4M
        if (m2.len <= m1.len) { /* No better match => encode ML1 immediately */
1223
12.1M
            optr = op;
1224
12.1M
            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
1225
12.1M
                    m1.len, m1.off,
1226
12.1M
                    limit, oend) )
1227
0
                goto _dest_overflow;
1228
12.1M
            continue;
1229
12.1M
        }
1230
1231
3.30M
        if (start0 < ip) {   /* first match was skipped at least once */
1232
328k
            if (start2 < ip + m0.len) {  /* squeezing ML1 between ML0(original ML1) and ML2 */
1233
219k
                ip = start0; m1 = m0;  /* restore initial Match1 */
1234
219k
        }   }
1235
1236
        /* Here, start0==ip */
1237
3.30M
        if ((start2 - ip) < 3) {  /* First Match too small : removed */
1238
2.18M
            ip = start2;
1239
2.18M
            m1 = m2;
1240
2.18M
            goto _Search2;
1241
2.18M
        }
1242
1243
1.38M
_Search3:
1244
1.38M
        if ((start2 - ip) < OPTIMAL_ML) {
1245
1.19M
            int correction;
1246
1.19M
            int new_ml = m1.len;
1247
1.19M
            if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;
1248
1.19M
            if (ip+new_ml > start2 + m2.len - MINMATCH)
1249
247
                new_ml = (int)(start2 - ip) + m2.len - MINMATCH;
1250
1.19M
            correction = new_ml - (int)(start2 - ip);
1251
1.19M
            if (correction > 0) {
1252
1.10M
                start2 += correction;
1253
1.10M
                m2.len -= correction;
1254
1.10M
            }
1255
1.19M
        }
1256
1257
1.38M
        if (start2 + m2.len <= mflimit) {
1258
1.37M
            start3 = start2 + m2.len - 3;
1259
1.37M
            m3 = LZ4HC_InsertAndGetWiderMatch(ctx,
1260
1.37M
                            start3, start2, matchlimit, m2.len,
1261
1.37M
                            maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);
1262
1.37M
            start3 += m3.back;
1263
1.37M
        } else {
1264
6.18k
            m3 = nomatch;  /* do not search further */
1265
6.18k
        }
1266
1267
1.38M
        if (m3.len <= m2.len) {  /* No better match => encode ML1 and ML2 */
1268
            /* ip & ref are known; Now for ml */
1269
797k
            if (start2 < ip+m1.len) m1.len = (int)(start2 - ip);
1270
            /* Now, encode 2 sequences */
1271
797k
            optr = op;
1272
797k
            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
1273
797k
                    m1.len, m1.off,
1274
797k
                    limit, oend) )
1275
0
                goto _dest_overflow;
1276
797k
            ip = start2;
1277
797k
            optr = op;
1278
797k
            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
1279
797k
                    m2.len, m2.off,
1280
797k
                    limit, oend) ) {
1281
0
                m1 = m2;
1282
0
                goto _dest_overflow;
1283
0
            }
1284
797k
            continue;
1285
797k
        }
1286
1287
588k
        if (start3 < ip+m1.len+3) {  /* Not enough space for match 2 : remove it */
1288
363k
            if (start3 >= (ip+m1.len)) {  /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */
1289
323k
                if (start2 < ip+m1.len) {
1290
20.4k
                    int correction = (int)(ip+m1.len - start2);
1291
20.4k
                    start2 += correction;
1292
20.4k
                    m2.len -= correction;
1293
20.4k
                    if (m2.len < MINMATCH) {
1294
196
                        start2 = start3;
1295
196
                        m2 = m3;
1296
196
                    }
1297
20.4k
                }
1298
1299
323k
                optr = op;
1300
323k
                if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
1301
323k
                        m1.len, m1.off,
1302
323k
                        limit, oend) )
1303
0
                    goto _dest_overflow;
1304
323k
                ip  = start3;
1305
323k
                m1 = m3;
1306
1307
323k
                start0 = start2;
1308
323k
                m0 = m2;
1309
323k
                goto _Search2;
1310
323k
            }
1311
1312
40.6k
            start2 = start3;
1313
40.6k
            m2 = m3;
1314
40.6k
            goto _Search3;
1315
363k
        }
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
224k
        if (start2 < ip+m1.len) {
1323
65.4k
            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
65.4k
            } else {
1334
65.4k
                m1.len = (int)(start2 - ip);
1335
65.4k
            }
1336
65.4k
        }
1337
224k
        optr = op;
1338
224k
        if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
1339
224k
                m1.len, m1.off,
1340
224k
                limit, oend) )
1341
0
            goto _dest_overflow;
1342
1343
        /* ML2 becomes ML1 */
1344
224k
        ip = start2; m1 = m2;
1345
1346
        /* ML3 becomes ML2 */
1347
224k
        start2 = start3; m2 = m3;
1348
1349
        /* let's find a new ML3 */
1350
224k
        goto _Search3;
1351
224k
    }
1352
1353
121k
_last_literals:
1354
    /* Encode Last Literals */
1355
121k
    {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */
1356
121k
        size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;
1357
121k
        size_t const totalSize = 1 + llAdd + lastRunSize;
1358
121k
        if (limit == fillOutput) oend += LASTLITERALS;  /* restore correct value */
1359
121k
        if (limit && (op + totalSize > oend)) {
1360
0
            if (limit == limitedOutput) return 0;
1361
            /* adapt lastRunSize to fill 'dest' */
1362
0
            lastRunSize  = (size_t)(oend - op) - 1 /*token*/;
1363
0
            llAdd = (lastRunSize + 256 - RUN_MASK) / 256;
1364
0
            lastRunSize -= llAdd;
1365
0
        }
1366
121k
        DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);
1367
121k
        ip = anchor + lastRunSize;  /* can be != iend if limit==fillOutput */
1368
1369
121k
        if (lastRunSize >= RUN_MASK) {
1370
7.97k
            size_t accumulator = lastRunSize - RUN_MASK;
1371
7.97k
            *op++ = (RUN_MASK << ML_BITS);
1372
50.5k
            for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;
1373
7.97k
            *op++ = (BYTE) accumulator;
1374
113k
        } else {
1375
113k
            *op++ = (BYTE)(lastRunSize << ML_BITS);
1376
113k
        }
1377
121k
        LZ4_memcpy(op, anchor, lastRunSize);
1378
121k
        op += lastRunSize;
1379
121k
    }
1380
1381
    /* End */
1382
0
    *srcSizePtr = (int) (((const char*)ip) - src);
1383
121k
    return (int) (((char*)op)-dst);
1384
1385
0
_dest_overflow:
1386
0
    if (limit == fillOutput) {
1387
        /* Assumption : @ip, @anchor, @optr and @m1 must be set correctly */
1388
0
        size_t const ll = (size_t)(ip - anchor);
1389
0
        size_t const ll_addbytes = (ll + 240) / 255;
1390
0
        size_t const ll_totalCost = 1 + ll_addbytes + ll;
1391
0
        BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */
1392
0
        DEBUGLOG(6, "Last sequence overflowing");
1393
0
        op = optr;  /* restore correct out pointer */
1394
0
        if (op + ll_totalCost <= maxLitPos) {
1395
            /* ll validated; now adjust match length */
1396
0
            size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));
1397
0
            size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);
1398
0
            assert(maxMlSize < INT_MAX); assert(m1.len >= 0);
1399
0
            if ((size_t)m1.len > maxMlSize) m1.len = (int)maxMlSize;
1400
0
            if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + m1.len >= MFLIMIT) {
1401
0
                LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), m1.len, m1.off, notLimited, oend);
1402
0
        }   }
1403
0
        goto _last_literals;
1404
0
    }
1405
    /* compression failed */
1406
0
    return 0;
1407
0
}
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
308k
{
1430
308k
    DEBUGLOG(5, "LZ4HC_compress_generic_internal(src=%p, srcSize=%d, dstCapacity=%d)",
1431
308k
                src, *srcSizePtr, dstCapacity);
1432
1433
    /* input sanitization */
1434
308k
    if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0;  /* Unsupported input size (too large or negative) */
1435
308k
    if (dstCapacity < 1) return 0;   /* Invalid: impossible to store anything */
1436
308k
    assert(dst); /* since dstCapacity >= 1, dst must be valid */
1437
308k
    if (*srcSizePtr == 0) { *dst = 0; return 1; }
1438
308k
    assert(src != NULL); /* since *srcSizePtr >= 1, src must be valid */
1439
1440
264k
    ctx->end += *srcSizePtr;
1441
264k
    {   cParams_t const cParam = LZ4HC_getCLevelParams(cLevel);
1442
264k
        HCfavor_e const favor = ctx->favorDecSpeed ? favorDecompressionSpeed : favorCompressionRatio;
1443
264k
        int result;
1444
1445
264k
        if (cParam.strat == lz4mid) {
1446
47.2k
            result = LZ4MID_compress(ctx,
1447
47.2k
                                src, dst, srcSizePtr, dstCapacity,
1448
47.2k
                                limit, dict);
1449
216k
        } else if (cParam.strat == lz4hc) {
1450
121k
            result = LZ4HC_compress_hashChain(ctx,
1451
121k
                                src, dst, srcSizePtr, dstCapacity,
1452
121k
                                cParam.nbSearches, limit, dict);
1453
121k
        } else {
1454
95.8k
            assert(cParam.strat == lz4opt);
1455
95.8k
            result = LZ4HC_compress_optimal(ctx,
1456
95.8k
                                src, dst, srcSizePtr, dstCapacity,
1457
95.8k
                                cParam.nbSearches, cParam.targetLength, limit,
1458
95.8k
                                cLevel >= LZ4HC_CLEVEL_MAX,   /* ultra mode */
1459
95.8k
                                dict, favor);
1460
95.8k
        }
1461
264k
        if (result <= 0) ctx->dirty = 1;
1462
264k
        return result;
1463
264k
    }
1464
264k
}
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
279k
{
1479
279k
    assert(ctx->dictCtx == NULL);
1480
279k
    return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, noDictCtx);
1481
279k
}
1482
1483
static int isStateCompatible(const LZ4HC_CCtx_internal* ctx1, const LZ4HC_CCtx_internal* ctx2)
1484
1.59k
{
1485
1.59k
    int const isMid1 = LZ4HC_getCLevelParams(ctx1->compressionLevel).strat == lz4mid;
1486
1.59k
    int const isMid2 = LZ4HC_getCLevelParams(ctx2->compressionLevel).strat == lz4mid;
1487
1.59k
    return !(isMid1 ^ isMid2);
1488
1.59k
}
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
29.9k
{
1501
29.9k
    const size_t position = (size_t)(ctx->end - ctx->prefixStart) + (ctx->dictLimit - ctx->lowLimit);
1502
29.9k
    assert(ctx->dictCtx != NULL);
1503
29.9k
    if (position >= 64 KB) {
1504
72
        ctx->dictCtx = NULL;
1505
72
        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
1506
29.8k
    } else if (position == 0 && *srcSizePtr > 4 KB && isStateCompatible(ctx, ctx->dictCtx)) {
1507
1.59k
        LZ4_memcpy(ctx, ctx->dictCtx, sizeof(LZ4HC_CCtx_internal));
1508
1.59k
        LZ4HC_setExternalDict(ctx, (const BYTE *)src);
1509
1.59k
        ctx->compressionLevel = (short)cLevel;
1510
1.59k
        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
1511
28.2k
    } else {
1512
28.2k
        return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, usingDictCtxHc);
1513
28.2k
    }
1514
29.9k
}
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
308k
{
1527
308k
    if (ctx->dictCtx == NULL) {
1528
278k
        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
1529
278k
    } else {
1530
29.9k
        return LZ4HC_compress_generic_dictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
1531
29.9k
    }
1532
308k
}
1533
1534
1535
0
int LZ4_sizeofStateHC(void) { return (int)sizeof(LZ4_streamHC_t); }
1536
1537
static size_t LZ4_streamHC_t_alignment(void)
1538
27.6k
{
1539
27.6k
#if LZ4_ALIGN_TEST
1540
27.6k
    typedef struct { char c; LZ4_streamHC_t t; } t_a;
1541
27.6k
    return sizeof(t_a) - sizeof(LZ4_streamHC_t);
1542
#else
1543
    return 1;  /* effectively disabled */
1544
#endif
1545
27.6k
}
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
0
{
1551
0
    LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse;
1552
0
    if (!LZ4_isAligned(state, LZ4_streamHC_t_alignment())) return 0;
1553
0
    LZ4_resetStreamHC_fast((LZ4_streamHC_t*)state, compressionLevel);
1554
0
    LZ4HC_init_internal (ctx, (const BYTE*)src);
1555
0
    if (dstCapacity < LZ4_compressBound(srcSize))
1556
0
        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
0
}
1560
1561
int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
1562
0
{
1563
0
    LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));
1564
0
    if (ctx==NULL) return 0;   /* init failure */
1565
0
    return LZ4_compress_HC_extStateHC_fastReset(state, src, dst, srcSize, dstCapacity, compressionLevel);
1566
0
}
1567
1568
int LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
1569
0
{
1570
0
    int cSize;
1571
0
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
1572
0
    LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));
1573
0
    if (statePtr==NULL) return 0;
1574
#else
1575
    LZ4_streamHC_t state;
1576
    LZ4_streamHC_t* const statePtr = &state;
1577
#endif
1578
0
    DEBUGLOG(5, "LZ4_compress_HC")
1579
0
    cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel);
1580
0
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
1581
0
    FREEMEM(statePtr);
1582
0
#endif
1583
0
    return cSize;
1584
0
}
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
0
{
1589
0
    LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));
1590
0
    if (ctx==NULL) return 0;   /* init failure */
1591
0
    LZ4HC_init_internal(&ctx->internal_donotuse, (const BYTE*) source);
1592
0
    LZ4_setCompressionLevel(ctx, cLevel);
1593
0
    return LZ4HC_compress_generic(&ctx->internal_donotuse, source, dest, sourceSizePtr, targetDestSize, cLevel, fillOutput);
1594
0
}
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
27.6k
{
1605
27.6k
    LZ4_streamHC_t* const state =
1606
27.6k
        (LZ4_streamHC_t*)ALLOC_AND_ZERO(sizeof(LZ4_streamHC_t));
1607
27.6k
    if (state == NULL) return NULL;
1608
27.6k
    LZ4_setCompressionLevel(state, LZ4HC_CLEVEL_DEFAULT);
1609
27.6k
    return state;
1610
27.6k
}
1611
1612
int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr)
1613
27.6k
{
1614
27.6k
    DEBUGLOG(4, "LZ4_freeStreamHC(%p)", LZ4_streamHCPtr);
1615
27.6k
    if (!LZ4_streamHCPtr) return 0;  /* support free on NULL */
1616
27.6k
    FREEMEM(LZ4_streamHCPtr);
1617
27.6k
    return 0;
1618
27.6k
}
1619
#endif
1620
1621
1622
LZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size)
1623
27.6k
{
1624
27.6k
    LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)buffer;
1625
27.6k
    DEBUGLOG(4, "LZ4_initStreamHC(%p, %u)", buffer, (unsigned)size);
1626
    /* check conditions */
1627
27.6k
    if (buffer == NULL) return NULL;
1628
27.6k
    if (size < sizeof(LZ4_streamHC_t)) return NULL;
1629
27.6k
    if (!LZ4_isAligned(buffer, LZ4_streamHC_t_alignment())) return NULL;
1630
    /* init */
1631
27.6k
    { LZ4HC_CCtx_internal* const hcstate = &(LZ4_streamHCPtr->internal_donotuse);
1632
27.6k
      MEM_INIT(hcstate, 0, sizeof(*hcstate)); }
1633
27.6k
    LZ4_setCompressionLevel(LZ4_streamHCPtr, LZ4HC_CLEVEL_DEFAULT);
1634
27.6k
    return LZ4_streamHCPtr;
1635
27.6k
}
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
110k
{
1646
110k
    LZ4HC_CCtx_internal* const s = &LZ4_streamHCPtr->internal_donotuse;
1647
110k
    DEBUGLOG(5, "LZ4_resetStreamHC_fast(%p, %d)", LZ4_streamHCPtr, compressionLevel);
1648
110k
    if (s->dirty) {
1649
0
        LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
1650
110k
    } else {
1651
110k
        assert(s->end >= s->prefixStart);
1652
110k
        s->dictLimit += (U32)(s->end - s->prefixStart);
1653
110k
        s->prefixStart = NULL;
1654
110k
        s->end = NULL;
1655
110k
        s->dictCtx = NULL;
1656
110k
    }
1657
110k
    LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);
1658
110k
}
1659
1660
void LZ4_setCompressionLevel(LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
1661
207k
{
1662
207k
    DEBUGLOG(5, "LZ4_setCompressionLevel(%p, %d)", LZ4_streamHCPtr, compressionLevel);
1663
207k
    if (compressionLevel < 1) compressionLevel = LZ4HC_CLEVEL_DEFAULT;
1664
207k
    if (compressionLevel > LZ4HC_CLEVEL_MAX) compressionLevel = LZ4HC_CLEVEL_MAX;
1665
207k
    LZ4_streamHCPtr->internal_donotuse.compressionLevel = (short)compressionLevel;
1666
207k
}
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
27.6k
{
1678
27.6k
    LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
1679
27.6k
    cParams_t cp;
1680
27.6k
    DEBUGLOG(4, "LZ4_loadDictHC(ctx:%p, dict:%p, dictSize:%d, clevel=%d)", LZ4_streamHCPtr, dictionary, dictSize, ctxPtr->compressionLevel);
1681
27.6k
    assert(dictSize >= 0);
1682
27.6k
    assert(LZ4_streamHCPtr != NULL);
1683
27.6k
    if (dictSize > 64 KB) {
1684
740
        dictionary += (size_t)dictSize - 64 KB;
1685
740
        dictSize = 64 KB;
1686
740
    }
1687
    /* need a full initialization, there are bad side-effects when using resetFast() */
1688
27.6k
    {   int const cLevel = ctxPtr->compressionLevel;
1689
27.6k
        LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
1690
27.6k
        LZ4_setCompressionLevel(LZ4_streamHCPtr, cLevel);
1691
27.6k
        cp = LZ4HC_getCLevelParams(cLevel);
1692
27.6k
    }
1693
27.6k
    LZ4HC_init_internal (ctxPtr, (const BYTE*)dictionary);
1694
27.6k
    ctxPtr->end = (const BYTE*)dictionary + dictSize;
1695
27.6k
    if (cp.strat == lz4mid) {
1696
4.41k
        LZ4MID_fillHTable (ctxPtr, dictionary, (size_t)dictSize);
1697
23.2k
    } else {
1698
23.2k
        if (dictSize >= LZ4HC_HASHSIZE) LZ4HC_Insert (ctxPtr, ctxPtr->end-3);
1699
23.2k
    }
1700
27.6k
    return dictSize;
1701
27.6k
}
1702
1703
13.8k
void LZ4_attach_HC_dictionary(LZ4_streamHC_t *working_stream, const LZ4_streamHC_t *dictionary_stream) {
1704
13.8k
    working_stream->internal_donotuse.dictCtx = dictionary_stream != NULL ? &(dictionary_stream->internal_donotuse) : NULL;
1705
13.8k
}
1706
1707
/* compression */
1708
1709
static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock)
1710
142k
{
1711
142k
    DEBUGLOG(4, "LZ4HC_setExternalDict(%p, %p)", ctxPtr, newBlock);
1712
142k
    if ( (ctxPtr->end >= ctxPtr->prefixStart + 4)
1713
97.9k
      && (LZ4HC_getCLevelParams(ctxPtr->compressionLevel).strat != lz4mid) ) {
1714
82.0k
        LZ4HC_Insert (ctxPtr, ctxPtr->end-3);  /* Referencing remaining dictionary content */
1715
82.0k
    }
1716
1717
    /* Only one memory segment for extDict, so any previous extDict is lost at this stage */
1718
142k
    ctxPtr->lowLimit  = ctxPtr->dictLimit;
1719
142k
    ctxPtr->dictStart  = ctxPtr->prefixStart;
1720
142k
    ctxPtr->dictLimit += (U32)(ctxPtr->end - ctxPtr->prefixStart);
1721
142k
    ctxPtr->prefixStart = newBlock;
1722
142k
    ctxPtr->end  = newBlock;
1723
142k
    ctxPtr->nextToUpdate = ctxPtr->dictLimit;   /* match referencing will resume from there */
1724
1725
    /* cannot reference an extDict and a dictCtx at the same time */
1726
142k
    ctxPtr->dictCtx = NULL;
1727
142k
}
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
308k
{
1735
308k
    LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
1736
308k
    DEBUGLOG(5, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)",
1737
308k
                LZ4_streamHCPtr, src, *srcSizePtr, limit);
1738
308k
    assert(ctxPtr != NULL);
1739
    /* auto-init if forgotten */
1740
308k
    if (ctxPtr->prefixStart == NULL)
1741
40.7k
        LZ4HC_init_internal (ctxPtr, (const BYTE*) src);
1742
1743
    /* Check overflow */
1744
308k
    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
308k
    if ((const BYTE*)src != ctxPtr->end)
1752
141k
        LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src);
1753
1754
    /* Check overlapping input/dictionary space */
1755
308k
    {   const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr;
1756
308k
        const BYTE* const dictBegin = ctxPtr->dictStart;
1757
308k
        const BYTE* const dictEnd   = ctxPtr->dictStart + (ctxPtr->dictLimit - ctxPtr->lowLimit);
1758
308k
        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
308k
    return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit);
1769
308k
}
1770
1771
int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int srcSize, int dstCapacity)
1772
308k
{
1773
308k
    DEBUGLOG(5, "LZ4_compress_HC_continue");
1774
308k
    if (dstCapacity < LZ4_compressBound(srcSize))
1775
0
        return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput);
1776
308k
    else
1777
308k
        return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, notLimited);
1778
308k
}
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
629M
{
1829
629M
    int price = litlen;
1830
629M
    assert(litlen >= 0);
1831
629M
    if (litlen >= (int)RUN_MASK)
1832
9.07M
        price += 1 + ((litlen-(int)RUN_MASK) / 255);
1833
629M
    return price;
1834
629M
}
1835
1836
/* requires mlen >= MINMATCH */
1837
LZ4_FORCE_INLINE int LZ4HC_sequencePrice(int litlen, int mlen)
1838
562M
{
1839
562M
    int price = 1 + 2 ; /* token + 16-bit offset */
1840
562M
    assert(litlen >= 0);
1841
562M
    assert(mlen >= MINMATCH);
1842
1843
562M
    price += LZ4HC_literalsPrice(litlen);
1844
1845
562M
    if (mlen >= (int)(ML_MASK+MINMATCH))
1846
497M
        price += 1 + ((mlen-(int)(ML_MASK+MINMATCH)) / 255);
1847
1848
562M
    return price;
1849
562M
}
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
103M
{
1858
103M
    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
103M
    LZ4HC_match_t md = LZ4HC_InsertAndGetWiderMatch(ctx, ip, ip, iHighLimit, minLen, nbSearches, 1 /*patternAnalysis*/, 1 /*chainSwap*/, dict, favorDecSpeed);
1863
103M
    assert(md.back == 0);
1864
103M
    if (md.len <= minLen) return match0;
1865
8.11M
    if (favorDecSpeed) {
1866
0
        if ((md.len>18) & (md.len<=36)) md.len=18;   /* favor dec.speed (shortcut) */
1867
0
    }
1868
8.11M
    return md;
1869
103M
}
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
95.8k
{
1891
95.8k
    int retval = 0;
1892
1.03G
#define TRAILING_LITERALS 3
1893
95.8k
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
1894
95.8k
    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
95.8k
    const BYTE* ip = (const BYTE*) source;
1900
95.8k
    const BYTE* anchor = ip;
1901
95.8k
    const BYTE* const iend = ip + *srcSizePtr;
1902
95.8k
    const BYTE* const mflimit = iend - MFLIMIT;
1903
95.8k
    const BYTE* const matchlimit = iend - LASTLITERALS;
1904
95.8k
    BYTE* op = (BYTE*) dst;
1905
95.8k
    BYTE* opSaved = (BYTE*) dst;
1906
95.8k
    BYTE* oend = op + dstCapacity;
1907
95.8k
    int ovml = MINMATCH;  /* overflow - last sequence */
1908
95.8k
    int ovoff = 0;
1909
1910
    /* init */
1911
95.8k
    DEBUGLOG(5, "LZ4HC_compress_optimal(dst=%p, dstCapa=%u)", dst, (unsigned)dstCapacity);
1912
95.8k
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
1913
95.8k
    if (opt == NULL) goto _return_label;
1914
95.8k
#endif
1915
1916
    /* preconditions verifications */
1917
95.8k
    assert(dstCapacity > 0);
1918
95.8k
    assert(dst != NULL);
1919
95.8k
    assert(*srcSizePtr > 0);
1920
95.8k
    assert(source != NULL);
1921
1922
95.8k
    *srcSizePtr = 0;
1923
95.8k
    if (limit == fillOutput) oend -= LASTLITERALS;   /* Hack for support LZ4 format restriction */
1924
95.8k
    if (sufficient_len >= LZ4_OPT_NUM) sufficient_len = LZ4_OPT_NUM-1;
1925
1926
    /* Main Loop */
1927
92.2M
    while (ip <= mflimit) {
1928
92.1M
         int const llen = (int)(ip - anchor);
1929
92.1M
         int best_mlen, best_off;
1930
92.1M
         int cur, last_match_pos = 0;
1931
1932
92.1M
         LZ4HC_match_t const firstMatch = LZ4HC_FindLongerMatch(ctx, ip, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);
1933
92.1M
         if (firstMatch.len==0) { ip++; continue; }
1934
1935
2.59M
         if ((size_t)firstMatch.len > sufficient_len) {
1936
             /* good enough solution : immediate encoding */
1937
144k
             int const firstML = firstMatch.len;
1938
144k
             opSaved = op;
1939
144k
             if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, firstMatch.off, limit, oend) ) {  /* updates ip, op and anchor */
1940
0
                 ovml = firstML;
1941
0
                 ovoff = firstMatch.off;
1942
0
                 goto _dest_overflow;
1943
0
             }
1944
144k
             continue;
1945
144k
         }
1946
1947
         /* set prices for first positions (literals) */
1948
2.45M
         {   int rPos;
1949
12.2M
             for (rPos = 0 ; rPos < MINMATCH ; rPos++) {
1950
9.80M
                 int const cost = LZ4HC_literalsPrice(llen + rPos);
1951
9.80M
                 opt[rPos].mlen = 1;
1952
9.80M
                 opt[rPos].off = 0;
1953
9.80M
                 opt[rPos].litlen = llen + rPos;
1954
9.80M
                 opt[rPos].price = cost;
1955
9.80M
                 DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup",
1956
9.80M
                             rPos, cost, opt[rPos].litlen);
1957
9.80M
         }   }
1958
         /* set prices using initial match */
1959
2.45M
         {   int const matchML = firstMatch.len;   /* necessarily < sufficient_len < LZ4_OPT_NUM */
1960
2.45M
             int const offset = firstMatch.off;
1961
2.45M
             int mlen;
1962
2.45M
             assert(matchML < LZ4_OPT_NUM);
1963
65.9M
             for (mlen = MINMATCH ; mlen <= matchML ; mlen++) {
1964
63.4M
                 int const cost = LZ4HC_sequencePrice(llen, mlen);
1965
63.4M
                 opt[mlen].mlen = mlen;
1966
63.4M
                 opt[mlen].off = offset;
1967
63.4M
                 opt[mlen].litlen = llen;
1968
63.4M
                 opt[mlen].price = cost;
1969
63.4M
                 DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i) -- initial setup",
1970
63.4M
                             mlen, cost, mlen);
1971
63.4M
         }   }
1972
2.45M
         last_match_pos = firstMatch.len;
1973
2.45M
         {   int addLit;
1974
9.80M
             for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {
1975
7.35M
                 opt[last_match_pos+addLit].mlen = 1; /* literal */
1976
7.35M
                 opt[last_match_pos+addLit].off = 0;
1977
7.35M
                 opt[last_match_pos+addLit].litlen = addLit;
1978
7.35M
                 opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);
1979
7.35M
                 DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup",
1980
7.35M
                             last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);
1981
7.35M
         }   }
1982
1983
         /* check further positions */
1984
122M
         for (cur = 1; cur < last_match_pos; cur++) {
1985
120M
             const BYTE* const curPtr = ip + cur;
1986
120M
             LZ4HC_match_t newMatch;
1987
1988
120M
             if (curPtr > mflimit) break;
1989
120M
             DEBUGLOG(7, "rPos:%u[%u] vs [%u]%u",
1990
120M
                     cur, opt[cur].price, opt[cur+1].price, cur+1);
1991
120M
             if (fullUpdate) {
1992
                 /* not useful to search here if next position has same (or lower) cost */
1993
89.7M
                 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
85.6M
                   && (opt[cur+MINMATCH].price < opt[cur].price + 3/*min seq price*/) )
1996
84.4M
                     continue;
1997
89.7M
             } else {
1998
                 /* not useful to search here if next position has same (or lower) cost */
1999
30.8M
                 if (opt[cur+1].price <= opt[cur].price) continue;
2000
30.8M
             }
2001
2002
11.1M
             DEBUGLOG(7, "search at rPos:%u", cur);
2003
11.1M
             if (fullUpdate)
2004
5.33M
                 newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);
2005
5.81M
             else
2006
                 /* only test matches of minimum length; slightly faster, but misses a few bytes */
2007
5.81M
                 newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, last_match_pos - cur, nbSearches, dict, favorDecSpeed);
2008
11.1M
             if (!newMatch.len) continue;
2009
2010
5.52M
             if ( ((size_t)newMatch.len > sufficient_len)
2011
5.48M
               || (newMatch.len + cur >= LZ4_OPT_NUM) ) {
2012
                 /* immediate encoding */
2013
40.3k
                 best_mlen = newMatch.len;
2014
40.3k
                 best_off = newMatch.off;
2015
40.3k
                 last_match_pos = cur + 1;
2016
40.3k
                 goto encode;
2017
40.3k
             }
2018
2019
             /* before match : set price with literals at beginning */
2020
5.48M
             {   int const baseLitlen = opt[cur].litlen;
2021
5.48M
                 int litlen;
2022
21.9M
                 for (litlen = 1; litlen < MINMATCH; litlen++) {
2023
16.4M
                     int const price = opt[cur].price - LZ4HC_literalsPrice(baseLitlen) + LZ4HC_literalsPrice(baseLitlen+litlen);
2024
16.4M
                     int const pos = cur + litlen;
2025
16.4M
                     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
5.48M
             {   int const matchML = newMatch.len;
2036
5.48M
                 int ml = MINMATCH;
2037
2038
5.48M
                 assert(cur + newMatch.len < LZ4_OPT_NUM);
2039
504M
                 for ( ; ml <= matchML ; ml++) {
2040
499M
                     int const pos = cur + ml;
2041
499M
                     int const offset = newMatch.off;
2042
499M
                     int price;
2043
499M
                     int ll;
2044
499M
                     DEBUGLOG(7, "testing price rPos %i (last_match_pos=%i)",
2045
499M
                                 pos, last_match_pos);
2046
499M
                     if (opt[cur].mlen == 1) {
2047
175M
                         ll = opt[cur].litlen;
2048
175M
                         price = ((cur > ll) ? opt[cur - ll].price : 0)
2049
175M
                               + LZ4HC_sequencePrice(ll, ml);
2050
323M
                     } else {
2051
323M
                         ll = 0;
2052
323M
                         price = opt[cur].price + LZ4HC_sequencePrice(0, ml);
2053
323M
                     }
2054
2055
499M
                    assert((U32)favorDecSpeed <= 1);
2056
499M
                     if (pos > last_match_pos+TRAILING_LITERALS
2057
449M
                      || price <= opt[pos].price - (int)favorDecSpeed) {
2058
80.0M
                         DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i)",
2059
80.0M
                                     pos, price, ml);
2060
80.0M
                         assert(pos < LZ4_OPT_NUM);
2061
80.0M
                         if ( (ml == matchML)  /* last pos of last match */
2062
3.02M
                           && (last_match_pos < pos) )
2063
2.72M
                             last_match_pos = pos;
2064
80.0M
                         opt[pos].mlen = ml;
2065
80.0M
                         opt[pos].off = offset;
2066
80.0M
                         opt[pos].litlen = ll;
2067
80.0M
                         opt[pos].price = price;
2068
80.0M
             }   }   }
2069
             /* complete following positions with literals */
2070
5.48M
             {   int addLit;
2071
21.9M
                 for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {
2072
16.4M
                     opt[last_match_pos+addLit].mlen = 1; /* literal */
2073
16.4M
                     opt[last_match_pos+addLit].off = 0;
2074
16.4M
                     opt[last_match_pos+addLit].litlen = addLit;
2075
16.4M
                     opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);
2076
16.4M
                     DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)", last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);
2077
16.4M
             }   }
2078
5.48M
         }  /* for (cur = 1; cur <= last_match_pos; cur++) */
2079
2080
2.45M
         assert(last_match_pos < LZ4_OPT_NUM + TRAILING_LITERALS);
2081
2.41M
         best_mlen = opt[last_match_pos].mlen;
2082
2.41M
         best_off = opt[last_match_pos].off;
2083
2.41M
         cur = last_match_pos - best_mlen;
2084
2085
2.45M
encode: /* cur, last_match_pos, best_mlen, best_off must be set */
2086
2.45M
         assert(cur < LZ4_OPT_NUM);
2087
2.45M
         assert(last_match_pos >= 1);  /* == 1 when only one candidate */
2088
2.45M
         DEBUGLOG(6, "reverse traversal, looking for shortest path (last_match_pos=%i)", last_match_pos);
2089
2.45M
         {   int candidate_pos = cur;
2090
2.45M
             int selected_matchLength = best_mlen;
2091
2.45M
             int selected_offset = best_off;
2092
4.39M
             while (1) {  /* from end to beginning */
2093
4.39M
                 int const next_matchLength = opt[candidate_pos].mlen;  /* can be 1, means literal */
2094
4.39M
                 int const next_offset = opt[candidate_pos].off;
2095
4.39M
                 DEBUGLOG(7, "pos %i: sequence length %i", candidate_pos, selected_matchLength);
2096
4.39M
                 opt[candidate_pos].mlen = selected_matchLength;
2097
4.39M
                 opt[candidate_pos].off = selected_offset;
2098
4.39M
                 selected_matchLength = next_matchLength;
2099
4.39M
                 selected_offset = next_offset;
2100
4.39M
                 if (next_matchLength > candidate_pos) break; /* last match elected, first match to encode */
2101
4.39M
                 assert(next_matchLength > 0);  /* can be 1, means literal */
2102
1.94M
                 candidate_pos -= next_matchLength;
2103
1.94M
         }   }
2104
2105
         /* encode all recorded sequences in order */
2106
2.45M
         {   int rPos = 0;  /* relative position (to ip) */
2107
6.84M
             while (rPos < last_match_pos) {
2108
4.39M
                 int const ml = opt[rPos].mlen;
2109
4.39M
                 int const offset = opt[rPos].off;
2110
4.39M
                 if (ml == 1) { ip++; rPos++; continue; }  /* literal; note: can end up with several literals, in which case, skip them */
2111
3.53M
                 rPos += ml;
2112
3.53M
                 assert(ml >= MINMATCH);
2113
3.53M
                 assert((offset >= 1) && (offset <= LZ4_DISTANCE_MAX));
2114
3.53M
                 opSaved = op;
2115
3.53M
                 if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, offset, limit, oend) ) {  /* updates ip, op and anchor */
2116
0
                     ovml = ml;
2117
0
                     ovoff = offset;
2118
0
                     goto _dest_overflow;
2119
0
         }   }   }
2120
2.45M
     }  /* while (ip <= mflimit) */
2121
2122
95.8k
_last_literals:
2123
     /* Encode Last Literals */
2124
95.8k
     {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */
2125
95.8k
         size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;
2126
95.8k
         size_t const totalSize = 1 + llAdd + lastRunSize;
2127
95.8k
         if (limit == fillOutput) oend += LASTLITERALS;  /* restore correct value */
2128
95.8k
         if (limit && (op + totalSize > oend)) {
2129
0
             if (limit == limitedOutput) { /* Check output limit */
2130
0
                retval = 0;
2131
0
                goto _return_label;
2132
0
             }
2133
             /* adapt lastRunSize to fill 'dst' */
2134
0
             lastRunSize  = (size_t)(oend - op) - 1 /*token*/;
2135
0
             llAdd = (lastRunSize + 256 - RUN_MASK) / 256;
2136
0
             lastRunSize -= llAdd;
2137
0
         }
2138
95.8k
         DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);
2139
95.8k
         ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */
2140
2141
95.8k
         if (lastRunSize >= RUN_MASK) {
2142
6.40k
             size_t accumulator = lastRunSize - RUN_MASK;
2143
6.40k
             *op++ = (RUN_MASK << ML_BITS);
2144
34.1k
             for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;
2145
6.40k
             *op++ = (BYTE) accumulator;
2146
89.4k
         } else {
2147
89.4k
             *op++ = (BYTE)(lastRunSize << ML_BITS);
2148
89.4k
         }
2149
95.8k
         LZ4_memcpy(op, anchor, lastRunSize);
2150
95.8k
         op += lastRunSize;
2151
95.8k
     }
2152
2153
     /* End */
2154
0
     *srcSizePtr = (int) (((const char*)ip) - source);
2155
95.8k
     retval = (int) ((char*)op-dst);
2156
95.8k
     goto _return_label;
2157
2158
0
_dest_overflow:
2159
0
if (limit == fillOutput) {
2160
     /* Assumption : ip, anchor, ovml and ovref must be set correctly */
2161
0
     size_t const ll = (size_t)(ip - anchor);
2162
0
     size_t const ll_addbytes = (ll + 240) / 255;
2163
0
     size_t const ll_totalCost = 1 + ll_addbytes + ll;
2164
0
     BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */
2165
0
     DEBUGLOG(6, "Last sequence overflowing (only %i bytes remaining)", (int)(oend-1-opSaved));
2166
0
     op = opSaved;  /* restore correct out pointer */
2167
0
     if (op + ll_totalCost <= maxLitPos) {
2168
         /* ll validated; now adjust match length */
2169
0
         size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));
2170
0
         size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);
2171
0
         assert(maxMlSize < INT_MAX); assert(ovml >= 0);
2172
0
         if ((size_t)ovml > maxMlSize) ovml = (int)maxMlSize;
2173
0
         if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ovml >= MFLIMIT) {
2174
0
             DEBUGLOG(6, "Space to end : %i + ml (%i)", (int)((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1), ovml);
2175
0
             DEBUGLOG(6, "Before : ip = %p, anchor = %p", ip, anchor);
2176
0
             LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ovml, ovoff, notLimited, oend);
2177
0
             DEBUGLOG(6, "After : ip = %p, anchor = %p", ip, anchor);
2178
0
     }   }
2179
0
     goto _last_literals;
2180
0
}
2181
95.8k
_return_label:
2182
95.8k
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
2183
95.8k
     if (opt) FREEMEM(opt);
2184
95.8k
#endif
2185
95.8k
     return retval;
2186
0
}
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
}