Coverage Report

Created: 2026-10-17 06:50

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