Coverage Report

Created: 2026-02-26 06:57

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