extlz4 0.3.3 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/Rakefile +43 -3
- data/contrib/lz4/CODING_STYLE +57 -0
- data/contrib/lz4/LICENSE +3 -2
- data/contrib/lz4/Makefile.inc +56 -30
- data/contrib/lz4/NEWS +46 -0
- data/contrib/lz4/README.md +17 -6
- data/contrib/lz4/SECURITY.md +17 -0
- data/contrib/lz4/build/README.md +4 -15
- data/contrib/lz4/build/VS2022/_build.bat +39 -0
- data/contrib/lz4/build/VS2022/_setup.bat +35 -0
- data/contrib/lz4/build/VS2022/_test.bat +38 -0
- data/contrib/lz4/build/VS2022/build-and-test-win32-debug.bat +26 -0
- data/contrib/lz4/build/VS2022/build-and-test-win32-release.bat +26 -0
- data/contrib/lz4/build/VS2022/build-and-test-x64-debug.bat +26 -0
- data/contrib/lz4/build/VS2022/build-and-test-x64-release.bat +26 -0
- data/contrib/lz4/build/{VS2017 → VS2022}/datagen/datagen.vcxproj +11 -7
- data/contrib/lz4/build/{VS2017 → VS2022}/frametest/frametest.vcxproj +4 -4
- data/contrib/lz4/build/{VS2017 → VS2022}/fullbench/fullbench.vcxproj +4 -4
- data/contrib/lz4/build/{VS2017 → VS2022}/fullbench-dll/fullbench-dll.vcxproj +4 -4
- data/contrib/lz4/build/{VS2017 → VS2022}/fuzzer/fuzzer.vcxproj +4 -4
- data/contrib/lz4/build/{VS2017 → VS2022}/liblz4/liblz4.vcxproj +4 -4
- data/contrib/lz4/build/{VS2010 → VS2022}/liblz4-dll/liblz4-dll.rc +1 -1
- data/contrib/lz4/build/{VS2017 → VS2022}/liblz4-dll/liblz4-dll.vcxproj +4 -4
- data/contrib/lz4/build/{VS2010 → VS2022}/lz4/lz4.rc +1 -1
- data/contrib/lz4/build/{VS2017 → VS2022}/lz4/lz4.vcxproj +33 -8
- data/contrib/lz4/build/{VS2017 → VS2022}/lz4.sln +5 -2
- data/contrib/lz4/build/cmake/CMakeLists.txt +133 -100
- data/contrib/lz4/build/cmake/lz4Config.cmake.in +2 -0
- data/contrib/lz4/build/meson/GetLz4LibraryVersion.py +39 -0
- data/contrib/lz4/build/meson/README.md +34 -0
- data/contrib/lz4/build/meson/meson/contrib/gen_manual/meson.build +42 -0
- data/contrib/lz4/build/meson/meson/contrib/meson.build +11 -0
- data/contrib/lz4/build/meson/meson/examples/meson.build +32 -0
- data/contrib/lz4/build/meson/meson/lib/meson.build +87 -0
- data/contrib/lz4/build/meson/meson/meson.build +135 -0
- data/contrib/lz4/build/meson/meson/ossfuzz/meson.build +35 -0
- data/contrib/lz4/build/meson/meson/programs/meson.build +91 -0
- data/contrib/lz4/build/meson/meson/tests/meson.build +162 -0
- data/contrib/lz4/build/meson/meson.build +31 -0
- data/contrib/lz4/build/meson/meson_options.txt +44 -0
- data/contrib/lz4/build/visual/README.md +5 -0
- data/contrib/lz4/build/visual/generate_solution.cmd +55 -0
- data/contrib/lz4/build/visual/generate_vs2015.cmd +3 -0
- data/contrib/lz4/build/visual/generate_vs2017.cmd +3 -0
- data/contrib/lz4/build/visual/generate_vs2019.cmd +3 -0
- data/contrib/lz4/build/visual/generate_vs2022.cmd +3 -0
- data/contrib/lz4/lib/LICENSE +1 -1
- data/contrib/lz4/lib/README.md +69 -13
- data/contrib/lz4/lib/liblz4-dll.rc.in +1 -1
- data/contrib/lz4/lib/liblz4.pc.in +3 -3
- data/contrib/lz4/lib/lz4.c +608 -274
- data/contrib/lz4/lib/lz4.h +212 -102
- data/contrib/lz4/lib/lz4file.c +341 -0
- data/contrib/lz4/lib/lz4file.h +93 -0
- data/contrib/lz4/lib/lz4frame.c +545 -308
- data/contrib/lz4/lib/lz4frame.h +252 -124
- data/contrib/lz4/lib/lz4frame_static.h +1 -1
- data/contrib/lz4/lib/lz4hc.c +1038 -461
- data/contrib/lz4/lib/lz4hc.h +57 -56
- data/contrib/lz4/lib/xxhash.c +21 -21
- data/contrib/lz4/ossfuzz/Makefile +1 -0
- data/contrib/lz4/ossfuzz/decompress_fuzzer.c +18 -2
- data/contrib/lz4/ossfuzz/fuzz_helpers.h +4 -3
- data/contrib/lz4/ossfuzz/round_trip_frame_uncompressed_fuzzer.c +134 -0
- data/contrib/lz4/ossfuzz/round_trip_fuzzer.c +66 -6
- data/ext/blockapi.c +19 -19
- data/ext/extlz4.h +12 -0
- data/ext/frameapi.c +26 -26
- data/ext/hashargs.c +7 -1
- metadata +47 -30
- data/contrib/lz4/build/VS2010/datagen/datagen.vcxproj +0 -169
- data/contrib/lz4/build/VS2010/frametest/frametest.vcxproj +0 -176
- data/contrib/lz4/build/VS2010/fullbench/fullbench.vcxproj +0 -176
- data/contrib/lz4/build/VS2010/fullbench-dll/fullbench-dll.vcxproj +0 -180
- data/contrib/lz4/build/VS2010/fuzzer/fuzzer.vcxproj +0 -173
- data/contrib/lz4/build/VS2010/liblz4/liblz4.vcxproj +0 -175
- data/contrib/lz4/build/VS2010/liblz4-dll/liblz4-dll.vcxproj +0 -179
- data/contrib/lz4/build/VS2010/lz4/lz4.vcxproj +0 -189
- data/contrib/lz4/build/VS2010/lz4.sln +0 -98
- data/contrib/lz4/build/VS2017/liblz4-dll/liblz4-dll.rc +0 -51
- data/contrib/lz4/build/VS2017/lz4/lz4.rc +0 -51
- data/contrib/lz4/tmp +0 -0
- data/contrib/lz4/tmpsparse +0 -0
data/contrib/lz4/lib/lz4hc.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
LZ4 HC - High Compression Mode of LZ4
|
3
|
-
Copyright (C) 2011-
|
3
|
+
Copyright (C) 2011-2020, Yann Collet.
|
4
4
|
|
5
5
|
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
6
6
|
|
@@ -39,10 +39,11 @@
|
|
39
39
|
***************************************/
|
40
40
|
|
41
41
|
/*! HEAPMODE :
|
42
|
-
* Select how
|
43
|
-
*
|
44
|
-
*
|
45
|
-
|
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
|
+
**/
|
46
47
|
#ifndef LZ4HC_HEAPMODE
|
47
48
|
# define LZ4HC_HEAPMODE 1
|
48
49
|
#endif
|
@@ -51,19 +52,19 @@
|
|
51
52
|
/*=== Dependency ===*/
|
52
53
|
#define LZ4_HC_STATIC_LINKING_ONLY
|
53
54
|
#include "lz4hc.h"
|
55
|
+
#include <limits.h>
|
54
56
|
|
55
57
|
|
56
|
-
/*===
|
57
|
-
#
|
58
|
+
/*=== Shared lz4.c code ===*/
|
59
|
+
#ifndef LZ4_SRC_INCLUDED
|
60
|
+
# if defined(__GNUC__)
|
58
61
|
# pragma GCC diagnostic ignored "-Wunused-function"
|
59
|
-
#endif
|
60
|
-
#if defined (__clang__)
|
62
|
+
# endif
|
63
|
+
# if defined (__clang__)
|
61
64
|
# pragma clang diagnostic ignored "-Wunused-function"
|
62
|
-
#endif
|
63
|
-
|
64
|
-
#
|
65
|
-
#ifndef LZ4_SRC_INCLUDED
|
66
|
-
#include "lz4.c" /* LZ4_count, constants, mem */
|
65
|
+
# endif
|
66
|
+
# define LZ4_COMMONDEFS_ONLY
|
67
|
+
# include "lz4.c" /* LZ4_count, constants, mem */
|
67
68
|
#endif
|
68
69
|
|
69
70
|
|
@@ -79,17 +80,158 @@ typedef enum { noDictCtx, usingDictCtxHc } dictCtx_directive;
|
|
79
80
|
/*=== Macros ===*/
|
80
81
|
#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
|
81
82
|
#define MAX(a,b) ( (a) > (b) ? (a) : (b) )
|
82
|
-
|
83
|
-
|
83
|
+
|
84
|
+
|
85
|
+
/*=== Levels definition ===*/
|
86
|
+
typedef enum { lz4mid, lz4hc, lz4opt } lz4hc_strat_e;
|
87
|
+
typedef struct {
|
88
|
+
lz4hc_strat_e strat;
|
89
|
+
int nbSearches;
|
90
|
+
U32 targetLength;
|
91
|
+
} cParams_t;
|
92
|
+
static const cParams_t k_clTable[LZ4HC_CLEVEL_MAX+1] = {
|
93
|
+
{ lz4mid, 2, 16 }, /* 0, unused */
|
94
|
+
{ lz4mid, 2, 16 }, /* 1, unused */
|
95
|
+
{ lz4mid, 2, 16 }, /* 2 */
|
96
|
+
{ lz4hc, 4, 16 }, /* 3 */
|
97
|
+
{ lz4hc, 8, 16 }, /* 4 */
|
98
|
+
{ lz4hc, 16, 16 }, /* 5 */
|
99
|
+
{ lz4hc, 32, 16 }, /* 6 */
|
100
|
+
{ lz4hc, 64, 16 }, /* 7 */
|
101
|
+
{ lz4hc, 128, 16 }, /* 8 */
|
102
|
+
{ lz4hc, 256, 16 }, /* 9 */
|
103
|
+
{ lz4opt, 96, 64 }, /*10==LZ4HC_CLEVEL_OPT_MIN*/
|
104
|
+
{ lz4opt, 512,128 }, /*11 */
|
105
|
+
{ lz4opt,16384,LZ4_OPT_NUM }, /* 12==LZ4HC_CLEVEL_MAX */
|
106
|
+
};
|
107
|
+
|
108
|
+
static cParams_t LZ4HC_getCLevelParams(int cLevel)
|
109
|
+
{
|
110
|
+
/* note : clevel convention is a bit different from lz4frame,
|
111
|
+
* possibly something worth revisiting for consistency */
|
112
|
+
if (cLevel < 1)
|
113
|
+
cLevel = LZ4HC_CLEVEL_DEFAULT;
|
114
|
+
cLevel = MIN(LZ4HC_CLEVEL_MAX, cLevel);
|
115
|
+
return k_clTable[cLevel];
|
116
|
+
}
|
117
|
+
|
118
|
+
|
119
|
+
/*=== Hashing ===*/
|
120
|
+
#define LZ4HC_HASHSIZE 4
|
121
|
+
#define HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG))
|
122
|
+
static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }
|
123
|
+
|
124
|
+
#if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2)
|
125
|
+
/* lie to the compiler about data alignment; use with caution */
|
126
|
+
static U64 LZ4_read64(const void* memPtr) { return *(const U64*) memPtr; }
|
127
|
+
|
128
|
+
#elif defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==1)
|
129
|
+
/* __pack instructions are safer, but compiler specific */
|
130
|
+
LZ4_PACK(typedef struct { U64 u64; }) LZ4_unalign64;
|
131
|
+
static U64 LZ4_read64(const void* ptr) { return ((const LZ4_unalign64*)ptr)->u64; }
|
132
|
+
|
133
|
+
#else /* safe and portable access using memcpy() */
|
134
|
+
static U64 LZ4_read64(const void* memPtr)
|
135
|
+
{
|
136
|
+
U64 val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val;
|
137
|
+
}
|
138
|
+
|
139
|
+
#endif /* LZ4_FORCE_MEMORY_ACCESS */
|
140
|
+
|
141
|
+
#define LZ4MID_HASHSIZE 8
|
142
|
+
#define LZ4MID_HASHLOG (LZ4HC_HASH_LOG-1)
|
143
|
+
#define LZ4MID_HASHTABLESIZE (1 << LZ4MID_HASHLOG)
|
144
|
+
|
145
|
+
static U32 LZ4MID_hash4(U32 v) { return (v * 2654435761U) >> (32-LZ4MID_HASHLOG); }
|
146
|
+
static U32 LZ4MID_hash4Ptr(const void* ptr) { return LZ4MID_hash4(LZ4_read32(ptr)); }
|
147
|
+
/* note: hash7 hashes the lower 56-bits.
|
148
|
+
* It presumes input was read using little endian.*/
|
149
|
+
static U32 LZ4MID_hash7(U64 v) { return (U32)(((v << (64-56)) * 58295818150454627ULL) >> (64-LZ4MID_HASHLOG)) ; }
|
150
|
+
static U64 LZ4_readLE64(const void* memPtr);
|
151
|
+
static U32 LZ4MID_hash8Ptr(const void* ptr) { return LZ4MID_hash7(LZ4_readLE64(ptr)); }
|
152
|
+
|
153
|
+
static U64 LZ4_readLE64(const void* memPtr)
|
154
|
+
{
|
155
|
+
if (LZ4_isLittleEndian()) {
|
156
|
+
return LZ4_read64(memPtr);
|
157
|
+
} else {
|
158
|
+
const BYTE* p = (const BYTE*)memPtr;
|
159
|
+
/* note: relies on the compiler to simplify this expression */
|
160
|
+
return (U64)p[0] | ((U64)p[1]<<8) | ((U64)p[2]<<16) | ((U64)p[3]<<24)
|
161
|
+
| ((U64)p[4]<<32) | ((U64)p[5]<<40) | ((U64)p[6]<<48) | ((U64)p[7]<<56);
|
162
|
+
}
|
163
|
+
}
|
164
|
+
|
165
|
+
|
166
|
+
/*=== Count match length ===*/
|
167
|
+
LZ4_FORCE_INLINE
|
168
|
+
unsigned LZ4HC_NbCommonBytes32(U32 val)
|
169
|
+
{
|
170
|
+
assert(val != 0);
|
171
|
+
if (LZ4_isLittleEndian()) {
|
172
|
+
# if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(LZ4_FORCE_SW_BITCOUNT)
|
173
|
+
unsigned long r;
|
174
|
+
_BitScanReverse(&r, val);
|
175
|
+
return (unsigned)((31 - r) >> 3);
|
176
|
+
# elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \
|
177
|
+
((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \
|
178
|
+
!defined(LZ4_FORCE_SW_BITCOUNT)
|
179
|
+
return (unsigned)__builtin_clz(val) >> 3;
|
180
|
+
# else
|
181
|
+
val >>= 8;
|
182
|
+
val = ((((val + 0x00FFFF00) | 0x00FFFFFF) + val) |
|
183
|
+
(val + 0x00FF0000)) >> 24;
|
184
|
+
return (unsigned)val ^ 3;
|
185
|
+
# endif
|
186
|
+
} else {
|
187
|
+
# if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(LZ4_FORCE_SW_BITCOUNT)
|
188
|
+
unsigned long r;
|
189
|
+
_BitScanForward(&r, val);
|
190
|
+
return (unsigned)(r >> 3);
|
191
|
+
# elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \
|
192
|
+
((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \
|
193
|
+
!defined(LZ4_FORCE_SW_BITCOUNT)
|
194
|
+
return (unsigned)__builtin_ctz(val) >> 3;
|
195
|
+
# else
|
196
|
+
const U32 m = 0x01010101;
|
197
|
+
return (unsigned)((((val - 1) ^ val) & (m - 1)) * m) >> 24;
|
198
|
+
# endif
|
199
|
+
}
|
200
|
+
}
|
201
|
+
|
202
|
+
/** LZ4HC_countBack() :
|
203
|
+
* @return : negative value, nb of common bytes before ip/match */
|
204
|
+
LZ4_FORCE_INLINE
|
205
|
+
int LZ4HC_countBack(const BYTE* const ip, const BYTE* const match,
|
206
|
+
const BYTE* const iMin, const BYTE* const mMin)
|
207
|
+
{
|
208
|
+
int back = 0;
|
209
|
+
int const min = (int)MAX(iMin - ip, mMin - match);
|
210
|
+
assert(min <= 0);
|
211
|
+
assert(ip >= iMin); assert((size_t)(ip-iMin) < (1U<<31));
|
212
|
+
assert(match >= mMin); assert((size_t)(match - mMin) < (1U<<31));
|
213
|
+
|
214
|
+
while ((back - min) > 3) {
|
215
|
+
U32 const v = LZ4_read32(ip + back - 4) ^ LZ4_read32(match + back - 4);
|
216
|
+
if (v) {
|
217
|
+
return (back - (int)LZ4HC_NbCommonBytes32(v));
|
218
|
+
} else back -= 4; /* 4-byte step */
|
219
|
+
}
|
220
|
+
/* check remainder if any */
|
221
|
+
while ( (back > min)
|
222
|
+
&& (ip[back-1] == match[back-1]) )
|
223
|
+
back--;
|
224
|
+
return back;
|
225
|
+
}
|
226
|
+
|
227
|
+
/*=== Chain table updates ===*/
|
84
228
|
#define DELTANEXTU16(table, pos) table[(U16)(pos)] /* faster */
|
85
229
|
/* Make fields passed to, and updated by LZ4HC_encodeSequence explicit */
|
86
230
|
#define UPDATABLE(ip, op, anchor) &ip, &op, &anchor
|
87
231
|
|
88
|
-
static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }
|
89
|
-
|
90
232
|
|
91
233
|
/**************************************
|
92
|
-
*
|
234
|
+
* Init
|
93
235
|
**************************************/
|
94
236
|
static void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4)
|
95
237
|
{
|
@@ -99,57 +241,564 @@ static void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4)
|
|
99
241
|
|
100
242
|
static void LZ4HC_init_internal (LZ4HC_CCtx_internal* hc4, const BYTE* start)
|
101
243
|
{
|
102
|
-
|
103
|
-
|
244
|
+
size_t const bufferSize = (size_t)(hc4->end - hc4->prefixStart);
|
245
|
+
size_t newStartingOffset = bufferSize + hc4->dictLimit;
|
246
|
+
DEBUGLOG(5, "LZ4HC_init_internal");
|
247
|
+
assert(newStartingOffset >= bufferSize); /* check overflow */
|
248
|
+
if (newStartingOffset > 1 GB) {
|
104
249
|
LZ4HC_clearTables(hc4);
|
105
|
-
|
250
|
+
newStartingOffset = 0;
|
106
251
|
}
|
107
|
-
|
108
|
-
hc4->nextToUpdate = (U32)
|
109
|
-
hc4->
|
252
|
+
newStartingOffset += 64 KB;
|
253
|
+
hc4->nextToUpdate = (U32)newStartingOffset;
|
254
|
+
hc4->prefixStart = start;
|
110
255
|
hc4->end = start;
|
111
|
-
hc4->
|
112
|
-
hc4->dictLimit = (U32)
|
113
|
-
hc4->lowLimit = (U32)
|
256
|
+
hc4->dictStart = start;
|
257
|
+
hc4->dictLimit = (U32)newStartingOffset;
|
258
|
+
hc4->lowLimit = (U32)newStartingOffset;
|
259
|
+
}
|
260
|
+
|
261
|
+
|
262
|
+
/**************************************
|
263
|
+
* Encode
|
264
|
+
**************************************/
|
265
|
+
/* LZ4HC_encodeSequence() :
|
266
|
+
* @return : 0 if ok,
|
267
|
+
* 1 if buffer issue detected */
|
268
|
+
LZ4_FORCE_INLINE int LZ4HC_encodeSequence (
|
269
|
+
const BYTE** _ip,
|
270
|
+
BYTE** _op,
|
271
|
+
const BYTE** _anchor,
|
272
|
+
int matchLength,
|
273
|
+
int offset,
|
274
|
+
limitedOutput_directive limit,
|
275
|
+
BYTE* oend)
|
276
|
+
{
|
277
|
+
#define ip (*_ip)
|
278
|
+
#define op (*_op)
|
279
|
+
#define anchor (*_anchor)
|
280
|
+
|
281
|
+
size_t length;
|
282
|
+
BYTE* const token = op++;
|
283
|
+
|
284
|
+
#if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 6)
|
285
|
+
static const BYTE* start = NULL;
|
286
|
+
static U32 totalCost = 0;
|
287
|
+
U32 const pos = (start==NULL) ? 0 : (U32)(anchor - start);
|
288
|
+
U32 const ll = (U32)(ip - anchor);
|
289
|
+
U32 const llAdd = (ll>=15) ? ((ll-15) / 255) + 1 : 0;
|
290
|
+
U32 const mlAdd = (matchLength>=19) ? ((matchLength-19) / 255) + 1 : 0;
|
291
|
+
U32 const cost = 1 + llAdd + ll + 2 + mlAdd;
|
292
|
+
if (start==NULL) start = anchor; /* only works for single segment */
|
293
|
+
/* g_debuglog_enable = (pos >= 2228) & (pos <= 2262); */
|
294
|
+
DEBUGLOG(6, "pos:%7u -- literals:%4u, match:%4i, offset:%5i, cost:%4u + %5u",
|
295
|
+
pos,
|
296
|
+
(U32)(ip - anchor), matchLength, offset,
|
297
|
+
cost, totalCost);
|
298
|
+
totalCost += cost;
|
299
|
+
#endif
|
300
|
+
|
301
|
+
/* Encode Literal length */
|
302
|
+
length = (size_t)(ip - anchor);
|
303
|
+
LZ4_STATIC_ASSERT(notLimited == 0);
|
304
|
+
/* Check output limit */
|
305
|
+
if (limit && ((op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) {
|
306
|
+
DEBUGLOG(6, "Not enough room to write %i literals (%i bytes remaining)",
|
307
|
+
(int)length, (int)(oend - op));
|
308
|
+
return 1;
|
309
|
+
}
|
310
|
+
if (length >= RUN_MASK) {
|
311
|
+
size_t len = length - RUN_MASK;
|
312
|
+
*token = (RUN_MASK << ML_BITS);
|
313
|
+
for(; len >= 255 ; len -= 255) *op++ = 255;
|
314
|
+
*op++ = (BYTE)len;
|
315
|
+
} else {
|
316
|
+
*token = (BYTE)(length << ML_BITS);
|
317
|
+
}
|
318
|
+
|
319
|
+
/* Copy Literals */
|
320
|
+
LZ4_wildCopy8(op, anchor, op + length);
|
321
|
+
op += length;
|
322
|
+
|
323
|
+
/* Encode Offset */
|
324
|
+
assert(offset <= LZ4_DISTANCE_MAX );
|
325
|
+
assert(offset > 0);
|
326
|
+
LZ4_writeLE16(op, (U16)(offset)); op += 2;
|
327
|
+
|
328
|
+
/* Encode MatchLength */
|
329
|
+
assert(matchLength >= MINMATCH);
|
330
|
+
length = (size_t)matchLength - MINMATCH;
|
331
|
+
if (limit && (op + (length / 255) + (1 + LASTLITERALS) > oend)) {
|
332
|
+
DEBUGLOG(6, "Not enough room to write match length");
|
333
|
+
return 1; /* Check output limit */
|
334
|
+
}
|
335
|
+
if (length >= ML_MASK) {
|
336
|
+
*token += ML_MASK;
|
337
|
+
length -= ML_MASK;
|
338
|
+
for(; length >= 510 ; length -= 510) { *op++ = 255; *op++ = 255; }
|
339
|
+
if (length >= 255) { length -= 255; *op++ = 255; }
|
340
|
+
*op++ = (BYTE)length;
|
341
|
+
} else {
|
342
|
+
*token += (BYTE)(length);
|
343
|
+
}
|
344
|
+
|
345
|
+
/* Prepare next loop */
|
346
|
+
ip += matchLength;
|
347
|
+
anchor = ip;
|
348
|
+
|
349
|
+
return 0;
|
350
|
+
|
351
|
+
#undef ip
|
352
|
+
#undef op
|
353
|
+
#undef anchor
|
114
354
|
}
|
115
355
|
|
116
356
|
|
357
|
+
typedef struct {
|
358
|
+
int off;
|
359
|
+
int len;
|
360
|
+
int back; /* negative value */
|
361
|
+
} LZ4HC_match_t;
|
362
|
+
|
363
|
+
LZ4HC_match_t LZ4HC_searchExtDict(const BYTE* ip, U32 ipIndex,
|
364
|
+
const BYTE* const iLowLimit, const BYTE* const iHighLimit,
|
365
|
+
const LZ4HC_CCtx_internal* dictCtx, U32 gDictEndIndex,
|
366
|
+
int currentBestML, int nbAttempts)
|
367
|
+
{
|
368
|
+
size_t const lDictEndIndex = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit;
|
369
|
+
U32 lDictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)];
|
370
|
+
U32 matchIndex = lDictMatchIndex + gDictEndIndex - (U32)lDictEndIndex;
|
371
|
+
int offset = 0, sBack = 0;
|
372
|
+
assert(lDictEndIndex <= 1 GB);
|
373
|
+
if (lDictMatchIndex>0)
|
374
|
+
DEBUGLOG(7, "lDictEndIndex = %zu, lDictMatchIndex = %u", lDictEndIndex, lDictMatchIndex);
|
375
|
+
while (ipIndex - matchIndex <= LZ4_DISTANCE_MAX && nbAttempts--) {
|
376
|
+
const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + lDictMatchIndex;
|
377
|
+
|
378
|
+
if (LZ4_read32(matchPtr) == LZ4_read32(ip)) {
|
379
|
+
int mlt;
|
380
|
+
int back = 0;
|
381
|
+
const BYTE* vLimit = ip + (lDictEndIndex - lDictMatchIndex);
|
382
|
+
if (vLimit > iHighLimit) vLimit = iHighLimit;
|
383
|
+
mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
|
384
|
+
back = (ip > iLowLimit) ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->prefixStart) : 0;
|
385
|
+
mlt -= back;
|
386
|
+
if (mlt > currentBestML) {
|
387
|
+
currentBestML = mlt;
|
388
|
+
offset = (int)(ipIndex - matchIndex);
|
389
|
+
sBack = back;
|
390
|
+
DEBUGLOG(7, "found match of length %i within extDictCtx", currentBestML);
|
391
|
+
} }
|
392
|
+
|
393
|
+
{ U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, lDictMatchIndex);
|
394
|
+
lDictMatchIndex -= nextOffset;
|
395
|
+
matchIndex -= nextOffset;
|
396
|
+
} }
|
397
|
+
|
398
|
+
{ LZ4HC_match_t md;
|
399
|
+
md.len = currentBestML;
|
400
|
+
md.off = offset;
|
401
|
+
md.back = sBack;
|
402
|
+
return md;
|
403
|
+
}
|
404
|
+
}
|
405
|
+
|
406
|
+
typedef LZ4HC_match_t (*LZ4MID_searchIntoDict_f)(const BYTE* ip, U32 ipIndex,
|
407
|
+
const BYTE* const iHighLimit,
|
408
|
+
const LZ4HC_CCtx_internal* dictCtx, U32 gDictEndIndex);
|
409
|
+
|
410
|
+
static LZ4HC_match_t LZ4MID_searchHCDict(const BYTE* ip, U32 ipIndex,
|
411
|
+
const BYTE* const iHighLimit,
|
412
|
+
const LZ4HC_CCtx_internal* dictCtx, U32 gDictEndIndex)
|
413
|
+
{
|
414
|
+
return LZ4HC_searchExtDict(ip,ipIndex,
|
415
|
+
ip, iHighLimit,
|
416
|
+
dictCtx, gDictEndIndex,
|
417
|
+
MINMATCH-1, 2);
|
418
|
+
}
|
419
|
+
|
420
|
+
static LZ4HC_match_t LZ4MID_searchExtDict(const BYTE* ip, U32 ipIndex,
|
421
|
+
const BYTE* const iHighLimit,
|
422
|
+
const LZ4HC_CCtx_internal* dictCtx, U32 gDictEndIndex)
|
423
|
+
{
|
424
|
+
size_t const lDictEndIndex = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit;
|
425
|
+
const U32* const hash4Table = dictCtx->hashTable;
|
426
|
+
const U32* const hash8Table = hash4Table + LZ4MID_HASHTABLESIZE;
|
427
|
+
DEBUGLOG(7, "LZ4MID_searchExtDict (ipIdx=%u)", ipIndex);
|
428
|
+
|
429
|
+
/* search long match first */
|
430
|
+
{ U32 l8DictMatchIndex = hash8Table[LZ4MID_hash8Ptr(ip)];
|
431
|
+
U32 m8Index = l8DictMatchIndex + gDictEndIndex - (U32)lDictEndIndex;
|
432
|
+
assert(lDictEndIndex <= 1 GB);
|
433
|
+
if (ipIndex - m8Index <= LZ4_DISTANCE_MAX) {
|
434
|
+
const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + l8DictMatchIndex;
|
435
|
+
const size_t safeLen = MIN(lDictEndIndex - l8DictMatchIndex, (size_t)(iHighLimit - ip));
|
436
|
+
int mlt = (int)LZ4_count(ip, matchPtr, ip + safeLen);
|
437
|
+
if (mlt >= MINMATCH) {
|
438
|
+
LZ4HC_match_t md;
|
439
|
+
DEBUGLOG(7, "Found long ExtDict match of len=%u", mlt);
|
440
|
+
md.len = mlt;
|
441
|
+
md.off = (int)(ipIndex - m8Index);
|
442
|
+
md.back = 0;
|
443
|
+
return md;
|
444
|
+
}
|
445
|
+
}
|
446
|
+
}
|
447
|
+
|
448
|
+
/* search for short match second */
|
449
|
+
{ U32 l4DictMatchIndex = hash4Table[LZ4MID_hash4Ptr(ip)];
|
450
|
+
U32 m4Index = l4DictMatchIndex + gDictEndIndex - (U32)lDictEndIndex;
|
451
|
+
if (ipIndex - m4Index <= LZ4_DISTANCE_MAX) {
|
452
|
+
const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + l4DictMatchIndex;
|
453
|
+
const size_t safeLen = MIN(lDictEndIndex - l4DictMatchIndex, (size_t)(iHighLimit - ip));
|
454
|
+
int mlt = (int)LZ4_count(ip, matchPtr, ip + safeLen);
|
455
|
+
if (mlt >= MINMATCH) {
|
456
|
+
LZ4HC_match_t md;
|
457
|
+
DEBUGLOG(7, "Found short ExtDict match of len=%u", mlt);
|
458
|
+
md.len = mlt;
|
459
|
+
md.off = (int)(ipIndex - m4Index);
|
460
|
+
md.back = 0;
|
461
|
+
return md;
|
462
|
+
}
|
463
|
+
}
|
464
|
+
}
|
465
|
+
|
466
|
+
/* nothing found */
|
467
|
+
{ LZ4HC_match_t const md = {0, 0, 0 };
|
468
|
+
return md;
|
469
|
+
}
|
470
|
+
}
|
471
|
+
|
472
|
+
/**************************************
|
473
|
+
* Mid Compression (level 2)
|
474
|
+
**************************************/
|
475
|
+
|
476
|
+
LZ4_FORCE_INLINE void
|
477
|
+
LZ4MID_addPosition(U32* hTable, U32 hValue, U32 index)
|
478
|
+
{
|
479
|
+
hTable[hValue] = index;
|
480
|
+
}
|
481
|
+
|
482
|
+
#define ADDPOS8(_p, _idx) LZ4MID_addPosition(hash8Table, LZ4MID_hash8Ptr(_p), _idx)
|
483
|
+
#define ADDPOS4(_p, _idx) LZ4MID_addPosition(hash4Table, LZ4MID_hash4Ptr(_p), _idx)
|
484
|
+
|
485
|
+
/* Fill hash tables with references into dictionary.
|
486
|
+
* The resulting table is only exploitable by LZ4MID (level 2) */
|
487
|
+
static void
|
488
|
+
LZ4MID_fillHTable (LZ4HC_CCtx_internal* cctx, const void* dict, size_t size)
|
489
|
+
{
|
490
|
+
U32* const hash4Table = cctx->hashTable;
|
491
|
+
U32* const hash8Table = hash4Table + LZ4MID_HASHTABLESIZE;
|
492
|
+
const BYTE* const prefixPtr = (const BYTE*)dict;
|
493
|
+
U32 const prefixIdx = cctx->dictLimit;
|
494
|
+
U32 const target = prefixIdx + (U32)size - LZ4MID_HASHSIZE;
|
495
|
+
U32 idx = cctx->nextToUpdate;
|
496
|
+
assert(dict == cctx->prefixStart);
|
497
|
+
DEBUGLOG(4, "LZ4MID_fillHTable (size:%zu)", size);
|
498
|
+
if (size <= LZ4MID_HASHSIZE)
|
499
|
+
return;
|
500
|
+
|
501
|
+
for (; idx < target; idx += 3) {
|
502
|
+
ADDPOS4(prefixPtr+idx-prefixIdx, idx);
|
503
|
+
ADDPOS8(prefixPtr+idx+1-prefixIdx, idx+1);
|
504
|
+
}
|
505
|
+
|
506
|
+
idx = (size > 32 KB + LZ4MID_HASHSIZE) ? target - 32 KB : cctx->nextToUpdate;
|
507
|
+
for (; idx < target; idx += 1) {
|
508
|
+
ADDPOS8(prefixPtr+idx-prefixIdx, idx);
|
509
|
+
}
|
510
|
+
|
511
|
+
cctx->nextToUpdate = target;
|
512
|
+
}
|
513
|
+
|
514
|
+
static LZ4MID_searchIntoDict_f select_searchDict_function(const LZ4HC_CCtx_internal* dictCtx)
|
515
|
+
{
|
516
|
+
if (dictCtx == NULL) return NULL;
|
517
|
+
if (LZ4HC_getCLevelParams(dictCtx->compressionLevel).strat == lz4mid)
|
518
|
+
return LZ4MID_searchExtDict;
|
519
|
+
return LZ4MID_searchHCDict;
|
520
|
+
}
|
521
|
+
|
522
|
+
static int LZ4MID_compress (
|
523
|
+
LZ4HC_CCtx_internal* const ctx,
|
524
|
+
const char* const src,
|
525
|
+
char* const dst,
|
526
|
+
int* srcSizePtr,
|
527
|
+
int const maxOutputSize,
|
528
|
+
const limitedOutput_directive limit,
|
529
|
+
const dictCtx_directive dict
|
530
|
+
)
|
531
|
+
{
|
532
|
+
U32* const hash4Table = ctx->hashTable;
|
533
|
+
U32* const hash8Table = hash4Table + LZ4MID_HASHTABLESIZE;
|
534
|
+
const BYTE* ip = (const BYTE*)src;
|
535
|
+
const BYTE* anchor = ip;
|
536
|
+
const BYTE* const iend = ip + *srcSizePtr;
|
537
|
+
const BYTE* const mflimit = iend - MFLIMIT;
|
538
|
+
const BYTE* const matchlimit = (iend - LASTLITERALS);
|
539
|
+
const BYTE* const ilimit = (iend - LZ4MID_HASHSIZE);
|
540
|
+
BYTE* op = (BYTE*)dst;
|
541
|
+
BYTE* oend = op + maxOutputSize;
|
542
|
+
|
543
|
+
const BYTE* const prefixPtr = ctx->prefixStart;
|
544
|
+
const U32 prefixIdx = ctx->dictLimit;
|
545
|
+
const U32 ilimitIdx = (U32)(ilimit - prefixPtr) + prefixIdx;
|
546
|
+
const BYTE* const dictStart = ctx->dictStart;
|
547
|
+
const U32 dictIdx = ctx->lowLimit;
|
548
|
+
const U32 gDictEndIndex = ctx->lowLimit;
|
549
|
+
const LZ4MID_searchIntoDict_f searchIntoDict = (dict == usingDictCtxHc) ? select_searchDict_function(ctx->dictCtx) : NULL;
|
550
|
+
unsigned matchLength;
|
551
|
+
unsigned matchDistance;
|
552
|
+
|
553
|
+
/* input sanitization */
|
554
|
+
DEBUGLOG(5, "LZ4MID_compress (%i bytes)", *srcSizePtr);
|
555
|
+
if (dict == usingDictCtxHc) DEBUGLOG(5, "usingDictCtxHc");
|
556
|
+
assert(*srcSizePtr >= 0);
|
557
|
+
if (*srcSizePtr) assert(src != NULL);
|
558
|
+
if (maxOutputSize) assert(dst != NULL);
|
559
|
+
if (*srcSizePtr < 0) return 0; /* invalid */
|
560
|
+
if (maxOutputSize < 0) return 0; /* invalid */
|
561
|
+
if (*srcSizePtr > LZ4_MAX_INPUT_SIZE) {
|
562
|
+
/* forbidden: no input is allowed to be that large */
|
563
|
+
return 0;
|
564
|
+
}
|
565
|
+
if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */
|
566
|
+
if (*srcSizePtr < LZ4_minLength)
|
567
|
+
goto _lz4mid_last_literals; /* Input too small, no compression (all literals) */
|
568
|
+
|
569
|
+
/* main loop */
|
570
|
+
while (ip <= mflimit) {
|
571
|
+
const U32 ipIndex = (U32)(ip - prefixPtr) + prefixIdx;
|
572
|
+
/* search long match */
|
573
|
+
{ U32 const h8 = LZ4MID_hash8Ptr(ip);
|
574
|
+
U32 const pos8 = hash8Table[h8];
|
575
|
+
assert(h8 < LZ4MID_HASHTABLESIZE);
|
576
|
+
assert(pos8 < ipIndex);
|
577
|
+
LZ4MID_addPosition(hash8Table, h8, ipIndex);
|
578
|
+
if (ipIndex - pos8 <= LZ4_DISTANCE_MAX) {
|
579
|
+
/* match candidate found */
|
580
|
+
if (pos8 >= prefixIdx) {
|
581
|
+
const BYTE* const matchPtr = prefixPtr + pos8 - prefixIdx;
|
582
|
+
assert(matchPtr < ip);
|
583
|
+
matchLength = LZ4_count(ip, matchPtr, matchlimit);
|
584
|
+
if (matchLength >= MINMATCH) {
|
585
|
+
DEBUGLOG(7, "found long match at pos %u (len=%u)", pos8, matchLength);
|
586
|
+
matchDistance = ipIndex - pos8;
|
587
|
+
goto _lz4mid_encode_sequence;
|
588
|
+
}
|
589
|
+
} else {
|
590
|
+
if (pos8 >= dictIdx) {
|
591
|
+
/* extDict match candidate */
|
592
|
+
const BYTE* const matchPtr = dictStart + (pos8 - dictIdx);
|
593
|
+
const size_t safeLen = MIN(prefixIdx - pos8, (size_t)(matchlimit - ip));
|
594
|
+
matchLength = LZ4_count(ip, matchPtr, ip + safeLen);
|
595
|
+
if (matchLength >= MINMATCH) {
|
596
|
+
DEBUGLOG(7, "found long match at ExtDict pos %u (len=%u)", pos8, matchLength);
|
597
|
+
matchDistance = ipIndex - pos8;
|
598
|
+
goto _lz4mid_encode_sequence;
|
599
|
+
}
|
600
|
+
}
|
601
|
+
}
|
602
|
+
} }
|
603
|
+
/* search short match */
|
604
|
+
{ U32 const h4 = LZ4MID_hash4Ptr(ip);
|
605
|
+
U32 const pos4 = hash4Table[h4];
|
606
|
+
assert(h4 < LZ4MID_HASHTABLESIZE);
|
607
|
+
assert(pos4 < ipIndex);
|
608
|
+
LZ4MID_addPosition(hash4Table, h4, ipIndex);
|
609
|
+
if (ipIndex - pos4 <= LZ4_DISTANCE_MAX) {
|
610
|
+
/* match candidate found */
|
611
|
+
if (pos4 >= prefixIdx) {
|
612
|
+
/* only search within prefix */
|
613
|
+
const BYTE* const matchPtr = prefixPtr + (pos4 - prefixIdx);
|
614
|
+
assert(matchPtr < ip);
|
615
|
+
assert(matchPtr >= prefixPtr);
|
616
|
+
matchLength = LZ4_count(ip, matchPtr, matchlimit);
|
617
|
+
if (matchLength >= MINMATCH) {
|
618
|
+
/* short match found, let's just check ip+1 for longer */
|
619
|
+
U32 const h8 = LZ4MID_hash8Ptr(ip+1);
|
620
|
+
U32 const pos8 = hash8Table[h8];
|
621
|
+
U32 const m2Distance = ipIndex + 1 - pos8;
|
622
|
+
matchDistance = ipIndex - pos4;
|
623
|
+
if ( m2Distance <= LZ4_DISTANCE_MAX
|
624
|
+
&& pos8 >= prefixIdx /* only search within prefix */
|
625
|
+
&& likely(ip < mflimit)
|
626
|
+
) {
|
627
|
+
const BYTE* const m2Ptr = prefixPtr + (pos8 - prefixIdx);
|
628
|
+
unsigned ml2 = LZ4_count(ip+1, m2Ptr, matchlimit);
|
629
|
+
if (ml2 > matchLength) {
|
630
|
+
LZ4MID_addPosition(hash8Table, h8, ipIndex+1);
|
631
|
+
ip++;
|
632
|
+
matchLength = ml2;
|
633
|
+
matchDistance = m2Distance;
|
634
|
+
} }
|
635
|
+
goto _lz4mid_encode_sequence;
|
636
|
+
}
|
637
|
+
} else {
|
638
|
+
if (pos4 >= dictIdx) {
|
639
|
+
/* extDict match candidate */
|
640
|
+
const BYTE* const matchPtr = dictStart + (pos4 - dictIdx);
|
641
|
+
const size_t safeLen = MIN(prefixIdx - pos4, (size_t)(matchlimit - ip));
|
642
|
+
matchLength = LZ4_count(ip, matchPtr, ip + safeLen);
|
643
|
+
if (matchLength >= MINMATCH) {
|
644
|
+
DEBUGLOG(7, "found match at ExtDict pos %u (len=%u)", pos4, matchLength);
|
645
|
+
matchDistance = ipIndex - pos4;
|
646
|
+
goto _lz4mid_encode_sequence;
|
647
|
+
}
|
648
|
+
}
|
649
|
+
}
|
650
|
+
} }
|
651
|
+
/* no match found in prefix */
|
652
|
+
if ( (dict == usingDictCtxHc)
|
653
|
+
&& (ipIndex - gDictEndIndex < LZ4_DISTANCE_MAX - 8) ) {
|
654
|
+
/* search a match into external dictionary */
|
655
|
+
LZ4HC_match_t dMatch = searchIntoDict(ip, ipIndex,
|
656
|
+
matchlimit,
|
657
|
+
ctx->dictCtx, gDictEndIndex);
|
658
|
+
if (dMatch.len >= MINMATCH) {
|
659
|
+
DEBUGLOG(7, "found Dictionary match (offset=%i)", dMatch.off);
|
660
|
+
assert(dMatch.back == 0);
|
661
|
+
matchLength = (unsigned)dMatch.len;
|
662
|
+
matchDistance = (unsigned)dMatch.off;
|
663
|
+
goto _lz4mid_encode_sequence;
|
664
|
+
}
|
665
|
+
}
|
666
|
+
/* no match found */
|
667
|
+
ip += 1 + ((ip-anchor) >> 9); /* skip faster over incompressible data */
|
668
|
+
continue;
|
669
|
+
|
670
|
+
_lz4mid_encode_sequence:
|
671
|
+
/* catch back */
|
672
|
+
while (((ip > anchor) & ((U32)(ip-prefixPtr) > matchDistance)) && (unlikely(ip[-1] == ip[-(int)matchDistance-1]))) {
|
673
|
+
ip--; matchLength++;
|
674
|
+
};
|
675
|
+
|
676
|
+
/* fill table with beginning of match */
|
677
|
+
ADDPOS8(ip+1, ipIndex+1);
|
678
|
+
ADDPOS8(ip+2, ipIndex+2);
|
679
|
+
ADDPOS4(ip+1, ipIndex+1);
|
680
|
+
|
681
|
+
/* encode */
|
682
|
+
{ BYTE* const saved_op = op;
|
683
|
+
/* LZ4HC_encodeSequence always updates @op; on success, it updates @ip and @anchor */
|
684
|
+
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
|
685
|
+
(int)matchLength, (int)matchDistance,
|
686
|
+
limit, oend) ) {
|
687
|
+
op = saved_op; /* restore @op value before failed LZ4HC_encodeSequence */
|
688
|
+
goto _lz4mid_dest_overflow;
|
689
|
+
}
|
690
|
+
}
|
691
|
+
|
692
|
+
/* fill table with end of match */
|
693
|
+
{ U32 endMatchIdx = (U32)(ip-prefixPtr) + prefixIdx;
|
694
|
+
U32 pos_m2 = endMatchIdx - 2;
|
695
|
+
if (pos_m2 < ilimitIdx) {
|
696
|
+
if (likely(ip - prefixPtr > 5)) {
|
697
|
+
ADDPOS8(ip-5, endMatchIdx - 5);
|
698
|
+
}
|
699
|
+
ADDPOS8(ip-3, endMatchIdx - 3);
|
700
|
+
ADDPOS8(ip-2, endMatchIdx - 2);
|
701
|
+
ADDPOS4(ip-2, endMatchIdx - 2);
|
702
|
+
ADDPOS4(ip-1, endMatchIdx - 1);
|
703
|
+
}
|
704
|
+
}
|
705
|
+
}
|
706
|
+
|
707
|
+
_lz4mid_last_literals:
|
708
|
+
/* Encode Last Literals */
|
709
|
+
{ size_t lastRunSize = (size_t)(iend - anchor); /* literals */
|
710
|
+
size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;
|
711
|
+
size_t const totalSize = 1 + llAdd + lastRunSize;
|
712
|
+
if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */
|
713
|
+
if (limit && (op + totalSize > oend)) {
|
714
|
+
if (limit == limitedOutput) return 0; /* not enough space in @dst */
|
715
|
+
/* adapt lastRunSize to fill 'dest' */
|
716
|
+
lastRunSize = (size_t)(oend - op) - 1 /*token*/;
|
717
|
+
llAdd = (lastRunSize + 256 - RUN_MASK) / 256;
|
718
|
+
lastRunSize -= llAdd;
|
719
|
+
}
|
720
|
+
DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);
|
721
|
+
ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */
|
722
|
+
|
723
|
+
if (lastRunSize >= RUN_MASK) {
|
724
|
+
size_t accumulator = lastRunSize - RUN_MASK;
|
725
|
+
*op++ = (RUN_MASK << ML_BITS);
|
726
|
+
for(; accumulator >= 255 ; accumulator -= 255)
|
727
|
+
*op++ = 255;
|
728
|
+
*op++ = (BYTE) accumulator;
|
729
|
+
} else {
|
730
|
+
*op++ = (BYTE)(lastRunSize << ML_BITS);
|
731
|
+
}
|
732
|
+
assert(lastRunSize <= (size_t)(oend - op));
|
733
|
+
LZ4_memcpy(op, anchor, lastRunSize);
|
734
|
+
op += lastRunSize;
|
735
|
+
}
|
736
|
+
|
737
|
+
/* End */
|
738
|
+
DEBUGLOG(5, "compressed %i bytes into %i bytes", *srcSizePtr, (int)((char*)op - dst));
|
739
|
+
assert(ip >= (const BYTE*)src);
|
740
|
+
assert(ip <= iend);
|
741
|
+
*srcSizePtr = (int)(ip - (const BYTE*)src);
|
742
|
+
assert((char*)op >= dst);
|
743
|
+
assert(op <= oend);
|
744
|
+
assert((char*)op - dst < INT_MAX);
|
745
|
+
return (int)((char*)op - dst);
|
746
|
+
|
747
|
+
_lz4mid_dest_overflow:
|
748
|
+
if (limit == fillOutput) {
|
749
|
+
/* Assumption : @ip, @anchor, @optr and @matchLength must be set correctly */
|
750
|
+
size_t const ll = (size_t)(ip - anchor);
|
751
|
+
size_t const ll_addbytes = (ll + 240) / 255;
|
752
|
+
size_t const ll_totalCost = 1 + ll_addbytes + ll;
|
753
|
+
BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */
|
754
|
+
DEBUGLOG(6, "Last sequence is overflowing : %u literals, %u remaining space",
|
755
|
+
(unsigned)ll, (unsigned)(oend-op));
|
756
|
+
if (op + ll_totalCost <= maxLitPos) {
|
757
|
+
/* ll validated; now adjust match length */
|
758
|
+
size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));
|
759
|
+
size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);
|
760
|
+
assert(maxMlSize < INT_MAX);
|
761
|
+
if ((size_t)matchLength > maxMlSize) matchLength= (unsigned)maxMlSize;
|
762
|
+
if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + matchLength >= MFLIMIT) {
|
763
|
+
DEBUGLOG(6, "Let's encode a last sequence (ll=%u, ml=%u)", (unsigned)ll, matchLength);
|
764
|
+
LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
|
765
|
+
(int)matchLength, (int)matchDistance,
|
766
|
+
notLimited, oend);
|
767
|
+
} }
|
768
|
+
DEBUGLOG(6, "Let's finish with a run of literals (%u bytes left)", (unsigned)(oend-op));
|
769
|
+
goto _lz4mid_last_literals;
|
770
|
+
}
|
771
|
+
/* compression failed */
|
772
|
+
return 0;
|
773
|
+
}
|
774
|
+
|
775
|
+
|
776
|
+
/**************************************
|
777
|
+
* HC Compression - Search
|
778
|
+
**************************************/
|
779
|
+
|
117
780
|
/* Update chains up to ip (excluded) */
|
118
781
|
LZ4_FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip)
|
119
782
|
{
|
120
783
|
U16* const chainTable = hc4->chainTable;
|
121
784
|
U32* const hashTable = hc4->hashTable;
|
122
|
-
const BYTE* const
|
123
|
-
U32 const
|
785
|
+
const BYTE* const prefixPtr = hc4->prefixStart;
|
786
|
+
U32 const prefixIdx = hc4->dictLimit;
|
787
|
+
U32 const target = (U32)(ip - prefixPtr) + prefixIdx;
|
124
788
|
U32 idx = hc4->nextToUpdate;
|
789
|
+
assert(ip >= prefixPtr);
|
790
|
+
assert(target >= prefixIdx);
|
125
791
|
|
126
792
|
while (idx < target) {
|
127
|
-
U32 const h = LZ4HC_hashPtr(
|
793
|
+
U32 const h = LZ4HC_hashPtr(prefixPtr+idx-prefixIdx);
|
128
794
|
size_t delta = idx - hashTable[h];
|
129
795
|
if (delta>LZ4_DISTANCE_MAX) delta = LZ4_DISTANCE_MAX;
|
130
796
|
DELTANEXTU16(chainTable, idx) = (U16)delta;
|
131
797
|
hashTable[h] = idx;
|
132
798
|
idx++;
|
133
|
-
}
|
134
|
-
|
135
|
-
hc4->nextToUpdate = target;
|
136
|
-
}
|
137
|
-
|
138
|
-
/** LZ4HC_countBack() :
|
139
|
-
* @return : negative value, nb of common bytes before ip/match */
|
140
|
-
LZ4_FORCE_INLINE
|
141
|
-
int LZ4HC_countBack(const BYTE* const ip, const BYTE* const match,
|
142
|
-
const BYTE* const iMin, const BYTE* const mMin)
|
143
|
-
{
|
144
|
-
int back = 0;
|
145
|
-
int const min = (int)MAX(iMin - ip, mMin - match);
|
146
|
-
assert(min <= 0);
|
147
|
-
assert(ip >= iMin); assert((size_t)(ip-iMin) < (1U<<31));
|
148
|
-
assert(match >= mMin); assert((size_t)(match - mMin) < (1U<<31));
|
149
|
-
while ( (back > min)
|
150
|
-
&& (ip[back-1] == match[back-1]) )
|
151
|
-
back--;
|
152
|
-
return back;
|
799
|
+
}
|
800
|
+
|
801
|
+
hc4->nextToUpdate = target;
|
153
802
|
}
|
154
803
|
|
155
804
|
#if defined(_MSC_VER)
|
@@ -193,15 +842,14 @@ LZ4HC_countPattern(const BYTE* ip, const BYTE* const iEnd, U32 const pattern32)
|
|
193
842
|
BYTE const byte = (BYTE)(pattern >> bitOffset);
|
194
843
|
if (*ip != byte) break;
|
195
844
|
ip ++; bitOffset -= 8;
|
196
|
-
|
197
|
-
}
|
845
|
+
} }
|
198
846
|
|
199
847
|
return (unsigned)(ip - iStart);
|
200
848
|
}
|
201
849
|
|
202
850
|
/* LZ4HC_reverseCountPattern() :
|
203
851
|
* pattern must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!)
|
204
|
-
* read using natural platform
|
852
|
+
* read using natural platform endianness */
|
205
853
|
static unsigned
|
206
854
|
LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern)
|
207
855
|
{
|
@@ -211,7 +859,7 @@ LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern)
|
|
211
859
|
if (LZ4_read32(ip-4) != pattern) break;
|
212
860
|
ip -= 4;
|
213
861
|
}
|
214
|
-
{ const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any
|
862
|
+
{ const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianness */
|
215
863
|
while (likely(ip>iLow)) {
|
216
864
|
if (ip[-1] != *bytePtr) break;
|
217
865
|
ip--; bytePtr--;
|
@@ -232,30 +880,29 @@ static int LZ4HC_protectDictEnd(U32 const dictLimit, U32 const matchIndex)
|
|
232
880
|
typedef enum { rep_untested, rep_not, rep_confirmed } repeat_state_e;
|
233
881
|
typedef enum { favorCompressionRatio=0, favorDecompressionSpeed } HCfavor_e;
|
234
882
|
|
235
|
-
|
883
|
+
|
884
|
+
LZ4_FORCE_INLINE LZ4HC_match_t
|
236
885
|
LZ4HC_InsertAndGetWiderMatch (
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
const int patternAnalysis,
|
246
|
-
const int chainSwap,
|
247
|
-
const dictCtx_directive dict,
|
248
|
-
const HCfavor_e favorDecSpeed)
|
886
|
+
LZ4HC_CCtx_internal* const hc4,
|
887
|
+
const BYTE* const ip,
|
888
|
+
const BYTE* const iLowLimit, const BYTE* const iHighLimit,
|
889
|
+
int longest,
|
890
|
+
const int maxNbAttempts,
|
891
|
+
const int patternAnalysis, const int chainSwap,
|
892
|
+
const dictCtx_directive dict,
|
893
|
+
const HCfavor_e favorDecSpeed)
|
249
894
|
{
|
250
895
|
U16* const chainTable = hc4->chainTable;
|
251
|
-
U32* const
|
252
|
-
const LZ4HC_CCtx_internal
|
253
|
-
const BYTE* const
|
254
|
-
const U32
|
255
|
-
const
|
256
|
-
const
|
257
|
-
const U32 lowestMatchIndex = (
|
258
|
-
const BYTE* const
|
896
|
+
U32* const hashTable = hc4->hashTable;
|
897
|
+
const LZ4HC_CCtx_internal* const dictCtx = hc4->dictCtx;
|
898
|
+
const BYTE* const prefixPtr = hc4->prefixStart;
|
899
|
+
const U32 prefixIdx = hc4->dictLimit;
|
900
|
+
const U32 ipIndex = (U32)(ip - prefixPtr) + prefixIdx;
|
901
|
+
const int withinStartDistance = (hc4->lowLimit + (LZ4_DISTANCE_MAX + 1) > ipIndex);
|
902
|
+
const U32 lowestMatchIndex = (withinStartDistance) ? hc4->lowLimit : ipIndex - LZ4_DISTANCE_MAX;
|
903
|
+
const BYTE* const dictStart = hc4->dictStart;
|
904
|
+
const U32 dictIdx = hc4->lowLimit;
|
905
|
+
const BYTE* const dictEnd = dictStart + prefixIdx - dictIdx;
|
259
906
|
int const lookBackLength = (int)(ip-iLowLimit);
|
260
907
|
int nbAttempts = maxNbAttempts;
|
261
908
|
U32 matchChainPos = 0;
|
@@ -263,54 +910,58 @@ LZ4HC_InsertAndGetWiderMatch (
|
|
263
910
|
U32 matchIndex;
|
264
911
|
repeat_state_e repeat = rep_untested;
|
265
912
|
size_t srcPatternLength = 0;
|
913
|
+
int offset = 0, sBack = 0;
|
266
914
|
|
267
915
|
DEBUGLOG(7, "LZ4HC_InsertAndGetWiderMatch");
|
268
916
|
/* First Match */
|
269
|
-
LZ4HC_Insert(hc4, ip);
|
270
|
-
matchIndex =
|
271
|
-
DEBUGLOG(7, "First match at index %u / %u (lowestMatchIndex)",
|
272
|
-
matchIndex, lowestMatchIndex);
|
917
|
+
LZ4HC_Insert(hc4, ip); /* insert all prior positions up to ip (excluded) */
|
918
|
+
matchIndex = hashTable[LZ4HC_hashPtr(ip)];
|
919
|
+
DEBUGLOG(7, "First candidate match for pos %u found at index %u / %u (lowestMatchIndex)",
|
920
|
+
ipIndex, matchIndex, lowestMatchIndex);
|
273
921
|
|
274
922
|
while ((matchIndex>=lowestMatchIndex) && (nbAttempts>0)) {
|
275
923
|
int matchLength=0;
|
276
924
|
nbAttempts--;
|
277
925
|
assert(matchIndex < ipIndex);
|
278
926
|
if (favorDecSpeed && (ipIndex - matchIndex < 8)) {
|
279
|
-
/* do nothing
|
280
|
-
|
281
|
-
|
282
|
-
|
927
|
+
/* do nothing:
|
928
|
+
* favorDecSpeed intentionally skips matches with offset < 8 */
|
929
|
+
} else if (matchIndex >= prefixIdx) { /* within current Prefix */
|
930
|
+
const BYTE* const matchPtr = prefixPtr + (matchIndex - prefixIdx);
|
283
931
|
assert(matchPtr < ip);
|
284
932
|
assert(longest >= 1);
|
285
933
|
if (LZ4_read16(iLowLimit + longest - 1) == LZ4_read16(matchPtr - lookBackLength + longest - 1)) {
|
286
934
|
if (LZ4_read32(matchPtr) == pattern) {
|
287
|
-
int const back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit,
|
935
|
+
int const back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, prefixPtr) : 0;
|
288
936
|
matchLength = MINMATCH + (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit);
|
289
937
|
matchLength -= back;
|
290
938
|
if (matchLength > longest) {
|
291
939
|
longest = matchLength;
|
292
|
-
|
293
|
-
|
940
|
+
offset = (int)(ipIndex - matchIndex);
|
941
|
+
sBack = back;
|
942
|
+
DEBUGLOG(7, "Found match of len=%i within prefix, offset=%i, back=%i", longest, offset, -back);
|
294
943
|
} } }
|
295
|
-
} else { /* lowestMatchIndex <= matchIndex < dictLimit */
|
296
|
-
const BYTE* const matchPtr =
|
297
|
-
|
298
|
-
|
944
|
+
} else { /* lowestMatchIndex <= matchIndex < dictLimit : within Ext Dict */
|
945
|
+
const BYTE* const matchPtr = dictStart + (matchIndex - dictIdx);
|
946
|
+
assert(matchIndex >= dictIdx);
|
947
|
+
if ( likely(matchIndex <= prefixIdx - 4)
|
948
|
+
&& (LZ4_read32(matchPtr) == pattern) ) {
|
299
949
|
int back = 0;
|
300
|
-
const BYTE* vLimit = ip + (
|
950
|
+
const BYTE* vLimit = ip + (prefixIdx - matchIndex);
|
301
951
|
if (vLimit > iHighLimit) vLimit = iHighLimit;
|
302
952
|
matchLength = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
|
303
953
|
if ((ip+matchLength == vLimit) && (vLimit < iHighLimit))
|
304
|
-
matchLength += LZ4_count(ip+matchLength,
|
954
|
+
matchLength += LZ4_count(ip+matchLength, prefixPtr, iHighLimit);
|
305
955
|
back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictStart) : 0;
|
306
956
|
matchLength -= back;
|
307
957
|
if (matchLength > longest) {
|
308
958
|
longest = matchLength;
|
309
|
-
|
310
|
-
|
959
|
+
offset = (int)(ipIndex - matchIndex);
|
960
|
+
sBack = back;
|
961
|
+
DEBUGLOG(7, "Found match of len=%i within dict, offset=%i, back=%i", longest, offset, -back);
|
311
962
|
} } }
|
312
963
|
|
313
|
-
if (chainSwap && matchLength==longest) {
|
964
|
+
if (chainSwap && matchLength==longest) { /* better match => select a better chain */
|
314
965
|
assert(lookBackLength==0); /* search forward only */
|
315
966
|
if (matchIndex + (U32)longest <= ipIndex) {
|
316
967
|
int const kTrigger = 4;
|
@@ -326,8 +977,7 @@ LZ4HC_InsertAndGetWiderMatch (
|
|
326
977
|
distanceToNextMatch = candidateDist;
|
327
978
|
matchChainPos = (U32)pos;
|
328
979
|
accel = 1 << kTrigger;
|
329
|
-
|
330
|
-
}
|
980
|
+
} }
|
331
981
|
if (distanceToNextMatch > 1) {
|
332
982
|
if (distanceToNextMatch > matchIndex) break; /* avoid overflow */
|
333
983
|
matchIndex -= distanceToNextMatch;
|
@@ -341,29 +991,31 @@ LZ4HC_InsertAndGetWiderMatch (
|
|
341
991
|
if (repeat == rep_untested) {
|
342
992
|
if ( ((pattern & 0xFFFF) == (pattern >> 16))
|
343
993
|
& ((pattern & 0xFF) == (pattern >> 24)) ) {
|
994
|
+
DEBUGLOG(7, "Repeat pattern detected, char %02X", pattern >> 24);
|
344
995
|
repeat = rep_confirmed;
|
345
996
|
srcPatternLength = LZ4HC_countPattern(ip+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern);
|
346
997
|
} else {
|
347
998
|
repeat = rep_not;
|
348
999
|
} }
|
349
1000
|
if ( (repeat == rep_confirmed) && (matchCandidateIdx >= lowestMatchIndex)
|
350
|
-
&& LZ4HC_protectDictEnd(
|
351
|
-
const int extDict = matchCandidateIdx <
|
352
|
-
const BYTE* const matchPtr =
|
1001
|
+
&& LZ4HC_protectDictEnd(prefixIdx, matchCandidateIdx) ) {
|
1002
|
+
const int extDict = matchCandidateIdx < prefixIdx;
|
1003
|
+
const BYTE* const matchPtr = extDict ? dictStart + (matchCandidateIdx - dictIdx) : prefixPtr + (matchCandidateIdx - prefixIdx);
|
353
1004
|
if (LZ4_read32(matchPtr) == pattern) { /* good candidate */
|
354
|
-
const BYTE* const
|
355
|
-
const BYTE* const iLimit = extDict ? dictBase + dictLimit : iHighLimit;
|
1005
|
+
const BYTE* const iLimit = extDict ? dictEnd : iHighLimit;
|
356
1006
|
size_t forwardPatternLength = LZ4HC_countPattern(matchPtr+sizeof(pattern), iLimit, pattern) + sizeof(pattern);
|
357
1007
|
if (extDict && matchPtr + forwardPatternLength == iLimit) {
|
358
1008
|
U32 const rotatedPattern = LZ4HC_rotatePattern(forwardPatternLength, pattern);
|
359
|
-
forwardPatternLength += LZ4HC_countPattern(
|
1009
|
+
forwardPatternLength += LZ4HC_countPattern(prefixPtr, iHighLimit, rotatedPattern);
|
360
1010
|
}
|
361
|
-
{ const BYTE* const lowestMatchPtr = extDict ? dictStart :
|
1011
|
+
{ const BYTE* const lowestMatchPtr = extDict ? dictStart : prefixPtr;
|
362
1012
|
size_t backLength = LZ4HC_reverseCountPattern(matchPtr, lowestMatchPtr, pattern);
|
363
1013
|
size_t currentSegmentLength;
|
364
|
-
if (!extDict
|
1014
|
+
if (!extDict
|
1015
|
+
&& matchPtr - backLength == prefixPtr
|
1016
|
+
&& dictIdx < prefixIdx) {
|
365
1017
|
U32 const rotatedPattern = LZ4HC_rotatePattern((U32)(-(int)backLength), pattern);
|
366
|
-
backLength += LZ4HC_reverseCountPattern(
|
1018
|
+
backLength += LZ4HC_reverseCountPattern(dictEnd, dictStart, rotatedPattern);
|
367
1019
|
}
|
368
1020
|
/* Limit backLength not go further than lowestMatchIndex */
|
369
1021
|
backLength = matchCandidateIdx - MAX(matchCandidateIdx - (U32)backLength, lowestMatchIndex);
|
@@ -373,29 +1025,30 @@ LZ4HC_InsertAndGetWiderMatch (
|
|
373
1025
|
if ( (currentSegmentLength >= srcPatternLength) /* current pattern segment large enough to contain full srcPatternLength */
|
374
1026
|
&& (forwardPatternLength <= srcPatternLength) ) { /* haven't reached this position yet */
|
375
1027
|
U32 const newMatchIndex = matchCandidateIdx + (U32)forwardPatternLength - (U32)srcPatternLength; /* best position, full pattern, might be followed by more match */
|
376
|
-
if (LZ4HC_protectDictEnd(
|
1028
|
+
if (LZ4HC_protectDictEnd(prefixIdx, newMatchIndex))
|
377
1029
|
matchIndex = newMatchIndex;
|
378
1030
|
else {
|
379
1031
|
/* Can only happen if started in the prefix */
|
380
|
-
assert(newMatchIndex >=
|
381
|
-
matchIndex =
|
1032
|
+
assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);
|
1033
|
+
matchIndex = prefixIdx;
|
382
1034
|
}
|
383
1035
|
} else {
|
384
1036
|
U32 const newMatchIndex = matchCandidateIdx - (U32)backLength; /* farthest position in current segment, will find a match of length currentSegmentLength + maybe some back */
|
385
|
-
if (!LZ4HC_protectDictEnd(
|
386
|
-
assert(newMatchIndex >=
|
387
|
-
matchIndex =
|
1037
|
+
if (!LZ4HC_protectDictEnd(prefixIdx, newMatchIndex)) {
|
1038
|
+
assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);
|
1039
|
+
matchIndex = prefixIdx;
|
388
1040
|
} else {
|
389
1041
|
matchIndex = newMatchIndex;
|
390
1042
|
if (lookBackLength==0) { /* no back possible */
|
391
1043
|
size_t const maxML = MIN(currentSegmentLength, srcPatternLength);
|
392
1044
|
if ((size_t)longest < maxML) {
|
393
|
-
assert(
|
394
|
-
if ((size_t)(ip -
|
1045
|
+
assert(prefixPtr - prefixIdx + matchIndex != ip);
|
1046
|
+
if ((size_t)(ip - prefixPtr) + prefixIdx - matchIndex > LZ4_DISTANCE_MAX) break;
|
395
1047
|
assert(maxML < 2 GB);
|
396
1048
|
longest = (int)maxML;
|
397
|
-
|
398
|
-
|
1049
|
+
offset = (int)(ipIndex - matchIndex);
|
1050
|
+
assert(sBack == 0);
|
1051
|
+
DEBUGLOG(7, "Found repeat pattern match of len=%i, offset=%i", longest, offset);
|
399
1052
|
}
|
400
1053
|
{ U32 const distToNextPattern = DELTANEXTU16(chainTable, matchIndex);
|
401
1054
|
if (distToNextPattern > matchIndex) break; /* avoid overflow */
|
@@ -412,13 +1065,14 @@ LZ4HC_InsertAndGetWiderMatch (
|
|
412
1065
|
|
413
1066
|
if ( dict == usingDictCtxHc
|
414
1067
|
&& nbAttempts > 0
|
415
|
-
&&
|
416
|
-
size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->
|
1068
|
+
&& withinStartDistance) {
|
1069
|
+
size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit;
|
417
1070
|
U32 dictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)];
|
418
1071
|
assert(dictEndOffset <= 1 GB);
|
419
1072
|
matchIndex = dictMatchIndex + lowestMatchIndex - (U32)dictEndOffset;
|
1073
|
+
if (dictMatchIndex>0) DEBUGLOG(7, "dictEndOffset = %zu, dictMatchIndex = %u => relative matchIndex = %i", dictEndOffset, dictMatchIndex, (int)dictMatchIndex - (int)dictEndOffset);
|
420
1074
|
while (ipIndex - matchIndex <= LZ4_DISTANCE_MAX && nbAttempts--) {
|
421
|
-
const BYTE* const matchPtr = dictCtx->
|
1075
|
+
const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + dictMatchIndex;
|
422
1076
|
|
423
1077
|
if (LZ4_read32(matchPtr) == pattern) {
|
424
1078
|
int mlt;
|
@@ -426,12 +1080,13 @@ LZ4HC_InsertAndGetWiderMatch (
|
|
426
1080
|
const BYTE* vLimit = ip + (dictEndOffset - dictMatchIndex);
|
427
1081
|
if (vLimit > iHighLimit) vLimit = iHighLimit;
|
428
1082
|
mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
|
429
|
-
back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->
|
1083
|
+
back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->prefixStart) : 0;
|
430
1084
|
mlt -= back;
|
431
1085
|
if (mlt > longest) {
|
432
1086
|
longest = mlt;
|
433
|
-
|
434
|
-
|
1087
|
+
offset = (int)(ipIndex - matchIndex);
|
1088
|
+
sBack = back;
|
1089
|
+
DEBUGLOG(7, "found match of length %i within extDictCtx", longest);
|
435
1090
|
} }
|
436
1091
|
|
437
1092
|
{ U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, dictMatchIndex);
|
@@ -439,112 +1094,29 @@ LZ4HC_InsertAndGetWiderMatch (
|
|
439
1094
|
matchIndex -= nextOffset;
|
440
1095
|
} } }
|
441
1096
|
|
442
|
-
|
1097
|
+
{ LZ4HC_match_t md;
|
1098
|
+
assert(longest >= 0);
|
1099
|
+
md.len = longest;
|
1100
|
+
md.off = offset;
|
1101
|
+
md.back = sBack;
|
1102
|
+
return md;
|
1103
|
+
}
|
443
1104
|
}
|
444
1105
|
|
445
|
-
LZ4_FORCE_INLINE
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
const dictCtx_directive dict)
|
1106
|
+
LZ4_FORCE_INLINE LZ4HC_match_t
|
1107
|
+
LZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4, /* Index table will be updated */
|
1108
|
+
const BYTE* const ip, const BYTE* const iLimit,
|
1109
|
+
const int maxNbAttempts,
|
1110
|
+
const int patternAnalysis,
|
1111
|
+
const dictCtx_directive dict)
|
452
1112
|
{
|
453
|
-
|
1113
|
+
DEBUGLOG(7, "LZ4HC_InsertAndFindBestMatch");
|
454
1114
|
/* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),
|
455
1115
|
* but this won't be the case here, as we define iLowLimit==ip,
|
456
1116
|
* so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */
|
457
|
-
return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1,
|
1117
|
+
return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, maxNbAttempts, patternAnalysis, 0 /*chainSwap*/, dict, favorCompressionRatio);
|
458
1118
|
}
|
459
1119
|
|
460
|
-
/* LZ4HC_encodeSequence() :
|
461
|
-
* @return : 0 if ok,
|
462
|
-
* 1 if buffer issue detected */
|
463
|
-
LZ4_FORCE_INLINE int LZ4HC_encodeSequence (
|
464
|
-
const BYTE** _ip,
|
465
|
-
BYTE** _op,
|
466
|
-
const BYTE** _anchor,
|
467
|
-
int matchLength,
|
468
|
-
const BYTE* const match,
|
469
|
-
limitedOutput_directive limit,
|
470
|
-
BYTE* oend)
|
471
|
-
{
|
472
|
-
#define ip (*_ip)
|
473
|
-
#define op (*_op)
|
474
|
-
#define anchor (*_anchor)
|
475
|
-
|
476
|
-
size_t length;
|
477
|
-
BYTE* const token = op++;
|
478
|
-
|
479
|
-
#if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 6)
|
480
|
-
static const BYTE* start = NULL;
|
481
|
-
static U32 totalCost = 0;
|
482
|
-
U32 const pos = (start==NULL) ? 0 : (U32)(anchor - start);
|
483
|
-
U32 const ll = (U32)(ip - anchor);
|
484
|
-
U32 const llAdd = (ll>=15) ? ((ll-15) / 255) + 1 : 0;
|
485
|
-
U32 const mlAdd = (matchLength>=19) ? ((matchLength-19) / 255) + 1 : 0;
|
486
|
-
U32 const cost = 1 + llAdd + ll + 2 + mlAdd;
|
487
|
-
if (start==NULL) start = anchor; /* only works for single segment */
|
488
|
-
/* g_debuglog_enable = (pos >= 2228) & (pos <= 2262); */
|
489
|
-
DEBUGLOG(6, "pos:%7u -- literals:%4u, match:%4i, offset:%5u, cost:%4u + %5u",
|
490
|
-
pos,
|
491
|
-
(U32)(ip - anchor), matchLength, (U32)(ip-match),
|
492
|
-
cost, totalCost);
|
493
|
-
totalCost += cost;
|
494
|
-
#endif
|
495
|
-
|
496
|
-
/* Encode Literal length */
|
497
|
-
length = (size_t)(ip - anchor);
|
498
|
-
LZ4_STATIC_ASSERT(notLimited == 0);
|
499
|
-
/* Check output limit */
|
500
|
-
if (limit && ((op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) {
|
501
|
-
DEBUGLOG(6, "Not enough room to write %i literals (%i bytes remaining)",
|
502
|
-
(int)length, (int)(oend - op));
|
503
|
-
return 1;
|
504
|
-
}
|
505
|
-
if (length >= RUN_MASK) {
|
506
|
-
size_t len = length - RUN_MASK;
|
507
|
-
*token = (RUN_MASK << ML_BITS);
|
508
|
-
for(; len >= 255 ; len -= 255) *op++ = 255;
|
509
|
-
*op++ = (BYTE)len;
|
510
|
-
} else {
|
511
|
-
*token = (BYTE)(length << ML_BITS);
|
512
|
-
}
|
513
|
-
|
514
|
-
/* Copy Literals */
|
515
|
-
LZ4_wildCopy8(op, anchor, op + length);
|
516
|
-
op += length;
|
517
|
-
|
518
|
-
/* Encode Offset */
|
519
|
-
assert( (ip - match) <= LZ4_DISTANCE_MAX ); /* note : consider providing offset as a value, rather than as a pointer difference */
|
520
|
-
LZ4_writeLE16(op, (U16)(ip - match)); op += 2;
|
521
|
-
|
522
|
-
/* Encode MatchLength */
|
523
|
-
assert(matchLength >= MINMATCH);
|
524
|
-
length = (size_t)matchLength - MINMATCH;
|
525
|
-
if (limit && (op + (length / 255) + (1 + LASTLITERALS) > oend)) {
|
526
|
-
DEBUGLOG(6, "Not enough room to write match length");
|
527
|
-
return 1; /* Check output limit */
|
528
|
-
}
|
529
|
-
if (length >= ML_MASK) {
|
530
|
-
*token += ML_MASK;
|
531
|
-
length -= ML_MASK;
|
532
|
-
for(; length >= 510 ; length -= 510) { *op++ = 255; *op++ = 255; }
|
533
|
-
if (length >= 255) { length -= 255; *op++ = 255; }
|
534
|
-
*op++ = (BYTE)length;
|
535
|
-
} else {
|
536
|
-
*token += (BYTE)(length);
|
537
|
-
}
|
538
|
-
|
539
|
-
/* Prepare next loop */
|
540
|
-
ip += matchLength;
|
541
|
-
anchor = ip;
|
542
|
-
|
543
|
-
return 0;
|
544
|
-
}
|
545
|
-
#undef ip
|
546
|
-
#undef op
|
547
|
-
#undef anchor
|
548
1120
|
|
549
1121
|
LZ4_FORCE_INLINE int LZ4HC_compress_hashChain (
|
550
1122
|
LZ4HC_CCtx_internal* const ctx,
|
@@ -570,127 +1142,130 @@ LZ4_FORCE_INLINE int LZ4HC_compress_hashChain (
|
|
570
1142
|
BYTE* op = (BYTE*) dest;
|
571
1143
|
BYTE* oend = op + maxOutputSize;
|
572
1144
|
|
573
|
-
int ml0, ml, ml2, ml3;
|
574
1145
|
const BYTE* start0;
|
575
|
-
const BYTE* ref0;
|
576
|
-
const BYTE* ref = NULL;
|
577
1146
|
const BYTE* start2 = NULL;
|
578
|
-
const BYTE* ref2 = NULL;
|
579
1147
|
const BYTE* start3 = NULL;
|
580
|
-
|
1148
|
+
LZ4HC_match_t m0, m1, m2, m3;
|
1149
|
+
const LZ4HC_match_t nomatch = {0, 0, 0};
|
581
1150
|
|
582
1151
|
/* init */
|
1152
|
+
DEBUGLOG(5, "LZ4HC_compress_hashChain (dict?=>%i)", dict);
|
583
1153
|
*srcSizePtr = 0;
|
584
1154
|
if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */
|
585
1155
|
if (inputSize < LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
|
586
1156
|
|
587
1157
|
/* Main Loop */
|
588
1158
|
while (ip <= mflimit) {
|
589
|
-
|
590
|
-
if (
|
1159
|
+
m1 = LZ4HC_InsertAndFindBestMatch(ctx, ip, matchlimit, maxNbAttempts, patternAnalysis, dict);
|
1160
|
+
if (m1.len<MINMATCH) { ip++; continue; }
|
591
1161
|
|
592
1162
|
/* saved, in case we would skip too much */
|
593
|
-
start0 = ip;
|
1163
|
+
start0 = ip; m0 = m1;
|
594
1164
|
|
595
1165
|
_Search2:
|
596
|
-
|
597
|
-
|
598
|
-
|
1166
|
+
DEBUGLOG(7, "_Search2 (currently found match of size %i)", m1.len);
|
1167
|
+
if (ip+m1.len <= mflimit) {
|
1168
|
+
start2 = ip + m1.len - 2;
|
1169
|
+
m2 = LZ4HC_InsertAndGetWiderMatch(ctx,
|
1170
|
+
start2, ip + 0, matchlimit, m1.len,
|
599
1171
|
maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);
|
1172
|
+
start2 += m2.back;
|
600
1173
|
} else {
|
601
|
-
|
1174
|
+
m2 = nomatch; /* do not search further */
|
602
1175
|
}
|
603
1176
|
|
604
|
-
if (
|
1177
|
+
if (m2.len <= m1.len) { /* No better match => encode ML1 immediately */
|
605
1178
|
optr = op;
|
606
|
-
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
|
1179
|
+
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
|
1180
|
+
m1.len, m1.off,
|
1181
|
+
limit, oend) )
|
1182
|
+
goto _dest_overflow;
|
607
1183
|
continue;
|
608
1184
|
}
|
609
1185
|
|
610
1186
|
if (start0 < ip) { /* first match was skipped at least once */
|
611
|
-
if (start2 < ip +
|
612
|
-
ip = start0;
|
1187
|
+
if (start2 < ip + m0.len) { /* squeezing ML1 between ML0(original ML1) and ML2 */
|
1188
|
+
ip = start0; m1 = m0; /* restore initial Match1 */
|
613
1189
|
} }
|
614
1190
|
|
615
1191
|
/* Here, start0==ip */
|
616
1192
|
if ((start2 - ip) < 3) { /* First Match too small : removed */
|
617
|
-
ml = ml2;
|
618
1193
|
ip = start2;
|
619
|
-
|
1194
|
+
m1 = m2;
|
620
1195
|
goto _Search2;
|
621
1196
|
}
|
622
1197
|
|
623
1198
|
_Search3:
|
624
|
-
/* At this stage, we have :
|
625
|
-
* ml2 > ml1, and
|
626
|
-
* ip1+3 <= ip2 (usually < ip1+ml1) */
|
627
1199
|
if ((start2 - ip) < OPTIMAL_ML) {
|
628
1200
|
int correction;
|
629
|
-
int new_ml =
|
1201
|
+
int new_ml = m1.len;
|
630
1202
|
if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;
|
631
|
-
if (ip+new_ml > start2 +
|
1203
|
+
if (ip+new_ml > start2 + m2.len - MINMATCH)
|
1204
|
+
new_ml = (int)(start2 - ip) + m2.len - MINMATCH;
|
632
1205
|
correction = new_ml - (int)(start2 - ip);
|
633
1206
|
if (correction > 0) {
|
634
1207
|
start2 += correction;
|
635
|
-
|
636
|
-
ml2 -= correction;
|
1208
|
+
m2.len -= correction;
|
637
1209
|
}
|
638
1210
|
}
|
639
|
-
/* Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) */
|
640
1211
|
|
641
|
-
if (start2 +
|
642
|
-
|
643
|
-
|
1212
|
+
if (start2 + m2.len <= mflimit) {
|
1213
|
+
start3 = start2 + m2.len - 3;
|
1214
|
+
m3 = LZ4HC_InsertAndGetWiderMatch(ctx,
|
1215
|
+
start3, start2, matchlimit, m2.len,
|
644
1216
|
maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);
|
1217
|
+
start3 += m3.back;
|
645
1218
|
} else {
|
646
|
-
|
1219
|
+
m3 = nomatch; /* do not search further */
|
647
1220
|
}
|
648
1221
|
|
649
|
-
if (
|
1222
|
+
if (m3.len <= m2.len) { /* No better match => encode ML1 and ML2 */
|
650
1223
|
/* ip & ref are known; Now for ml */
|
651
|
-
if (start2 < ip+
|
1224
|
+
if (start2 < ip+m1.len) m1.len = (int)(start2 - ip);
|
652
1225
|
/* Now, encode 2 sequences */
|
653
1226
|
optr = op;
|
654
|
-
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
|
1227
|
+
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
|
1228
|
+
m1.len, m1.off,
|
1229
|
+
limit, oend) )
|
1230
|
+
goto _dest_overflow;
|
655
1231
|
ip = start2;
|
656
1232
|
optr = op;
|
657
|
-
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
|
658
|
-
|
659
|
-
|
1233
|
+
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
|
1234
|
+
m2.len, m2.off,
|
1235
|
+
limit, oend) ) {
|
1236
|
+
m1 = m2;
|
660
1237
|
goto _dest_overflow;
|
661
1238
|
}
|
662
1239
|
continue;
|
663
1240
|
}
|
664
1241
|
|
665
|
-
if (start3 < ip+
|
666
|
-
if (start3 >= (ip+
|
667
|
-
if (start2 < ip+
|
668
|
-
int correction = (int)(ip+
|
1242
|
+
if (start3 < ip+m1.len+3) { /* Not enough space for match 2 : remove it */
|
1243
|
+
if (start3 >= (ip+m1.len)) { /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */
|
1244
|
+
if (start2 < ip+m1.len) {
|
1245
|
+
int correction = (int)(ip+m1.len - start2);
|
669
1246
|
start2 += correction;
|
670
|
-
|
671
|
-
|
672
|
-
if (ml2 < MINMATCH) {
|
1247
|
+
m2.len -= correction;
|
1248
|
+
if (m2.len < MINMATCH) {
|
673
1249
|
start2 = start3;
|
674
|
-
|
675
|
-
ml2 = ml3;
|
1250
|
+
m2 = m3;
|
676
1251
|
}
|
677
1252
|
}
|
678
1253
|
|
679
1254
|
optr = op;
|
680
|
-
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
|
1255
|
+
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
|
1256
|
+
m1.len, m1.off,
|
1257
|
+
limit, oend) )
|
1258
|
+
goto _dest_overflow;
|
681
1259
|
ip = start3;
|
682
|
-
|
683
|
-
ml = ml3;
|
1260
|
+
m1 = m3;
|
684
1261
|
|
685
1262
|
start0 = start2;
|
686
|
-
|
687
|
-
ml0 = ml2;
|
1263
|
+
m0 = m2;
|
688
1264
|
goto _Search2;
|
689
1265
|
}
|
690
1266
|
|
691
1267
|
start2 = start3;
|
692
|
-
|
693
|
-
ml2 = ml3;
|
1268
|
+
m2 = m3;
|
694
1269
|
goto _Search3;
|
695
1270
|
}
|
696
1271
|
|
@@ -699,29 +1274,32 @@ _Search3:
|
|
699
1274
|
* let's write the first one ML1.
|
700
1275
|
* ip & ref are known; Now decide ml.
|
701
1276
|
*/
|
702
|
-
if (start2 < ip+
|
1277
|
+
if (start2 < ip+m1.len) {
|
703
1278
|
if ((start2 - ip) < OPTIMAL_ML) {
|
704
1279
|
int correction;
|
705
|
-
if (
|
706
|
-
if (ip +
|
707
|
-
|
1280
|
+
if (m1.len > OPTIMAL_ML) m1.len = OPTIMAL_ML;
|
1281
|
+
if (ip + m1.len > start2 + m2.len - MINMATCH)
|
1282
|
+
m1.len = (int)(start2 - ip) + m2.len - MINMATCH;
|
1283
|
+
correction = m1.len - (int)(start2 - ip);
|
708
1284
|
if (correction > 0) {
|
709
1285
|
start2 += correction;
|
710
|
-
|
711
|
-
ml2 -= correction;
|
1286
|
+
m2.len -= correction;
|
712
1287
|
}
|
713
1288
|
} else {
|
714
|
-
|
1289
|
+
m1.len = (int)(start2 - ip);
|
715
1290
|
}
|
716
1291
|
}
|
717
1292
|
optr = op;
|
718
|
-
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
|
1293
|
+
if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
|
1294
|
+
m1.len, m1.off,
|
1295
|
+
limit, oend) )
|
1296
|
+
goto _dest_overflow;
|
719
1297
|
|
720
1298
|
/* ML2 becomes ML1 */
|
721
|
-
ip = start2;
|
1299
|
+
ip = start2; m1 = m2;
|
722
1300
|
|
723
1301
|
/* ML3 becomes ML2 */
|
724
|
-
start2 = start3;
|
1302
|
+
start2 = start3; m2 = m3;
|
725
1303
|
|
726
1304
|
/* let's find a new ML3 */
|
727
1305
|
goto _Search3;
|
@@ -751,7 +1329,7 @@ _last_literals:
|
|
751
1329
|
} else {
|
752
1330
|
*op++ = (BYTE)(lastRunSize << ML_BITS);
|
753
1331
|
}
|
754
|
-
|
1332
|
+
LZ4_memcpy(op, anchor, lastRunSize);
|
755
1333
|
op += lastRunSize;
|
756
1334
|
}
|
757
1335
|
|
@@ -761,7 +1339,7 @@ _last_literals:
|
|
761
1339
|
|
762
1340
|
_dest_overflow:
|
763
1341
|
if (limit == fillOutput) {
|
764
|
-
/* Assumption : ip, anchor,
|
1342
|
+
/* Assumption : @ip, @anchor, @optr and @m1 must be set correctly */
|
765
1343
|
size_t const ll = (size_t)(ip - anchor);
|
766
1344
|
size_t const ll_addbytes = (ll + 240) / 255;
|
767
1345
|
size_t const ll_totalCost = 1 + ll_addbytes + ll;
|
@@ -772,10 +1350,10 @@ _dest_overflow:
|
|
772
1350
|
/* ll validated; now adjust match length */
|
773
1351
|
size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));
|
774
1352
|
size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);
|
775
|
-
assert(maxMlSize < INT_MAX); assert(
|
776
|
-
if ((size_t)
|
777
|
-
if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 +
|
778
|
-
LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
|
1353
|
+
assert(maxMlSize < INT_MAX); assert(m1.len >= 0);
|
1354
|
+
if ((size_t)m1.len > maxMlSize) m1.len = (int)maxMlSize;
|
1355
|
+
if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + m1.len >= MFLIMIT) {
|
1356
|
+
LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), m1.len, m1.off, notLimited, oend);
|
779
1357
|
} }
|
780
1358
|
goto _last_literals;
|
781
1359
|
}
|
@@ -792,54 +1370,34 @@ static int LZ4HC_compress_optimal( LZ4HC_CCtx_internal* ctx,
|
|
792
1370
|
const dictCtx_directive dict,
|
793
1371
|
const HCfavor_e favorDecSpeed);
|
794
1372
|
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
1373
|
+
LZ4_FORCE_INLINE int
|
1374
|
+
LZ4HC_compress_generic_internal (
|
1375
|
+
LZ4HC_CCtx_internal* const ctx,
|
1376
|
+
const char* const src,
|
1377
|
+
char* const dst,
|
1378
|
+
int* const srcSizePtr,
|
1379
|
+
int const dstCapacity,
|
1380
|
+
int cLevel,
|
1381
|
+
const limitedOutput_directive limit,
|
1382
|
+
const dictCtx_directive dict
|
1383
|
+
)
|
806
1384
|
{
|
807
|
-
|
808
|
-
|
809
|
-
lz4hc_strat_e strat;
|
810
|
-
int nbSearches;
|
811
|
-
U32 targetLength;
|
812
|
-
} cParams_t;
|
813
|
-
static const cParams_t clTable[LZ4HC_CLEVEL_MAX+1] = {
|
814
|
-
{ lz4hc, 2, 16 }, /* 0, unused */
|
815
|
-
{ lz4hc, 2, 16 }, /* 1, unused */
|
816
|
-
{ lz4hc, 2, 16 }, /* 2, unused */
|
817
|
-
{ lz4hc, 4, 16 }, /* 3 */
|
818
|
-
{ lz4hc, 8, 16 }, /* 4 */
|
819
|
-
{ lz4hc, 16, 16 }, /* 5 */
|
820
|
-
{ lz4hc, 32, 16 }, /* 6 */
|
821
|
-
{ lz4hc, 64, 16 }, /* 7 */
|
822
|
-
{ lz4hc, 128, 16 }, /* 8 */
|
823
|
-
{ lz4hc, 256, 16 }, /* 9 */
|
824
|
-
{ lz4opt, 96, 64 }, /*10==LZ4HC_CLEVEL_OPT_MIN*/
|
825
|
-
{ lz4opt, 512,128 }, /*11 */
|
826
|
-
{ lz4opt,16384,LZ4_OPT_NUM }, /* 12==LZ4HC_CLEVEL_MAX */
|
827
|
-
};
|
828
|
-
|
829
|
-
DEBUGLOG(4, "LZ4HC_compress_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)",
|
830
|
-
ctx, src, *srcSizePtr, limit);
|
1385
|
+
DEBUGLOG(5, "LZ4HC_compress_generic_internal(src=%p, srcSize=%d)",
|
1386
|
+
src, *srcSizePtr);
|
831
1387
|
|
832
1388
|
if (limit == fillOutput && dstCapacity < 1) return 0; /* Impossible to store anything */
|
833
|
-
if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0;
|
1389
|
+
if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size (too large or negative) */
|
834
1390
|
|
835
1391
|
ctx->end += *srcSizePtr;
|
836
|
-
|
837
|
-
cLevel = MIN(LZ4HC_CLEVEL_MAX, cLevel);
|
838
|
-
{ cParams_t const cParam = clTable[cLevel];
|
1392
|
+
{ cParams_t const cParam = LZ4HC_getCLevelParams(cLevel);
|
839
1393
|
HCfavor_e const favor = ctx->favorDecSpeed ? favorDecompressionSpeed : favorCompressionRatio;
|
840
1394
|
int result;
|
841
1395
|
|
842
|
-
if (cParam.strat ==
|
1396
|
+
if (cParam.strat == lz4mid) {
|
1397
|
+
result = LZ4MID_compress(ctx,
|
1398
|
+
src, dst, srcSizePtr, dstCapacity,
|
1399
|
+
limit, dict);
|
1400
|
+
} else if (cParam.strat == lz4hc) {
|
843
1401
|
result = LZ4HC_compress_hashChain(ctx,
|
844
1402
|
src, dst, srcSizePtr, dstCapacity,
|
845
1403
|
cParam.nbSearches, limit, dict);
|
@@ -848,7 +1406,7 @@ LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal (
|
|
848
1406
|
result = LZ4HC_compress_optimal(ctx,
|
849
1407
|
src, dst, srcSizePtr, dstCapacity,
|
850
1408
|
cParam.nbSearches, cParam.targetLength, limit,
|
851
|
-
cLevel
|
1409
|
+
cLevel >= LZ4HC_CLEVEL_MAX, /* ultra mode */
|
852
1410
|
dict, favor);
|
853
1411
|
}
|
854
1412
|
if (result <= 0) ctx->dirty = 1;
|
@@ -873,6 +1431,13 @@ LZ4HC_compress_generic_noDictCtx (
|
|
873
1431
|
return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, noDictCtx);
|
874
1432
|
}
|
875
1433
|
|
1434
|
+
static int isStateCompatible(const LZ4HC_CCtx_internal* ctx1, const LZ4HC_CCtx_internal* ctx2)
|
1435
|
+
{
|
1436
|
+
int const isMid1 = LZ4HC_getCLevelParams(ctx1->compressionLevel).strat == lz4mid;
|
1437
|
+
int const isMid2 = LZ4HC_getCLevelParams(ctx2->compressionLevel).strat == lz4mid;
|
1438
|
+
return !(isMid1 ^ isMid2);
|
1439
|
+
}
|
1440
|
+
|
876
1441
|
static int
|
877
1442
|
LZ4HC_compress_generic_dictCtx (
|
878
1443
|
LZ4HC_CCtx_internal* const ctx,
|
@@ -884,13 +1449,13 @@ LZ4HC_compress_generic_dictCtx (
|
|
884
1449
|
limitedOutput_directive limit
|
885
1450
|
)
|
886
1451
|
{
|
887
|
-
const size_t position = (size_t)(ctx->end - ctx->
|
1452
|
+
const size_t position = (size_t)(ctx->end - ctx->prefixStart) + (ctx->dictLimit - ctx->lowLimit);
|
888
1453
|
assert(ctx->dictCtx != NULL);
|
889
1454
|
if (position >= 64 KB) {
|
890
1455
|
ctx->dictCtx = NULL;
|
891
1456
|
return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
|
892
|
-
} else if (position == 0 && *srcSizePtr > 4 KB) {
|
893
|
-
|
1457
|
+
} else if (position == 0 && *srcSizePtr > 4 KB && isStateCompatible(ctx, ctx->dictCtx)) {
|
1458
|
+
LZ4_memcpy(ctx, ctx->dictCtx, sizeof(LZ4HC_CCtx_internal));
|
894
1459
|
LZ4HC_setExternalDict(ctx, (const BYTE *)src);
|
895
1460
|
ctx->compressionLevel = (short)cLevel;
|
896
1461
|
return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
|
@@ -953,13 +1518,16 @@ int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int src
|
|
953
1518
|
|
954
1519
|
int LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
|
955
1520
|
{
|
1521
|
+
int cSize;
|
956
1522
|
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
|
957
1523
|
LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));
|
1524
|
+
if (statePtr==NULL) return 0;
|
958
1525
|
#else
|
959
1526
|
LZ4_streamHC_t state;
|
960
1527
|
LZ4_streamHC_t* const statePtr = &state;
|
961
1528
|
#endif
|
962
|
-
|
1529
|
+
DEBUGLOG(5, "LZ4_compress_HC")
|
1530
|
+
cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel);
|
963
1531
|
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
|
964
1532
|
FREEMEM(statePtr);
|
965
1533
|
#endif
|
@@ -982,6 +1550,7 @@ int LZ4_compress_HC_destSize(void* state, const char* source, char* dest, int* s
|
|
982
1550
|
* Streaming Functions
|
983
1551
|
**************************************/
|
984
1552
|
/* allocation */
|
1553
|
+
#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)
|
985
1554
|
LZ4_streamHC_t* LZ4_createStreamHC(void)
|
986
1555
|
{
|
987
1556
|
LZ4_streamHC_t* const state =
|
@@ -998,13 +1567,12 @@ int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr)
|
|
998
1567
|
FREEMEM(LZ4_streamHCPtr);
|
999
1568
|
return 0;
|
1000
1569
|
}
|
1570
|
+
#endif
|
1001
1571
|
|
1002
1572
|
|
1003
1573
|
LZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size)
|
1004
1574
|
{
|
1005
1575
|
LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)buffer;
|
1006
|
-
/* if compilation fails here, LZ4_STREAMHCSIZE must be increased */
|
1007
|
-
LZ4_STATIC_ASSERT(sizeof(LZ4HC_CCtx_internal) <= LZ4_STREAMHCSIZE);
|
1008
1576
|
DEBUGLOG(4, "LZ4_initStreamHC(%p, %u)", buffer, (unsigned)size);
|
1009
1577
|
/* check conditions */
|
1010
1578
|
if (buffer == NULL) return NULL;
|
@@ -1026,14 +1594,16 @@ void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
|
|
1026
1594
|
|
1027
1595
|
void LZ4_resetStreamHC_fast (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
|
1028
1596
|
{
|
1029
|
-
|
1030
|
-
|
1597
|
+
LZ4HC_CCtx_internal* const s = &LZ4_streamHCPtr->internal_donotuse;
|
1598
|
+
DEBUGLOG(5, "LZ4_resetStreamHC_fast(%p, %d)", LZ4_streamHCPtr, compressionLevel);
|
1599
|
+
if (s->dirty) {
|
1031
1600
|
LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
|
1032
1601
|
} else {
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1602
|
+
assert(s->end >= s->prefixStart);
|
1603
|
+
s->dictLimit += (U32)(s->end - s->prefixStart);
|
1604
|
+
s->prefixStart = NULL;
|
1605
|
+
s->end = NULL;
|
1606
|
+
s->dictCtx = NULL;
|
1037
1607
|
}
|
1038
1608
|
LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);
|
1039
1609
|
}
|
@@ -1057,7 +1627,9 @@ int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr,
|
|
1057
1627
|
const char* dictionary, int dictSize)
|
1058
1628
|
{
|
1059
1629
|
LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
|
1060
|
-
|
1630
|
+
cParams_t cp;
|
1631
|
+
DEBUGLOG(4, "LZ4_loadDictHC(ctx:%p, dict:%p, dictSize:%d, clevel=%d)", LZ4_streamHCPtr, dictionary, dictSize, ctxPtr->compressionLevel);
|
1632
|
+
assert(dictSize >= 0);
|
1061
1633
|
assert(LZ4_streamHCPtr != NULL);
|
1062
1634
|
if (dictSize > 64 KB) {
|
1063
1635
|
dictionary += (size_t)dictSize - 64 KB;
|
@@ -1067,10 +1639,15 @@ int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr,
|
|
1067
1639
|
{ int const cLevel = ctxPtr->compressionLevel;
|
1068
1640
|
LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
|
1069
1641
|
LZ4_setCompressionLevel(LZ4_streamHCPtr, cLevel);
|
1642
|
+
cp = LZ4HC_getCLevelParams(cLevel);
|
1070
1643
|
}
|
1071
1644
|
LZ4HC_init_internal (ctxPtr, (const BYTE*)dictionary);
|
1072
1645
|
ctxPtr->end = (const BYTE*)dictionary + dictSize;
|
1073
|
-
if (
|
1646
|
+
if (cp.strat == lz4mid) {
|
1647
|
+
LZ4MID_fillHTable (ctxPtr, dictionary, (size_t)dictSize);
|
1648
|
+
} else {
|
1649
|
+
if (dictSize >= LZ4HC_HASHSIZE) LZ4HC_Insert (ctxPtr, ctxPtr->end-3);
|
1650
|
+
}
|
1074
1651
|
return dictSize;
|
1075
1652
|
}
|
1076
1653
|
|
@@ -1083,14 +1660,16 @@ void LZ4_attach_HC_dictionary(LZ4_streamHC_t *working_stream, const LZ4_streamHC
|
|
1083
1660
|
static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock)
|
1084
1661
|
{
|
1085
1662
|
DEBUGLOG(4, "LZ4HC_setExternalDict(%p, %p)", ctxPtr, newBlock);
|
1086
|
-
if (ctxPtr->end >= ctxPtr->
|
1087
|
-
|
1663
|
+
if ( (ctxPtr->end >= ctxPtr->prefixStart + 4)
|
1664
|
+
&& (LZ4HC_getCLevelParams(ctxPtr->compressionLevel).strat != lz4mid) ) {
|
1665
|
+
LZ4HC_Insert (ctxPtr, ctxPtr->end-3); /* Referencing remaining dictionary content */
|
1666
|
+
}
|
1088
1667
|
|
1089
1668
|
/* Only one memory segment for extDict, so any previous extDict is lost at this stage */
|
1090
1669
|
ctxPtr->lowLimit = ctxPtr->dictLimit;
|
1091
|
-
ctxPtr->
|
1092
|
-
ctxPtr->
|
1093
|
-
ctxPtr->
|
1670
|
+
ctxPtr->dictStart = ctxPtr->prefixStart;
|
1671
|
+
ctxPtr->dictLimit += (U32)(ctxPtr->end - ctxPtr->prefixStart);
|
1672
|
+
ctxPtr->prefixStart = newBlock;
|
1094
1673
|
ctxPtr->end = newBlock;
|
1095
1674
|
ctxPtr->nextToUpdate = ctxPtr->dictLimit; /* match referencing will resume from there */
|
1096
1675
|
|
@@ -1109,11 +1688,12 @@ LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,
|
|
1109
1688
|
LZ4_streamHCPtr, src, *srcSizePtr, limit);
|
1110
1689
|
assert(ctxPtr != NULL);
|
1111
1690
|
/* auto-init if forgotten */
|
1112
|
-
if (ctxPtr->
|
1691
|
+
if (ctxPtr->prefixStart == NULL)
|
1692
|
+
LZ4HC_init_internal (ctxPtr, (const BYTE*) src);
|
1113
1693
|
|
1114
1694
|
/* Check overflow */
|
1115
|
-
if ((size_t)(ctxPtr->end - ctxPtr->
|
1116
|
-
size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->
|
1695
|
+
if ((size_t)(ctxPtr->end - ctxPtr->prefixStart) + ctxPtr->dictLimit > 2 GB) {
|
1696
|
+
size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->prefixStart);
|
1117
1697
|
if (dictSize > 64 KB) dictSize = 64 KB;
|
1118
1698
|
LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize);
|
1119
1699
|
}
|
@@ -1124,19 +1704,24 @@ LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,
|
|
1124
1704
|
|
1125
1705
|
/* Check overlapping input/dictionary space */
|
1126
1706
|
{ const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr;
|
1127
|
-
const BYTE* const dictBegin = ctxPtr->
|
1128
|
-
const BYTE* const dictEnd = ctxPtr->
|
1707
|
+
const BYTE* const dictBegin = ctxPtr->dictStart;
|
1708
|
+
const BYTE* const dictEnd = ctxPtr->dictStart + (ctxPtr->dictLimit - ctxPtr->lowLimit);
|
1129
1709
|
if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) {
|
1130
1710
|
if (sourceEnd > dictEnd) sourceEnd = dictEnd;
|
1131
|
-
ctxPtr->lowLimit
|
1132
|
-
|
1133
|
-
|
1711
|
+
ctxPtr->lowLimit += (U32)(sourceEnd - ctxPtr->dictStart);
|
1712
|
+
ctxPtr->dictStart += (U32)(sourceEnd - ctxPtr->dictStart);
|
1713
|
+
/* invalidate dictionary is it's too small */
|
1714
|
+
if (ctxPtr->dictLimit - ctxPtr->lowLimit < LZ4HC_HASHSIZE) {
|
1715
|
+
ctxPtr->lowLimit = ctxPtr->dictLimit;
|
1716
|
+
ctxPtr->dictStart = ctxPtr->prefixStart;
|
1717
|
+
} } }
|
1134
1718
|
|
1135
1719
|
return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit);
|
1136
1720
|
}
|
1137
1721
|
|
1138
1722
|
int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int srcSize, int dstCapacity)
|
1139
1723
|
{
|
1724
|
+
DEBUGLOG(5, "LZ4_compress_HC_continue");
|
1140
1725
|
if (dstCapacity < LZ4_compressBound(srcSize))
|
1141
1726
|
return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput);
|
1142
1727
|
else
|
@@ -1149,7 +1734,6 @@ int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const ch
|
|
1149
1734
|
}
|
1150
1735
|
|
1151
1736
|
|
1152
|
-
|
1153
1737
|
/* LZ4_saveDictHC :
|
1154
1738
|
* save history content
|
1155
1739
|
* into a user-provided buffer
|
@@ -1158,7 +1742,7 @@ int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const ch
|
|
1158
1742
|
int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)
|
1159
1743
|
{
|
1160
1744
|
LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse;
|
1161
|
-
int const prefixSize = (int)(streamPtr->end -
|
1745
|
+
int const prefixSize = (int)(streamPtr->end - streamPtr->prefixStart);
|
1162
1746
|
DEBUGLOG(5, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize);
|
1163
1747
|
assert(prefixSize >= 0);
|
1164
1748
|
if (dictSize > 64 KB) dictSize = 64 KB;
|
@@ -1166,12 +1750,13 @@ int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictS
|
|
1166
1750
|
if (dictSize > prefixSize) dictSize = prefixSize;
|
1167
1751
|
if (safeBuffer == NULL) assert(dictSize == 0);
|
1168
1752
|
if (dictSize > 0)
|
1169
|
-
|
1170
|
-
{ U32 const endIndex = (U32)(streamPtr->end - streamPtr->
|
1171
|
-
streamPtr->end = (const BYTE*)safeBuffer + dictSize;
|
1172
|
-
streamPtr->
|
1753
|
+
LZ4_memmove(safeBuffer, streamPtr->end - dictSize, (size_t)dictSize);
|
1754
|
+
{ U32 const endIndex = (U32)(streamPtr->end - streamPtr->prefixStart) + streamPtr->dictLimit;
|
1755
|
+
streamPtr->end = (safeBuffer == NULL) ? NULL : (const BYTE*)safeBuffer + dictSize;
|
1756
|
+
streamPtr->prefixStart = (const BYTE*)safeBuffer;
|
1173
1757
|
streamPtr->dictLimit = endIndex - (U32)dictSize;
|
1174
1758
|
streamPtr->lowLimit = endIndex - (U32)dictSize;
|
1759
|
+
streamPtr->dictStart = streamPtr->prefixStart;
|
1175
1760
|
if (streamPtr->nextToUpdate < streamPtr->dictLimit)
|
1176
1761
|
streamPtr->nextToUpdate = streamPtr->dictLimit;
|
1177
1762
|
}
|
@@ -1179,73 +1764,6 @@ int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictS
|
|
1179
1764
|
}
|
1180
1765
|
|
1181
1766
|
|
1182
|
-
/***************************************************
|
1183
|
-
* Deprecated Functions
|
1184
|
-
***************************************************/
|
1185
|
-
|
1186
|
-
/* These functions currently generate deprecation warnings */
|
1187
|
-
|
1188
|
-
/* Wrappers for deprecated compression functions */
|
1189
|
-
int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
|
1190
|
-
int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); }
|
1191
|
-
int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
|
1192
|
-
int LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); }
|
1193
|
-
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); }
|
1194
|
-
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); }
|
1195
|
-
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); }
|
1196
|
-
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); }
|
1197
|
-
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)); }
|
1198
|
-
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); }
|
1199
|
-
|
1200
|
-
|
1201
|
-
/* Deprecated streaming functions */
|
1202
|
-
int LZ4_sizeofStreamStateHC(void) { return LZ4_STREAMHCSIZE; }
|
1203
|
-
|
1204
|
-
/* state is presumed correctly sized, aka >= sizeof(LZ4_streamHC_t)
|
1205
|
-
* @return : 0 on success, !=0 if error */
|
1206
|
-
int LZ4_resetStreamStateHC(void* state, char* inputBuffer)
|
1207
|
-
{
|
1208
|
-
LZ4_streamHC_t* const hc4 = LZ4_initStreamHC(state, sizeof(*hc4));
|
1209
|
-
if (hc4 == NULL) return 1; /* init failed */
|
1210
|
-
LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
|
1211
|
-
return 0;
|
1212
|
-
}
|
1213
|
-
|
1214
|
-
void* LZ4_createHC (const char* inputBuffer)
|
1215
|
-
{
|
1216
|
-
LZ4_streamHC_t* const hc4 = LZ4_createStreamHC();
|
1217
|
-
if (hc4 == NULL) return NULL; /* not enough memory */
|
1218
|
-
LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
|
1219
|
-
return hc4;
|
1220
|
-
}
|
1221
|
-
|
1222
|
-
int LZ4_freeHC (void* LZ4HC_Data)
|
1223
|
-
{
|
1224
|
-
if (!LZ4HC_Data) return 0; /* support free on NULL */
|
1225
|
-
FREEMEM(LZ4HC_Data);
|
1226
|
-
return 0;
|
1227
|
-
}
|
1228
|
-
|
1229
|
-
int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)
|
1230
|
-
{
|
1231
|
-
return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited);
|
1232
|
-
}
|
1233
|
-
|
1234
|
-
int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel)
|
1235
|
-
{
|
1236
|
-
return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput);
|
1237
|
-
}
|
1238
|
-
|
1239
|
-
char* LZ4_slideInputBufferHC(void* LZ4HC_Data)
|
1240
|
-
{
|
1241
|
-
LZ4_streamHC_t *ctx = (LZ4_streamHC_t*)LZ4HC_Data;
|
1242
|
-
const BYTE *bufferStart = ctx->internal_donotuse.base + ctx->internal_donotuse.lowLimit;
|
1243
|
-
LZ4_resetStreamHC_fast(ctx, ctx->internal_donotuse.compressionLevel);
|
1244
|
-
/* avoid const char * -> char * conversion warning :( */
|
1245
|
-
return (char *)(uptrval)bufferStart;
|
1246
|
-
}
|
1247
|
-
|
1248
|
-
|
1249
1767
|
/* ================================================
|
1250
1768
|
* LZ4 Optimal parser (levels [LZ4HC_CLEVEL_OPT_MIN - LZ4HC_CLEVEL_MAX])
|
1251
1769
|
* ===============================================*/
|
@@ -1266,7 +1784,6 @@ LZ4_FORCE_INLINE int LZ4HC_literalsPrice(int const litlen)
|
|
1266
1784
|
return price;
|
1267
1785
|
}
|
1268
1786
|
|
1269
|
-
|
1270
1787
|
/* requires mlen >= MINMATCH */
|
1271
1788
|
LZ4_FORCE_INLINE int LZ4HC_sequencePrice(int litlen, int mlen)
|
1272
1789
|
{
|
@@ -1282,12 +1799,6 @@ LZ4_FORCE_INLINE int LZ4HC_sequencePrice(int litlen, int mlen)
|
|
1282
1799
|
return price;
|
1283
1800
|
}
|
1284
1801
|
|
1285
|
-
|
1286
|
-
typedef struct {
|
1287
|
-
int off;
|
1288
|
-
int len;
|
1289
|
-
} LZ4HC_match_t;
|
1290
|
-
|
1291
1802
|
LZ4_FORCE_INLINE LZ4HC_match_t
|
1292
1803
|
LZ4HC_FindLongerMatch(LZ4HC_CCtx_internal* const ctx,
|
1293
1804
|
const BYTE* ip, const BYTE* const iHighLimit,
|
@@ -1295,19 +1806,17 @@ LZ4HC_FindLongerMatch(LZ4HC_CCtx_internal* const ctx,
|
|
1295
1806
|
const dictCtx_directive dict,
|
1296
1807
|
const HCfavor_e favorDecSpeed)
|
1297
1808
|
{
|
1298
|
-
LZ4HC_match_t
|
1299
|
-
const BYTE* matchPtr = NULL;
|
1809
|
+
LZ4HC_match_t const match0 = { 0 , 0, 0 };
|
1300
1810
|
/* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),
|
1301
1811
|
* but this won't be the case here, as we define iLowLimit==ip,
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1812
|
+
** so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */
|
1813
|
+
LZ4HC_match_t md = LZ4HC_InsertAndGetWiderMatch(ctx, ip, ip, iHighLimit, minLen, nbSearches, 1 /*patternAnalysis*/, 1 /*chainSwap*/, dict, favorDecSpeed);
|
1814
|
+
assert(md.back == 0);
|
1815
|
+
if (md.len <= minLen) return match0;
|
1305
1816
|
if (favorDecSpeed) {
|
1306
|
-
if ((
|
1817
|
+
if ((md.len>18) & (md.len<=36)) md.len=18; /* favor dec.speed (shortcut) */
|
1307
1818
|
}
|
1308
|
-
|
1309
|
-
match.off = (int)(ip-matchPtr);
|
1310
|
-
return match;
|
1819
|
+
return md;
|
1311
1820
|
}
|
1312
1821
|
|
1313
1822
|
|
@@ -1325,7 +1834,7 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,
|
|
1325
1834
|
{
|
1326
1835
|
int retval = 0;
|
1327
1836
|
#define TRAILING_LITERALS 3
|
1328
|
-
#
|
1837
|
+
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
|
1329
1838
|
LZ4HC_optimal_t* const opt = (LZ4HC_optimal_t*)ALLOC(sizeof(LZ4HC_optimal_t) * (LZ4_OPT_NUM + TRAILING_LITERALS));
|
1330
1839
|
#else
|
1331
1840
|
LZ4HC_optimal_t opt[LZ4_OPT_NUM + TRAILING_LITERALS]; /* ~64 KB, which is a bit large for stack... */
|
@@ -1340,10 +1849,10 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,
|
|
1340
1849
|
BYTE* opSaved = (BYTE*) dst;
|
1341
1850
|
BYTE* oend = op + dstCapacity;
|
1342
1851
|
int ovml = MINMATCH; /* overflow - last sequence */
|
1343
|
-
|
1852
|
+
int ovoff = 0;
|
1344
1853
|
|
1345
1854
|
/* init */
|
1346
|
-
#
|
1855
|
+
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
|
1347
1856
|
if (opt == NULL) goto _return_label;
|
1348
1857
|
#endif
|
1349
1858
|
DEBUGLOG(5, "LZ4HC_compress_optimal(dst=%p, dstCapa=%u)", dst, (unsigned)dstCapacity);
|
@@ -1363,11 +1872,10 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,
|
|
1363
1872
|
if ((size_t)firstMatch.len > sufficient_len) {
|
1364
1873
|
/* good enough solution : immediate encoding */
|
1365
1874
|
int const firstML = firstMatch.len;
|
1366
|
-
const BYTE* const matchPos = ip - firstMatch.off;
|
1367
1875
|
opSaved = op;
|
1368
|
-
if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML,
|
1876
|
+
if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, firstMatch.off, limit, oend) ) { /* updates ip, op and anchor */
|
1369
1877
|
ovml = firstML;
|
1370
|
-
|
1878
|
+
ovoff = firstMatch.off;
|
1371
1879
|
goto _dest_overflow;
|
1372
1880
|
}
|
1373
1881
|
continue;
|
@@ -1385,11 +1893,11 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,
|
|
1385
1893
|
rPos, cost, opt[rPos].litlen);
|
1386
1894
|
} }
|
1387
1895
|
/* set prices using initial match */
|
1388
|
-
{ int
|
1389
|
-
int const matchML = firstMatch.len; /* necessarily < sufficient_len < LZ4_OPT_NUM */
|
1896
|
+
{ int const matchML = firstMatch.len; /* necessarily < sufficient_len < LZ4_OPT_NUM */
|
1390
1897
|
int const offset = firstMatch.off;
|
1898
|
+
int mlen;
|
1391
1899
|
assert(matchML < LZ4_OPT_NUM);
|
1392
|
-
for ( ; mlen <= matchML ; mlen++) {
|
1900
|
+
for (mlen = MINMATCH ; mlen <= matchML ; mlen++) {
|
1393
1901
|
int const cost = LZ4HC_sequencePrice(llen, mlen);
|
1394
1902
|
opt[mlen].mlen = mlen;
|
1395
1903
|
opt[mlen].off = offset;
|
@@ -1541,9 +2049,9 @@ encode: /* cur, last_match_pos, best_mlen, best_off must be set */
|
|
1541
2049
|
assert(ml >= MINMATCH);
|
1542
2050
|
assert((offset >= 1) && (offset <= LZ4_DISTANCE_MAX));
|
1543
2051
|
opSaved = op;
|
1544
|
-
if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml,
|
2052
|
+
if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, offset, limit, oend) ) { /* updates ip, op and anchor */
|
1545
2053
|
ovml = ml;
|
1546
|
-
|
2054
|
+
ovoff = offset;
|
1547
2055
|
goto _dest_overflow;
|
1548
2056
|
} } }
|
1549
2057
|
} /* while (ip <= mflimit) */
|
@@ -1575,7 +2083,7 @@ _last_literals:
|
|
1575
2083
|
} else {
|
1576
2084
|
*op++ = (BYTE)(lastRunSize << ML_BITS);
|
1577
2085
|
}
|
1578
|
-
|
2086
|
+
LZ4_memcpy(op, anchor, lastRunSize);
|
1579
2087
|
op += lastRunSize;
|
1580
2088
|
}
|
1581
2089
|
|
@@ -1602,14 +2110,83 @@ if (limit == fillOutput) {
|
|
1602
2110
|
if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ovml >= MFLIMIT) {
|
1603
2111
|
DEBUGLOG(6, "Space to end : %i + ml (%i)", (int)((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1), ovml);
|
1604
2112
|
DEBUGLOG(6, "Before : ip = %p, anchor = %p", ip, anchor);
|
1605
|
-
LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ovml,
|
2113
|
+
LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ovml, ovoff, notLimited, oend);
|
1606
2114
|
DEBUGLOG(6, "After : ip = %p, anchor = %p", ip, anchor);
|
1607
2115
|
} }
|
1608
2116
|
goto _last_literals;
|
1609
2117
|
}
|
1610
2118
|
_return_label:
|
1611
|
-
#
|
1612
|
-
FREEMEM(opt);
|
2119
|
+
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
|
2120
|
+
if (opt) FREEMEM(opt);
|
1613
2121
|
#endif
|
1614
2122
|
return retval;
|
1615
2123
|
}
|
2124
|
+
|
2125
|
+
|
2126
|
+
/***************************************************
|
2127
|
+
* Deprecated Functions
|
2128
|
+
***************************************************/
|
2129
|
+
|
2130
|
+
/* These functions currently generate deprecation warnings */
|
2131
|
+
|
2132
|
+
/* Wrappers for deprecated compression functions */
|
2133
|
+
int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
|
2134
|
+
int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); }
|
2135
|
+
int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
|
2136
|
+
int LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); }
|
2137
|
+
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); }
|
2138
|
+
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); }
|
2139
|
+
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); }
|
2140
|
+
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); }
|
2141
|
+
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)); }
|
2142
|
+
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); }
|
2143
|
+
|
2144
|
+
|
2145
|
+
/* Deprecated streaming functions */
|
2146
|
+
int LZ4_sizeofStreamStateHC(void) { return sizeof(LZ4_streamHC_t); }
|
2147
|
+
|
2148
|
+
/* state is presumed correctly sized, aka >= sizeof(LZ4_streamHC_t)
|
2149
|
+
* @return : 0 on success, !=0 if error */
|
2150
|
+
int LZ4_resetStreamStateHC(void* state, char* inputBuffer)
|
2151
|
+
{
|
2152
|
+
LZ4_streamHC_t* const hc4 = LZ4_initStreamHC(state, sizeof(*hc4));
|
2153
|
+
if (hc4 == NULL) return 1; /* init failed */
|
2154
|
+
LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
|
2155
|
+
return 0;
|
2156
|
+
}
|
2157
|
+
|
2158
|
+
#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)
|
2159
|
+
void* LZ4_createHC (const char* inputBuffer)
|
2160
|
+
{
|
2161
|
+
LZ4_streamHC_t* const hc4 = LZ4_createStreamHC();
|
2162
|
+
if (hc4 == NULL) return NULL; /* not enough memory */
|
2163
|
+
LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
|
2164
|
+
return hc4;
|
2165
|
+
}
|
2166
|
+
|
2167
|
+
int LZ4_freeHC (void* LZ4HC_Data)
|
2168
|
+
{
|
2169
|
+
if (!LZ4HC_Data) return 0; /* support free on NULL */
|
2170
|
+
FREEMEM(LZ4HC_Data);
|
2171
|
+
return 0;
|
2172
|
+
}
|
2173
|
+
#endif
|
2174
|
+
|
2175
|
+
int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)
|
2176
|
+
{
|
2177
|
+
return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited);
|
2178
|
+
}
|
2179
|
+
|
2180
|
+
int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel)
|
2181
|
+
{
|
2182
|
+
return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput);
|
2183
|
+
}
|
2184
|
+
|
2185
|
+
char* LZ4_slideInputBufferHC(void* LZ4HC_Data)
|
2186
|
+
{
|
2187
|
+
LZ4HC_CCtx_internal* const s = &((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse;
|
2188
|
+
const BYTE* const bufferStart = s->prefixStart - s->dictLimit + s->lowLimit;
|
2189
|
+
LZ4_resetStreamHC_fast((LZ4_streamHC_t*)LZ4HC_Data, s->compressionLevel);
|
2190
|
+
/* ugly conversion trick, required to evade (const char*) -> (char*) cast-qual warning :( */
|
2191
|
+
return (char*)(uptrval)bufferStart;
|
2192
|
+
}
|