Coverage Report

Created: 2024-05-21 06:40

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