Coverage Report

Created: 2025-08-26 06:42

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