Coverage Report

Created: 2026-11-12 06:26

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