extlz4 0.2.5 → 0.3.4
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/HISTORY.ja.md +16 -1
- data/README.md +49 -51
- data/Rakefile +22 -0
- data/bin/extlz4 +1 -1
- data/contrib/lz4/LICENSE +2 -1
- data/contrib/lz4/Makefile.inc +111 -0
- data/contrib/lz4/NEWS +97 -0
- data/contrib/lz4/README.md +41 -36
- data/contrib/lz4/build/README.md +55 -0
- data/contrib/lz4/build/VS2010/datagen/datagen.vcxproj +169 -0
- data/contrib/lz4/build/VS2010/frametest/frametest.vcxproj +176 -0
- data/contrib/lz4/build/VS2010/fullbench/fullbench.vcxproj +176 -0
- data/contrib/lz4/build/VS2010/fullbench-dll/fullbench-dll.vcxproj +180 -0
- data/contrib/lz4/build/VS2010/fuzzer/fuzzer.vcxproj +173 -0
- data/contrib/lz4/build/VS2010/liblz4/liblz4.vcxproj +175 -0
- data/contrib/lz4/build/VS2010/liblz4-dll/liblz4-dll.rc +51 -0
- data/contrib/lz4/build/VS2010/liblz4-dll/liblz4-dll.vcxproj +179 -0
- data/contrib/lz4/build/VS2010/lz4/lz4.rc +51 -0
- data/contrib/lz4/build/VS2010/lz4/lz4.vcxproj +189 -0
- data/contrib/lz4/build/VS2010/lz4.sln +98 -0
- data/contrib/lz4/build/VS2017/datagen/datagen.vcxproj +173 -0
- data/contrib/lz4/build/VS2017/frametest/frametest.vcxproj +180 -0
- data/contrib/lz4/build/VS2017/fullbench/fullbench.vcxproj +180 -0
- data/contrib/lz4/build/VS2017/fullbench-dll/fullbench-dll.vcxproj +184 -0
- data/contrib/lz4/build/VS2017/fuzzer/fuzzer.vcxproj +177 -0
- data/contrib/lz4/build/VS2017/liblz4/liblz4.vcxproj +179 -0
- data/contrib/lz4/build/VS2017/liblz4-dll/liblz4-dll.rc +51 -0
- data/contrib/lz4/build/VS2017/liblz4-dll/liblz4-dll.vcxproj +183 -0
- data/contrib/lz4/build/VS2017/lz4/lz4.rc +51 -0
- data/contrib/lz4/build/VS2017/lz4/lz4.vcxproj +175 -0
- data/contrib/lz4/build/VS2017/lz4.sln +103 -0
- data/contrib/lz4/build/VS2022/datagen/datagen.vcxproj +173 -0
- data/contrib/lz4/build/VS2022/frametest/frametest.vcxproj +180 -0
- data/contrib/lz4/build/VS2022/fullbench/fullbench.vcxproj +180 -0
- data/contrib/lz4/build/VS2022/fullbench-dll/fullbench-dll.vcxproj +184 -0
- data/contrib/lz4/build/VS2022/fuzzer/fuzzer.vcxproj +177 -0
- data/contrib/lz4/build/VS2022/liblz4/liblz4.vcxproj +179 -0
- data/contrib/lz4/build/VS2022/liblz4-dll/liblz4-dll.rc +51 -0
- data/contrib/lz4/build/VS2022/liblz4-dll/liblz4-dll.vcxproj +183 -0
- data/contrib/lz4/build/VS2022/lz4.sln +103 -0
- data/contrib/lz4/build/cmake/CMakeLists.txt +273 -0
- data/contrib/lz4/build/cmake/lz4Config.cmake.in +2 -0
- data/contrib/lz4/lib/LICENSE +1 -1
- data/contrib/lz4/lib/README.md +111 -15
- data/contrib/lz4/lib/liblz4-dll.rc.in +35 -0
- data/contrib/lz4/lib/liblz4.pc.in +3 -3
- data/contrib/lz4/lib/lz4.c +1891 -733
- data/contrib/lz4/lib/lz4.h +597 -234
- data/contrib/lz4/lib/lz4file.c +311 -0
- data/contrib/lz4/lib/lz4file.h +93 -0
- data/contrib/lz4/lib/lz4frame.c +896 -493
- data/contrib/lz4/lib/lz4frame.h +408 -107
- data/contrib/lz4/lib/lz4frame_static.h +5 -112
- data/contrib/lz4/lib/lz4hc.c +1039 -301
- data/contrib/lz4/lib/lz4hc.h +264 -123
- data/contrib/lz4/lib/xxhash.c +376 -240
- data/contrib/lz4/lib/xxhash.h +128 -93
- data/contrib/lz4/ossfuzz/Makefile +79 -0
- data/contrib/lz4/ossfuzz/compress_frame_fuzzer.c +48 -0
- data/contrib/lz4/ossfuzz/compress_fuzzer.c +58 -0
- data/contrib/lz4/ossfuzz/compress_hc_fuzzer.c +64 -0
- data/contrib/lz4/ossfuzz/decompress_frame_fuzzer.c +75 -0
- data/contrib/lz4/ossfuzz/decompress_fuzzer.c +78 -0
- data/contrib/lz4/ossfuzz/fuzz.h +48 -0
- data/contrib/lz4/ossfuzz/fuzz_data_producer.c +77 -0
- data/contrib/lz4/ossfuzz/fuzz_data_producer.h +36 -0
- data/contrib/lz4/ossfuzz/fuzz_helpers.h +95 -0
- data/contrib/lz4/ossfuzz/lz4_helpers.c +51 -0
- data/contrib/lz4/ossfuzz/lz4_helpers.h +13 -0
- data/contrib/lz4/ossfuzz/ossfuzz.sh +23 -0
- data/contrib/lz4/ossfuzz/round_trip_frame_fuzzer.c +43 -0
- data/contrib/lz4/ossfuzz/round_trip_frame_uncompressed_fuzzer.c +134 -0
- data/contrib/lz4/ossfuzz/round_trip_fuzzer.c +117 -0
- data/contrib/lz4/ossfuzz/round_trip_hc_fuzzer.c +44 -0
- data/contrib/lz4/ossfuzz/round_trip_stream_fuzzer.c +302 -0
- data/contrib/lz4/ossfuzz/standaloneengine.c +74 -0
- data/contrib/lz4/ossfuzz/travisoss.sh +26 -0
- data/ext/blockapi.c +13 -48
- data/ext/extlz4.c +2 -0
- data/ext/extlz4.h +17 -0
- data/ext/frameapi.c +3 -14
- data/ext/hashargs.c +9 -3
- data/ext/hashargs.h +1 -1
- data/ext/lz4_amalgam.c +0 -23
- data/gemstub.rb +5 -16
- data/lib/extlz4/oldstream.rb +1 -1
- data/lib/extlz4.rb +51 -3
- data/test/common.rb +2 -2
- metadata +84 -16
- data/contrib/lz4/circle.yml +0 -38
- data/contrib/lz4/lib/lz4opt.h +0 -356
- data/lib/extlz4/version.rb +0 -3
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
|
|
@@ -42,7 +42,7 @@
|
|
42
42
|
* Select how default compression function will allocate workplace memory,
|
43
43
|
* in stack (0:fastest), or in heap (1:requires malloc()).
|
44
44
|
* Since workplace is rather large, heap mode is recommended.
|
45
|
-
|
45
|
+
**/
|
46
46
|
#ifndef LZ4HC_HEAPMODE
|
47
47
|
# define LZ4HC_HEAPMODE 1
|
48
48
|
#endif
|
@@ -53,7 +53,7 @@
|
|
53
53
|
#include "lz4hc.h"
|
54
54
|
|
55
55
|
|
56
|
-
/*=== Common
|
56
|
+
/*=== Common definitions ===*/
|
57
57
|
#if defined(__GNUC__)
|
58
58
|
# pragma GCC diagnostic ignored "-Wunused-function"
|
59
59
|
#endif
|
@@ -62,11 +62,18 @@
|
|
62
62
|
#endif
|
63
63
|
|
64
64
|
#define LZ4_COMMONDEFS_ONLY
|
65
|
+
#ifndef LZ4_SRC_INCLUDED
|
65
66
|
#include "lz4.c" /* LZ4_count, constants, mem */
|
67
|
+
#endif
|
68
|
+
|
69
|
+
|
70
|
+
/*=== Enums ===*/
|
71
|
+
typedef enum { noDictCtx, usingDictCtxHc } dictCtx_directive;
|
66
72
|
|
67
73
|
|
68
74
|
/*=== Constants ===*/
|
69
75
|
#define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH)
|
76
|
+
#define LZ4_OPT_NUM (1<<12)
|
70
77
|
|
71
78
|
|
72
79
|
/*=== Macros ===*/
|
@@ -75,24 +82,37 @@
|
|
75
82
|
#define HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG))
|
76
83
|
#define DELTANEXTMAXD(p) chainTable[(p) & LZ4HC_MAXD_MASK] /* flexible, LZ4HC_MAXD dependent */
|
77
84
|
#define DELTANEXTU16(table, pos) table[(U16)(pos)] /* faster */
|
85
|
+
/* Make fields passed to, and updated by LZ4HC_encodeSequence explicit */
|
86
|
+
#define UPDATABLE(ip, op, anchor) &ip, &op, &anchor
|
78
87
|
|
79
88
|
static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }
|
80
89
|
|
81
90
|
|
82
|
-
|
83
91
|
/**************************************
|
84
92
|
* HC Compression
|
85
93
|
**************************************/
|
86
|
-
static void
|
94
|
+
static void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4)
|
87
95
|
{
|
88
|
-
MEM_INIT(
|
96
|
+
MEM_INIT(hc4->hashTable, 0, sizeof(hc4->hashTable));
|
89
97
|
MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));
|
90
|
-
|
91
|
-
|
98
|
+
}
|
99
|
+
|
100
|
+
static void LZ4HC_init_internal (LZ4HC_CCtx_internal* hc4, const BYTE* start)
|
101
|
+
{
|
102
|
+
size_t const bufferSize = (size_t)(hc4->end - hc4->prefixStart);
|
103
|
+
size_t newStartingOffset = bufferSize + hc4->dictLimit;
|
104
|
+
assert(newStartingOffset >= bufferSize); /* check overflow */
|
105
|
+
if (newStartingOffset > 1 GB) {
|
106
|
+
LZ4HC_clearTables(hc4);
|
107
|
+
newStartingOffset = 0;
|
108
|
+
}
|
109
|
+
newStartingOffset += 64 KB;
|
110
|
+
hc4->nextToUpdate = (U32)newStartingOffset;
|
111
|
+
hc4->prefixStart = start;
|
92
112
|
hc4->end = start;
|
93
|
-
hc4->
|
94
|
-
hc4->dictLimit =
|
95
|
-
hc4->lowLimit =
|
113
|
+
hc4->dictStart = start;
|
114
|
+
hc4->dictLimit = (U32)newStartingOffset;
|
115
|
+
hc4->lowLimit = (U32)newStartingOffset;
|
96
116
|
}
|
97
117
|
|
98
118
|
|
@@ -101,14 +121,17 @@ LZ4_FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip)
|
|
101
121
|
{
|
102
122
|
U16* const chainTable = hc4->chainTable;
|
103
123
|
U32* const hashTable = hc4->hashTable;
|
104
|
-
const BYTE* const
|
105
|
-
U32 const
|
124
|
+
const BYTE* const prefixPtr = hc4->prefixStart;
|
125
|
+
U32 const prefixIdx = hc4->dictLimit;
|
126
|
+
U32 const target = (U32)(ip - prefixPtr) + prefixIdx;
|
106
127
|
U32 idx = hc4->nextToUpdate;
|
128
|
+
assert(ip >= prefixPtr);
|
129
|
+
assert(target >= prefixIdx);
|
107
130
|
|
108
131
|
while (idx < target) {
|
109
|
-
U32 const h = LZ4HC_hashPtr(
|
132
|
+
U32 const h = LZ4HC_hashPtr(prefixPtr+idx-prefixIdx);
|
110
133
|
size_t delta = idx - hashTable[h];
|
111
|
-
if (delta>
|
134
|
+
if (delta>LZ4_DISTANCE_MAX) delta = LZ4_DISTANCE_MAX;
|
112
135
|
DELTANEXTU16(chainTable, idx) = (U16)delta;
|
113
136
|
hashTable[h] = idx;
|
114
137
|
idx++;
|
@@ -123,20 +146,39 @@ LZ4_FORCE_INLINE
|
|
123
146
|
int LZ4HC_countBack(const BYTE* const ip, const BYTE* const match,
|
124
147
|
const BYTE* const iMin, const BYTE* const mMin)
|
125
148
|
{
|
126
|
-
int back=0;
|
127
|
-
|
128
|
-
|
129
|
-
|
149
|
+
int back = 0;
|
150
|
+
int const min = (int)MAX(iMin - ip, mMin - match);
|
151
|
+
assert(min <= 0);
|
152
|
+
assert(ip >= iMin); assert((size_t)(ip-iMin) < (1U<<31));
|
153
|
+
assert(match >= mMin); assert((size_t)(match - mMin) < (1U<<31));
|
154
|
+
while ( (back > min)
|
155
|
+
&& (ip[back-1] == match[back-1]) )
|
130
156
|
back--;
|
131
157
|
return back;
|
132
158
|
}
|
133
159
|
|
160
|
+
#if defined(_MSC_VER)
|
161
|
+
# define LZ4HC_rotl32(x,r) _rotl(x,r)
|
162
|
+
#else
|
163
|
+
# define LZ4HC_rotl32(x,r) ((x << r) | (x >> (32 - r)))
|
164
|
+
#endif
|
165
|
+
|
166
|
+
|
167
|
+
static U32 LZ4HC_rotatePattern(size_t const rotate, U32 const pattern)
|
168
|
+
{
|
169
|
+
size_t const bitsToRotate = (rotate & (sizeof(pattern) - 1)) << 3;
|
170
|
+
if (bitsToRotate == 0) return pattern;
|
171
|
+
return LZ4HC_rotl32(pattern, (int)bitsToRotate);
|
172
|
+
}
|
173
|
+
|
134
174
|
/* LZ4HC_countPattern() :
|
135
175
|
* pattern32 must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!) */
|
136
|
-
static unsigned
|
176
|
+
static unsigned
|
177
|
+
LZ4HC_countPattern(const BYTE* ip, const BYTE* const iEnd, U32 const pattern32)
|
137
178
|
{
|
138
179
|
const BYTE* const iStart = ip;
|
139
|
-
reg_t const pattern = (sizeof(pattern)==8) ?
|
180
|
+
reg_t const pattern = (sizeof(pattern)==8) ?
|
181
|
+
(reg_t)pattern32 + (((reg_t)pattern32) << (sizeof(pattern)*4)) : pattern32;
|
140
182
|
|
141
183
|
while (likely(ip < iEnd-(sizeof(pattern)-1))) {
|
142
184
|
reg_t const diff = LZ4_read_ARCH(ip) ^ pattern;
|
@@ -156,16 +198,16 @@ static unsigned LZ4HC_countPattern(const BYTE* ip, const BYTE* const iEnd, U32 c
|
|
156
198
|
BYTE const byte = (BYTE)(pattern >> bitOffset);
|
157
199
|
if (*ip != byte) break;
|
158
200
|
ip ++; bitOffset -= 8;
|
159
|
-
|
160
|
-
}
|
201
|
+
} }
|
161
202
|
|
162
203
|
return (unsigned)(ip - iStart);
|
163
204
|
}
|
164
205
|
|
165
206
|
/* LZ4HC_reverseCountPattern() :
|
166
207
|
* pattern must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!)
|
167
|
-
* read using natural platform
|
168
|
-
static unsigned
|
208
|
+
* read using natural platform endianness */
|
209
|
+
static unsigned
|
210
|
+
LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern)
|
169
211
|
{
|
170
212
|
const BYTE* const iStart = ip;
|
171
213
|
|
@@ -173,7 +215,7 @@ static unsigned LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow
|
|
173
215
|
if (LZ4_read32(ip-4) != pattern) break;
|
174
216
|
ip -= 4;
|
175
217
|
}
|
176
|
-
{ const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any
|
218
|
+
{ const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianness */
|
177
219
|
while (likely(ip>iLow)) {
|
178
220
|
if (ip[-1] != *bytePtr) break;
|
179
221
|
ip--; bytePtr--;
|
@@ -181,28 +223,46 @@ static unsigned LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow
|
|
181
223
|
return (unsigned)(iStart - ip);
|
182
224
|
}
|
183
225
|
|
184
|
-
|
226
|
+
/* LZ4HC_protectDictEnd() :
|
227
|
+
* Checks if the match is in the last 3 bytes of the dictionary, so reading the
|
228
|
+
* 4 byte MINMATCH would overflow.
|
229
|
+
* @returns true if the match index is okay.
|
230
|
+
*/
|
231
|
+
static int LZ4HC_protectDictEnd(U32 const dictLimit, U32 const matchIndex)
|
232
|
+
{
|
233
|
+
return ((U32)((dictLimit - 1) - matchIndex) >= 3);
|
234
|
+
}
|
185
235
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
236
|
+
typedef enum { rep_untested, rep_not, rep_confirmed } repeat_state_e;
|
237
|
+
typedef enum { favorCompressionRatio=0, favorDecompressionSpeed } HCfavor_e;
|
238
|
+
|
239
|
+
LZ4_FORCE_INLINE int
|
240
|
+
LZ4HC_InsertAndGetWiderMatch (
|
241
|
+
LZ4HC_CCtx_internal* const hc4,
|
242
|
+
const BYTE* const ip,
|
243
|
+
const BYTE* const iLowLimit, const BYTE* const iHighLimit,
|
244
|
+
int longest,
|
245
|
+
const BYTE** matchpos,
|
246
|
+
const BYTE** startpos,
|
247
|
+
const int maxNbAttempts,
|
248
|
+
const int patternAnalysis, const int chainSwap,
|
249
|
+
const dictCtx_directive dict,
|
250
|
+
const HCfavor_e favorDecSpeed)
|
196
251
|
{
|
197
252
|
U16* const chainTable = hc4->chainTable;
|
198
253
|
U32* const HashTable = hc4->hashTable;
|
199
|
-
const
|
200
|
-
const
|
201
|
-
const
|
202
|
-
const U32
|
203
|
-
const
|
204
|
-
|
254
|
+
const LZ4HC_CCtx_internal * const dictCtx = hc4->dictCtx;
|
255
|
+
const BYTE* const prefixPtr = hc4->prefixStart;
|
256
|
+
const U32 prefixIdx = hc4->dictLimit;
|
257
|
+
const U32 ipIndex = (U32)(ip - prefixPtr) + prefixIdx;
|
258
|
+
const int withinStartDistance = (hc4->lowLimit + (LZ4_DISTANCE_MAX + 1) > ipIndex);
|
259
|
+
const U32 lowestMatchIndex = (withinStartDistance) ? hc4->lowLimit : ipIndex - LZ4_DISTANCE_MAX;
|
260
|
+
const BYTE* const dictStart = hc4->dictStart;
|
261
|
+
const U32 dictIdx = hc4->lowLimit;
|
262
|
+
const BYTE* const dictEnd = dictStart + prefixIdx - dictIdx;
|
263
|
+
int const lookBackLength = (int)(ip-iLowLimit);
|
205
264
|
int nbAttempts = maxNbAttempts;
|
265
|
+
U32 matchChainPos = 0;
|
206
266
|
U32 const pattern = LZ4_read32(ip);
|
207
267
|
U32 matchIndex;
|
208
268
|
repeat_state_e repeat = rep_untested;
|
@@ -212,200 +272,297 @@ LZ4_FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch (
|
|
212
272
|
/* First Match */
|
213
273
|
LZ4HC_Insert(hc4, ip);
|
214
274
|
matchIndex = HashTable[LZ4HC_hashPtr(ip)];
|
215
|
-
DEBUGLOG(7, "First match at index %u / %u (
|
216
|
-
matchIndex,
|
275
|
+
DEBUGLOG(7, "First match at index %u / %u (lowestMatchIndex)",
|
276
|
+
matchIndex, lowestMatchIndex);
|
217
277
|
|
218
|
-
while ((matchIndex>=
|
219
|
-
|
278
|
+
while ((matchIndex>=lowestMatchIndex) && (nbAttempts>0)) {
|
279
|
+
int matchLength=0;
|
220
280
|
nbAttempts--;
|
221
|
-
|
222
|
-
|
223
|
-
|
281
|
+
assert(matchIndex < ipIndex);
|
282
|
+
if (favorDecSpeed && (ipIndex - matchIndex < 8)) {
|
283
|
+
/* do nothing */
|
284
|
+
} else if (matchIndex >= prefixIdx) { /* within current Prefix */
|
285
|
+
const BYTE* const matchPtr = prefixPtr + matchIndex - prefixIdx;
|
286
|
+
assert(matchPtr < ip);
|
287
|
+
assert(longest >= 1);
|
288
|
+
if (LZ4_read16(iLowLimit + longest - 1) == LZ4_read16(matchPtr - lookBackLength + longest - 1)) {
|
224
289
|
if (LZ4_read32(matchPtr) == pattern) {
|
225
|
-
int
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
if (mlt > longest) {
|
240
|
-
longest = mlt;
|
241
|
-
*matchpos = matchPtr+back;
|
242
|
-
*startpos = ip+back;
|
243
|
-
} }
|
244
|
-
}
|
245
|
-
} else { /* matchIndex < dictLimit */
|
246
|
-
const BYTE* const matchPtr = dictBase + matchIndex;
|
247
|
-
if (LZ4_read32(matchPtr) == pattern) {
|
248
|
-
int mlt;
|
290
|
+
int const back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, prefixPtr) : 0;
|
291
|
+
matchLength = MINMATCH + (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit);
|
292
|
+
matchLength -= back;
|
293
|
+
if (matchLength > longest) {
|
294
|
+
longest = matchLength;
|
295
|
+
*matchpos = matchPtr + back;
|
296
|
+
*startpos = ip + back;
|
297
|
+
} } }
|
298
|
+
} else { /* lowestMatchIndex <= matchIndex < dictLimit */
|
299
|
+
const BYTE* const matchPtr = dictStart + (matchIndex - dictIdx);
|
300
|
+
assert(matchIndex >= dictIdx);
|
301
|
+
if ( likely(matchIndex <= prefixIdx - 4)
|
302
|
+
&& (LZ4_read32(matchPtr) == pattern) ) {
|
249
303
|
int back = 0;
|
250
|
-
const BYTE* vLimit = ip + (
|
304
|
+
const BYTE* vLimit = ip + (prefixIdx - matchIndex);
|
251
305
|
if (vLimit > iHighLimit) vLimit = iHighLimit;
|
252
|
-
|
253
|
-
if ((ip+
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
if (mlt > longest) {
|
261
|
-
longest = mlt;
|
262
|
-
*matchpos = base + matchIndex + back;
|
306
|
+
matchLength = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
|
307
|
+
if ((ip+matchLength == vLimit) && (vLimit < iHighLimit))
|
308
|
+
matchLength += LZ4_count(ip+matchLength, prefixPtr, iHighLimit);
|
309
|
+
back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictStart) : 0;
|
310
|
+
matchLength -= back;
|
311
|
+
if (matchLength > longest) {
|
312
|
+
longest = matchLength;
|
313
|
+
*matchpos = prefixPtr - prefixIdx + matchIndex + back; /* virtual pos, relative to ip, to retrieve offset */
|
263
314
|
*startpos = ip + back;
|
264
315
|
} } }
|
265
316
|
|
266
|
-
{
|
267
|
-
|
268
|
-
if (
|
317
|
+
if (chainSwap && matchLength==longest) { /* better match => select a better chain */
|
318
|
+
assert(lookBackLength==0); /* search forward only */
|
319
|
+
if (matchIndex + (U32)longest <= ipIndex) {
|
320
|
+
int const kTrigger = 4;
|
321
|
+
U32 distanceToNextMatch = 1;
|
322
|
+
int const end = longest - MINMATCH + 1;
|
323
|
+
int step = 1;
|
324
|
+
int accel = 1 << kTrigger;
|
325
|
+
int pos;
|
326
|
+
for (pos = 0; pos < end; pos += step) {
|
327
|
+
U32 const candidateDist = DELTANEXTU16(chainTable, matchIndex + (U32)pos);
|
328
|
+
step = (accel++ >> kTrigger);
|
329
|
+
if (candidateDist > distanceToNextMatch) {
|
330
|
+
distanceToNextMatch = candidateDist;
|
331
|
+
matchChainPos = (U32)pos;
|
332
|
+
accel = 1 << kTrigger;
|
333
|
+
} }
|
334
|
+
if (distanceToNextMatch > 1) {
|
335
|
+
if (distanceToNextMatch > matchIndex) break; /* avoid overflow */
|
336
|
+
matchIndex -= distanceToNextMatch;
|
337
|
+
continue;
|
338
|
+
} } }
|
339
|
+
|
340
|
+
{ U32 const distNextMatch = DELTANEXTU16(chainTable, matchIndex);
|
341
|
+
if (patternAnalysis && distNextMatch==1 && matchChainPos==0) {
|
342
|
+
U32 const matchCandidateIdx = matchIndex-1;
|
269
343
|
/* may be a repeated pattern */
|
270
344
|
if (repeat == rep_untested) {
|
271
345
|
if ( ((pattern & 0xFFFF) == (pattern >> 16))
|
272
346
|
& ((pattern & 0xFF) == (pattern >> 24)) ) {
|
273
347
|
repeat = rep_confirmed;
|
274
|
-
srcPatternLength = LZ4HC_countPattern(ip+
|
348
|
+
srcPatternLength = LZ4HC_countPattern(ip+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern);
|
275
349
|
} else {
|
276
350
|
repeat = rep_not;
|
277
351
|
} }
|
278
|
-
if ( (repeat == rep_confirmed)
|
279
|
-
&& (
|
280
|
-
const
|
352
|
+
if ( (repeat == rep_confirmed) && (matchCandidateIdx >= lowestMatchIndex)
|
353
|
+
&& LZ4HC_protectDictEnd(prefixIdx, matchCandidateIdx) ) {
|
354
|
+
const int extDict = matchCandidateIdx < prefixIdx;
|
355
|
+
const BYTE* const matchPtr = (extDict ? dictStart - dictIdx : prefixPtr - prefixIdx) + matchCandidateIdx;
|
281
356
|
if (LZ4_read32(matchPtr) == pattern) { /* good candidate */
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
if ( (currentSegmentLength >= srcPatternLength) /* current pattern segment large enough to contain full srcPatternLength */
|
288
|
-
&& (forwardPatternLength <= srcPatternLength) ) { /* haven't reached this position yet */
|
289
|
-
matchIndex += (U32)forwardPatternLength - (U32)srcPatternLength; /* best position, full pattern, might be followed by more match */
|
290
|
-
} else {
|
291
|
-
matchIndex -= (U32)backLength; /* let's go to farthest segment position, will find a match of length currentSegmentLength + maybe some back */
|
357
|
+
const BYTE* const iLimit = extDict ? dictEnd : iHighLimit;
|
358
|
+
size_t forwardPatternLength = LZ4HC_countPattern(matchPtr+sizeof(pattern), iLimit, pattern) + sizeof(pattern);
|
359
|
+
if (extDict && matchPtr + forwardPatternLength == iLimit) {
|
360
|
+
U32 const rotatedPattern = LZ4HC_rotatePattern(forwardPatternLength, pattern);
|
361
|
+
forwardPatternLength += LZ4HC_countPattern(prefixPtr, iHighLimit, rotatedPattern);
|
292
362
|
}
|
293
|
-
|
294
|
-
|
363
|
+
{ const BYTE* const lowestMatchPtr = extDict ? dictStart : prefixPtr;
|
364
|
+
size_t backLength = LZ4HC_reverseCountPattern(matchPtr, lowestMatchPtr, pattern);
|
365
|
+
size_t currentSegmentLength;
|
366
|
+
if (!extDict
|
367
|
+
&& matchPtr - backLength == prefixPtr
|
368
|
+
&& dictIdx < prefixIdx) {
|
369
|
+
U32 const rotatedPattern = LZ4HC_rotatePattern((U32)(-(int)backLength), pattern);
|
370
|
+
backLength += LZ4HC_reverseCountPattern(dictEnd, dictStart, rotatedPattern);
|
371
|
+
}
|
372
|
+
/* Limit backLength not go further than lowestMatchIndex */
|
373
|
+
backLength = matchCandidateIdx - MAX(matchCandidateIdx - (U32)backLength, lowestMatchIndex);
|
374
|
+
assert(matchCandidateIdx - backLength >= lowestMatchIndex);
|
375
|
+
currentSegmentLength = backLength + forwardPatternLength;
|
376
|
+
/* Adjust to end of pattern if the source pattern fits, otherwise the beginning of the pattern */
|
377
|
+
if ( (currentSegmentLength >= srcPatternLength) /* current pattern segment large enough to contain full srcPatternLength */
|
378
|
+
&& (forwardPatternLength <= srcPatternLength) ) { /* haven't reached this position yet */
|
379
|
+
U32 const newMatchIndex = matchCandidateIdx + (U32)forwardPatternLength - (U32)srcPatternLength; /* best position, full pattern, might be followed by more match */
|
380
|
+
if (LZ4HC_protectDictEnd(prefixIdx, newMatchIndex))
|
381
|
+
matchIndex = newMatchIndex;
|
382
|
+
else {
|
383
|
+
/* Can only happen if started in the prefix */
|
384
|
+
assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);
|
385
|
+
matchIndex = prefixIdx;
|
386
|
+
}
|
387
|
+
} else {
|
388
|
+
U32 const newMatchIndex = matchCandidateIdx - (U32)backLength; /* farthest position in current segment, will find a match of length currentSegmentLength + maybe some back */
|
389
|
+
if (!LZ4HC_protectDictEnd(prefixIdx, newMatchIndex)) {
|
390
|
+
assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);
|
391
|
+
matchIndex = prefixIdx;
|
392
|
+
} else {
|
393
|
+
matchIndex = newMatchIndex;
|
394
|
+
if (lookBackLength==0) { /* no back possible */
|
395
|
+
size_t const maxML = MIN(currentSegmentLength, srcPatternLength);
|
396
|
+
if ((size_t)longest < maxML) {
|
397
|
+
assert(prefixPtr - prefixIdx + matchIndex != ip);
|
398
|
+
if ((size_t)(ip - prefixPtr) + prefixIdx - matchIndex > LZ4_DISTANCE_MAX) break;
|
399
|
+
assert(maxML < 2 GB);
|
400
|
+
longest = (int)maxML;
|
401
|
+
*matchpos = prefixPtr - prefixIdx + matchIndex; /* virtual pos, relative to ip, to retrieve offset */
|
402
|
+
*startpos = ip;
|
403
|
+
}
|
404
|
+
{ U32 const distToNextPattern = DELTANEXTU16(chainTable, matchIndex);
|
405
|
+
if (distToNextPattern > matchIndex) break; /* avoid overflow */
|
406
|
+
matchIndex -= distToNextPattern;
|
407
|
+
} } } } }
|
408
|
+
continue;
|
409
|
+
} }
|
410
|
+
} } /* PA optimization */
|
411
|
+
|
412
|
+
/* follow current chain */
|
413
|
+
matchIndex -= DELTANEXTU16(chainTable, matchIndex + matchChainPos);
|
414
|
+
|
415
|
+
} /* while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) */
|
416
|
+
|
417
|
+
if ( dict == usingDictCtxHc
|
418
|
+
&& nbAttempts > 0
|
419
|
+
&& ipIndex - lowestMatchIndex < LZ4_DISTANCE_MAX) {
|
420
|
+
size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit;
|
421
|
+
U32 dictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)];
|
422
|
+
assert(dictEndOffset <= 1 GB);
|
423
|
+
matchIndex = dictMatchIndex + lowestMatchIndex - (U32)dictEndOffset;
|
424
|
+
while (ipIndex - matchIndex <= LZ4_DISTANCE_MAX && nbAttempts--) {
|
425
|
+
const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + dictMatchIndex;
|
426
|
+
|
427
|
+
if (LZ4_read32(matchPtr) == pattern) {
|
428
|
+
int mlt;
|
429
|
+
int back = 0;
|
430
|
+
const BYTE* vLimit = ip + (dictEndOffset - dictMatchIndex);
|
431
|
+
if (vLimit > iHighLimit) vLimit = iHighLimit;
|
432
|
+
mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
|
433
|
+
back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->prefixStart) : 0;
|
434
|
+
mlt -= back;
|
435
|
+
if (mlt > longest) {
|
436
|
+
longest = mlt;
|
437
|
+
*matchpos = prefixPtr - prefixIdx + matchIndex + back;
|
438
|
+
*startpos = ip + back;
|
439
|
+
} }
|
440
|
+
|
441
|
+
{ U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, dictMatchIndex);
|
442
|
+
dictMatchIndex -= nextOffset;
|
443
|
+
matchIndex -= nextOffset;
|
444
|
+
} } }
|
295
445
|
|
296
446
|
return longest;
|
297
447
|
}
|
298
448
|
|
299
|
-
LZ4_FORCE_INLINE
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
449
|
+
LZ4_FORCE_INLINE int
|
450
|
+
LZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4, /* Index table will be updated */
|
451
|
+
const BYTE* const ip, const BYTE* const iLimit,
|
452
|
+
const BYTE** matchpos,
|
453
|
+
const int maxNbAttempts,
|
454
|
+
const int patternAnalysis,
|
455
|
+
const dictCtx_directive dict)
|
305
456
|
{
|
306
457
|
const BYTE* uselessPtr = ip;
|
307
458
|
/* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),
|
308
459
|
* but this won't be the case here, as we define iLowLimit==ip,
|
309
460
|
* so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */
|
310
|
-
return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, matchpos, &uselessPtr, maxNbAttempts, patternAnalysis);
|
461
|
+
return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, matchpos, &uselessPtr, maxNbAttempts, patternAnalysis, 0 /*chainSwap*/, dict, favorCompressionRatio);
|
311
462
|
}
|
312
463
|
|
313
|
-
|
314
|
-
|
315
|
-
typedef enum {
|
316
|
-
noLimit = 0,
|
317
|
-
limitedOutput = 1,
|
318
|
-
limitedDestSize = 2,
|
319
|
-
} limitedOutput_directive;
|
320
|
-
|
321
464
|
/* LZ4HC_encodeSequence() :
|
322
465
|
* @return : 0 if ok,
|
323
466
|
* 1 if buffer issue detected */
|
324
467
|
LZ4_FORCE_INLINE int LZ4HC_encodeSequence (
|
325
|
-
const BYTE**
|
326
|
-
BYTE**
|
327
|
-
const BYTE**
|
468
|
+
const BYTE** _ip,
|
469
|
+
BYTE** _op,
|
470
|
+
const BYTE** _anchor,
|
328
471
|
int matchLength,
|
329
472
|
const BYTE* const match,
|
330
473
|
limitedOutput_directive limit,
|
331
474
|
BYTE* oend)
|
332
475
|
{
|
476
|
+
#define ip (*_ip)
|
477
|
+
#define op (*_op)
|
478
|
+
#define anchor (*_anchor)
|
479
|
+
|
333
480
|
size_t length;
|
334
|
-
BYTE* const token =
|
481
|
+
BYTE* const token = op++;
|
335
482
|
|
336
|
-
#if defined(LZ4_DEBUG) && (LZ4_DEBUG >=
|
483
|
+
#if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 6)
|
337
484
|
static const BYTE* start = NULL;
|
338
485
|
static U32 totalCost = 0;
|
339
|
-
U32 const pos = (start==NULL) ? 0 : (U32)(
|
340
|
-
U32 const ll = (U32)(
|
486
|
+
U32 const pos = (start==NULL) ? 0 : (U32)(anchor - start);
|
487
|
+
U32 const ll = (U32)(ip - anchor);
|
341
488
|
U32 const llAdd = (ll>=15) ? ((ll-15) / 255) + 1 : 0;
|
342
489
|
U32 const mlAdd = (matchLength>=19) ? ((matchLength-19) / 255) + 1 : 0;
|
343
490
|
U32 const cost = 1 + llAdd + ll + 2 + mlAdd;
|
344
|
-
if (start==NULL) start =
|
345
|
-
|
346
|
-
DEBUGLOG(
|
491
|
+
if (start==NULL) start = anchor; /* only works for single segment */
|
492
|
+
/* g_debuglog_enable = (pos >= 2228) & (pos <= 2262); */
|
493
|
+
DEBUGLOG(6, "pos:%7u -- literals:%4u, match:%4i, offset:%5u, cost:%4u + %5u",
|
347
494
|
pos,
|
348
|
-
(U32)(
|
495
|
+
(U32)(ip - anchor), matchLength, (U32)(ip-match),
|
349
496
|
cost, totalCost);
|
350
497
|
totalCost += cost;
|
351
498
|
#endif
|
352
499
|
|
353
500
|
/* Encode Literal length */
|
354
|
-
length = (size_t)(
|
355
|
-
|
501
|
+
length = (size_t)(ip - anchor);
|
502
|
+
LZ4_STATIC_ASSERT(notLimited == 0);
|
503
|
+
/* Check output limit */
|
504
|
+
if (limit && ((op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) {
|
505
|
+
DEBUGLOG(6, "Not enough room to write %i literals (%i bytes remaining)",
|
506
|
+
(int)length, (int)(oend - op));
|
507
|
+
return 1;
|
508
|
+
}
|
356
509
|
if (length >= RUN_MASK) {
|
357
510
|
size_t len = length - RUN_MASK;
|
358
511
|
*token = (RUN_MASK << ML_BITS);
|
359
|
-
for(; len >= 255 ; len -= 255) *
|
360
|
-
*
|
512
|
+
for(; len >= 255 ; len -= 255) *op++ = 255;
|
513
|
+
*op++ = (BYTE)len;
|
361
514
|
} else {
|
362
515
|
*token = (BYTE)(length << ML_BITS);
|
363
516
|
}
|
364
517
|
|
365
518
|
/* Copy Literals */
|
366
|
-
|
367
|
-
|
519
|
+
LZ4_wildCopy8(op, anchor, op + length);
|
520
|
+
op += length;
|
368
521
|
|
369
522
|
/* Encode Offset */
|
370
|
-
|
523
|
+
assert( (ip - match) <= LZ4_DISTANCE_MAX ); /* note : consider providing offset as a value, rather than as a pointer difference */
|
524
|
+
LZ4_writeLE16(op, (U16)(ip - match)); op += 2;
|
371
525
|
|
372
526
|
/* Encode MatchLength */
|
373
527
|
assert(matchLength >= MINMATCH);
|
374
|
-
length = (size_t)
|
375
|
-
if (
|
528
|
+
length = (size_t)matchLength - MINMATCH;
|
529
|
+
if (limit && (op + (length / 255) + (1 + LASTLITERALS) > oend)) {
|
530
|
+
DEBUGLOG(6, "Not enough room to write match length");
|
531
|
+
return 1; /* Check output limit */
|
532
|
+
}
|
376
533
|
if (length >= ML_MASK) {
|
377
534
|
*token += ML_MASK;
|
378
535
|
length -= ML_MASK;
|
379
|
-
for(; length >= 510 ; length -= 510) { *
|
380
|
-
if (length >= 255) { length -= 255; *
|
381
|
-
*
|
536
|
+
for(; length >= 510 ; length -= 510) { *op++ = 255; *op++ = 255; }
|
537
|
+
if (length >= 255) { length -= 255; *op++ = 255; }
|
538
|
+
*op++ = (BYTE)length;
|
382
539
|
} else {
|
383
540
|
*token += (BYTE)(length);
|
384
541
|
}
|
385
542
|
|
386
543
|
/* Prepare next loop */
|
387
|
-
|
388
|
-
|
544
|
+
ip += matchLength;
|
545
|
+
anchor = ip;
|
389
546
|
|
390
547
|
return 0;
|
391
548
|
}
|
549
|
+
#undef ip
|
550
|
+
#undef op
|
551
|
+
#undef anchor
|
392
552
|
|
393
|
-
|
394
|
-
#include "lz4opt.h"
|
395
|
-
|
396
|
-
|
397
|
-
static int LZ4HC_compress_hashChain (
|
553
|
+
LZ4_FORCE_INLINE int LZ4HC_compress_hashChain (
|
398
554
|
LZ4HC_CCtx_internal* const ctx,
|
399
555
|
const char* const source,
|
400
556
|
char* const dest,
|
401
557
|
int* srcSizePtr,
|
402
558
|
int const maxOutputSize,
|
403
|
-
|
404
|
-
limitedOutput_directive limit
|
559
|
+
int maxNbAttempts,
|
560
|
+
const limitedOutput_directive limit,
|
561
|
+
const dictCtx_directive dict
|
405
562
|
)
|
406
563
|
{
|
407
564
|
const int inputSize = *srcSizePtr;
|
408
|
-
const int patternAnalysis = (maxNbAttempts >
|
565
|
+
const int patternAnalysis = (maxNbAttempts > 128); /* levels 9+ */
|
409
566
|
|
410
567
|
const BYTE* ip = (const BYTE*) source;
|
411
568
|
const BYTE* anchor = ip;
|
@@ -417,51 +574,47 @@ static int LZ4HC_compress_hashChain (
|
|
417
574
|
BYTE* op = (BYTE*) dest;
|
418
575
|
BYTE* oend = op + maxOutputSize;
|
419
576
|
|
420
|
-
int ml, ml2, ml3
|
577
|
+
int ml0, ml, ml2, ml3;
|
578
|
+
const BYTE* start0;
|
579
|
+
const BYTE* ref0;
|
421
580
|
const BYTE* ref = NULL;
|
422
581
|
const BYTE* start2 = NULL;
|
423
582
|
const BYTE* ref2 = NULL;
|
424
583
|
const BYTE* start3 = NULL;
|
425
584
|
const BYTE* ref3 = NULL;
|
426
|
-
const BYTE* start0;
|
427
|
-
const BYTE* ref0;
|
428
585
|
|
429
586
|
/* init */
|
430
587
|
*srcSizePtr = 0;
|
431
|
-
if (limit ==
|
432
|
-
if (inputSize < LZ4_minLength) goto _last_literals;
|
588
|
+
if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */
|
589
|
+
if (inputSize < LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
|
433
590
|
|
434
591
|
/* Main Loop */
|
435
|
-
while (ip
|
436
|
-
ml = LZ4HC_InsertAndFindBestMatch
|
592
|
+
while (ip <= mflimit) {
|
593
|
+
ml = LZ4HC_InsertAndFindBestMatch(ctx, ip, matchlimit, &ref, maxNbAttempts, patternAnalysis, dict);
|
437
594
|
if (ml<MINMATCH) { ip++; continue; }
|
438
595
|
|
439
596
|
/* saved, in case we would skip too much */
|
440
|
-
start0 = ip;
|
441
|
-
ref0 = ref;
|
442
|
-
ml0 = ml;
|
597
|
+
start0 = ip; ref0 = ref; ml0 = ml;
|
443
598
|
|
444
599
|
_Search2:
|
445
|
-
if (ip+ml
|
600
|
+
if (ip+ml <= mflimit) {
|
446
601
|
ml2 = LZ4HC_InsertAndGetWiderMatch(ctx,
|
447
602
|
ip + ml - 2, ip + 0, matchlimit, ml, &ref2, &start2,
|
448
|
-
maxNbAttempts, patternAnalysis);
|
449
|
-
else
|
603
|
+
maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);
|
604
|
+
} else {
|
450
605
|
ml2 = ml;
|
606
|
+
}
|
451
607
|
|
452
|
-
if (ml2 == ml) { /* No better match */
|
608
|
+
if (ml2 == ml) { /* No better match => encode ML1 */
|
453
609
|
optr = op;
|
454
|
-
if (LZ4HC_encodeSequence(
|
610
|
+
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
|
455
611
|
continue;
|
456
612
|
}
|
457
613
|
|
458
|
-
if (start0 < ip) {
|
459
|
-
if (start2 < ip + ml0) { /*
|
460
|
-
ip = start0;
|
461
|
-
|
462
|
-
ml = ml0;
|
463
|
-
}
|
464
|
-
}
|
614
|
+
if (start0 < ip) { /* first match was skipped at least once */
|
615
|
+
if (start2 < ip + ml0) { /* squeezing ML1 between ML0(original ML1) and ML2 */
|
616
|
+
ip = start0; ref = ref0; ml = ml0; /* restore initial ML1 */
|
617
|
+
} }
|
465
618
|
|
466
619
|
/* Here, start0==ip */
|
467
620
|
if ((start2 - ip) < 3) { /* First Match too small : removed */
|
@@ -489,22 +642,27 @@ _Search3:
|
|
489
642
|
}
|
490
643
|
/* Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) */
|
491
644
|
|
492
|
-
if (start2 + ml2
|
645
|
+
if (start2 + ml2 <= mflimit) {
|
493
646
|
ml3 = LZ4HC_InsertAndGetWiderMatch(ctx,
|
494
647
|
start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3,
|
495
|
-
maxNbAttempts, patternAnalysis);
|
496
|
-
else
|
648
|
+
maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);
|
649
|
+
} else {
|
497
650
|
ml3 = ml2;
|
651
|
+
}
|
498
652
|
|
499
|
-
if (ml3 == ml2) { /* No better match
|
653
|
+
if (ml3 == ml2) { /* No better match => encode ML1 and ML2 */
|
500
654
|
/* ip & ref are known; Now for ml */
|
501
655
|
if (start2 < ip+ml) ml = (int)(start2 - ip);
|
502
656
|
/* Now, encode 2 sequences */
|
503
657
|
optr = op;
|
504
|
-
if (LZ4HC_encodeSequence(
|
658
|
+
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
|
505
659
|
ip = start2;
|
506
660
|
optr = op;
|
507
|
-
if (LZ4HC_encodeSequence(
|
661
|
+
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml2, ref2, limit, oend)) {
|
662
|
+
ml = ml2;
|
663
|
+
ref = ref2;
|
664
|
+
goto _dest_overflow;
|
665
|
+
}
|
508
666
|
continue;
|
509
667
|
}
|
510
668
|
|
@@ -523,7 +681,7 @@ _Search3:
|
|
523
681
|
}
|
524
682
|
|
525
683
|
optr = op;
|
526
|
-
if (LZ4HC_encodeSequence(
|
684
|
+
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
|
527
685
|
ip = start3;
|
528
686
|
ref = ref3;
|
529
687
|
ml = ml3;
|
@@ -541,11 +699,12 @@ _Search3:
|
|
541
699
|
}
|
542
700
|
|
543
701
|
/*
|
544
|
-
* OK, now we have 3 ascending matches;
|
545
|
-
*
|
702
|
+
* OK, now we have 3 ascending matches;
|
703
|
+
* let's write the first one ML1.
|
704
|
+
* ip & ref are known; Now decide ml.
|
546
705
|
*/
|
547
706
|
if (start2 < ip+ml) {
|
548
|
-
if ((start2 - ip) <
|
707
|
+
if ((start2 - ip) < OPTIMAL_ML) {
|
549
708
|
int correction;
|
550
709
|
if (ml > OPTIMAL_ML) ml = OPTIMAL_ML;
|
551
710
|
if (ip + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - ip) + ml2 - MINMATCH;
|
@@ -560,33 +719,33 @@ _Search3:
|
|
560
719
|
}
|
561
720
|
}
|
562
721
|
optr = op;
|
563
|
-
if (LZ4HC_encodeSequence(
|
722
|
+
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
|
564
723
|
|
565
|
-
|
566
|
-
ref = ref2;
|
567
|
-
ml = ml2;
|
724
|
+
/* ML2 becomes ML1 */
|
725
|
+
ip = start2; ref = ref2; ml = ml2;
|
568
726
|
|
569
|
-
|
570
|
-
ref2 = ref3;
|
571
|
-
ml2 = ml3;
|
727
|
+
/* ML3 becomes ML2 */
|
728
|
+
start2 = start3; ref2 = ref3; ml2 = ml3;
|
572
729
|
|
730
|
+
/* let's find a new ML3 */
|
573
731
|
goto _Search3;
|
574
732
|
}
|
575
733
|
|
576
734
|
_last_literals:
|
577
735
|
/* Encode Last Literals */
|
578
736
|
{ size_t lastRunSize = (size_t)(iend - anchor); /* literals */
|
579
|
-
size_t
|
580
|
-
size_t const totalSize = 1 +
|
581
|
-
if (limit ==
|
737
|
+
size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;
|
738
|
+
size_t const totalSize = 1 + llAdd + lastRunSize;
|
739
|
+
if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */
|
582
740
|
if (limit && (op + totalSize > oend)) {
|
583
|
-
if (limit == limitedOutput) return 0;
|
741
|
+
if (limit == limitedOutput) return 0;
|
584
742
|
/* adapt lastRunSize to fill 'dest' */
|
585
|
-
lastRunSize = (size_t)(oend - op) - 1
|
586
|
-
|
587
|
-
lastRunSize -=
|
743
|
+
lastRunSize = (size_t)(oend - op) - 1 /*token*/;
|
744
|
+
llAdd = (lastRunSize + 256 - RUN_MASK) / 256;
|
745
|
+
lastRunSize -= llAdd;
|
588
746
|
}
|
589
|
-
|
747
|
+
DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);
|
748
|
+
ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */
|
590
749
|
|
591
750
|
if (lastRunSize >= RUN_MASK) {
|
592
751
|
size_t accumulator = lastRunSize - RUN_MASK;
|
@@ -596,7 +755,7 @@ _last_literals:
|
|
596
755
|
} else {
|
597
756
|
*op++ = (BYTE)(lastRunSize << ML_BITS);
|
598
757
|
}
|
599
|
-
|
758
|
+
LZ4_memcpy(op, anchor, lastRunSize);
|
600
759
|
op += lastRunSize;
|
601
760
|
}
|
602
761
|
|
@@ -605,103 +764,222 @@ _last_literals:
|
|
605
764
|
return (int) (((char*)op)-dest);
|
606
765
|
|
607
766
|
_dest_overflow:
|
608
|
-
if (limit ==
|
767
|
+
if (limit == fillOutput) {
|
768
|
+
/* Assumption : ip, anchor, ml and ref must be set correctly */
|
769
|
+
size_t const ll = (size_t)(ip - anchor);
|
770
|
+
size_t const ll_addbytes = (ll + 240) / 255;
|
771
|
+
size_t const ll_totalCost = 1 + ll_addbytes + ll;
|
772
|
+
BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */
|
773
|
+
DEBUGLOG(6, "Last sequence overflowing");
|
609
774
|
op = optr; /* restore correct out pointer */
|
775
|
+
if (op + ll_totalCost <= maxLitPos) {
|
776
|
+
/* ll validated; now adjust match length */
|
777
|
+
size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));
|
778
|
+
size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);
|
779
|
+
assert(maxMlSize < INT_MAX); assert(ml >= 0);
|
780
|
+
if ((size_t)ml > maxMlSize) ml = (int)maxMlSize;
|
781
|
+
if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ml >= MFLIMIT) {
|
782
|
+
LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, notLimited, oend);
|
783
|
+
} }
|
610
784
|
goto _last_literals;
|
611
785
|
}
|
786
|
+
/* compression failed */
|
612
787
|
return 0;
|
613
788
|
}
|
614
789
|
|
615
790
|
|
616
|
-
static int
|
791
|
+
static int LZ4HC_compress_optimal( LZ4HC_CCtx_internal* ctx,
|
792
|
+
const char* const source, char* dst,
|
793
|
+
int* srcSizePtr, int dstCapacity,
|
794
|
+
int const nbSearches, size_t sufficient_len,
|
795
|
+
const limitedOutput_directive limit, int const fullUpdate,
|
796
|
+
const dictCtx_directive dict,
|
797
|
+
const HCfavor_e favorDecSpeed);
|
798
|
+
|
799
|
+
|
800
|
+
LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal (
|
617
801
|
LZ4HC_CCtx_internal* const ctx,
|
618
802
|
const char* const src,
|
619
803
|
char* const dst,
|
620
804
|
int* const srcSizePtr,
|
621
805
|
int const dstCapacity,
|
622
806
|
int cLevel,
|
623
|
-
limitedOutput_directive limit
|
807
|
+
const limitedOutput_directive limit,
|
808
|
+
const dictCtx_directive dict
|
624
809
|
)
|
625
810
|
{
|
626
811
|
typedef enum { lz4hc, lz4opt } lz4hc_strat_e;
|
627
812
|
typedef struct {
|
628
813
|
lz4hc_strat_e strat;
|
629
|
-
|
814
|
+
int nbSearches;
|
630
815
|
U32 targetLength;
|
631
816
|
} cParams_t;
|
632
817
|
static const cParams_t clTable[LZ4HC_CLEVEL_MAX+1] = {
|
633
|
-
{ lz4hc,
|
634
|
-
{ lz4hc,
|
635
|
-
{ lz4hc,
|
636
|
-
{ lz4hc,
|
637
|
-
{ lz4hc,
|
638
|
-
{ lz4hc,
|
639
|
-
{ lz4hc,
|
640
|
-
{ lz4hc,
|
641
|
-
{ lz4hc,
|
642
|
-
{ lz4hc,
|
643
|
-
{ lz4opt,
|
644
|
-
{ lz4opt,
|
645
|
-
{ lz4opt,
|
818
|
+
{ lz4hc, 2, 16 }, /* 0, unused */
|
819
|
+
{ lz4hc, 2, 16 }, /* 1, unused */
|
820
|
+
{ lz4hc, 2, 16 }, /* 2, unused */
|
821
|
+
{ lz4hc, 4, 16 }, /* 3 */
|
822
|
+
{ lz4hc, 8, 16 }, /* 4 */
|
823
|
+
{ lz4hc, 16, 16 }, /* 5 */
|
824
|
+
{ lz4hc, 32, 16 }, /* 6 */
|
825
|
+
{ lz4hc, 64, 16 }, /* 7 */
|
826
|
+
{ lz4hc, 128, 16 }, /* 8 */
|
827
|
+
{ lz4hc, 256, 16 }, /* 9 */
|
828
|
+
{ lz4opt, 96, 64 }, /*10==LZ4HC_CLEVEL_OPT_MIN*/
|
829
|
+
{ lz4opt, 512,128 }, /*11 */
|
830
|
+
{ lz4opt,16384,LZ4_OPT_NUM }, /* 12==LZ4HC_CLEVEL_MAX */
|
646
831
|
};
|
647
832
|
|
648
|
-
|
649
|
-
|
833
|
+
DEBUGLOG(4, "LZ4HC_compress_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)",
|
834
|
+
ctx, src, *srcSizePtr, limit);
|
835
|
+
|
836
|
+
if (limit == fillOutput && dstCapacity < 1) return 0; /* Impossible to store anything */
|
837
|
+
if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size (too large or negative) */
|
650
838
|
|
651
839
|
ctx->end += *srcSizePtr;
|
652
840
|
if (cLevel < 1) cLevel = LZ4HC_CLEVEL_DEFAULT; /* note : convention is different from lz4frame, maybe something to review */
|
653
841
|
cLevel = MIN(LZ4HC_CLEVEL_MAX, cLevel);
|
654
|
-
assert(cLevel >= 0);
|
655
|
-
assert(cLevel <= LZ4HC_CLEVEL_MAX);
|
656
842
|
{ cParams_t const cParam = clTable[cLevel];
|
657
|
-
|
658
|
-
|
843
|
+
HCfavor_e const favor = ctx->favorDecSpeed ? favorDecompressionSpeed : favorCompressionRatio;
|
844
|
+
int result;
|
845
|
+
|
846
|
+
if (cParam.strat == lz4hc) {
|
847
|
+
result = LZ4HC_compress_hashChain(ctx,
|
848
|
+
src, dst, srcSizePtr, dstCapacity,
|
849
|
+
cParam.nbSearches, limit, dict);
|
850
|
+
} else {
|
851
|
+
assert(cParam.strat == lz4opt);
|
852
|
+
result = LZ4HC_compress_optimal(ctx,
|
659
853
|
src, dst, srcSizePtr, dstCapacity,
|
660
|
-
cParam.nbSearches, limit
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
854
|
+
cParam.nbSearches, cParam.targetLength, limit,
|
855
|
+
cLevel == LZ4HC_CLEVEL_MAX, /* ultra mode */
|
856
|
+
dict, favor);
|
857
|
+
}
|
858
|
+
if (result <= 0) ctx->dirty = 1;
|
859
|
+
return result;
|
666
860
|
}
|
667
861
|
}
|
668
862
|
|
863
|
+
static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock);
|
864
|
+
|
865
|
+
static int
|
866
|
+
LZ4HC_compress_generic_noDictCtx (
|
867
|
+
LZ4HC_CCtx_internal* const ctx,
|
868
|
+
const char* const src,
|
869
|
+
char* const dst,
|
870
|
+
int* const srcSizePtr,
|
871
|
+
int const dstCapacity,
|
872
|
+
int cLevel,
|
873
|
+
limitedOutput_directive limit
|
874
|
+
)
|
875
|
+
{
|
876
|
+
assert(ctx->dictCtx == NULL);
|
877
|
+
return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, noDictCtx);
|
878
|
+
}
|
669
879
|
|
670
|
-
int
|
880
|
+
static int
|
881
|
+
LZ4HC_compress_generic_dictCtx (
|
882
|
+
LZ4HC_CCtx_internal* const ctx,
|
883
|
+
const char* const src,
|
884
|
+
char* const dst,
|
885
|
+
int* const srcSizePtr,
|
886
|
+
int const dstCapacity,
|
887
|
+
int cLevel,
|
888
|
+
limitedOutput_directive limit
|
889
|
+
)
|
890
|
+
{
|
891
|
+
const size_t position = (size_t)(ctx->end - ctx->prefixStart) + (ctx->dictLimit - ctx->lowLimit);
|
892
|
+
assert(ctx->dictCtx != NULL);
|
893
|
+
if (position >= 64 KB) {
|
894
|
+
ctx->dictCtx = NULL;
|
895
|
+
return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
|
896
|
+
} else if (position == 0 && *srcSizePtr > 4 KB) {
|
897
|
+
LZ4_memcpy(ctx, ctx->dictCtx, sizeof(LZ4HC_CCtx_internal));
|
898
|
+
LZ4HC_setExternalDict(ctx, (const BYTE *)src);
|
899
|
+
ctx->compressionLevel = (short)cLevel;
|
900
|
+
return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
|
901
|
+
} else {
|
902
|
+
return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, usingDictCtxHc);
|
903
|
+
}
|
904
|
+
}
|
671
905
|
|
672
|
-
|
906
|
+
static int
|
907
|
+
LZ4HC_compress_generic (
|
908
|
+
LZ4HC_CCtx_internal* const ctx,
|
909
|
+
const char* const src,
|
910
|
+
char* const dst,
|
911
|
+
int* const srcSizePtr,
|
912
|
+
int const dstCapacity,
|
913
|
+
int cLevel,
|
914
|
+
limitedOutput_directive limit
|
915
|
+
)
|
916
|
+
{
|
917
|
+
if (ctx->dictCtx == NULL) {
|
918
|
+
return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
|
919
|
+
} else {
|
920
|
+
return LZ4HC_compress_generic_dictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
|
921
|
+
}
|
922
|
+
}
|
923
|
+
|
924
|
+
|
925
|
+
int LZ4_sizeofStateHC(void) { return (int)sizeof(LZ4_streamHC_t); }
|
926
|
+
|
927
|
+
static size_t LZ4_streamHC_t_alignment(void)
|
928
|
+
{
|
929
|
+
#if LZ4_ALIGN_TEST
|
930
|
+
typedef struct { char c; LZ4_streamHC_t t; } t_a;
|
931
|
+
return sizeof(t_a) - sizeof(LZ4_streamHC_t);
|
932
|
+
#else
|
933
|
+
return 1; /* effectively disabled */
|
934
|
+
#endif
|
935
|
+
}
|
936
|
+
|
937
|
+
/* state is presumed correctly initialized,
|
938
|
+
* in which case its size and alignment have already been validate */
|
939
|
+
int LZ4_compress_HC_extStateHC_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
|
673
940
|
{
|
674
941
|
LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse;
|
675
|
-
if ((
|
676
|
-
|
942
|
+
if (!LZ4_isAligned(state, LZ4_streamHC_t_alignment())) return 0;
|
943
|
+
LZ4_resetStreamHC_fast((LZ4_streamHC_t*)state, compressionLevel);
|
944
|
+
LZ4HC_init_internal (ctx, (const BYTE*)src);
|
677
945
|
if (dstCapacity < LZ4_compressBound(srcSize))
|
678
946
|
return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, limitedOutput);
|
679
947
|
else
|
680
|
-
return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel,
|
948
|
+
return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, notLimited);
|
949
|
+
}
|
950
|
+
|
951
|
+
int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
|
952
|
+
{
|
953
|
+
LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));
|
954
|
+
if (ctx==NULL) return 0; /* init failure */
|
955
|
+
return LZ4_compress_HC_extStateHC_fastReset(state, src, dst, srcSize, dstCapacity, compressionLevel);
|
681
956
|
}
|
682
957
|
|
683
958
|
int LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
|
684
959
|
{
|
960
|
+
int cSize;
|
685
961
|
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
|
686
|
-
LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)
|
962
|
+
LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));
|
963
|
+
if (statePtr==NULL) return 0;
|
687
964
|
#else
|
688
965
|
LZ4_streamHC_t state;
|
689
966
|
LZ4_streamHC_t* const statePtr = &state;
|
690
967
|
#endif
|
691
|
-
|
968
|
+
cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel);
|
692
969
|
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
|
693
|
-
|
970
|
+
FREEMEM(statePtr);
|
694
971
|
#endif
|
695
972
|
return cSize;
|
696
973
|
}
|
697
974
|
|
698
|
-
/*
|
699
|
-
*
|
700
|
-
int LZ4_compress_HC_destSize(void* LZ4HC_Data, const char* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel)
|
975
|
+
/* state is presumed sized correctly (>= sizeof(LZ4_streamHC_t)) */
|
976
|
+
int LZ4_compress_HC_destSize(void* state, const char* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel)
|
701
977
|
{
|
702
|
-
|
703
|
-
|
704
|
-
|
978
|
+
LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));
|
979
|
+
if (ctx==NULL) return 0; /* init failure */
|
980
|
+
LZ4HC_init_internal(&ctx->internal_donotuse, (const BYTE*) source);
|
981
|
+
LZ4_setCompressionLevel(ctx, cLevel);
|
982
|
+
return LZ4HC_compress_generic(&ctx->internal_donotuse, source, dest, sourceSizePtr, targetDestSize, cLevel, fillOutput);
|
705
983
|
}
|
706
984
|
|
707
985
|
|
@@ -710,87 +988,162 @@ int LZ4_compress_HC_destSize(void* LZ4HC_Data, const char* source, char* dest, i
|
|
710
988
|
* Streaming Functions
|
711
989
|
**************************************/
|
712
990
|
/* allocation */
|
713
|
-
|
714
|
-
|
991
|
+
#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)
|
992
|
+
LZ4_streamHC_t* LZ4_createStreamHC(void)
|
993
|
+
{
|
994
|
+
LZ4_streamHC_t* const state =
|
995
|
+
(LZ4_streamHC_t*)ALLOC_AND_ZERO(sizeof(LZ4_streamHC_t));
|
996
|
+
if (state == NULL) return NULL;
|
997
|
+
LZ4_setCompressionLevel(state, LZ4HC_CLEVEL_DEFAULT);
|
998
|
+
return state;
|
999
|
+
}
|
1000
|
+
|
1001
|
+
int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr)
|
1002
|
+
{
|
1003
|
+
DEBUGLOG(4, "LZ4_freeStreamHC(%p)", LZ4_streamHCPtr);
|
715
1004
|
if (!LZ4_streamHCPtr) return 0; /* support free on NULL */
|
716
|
-
|
1005
|
+
FREEMEM(LZ4_streamHCPtr);
|
717
1006
|
return 0;
|
718
1007
|
}
|
1008
|
+
#endif
|
719
1009
|
|
720
1010
|
|
721
|
-
|
1011
|
+
LZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size)
|
1012
|
+
{
|
1013
|
+
LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)buffer;
|
1014
|
+
DEBUGLOG(4, "LZ4_initStreamHC(%p, %u)", buffer, (unsigned)size);
|
1015
|
+
/* check conditions */
|
1016
|
+
if (buffer == NULL) return NULL;
|
1017
|
+
if (size < sizeof(LZ4_streamHC_t)) return NULL;
|
1018
|
+
if (!LZ4_isAligned(buffer, LZ4_streamHC_t_alignment())) return NULL;
|
1019
|
+
/* init */
|
1020
|
+
{ LZ4HC_CCtx_internal* const hcstate = &(LZ4_streamHCPtr->internal_donotuse);
|
1021
|
+
MEM_INIT(hcstate, 0, sizeof(*hcstate)); }
|
1022
|
+
LZ4_setCompressionLevel(LZ4_streamHCPtr, LZ4HC_CLEVEL_DEFAULT);
|
1023
|
+
return LZ4_streamHCPtr;
|
1024
|
+
}
|
1025
|
+
|
1026
|
+
/* just a stub */
|
722
1027
|
void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
|
723
1028
|
{
|
724
|
-
|
725
|
-
LZ4_streamHCPtr
|
1029
|
+
LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
|
1030
|
+
LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);
|
1031
|
+
}
|
1032
|
+
|
1033
|
+
void LZ4_resetStreamHC_fast (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
|
1034
|
+
{
|
1035
|
+
DEBUGLOG(4, "LZ4_resetStreamHC_fast(%p, %d)", LZ4_streamHCPtr, compressionLevel);
|
1036
|
+
if (LZ4_streamHCPtr->internal_donotuse.dirty) {
|
1037
|
+
LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
|
1038
|
+
} else {
|
1039
|
+
/* preserve end - prefixStart : can trigger clearTable's threshold */
|
1040
|
+
if (LZ4_streamHCPtr->internal_donotuse.end != NULL) {
|
1041
|
+
LZ4_streamHCPtr->internal_donotuse.end -= (uptrval)LZ4_streamHCPtr->internal_donotuse.prefixStart;
|
1042
|
+
} else {
|
1043
|
+
assert(LZ4_streamHCPtr->internal_donotuse.prefixStart == NULL);
|
1044
|
+
}
|
1045
|
+
LZ4_streamHCPtr->internal_donotuse.prefixStart = NULL;
|
1046
|
+
LZ4_streamHCPtr->internal_donotuse.dictCtx = NULL;
|
1047
|
+
}
|
726
1048
|
LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);
|
727
1049
|
}
|
728
1050
|
|
729
1051
|
void LZ4_setCompressionLevel(LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
|
730
1052
|
{
|
731
|
-
|
1053
|
+
DEBUGLOG(5, "LZ4_setCompressionLevel(%p, %d)", LZ4_streamHCPtr, compressionLevel);
|
1054
|
+
if (compressionLevel < 1) compressionLevel = LZ4HC_CLEVEL_DEFAULT;
|
732
1055
|
if (compressionLevel > LZ4HC_CLEVEL_MAX) compressionLevel = LZ4HC_CLEVEL_MAX;
|
733
|
-
LZ4_streamHCPtr->internal_donotuse.compressionLevel = compressionLevel;
|
1056
|
+
LZ4_streamHCPtr->internal_donotuse.compressionLevel = (short)compressionLevel;
|
734
1057
|
}
|
735
1058
|
|
736
|
-
|
1059
|
+
void LZ4_favorDecompressionSpeed(LZ4_streamHC_t* LZ4_streamHCPtr, int favor)
|
1060
|
+
{
|
1061
|
+
LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = (favor!=0);
|
1062
|
+
}
|
1063
|
+
|
1064
|
+
/* LZ4_loadDictHC() :
|
1065
|
+
* LZ4_streamHCPtr is presumed properly initialized */
|
1066
|
+
int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr,
|
1067
|
+
const char* dictionary, int dictSize)
|
737
1068
|
{
|
738
1069
|
LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
|
1070
|
+
DEBUGLOG(4, "LZ4_loadDictHC(ctx:%p, dict:%p, dictSize:%d)", LZ4_streamHCPtr, dictionary, dictSize);
|
1071
|
+
assert(LZ4_streamHCPtr != NULL);
|
739
1072
|
if (dictSize > 64 KB) {
|
740
|
-
dictionary += dictSize - 64 KB;
|
1073
|
+
dictionary += (size_t)dictSize - 64 KB;
|
741
1074
|
dictSize = 64 KB;
|
742
1075
|
}
|
743
|
-
|
1076
|
+
/* need a full initialization, there are bad side-effects when using resetFast() */
|
1077
|
+
{ int const cLevel = ctxPtr->compressionLevel;
|
1078
|
+
LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
|
1079
|
+
LZ4_setCompressionLevel(LZ4_streamHCPtr, cLevel);
|
1080
|
+
}
|
1081
|
+
LZ4HC_init_internal (ctxPtr, (const BYTE*)dictionary);
|
744
1082
|
ctxPtr->end = (const BYTE*)dictionary + dictSize;
|
745
1083
|
if (dictSize >= 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3);
|
746
1084
|
return dictSize;
|
747
1085
|
}
|
748
1086
|
|
1087
|
+
void LZ4_attach_HC_dictionary(LZ4_streamHC_t *working_stream, const LZ4_streamHC_t *dictionary_stream) {
|
1088
|
+
working_stream->internal_donotuse.dictCtx = dictionary_stream != NULL ? &(dictionary_stream->internal_donotuse) : NULL;
|
1089
|
+
}
|
749
1090
|
|
750
1091
|
/* compression */
|
751
1092
|
|
752
1093
|
static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock)
|
753
1094
|
{
|
754
|
-
|
1095
|
+
DEBUGLOG(4, "LZ4HC_setExternalDict(%p, %p)", ctxPtr, newBlock);
|
1096
|
+
if (ctxPtr->end >= ctxPtr->prefixStart + 4)
|
1097
|
+
LZ4HC_Insert (ctxPtr, ctxPtr->end-3); /* Referencing remaining dictionary content */
|
755
1098
|
|
756
1099
|
/* Only one memory segment for extDict, so any previous extDict is lost at this stage */
|
757
1100
|
ctxPtr->lowLimit = ctxPtr->dictLimit;
|
758
|
-
ctxPtr->
|
759
|
-
ctxPtr->
|
760
|
-
ctxPtr->
|
1101
|
+
ctxPtr->dictStart = ctxPtr->prefixStart;
|
1102
|
+
ctxPtr->dictLimit += (U32)(ctxPtr->end - ctxPtr->prefixStart);
|
1103
|
+
ctxPtr->prefixStart = newBlock;
|
761
1104
|
ctxPtr->end = newBlock;
|
762
1105
|
ctxPtr->nextToUpdate = ctxPtr->dictLimit; /* match referencing will resume from there */
|
1106
|
+
|
1107
|
+
/* cannot reference an extDict and a dictCtx at the same time */
|
1108
|
+
ctxPtr->dictCtx = NULL;
|
763
1109
|
}
|
764
1110
|
|
765
|
-
static int
|
766
|
-
|
767
|
-
|
768
|
-
|
1111
|
+
static int
|
1112
|
+
LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,
|
1113
|
+
const char* src, char* dst,
|
1114
|
+
int* srcSizePtr, int dstCapacity,
|
1115
|
+
limitedOutput_directive limit)
|
769
1116
|
{
|
770
1117
|
LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
|
1118
|
+
DEBUGLOG(5, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)",
|
1119
|
+
LZ4_streamHCPtr, src, *srcSizePtr, limit);
|
1120
|
+
assert(ctxPtr != NULL);
|
771
1121
|
/* auto-init if forgotten */
|
772
|
-
if (ctxPtr->
|
1122
|
+
if (ctxPtr->prefixStart == NULL) LZ4HC_init_internal (ctxPtr, (const BYTE*) src);
|
773
1123
|
|
774
1124
|
/* Check overflow */
|
775
|
-
if ((size_t)(ctxPtr->end - ctxPtr->
|
776
|
-
size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->
|
1125
|
+
if ((size_t)(ctxPtr->end - ctxPtr->prefixStart) + ctxPtr->dictLimit > 2 GB) {
|
1126
|
+
size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->prefixStart);
|
777
1127
|
if (dictSize > 64 KB) dictSize = 64 KB;
|
778
1128
|
LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize);
|
779
1129
|
}
|
780
1130
|
|
781
1131
|
/* Check if blocks follow each other */
|
782
|
-
if ((const BYTE*)src != ctxPtr->end)
|
1132
|
+
if ((const BYTE*)src != ctxPtr->end)
|
1133
|
+
LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src);
|
783
1134
|
|
784
1135
|
/* Check overlapping input/dictionary space */
|
785
1136
|
{ const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr;
|
786
|
-
const BYTE* const dictBegin = ctxPtr->
|
787
|
-
const BYTE* const dictEnd = ctxPtr->
|
1137
|
+
const BYTE* const dictBegin = ctxPtr->dictStart;
|
1138
|
+
const BYTE* const dictEnd = ctxPtr->dictStart + (ctxPtr->dictLimit - ctxPtr->lowLimit);
|
788
1139
|
if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) {
|
789
1140
|
if (sourceEnd > dictEnd) sourceEnd = dictEnd;
|
790
|
-
ctxPtr->lowLimit
|
791
|
-
|
792
|
-
|
793
|
-
|
1141
|
+
ctxPtr->lowLimit += (U32)(sourceEnd - ctxPtr->dictStart);
|
1142
|
+
ctxPtr->dictStart += (U32)(sourceEnd - ctxPtr->dictStart);
|
1143
|
+
if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) {
|
1144
|
+
ctxPtr->lowLimit = ctxPtr->dictLimit;
|
1145
|
+
ctxPtr->dictStart = ctxPtr->prefixStart;
|
1146
|
+
} } }
|
794
1147
|
|
795
1148
|
return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit);
|
796
1149
|
}
|
@@ -800,42 +1153,53 @@ int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src,
|
|
800
1153
|
if (dstCapacity < LZ4_compressBound(srcSize))
|
801
1154
|
return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput);
|
802
1155
|
else
|
803
|
-
return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity,
|
1156
|
+
return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, notLimited);
|
804
1157
|
}
|
805
1158
|
|
806
1159
|
int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int targetDestSize)
|
807
1160
|
{
|
808
|
-
return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize,
|
1161
|
+
return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, fillOutput);
|
809
1162
|
}
|
810
1163
|
|
811
1164
|
|
812
1165
|
|
813
|
-
/*
|
814
|
-
|
1166
|
+
/* LZ4_saveDictHC :
|
1167
|
+
* save history content
|
1168
|
+
* into a user-provided buffer
|
1169
|
+
* which is then used to continue compression
|
1170
|
+
*/
|
815
1171
|
int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)
|
816
1172
|
{
|
817
1173
|
LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse;
|
818
|
-
int const prefixSize = (int)(streamPtr->end -
|
1174
|
+
int const prefixSize = (int)(streamPtr->end - streamPtr->prefixStart);
|
1175
|
+
DEBUGLOG(5, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize);
|
1176
|
+
assert(prefixSize >= 0);
|
819
1177
|
if (dictSize > 64 KB) dictSize = 64 KB;
|
820
1178
|
if (dictSize < 4) dictSize = 0;
|
821
1179
|
if (dictSize > prefixSize) dictSize = prefixSize;
|
822
|
-
|
823
|
-
|
1180
|
+
if (safeBuffer == NULL) assert(dictSize == 0);
|
1181
|
+
if (dictSize > 0)
|
1182
|
+
LZ4_memmove(safeBuffer, streamPtr->end - dictSize, dictSize);
|
1183
|
+
{ U32 const endIndex = (U32)(streamPtr->end - streamPtr->prefixStart) + streamPtr->dictLimit;
|
824
1184
|
streamPtr->end = (const BYTE*)safeBuffer + dictSize;
|
825
|
-
streamPtr->
|
826
|
-
streamPtr->dictLimit = endIndex - dictSize;
|
827
|
-
streamPtr->lowLimit = endIndex - dictSize;
|
828
|
-
|
1185
|
+
streamPtr->prefixStart = streamPtr->end - dictSize;
|
1186
|
+
streamPtr->dictLimit = endIndex - (U32)dictSize;
|
1187
|
+
streamPtr->lowLimit = endIndex - (U32)dictSize;
|
1188
|
+
streamPtr->dictStart = streamPtr->prefixStart;
|
1189
|
+
if (streamPtr->nextToUpdate < streamPtr->dictLimit)
|
1190
|
+
streamPtr->nextToUpdate = streamPtr->dictLimit;
|
829
1191
|
}
|
830
1192
|
return dictSize;
|
831
1193
|
}
|
832
1194
|
|
833
1195
|
|
834
|
-
|
1196
|
+
/***************************************************
|
835
1197
|
* Deprecated Functions
|
836
|
-
|
1198
|
+
***************************************************/
|
1199
|
+
|
837
1200
|
/* These functions currently generate deprecation warnings */
|
838
|
-
|
1201
|
+
|
1202
|
+
/* Wrappers for deprecated compression functions */
|
839
1203
|
int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
|
840
1204
|
int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); }
|
841
1205
|
int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
|
@@ -849,35 +1213,38 @@ int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* ctx, const char* src,
|
|
849
1213
|
|
850
1214
|
|
851
1215
|
/* Deprecated streaming functions */
|
852
|
-
int LZ4_sizeofStreamStateHC(void) { return
|
1216
|
+
int LZ4_sizeofStreamStateHC(void) { return sizeof(LZ4_streamHC_t); }
|
853
1217
|
|
1218
|
+
/* state is presumed correctly sized, aka >= sizeof(LZ4_streamHC_t)
|
1219
|
+
* @return : 0 on success, !=0 if error */
|
854
1220
|
int LZ4_resetStreamStateHC(void* state, char* inputBuffer)
|
855
1221
|
{
|
856
|
-
|
857
|
-
if (
|
858
|
-
|
859
|
-
ctx->inputBuffer = (BYTE*)inputBuffer;
|
1222
|
+
LZ4_streamHC_t* const hc4 = LZ4_initStreamHC(state, sizeof(*hc4));
|
1223
|
+
if (hc4 == NULL) return 1; /* init failed */
|
1224
|
+
LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
|
860
1225
|
return 0;
|
861
1226
|
}
|
862
1227
|
|
863
|
-
|
1228
|
+
#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)
|
1229
|
+
void* LZ4_createHC (const char* inputBuffer)
|
864
1230
|
{
|
865
|
-
LZ4_streamHC_t* hc4 = (
|
1231
|
+
LZ4_streamHC_t* const hc4 = LZ4_createStreamHC();
|
866
1232
|
if (hc4 == NULL) return NULL; /* not enough memory */
|
867
|
-
|
868
|
-
hc4->internal_donotuse.inputBuffer = (BYTE*)inputBuffer;
|
1233
|
+
LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
|
869
1234
|
return hc4;
|
870
1235
|
}
|
871
1236
|
|
872
|
-
int LZ4_freeHC (void* LZ4HC_Data)
|
1237
|
+
int LZ4_freeHC (void* LZ4HC_Data)
|
1238
|
+
{
|
873
1239
|
if (!LZ4HC_Data) return 0; /* support free on NULL */
|
874
1240
|
FREEMEM(LZ4HC_Data);
|
875
1241
|
return 0;
|
876
1242
|
}
|
1243
|
+
#endif
|
877
1244
|
|
878
1245
|
int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)
|
879
1246
|
{
|
880
|
-
return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel,
|
1247
|
+
return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited);
|
881
1248
|
}
|
882
1249
|
|
883
1250
|
int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel)
|
@@ -887,7 +1254,378 @@ int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, c
|
|
887
1254
|
|
888
1255
|
char* LZ4_slideInputBufferHC(void* LZ4HC_Data)
|
889
1256
|
{
|
890
|
-
|
891
|
-
|
892
|
-
|
1257
|
+
LZ4_streamHC_t* const ctx = (LZ4_streamHC_t*)LZ4HC_Data;
|
1258
|
+
const BYTE* bufferStart = ctx->internal_donotuse.prefixStart - ctx->internal_donotuse.dictLimit + ctx->internal_donotuse.lowLimit;
|
1259
|
+
LZ4_resetStreamHC_fast(ctx, ctx->internal_donotuse.compressionLevel);
|
1260
|
+
/* avoid const char * -> char * conversion warning :( */
|
1261
|
+
return (char*)(uptrval)bufferStart;
|
1262
|
+
}
|
1263
|
+
|
1264
|
+
|
1265
|
+
/* ================================================
|
1266
|
+
* LZ4 Optimal parser (levels [LZ4HC_CLEVEL_OPT_MIN - LZ4HC_CLEVEL_MAX])
|
1267
|
+
* ===============================================*/
|
1268
|
+
typedef struct {
|
1269
|
+
int price;
|
1270
|
+
int off;
|
1271
|
+
int mlen;
|
1272
|
+
int litlen;
|
1273
|
+
} LZ4HC_optimal_t;
|
1274
|
+
|
1275
|
+
/* price in bytes */
|
1276
|
+
LZ4_FORCE_INLINE int LZ4HC_literalsPrice(int const litlen)
|
1277
|
+
{
|
1278
|
+
int price = litlen;
|
1279
|
+
assert(litlen >= 0);
|
1280
|
+
if (litlen >= (int)RUN_MASK)
|
1281
|
+
price += 1 + ((litlen-(int)RUN_MASK) / 255);
|
1282
|
+
return price;
|
1283
|
+
}
|
1284
|
+
|
1285
|
+
|
1286
|
+
/* requires mlen >= MINMATCH */
|
1287
|
+
LZ4_FORCE_INLINE int LZ4HC_sequencePrice(int litlen, int mlen)
|
1288
|
+
{
|
1289
|
+
int price = 1 + 2 ; /* token + 16-bit offset */
|
1290
|
+
assert(litlen >= 0);
|
1291
|
+
assert(mlen >= MINMATCH);
|
1292
|
+
|
1293
|
+
price += LZ4HC_literalsPrice(litlen);
|
1294
|
+
|
1295
|
+
if (mlen >= (int)(ML_MASK+MINMATCH))
|
1296
|
+
price += 1 + ((mlen-(int)(ML_MASK+MINMATCH)) / 255);
|
1297
|
+
|
1298
|
+
return price;
|
1299
|
+
}
|
1300
|
+
|
1301
|
+
|
1302
|
+
typedef struct {
|
1303
|
+
int off;
|
1304
|
+
int len;
|
1305
|
+
} LZ4HC_match_t;
|
1306
|
+
|
1307
|
+
LZ4_FORCE_INLINE LZ4HC_match_t
|
1308
|
+
LZ4HC_FindLongerMatch(LZ4HC_CCtx_internal* const ctx,
|
1309
|
+
const BYTE* ip, const BYTE* const iHighLimit,
|
1310
|
+
int minLen, int nbSearches,
|
1311
|
+
const dictCtx_directive dict,
|
1312
|
+
const HCfavor_e favorDecSpeed)
|
1313
|
+
{
|
1314
|
+
LZ4HC_match_t match = { 0 , 0 };
|
1315
|
+
const BYTE* matchPtr = NULL;
|
1316
|
+
/* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),
|
1317
|
+
* but this won't be the case here, as we define iLowLimit==ip,
|
1318
|
+
* so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */
|
1319
|
+
int matchLength = LZ4HC_InsertAndGetWiderMatch(ctx, ip, ip, iHighLimit, minLen, &matchPtr, &ip, nbSearches, 1 /*patternAnalysis*/, 1 /*chainSwap*/, dict, favorDecSpeed);
|
1320
|
+
if (matchLength <= minLen) return match;
|
1321
|
+
if (favorDecSpeed) {
|
1322
|
+
if ((matchLength>18) & (matchLength<=36)) matchLength=18; /* favor shortcut */
|
1323
|
+
}
|
1324
|
+
match.len = matchLength;
|
1325
|
+
match.off = (int)(ip-matchPtr);
|
1326
|
+
return match;
|
1327
|
+
}
|
1328
|
+
|
1329
|
+
|
1330
|
+
static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,
|
1331
|
+
const char* const source,
|
1332
|
+
char* dst,
|
1333
|
+
int* srcSizePtr,
|
1334
|
+
int dstCapacity,
|
1335
|
+
int const nbSearches,
|
1336
|
+
size_t sufficient_len,
|
1337
|
+
const limitedOutput_directive limit,
|
1338
|
+
int const fullUpdate,
|
1339
|
+
const dictCtx_directive dict,
|
1340
|
+
const HCfavor_e favorDecSpeed)
|
1341
|
+
{
|
1342
|
+
int retval = 0;
|
1343
|
+
#define TRAILING_LITERALS 3
|
1344
|
+
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
|
1345
|
+
LZ4HC_optimal_t* const opt = (LZ4HC_optimal_t*)ALLOC(sizeof(LZ4HC_optimal_t) * (LZ4_OPT_NUM + TRAILING_LITERALS));
|
1346
|
+
#else
|
1347
|
+
LZ4HC_optimal_t opt[LZ4_OPT_NUM + TRAILING_LITERALS]; /* ~64 KB, which is a bit large for stack... */
|
1348
|
+
#endif
|
1349
|
+
|
1350
|
+
const BYTE* ip = (const BYTE*) source;
|
1351
|
+
const BYTE* anchor = ip;
|
1352
|
+
const BYTE* const iend = ip + *srcSizePtr;
|
1353
|
+
const BYTE* const mflimit = iend - MFLIMIT;
|
1354
|
+
const BYTE* const matchlimit = iend - LASTLITERALS;
|
1355
|
+
BYTE* op = (BYTE*) dst;
|
1356
|
+
BYTE* opSaved = (BYTE*) dst;
|
1357
|
+
BYTE* oend = op + dstCapacity;
|
1358
|
+
int ovml = MINMATCH; /* overflow - last sequence */
|
1359
|
+
const BYTE* ovref = NULL;
|
1360
|
+
|
1361
|
+
/* init */
|
1362
|
+
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
|
1363
|
+
if (opt == NULL) goto _return_label;
|
1364
|
+
#endif
|
1365
|
+
DEBUGLOG(5, "LZ4HC_compress_optimal(dst=%p, dstCapa=%u)", dst, (unsigned)dstCapacity);
|
1366
|
+
*srcSizePtr = 0;
|
1367
|
+
if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */
|
1368
|
+
if (sufficient_len >= LZ4_OPT_NUM) sufficient_len = LZ4_OPT_NUM-1;
|
1369
|
+
|
1370
|
+
/* Main Loop */
|
1371
|
+
while (ip <= mflimit) {
|
1372
|
+
int const llen = (int)(ip - anchor);
|
1373
|
+
int best_mlen, best_off;
|
1374
|
+
int cur, last_match_pos = 0;
|
1375
|
+
|
1376
|
+
LZ4HC_match_t const firstMatch = LZ4HC_FindLongerMatch(ctx, ip, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);
|
1377
|
+
if (firstMatch.len==0) { ip++; continue; }
|
1378
|
+
|
1379
|
+
if ((size_t)firstMatch.len > sufficient_len) {
|
1380
|
+
/* good enough solution : immediate encoding */
|
1381
|
+
int const firstML = firstMatch.len;
|
1382
|
+
const BYTE* const matchPos = ip - firstMatch.off;
|
1383
|
+
opSaved = op;
|
1384
|
+
if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, matchPos, limit, oend) ) { /* updates ip, op and anchor */
|
1385
|
+
ovml = firstML;
|
1386
|
+
ovref = matchPos;
|
1387
|
+
goto _dest_overflow;
|
1388
|
+
}
|
1389
|
+
continue;
|
1390
|
+
}
|
1391
|
+
|
1392
|
+
/* set prices for first positions (literals) */
|
1393
|
+
{ int rPos;
|
1394
|
+
for (rPos = 0 ; rPos < MINMATCH ; rPos++) {
|
1395
|
+
int const cost = LZ4HC_literalsPrice(llen + rPos);
|
1396
|
+
opt[rPos].mlen = 1;
|
1397
|
+
opt[rPos].off = 0;
|
1398
|
+
opt[rPos].litlen = llen + rPos;
|
1399
|
+
opt[rPos].price = cost;
|
1400
|
+
DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup",
|
1401
|
+
rPos, cost, opt[rPos].litlen);
|
1402
|
+
} }
|
1403
|
+
/* set prices using initial match */
|
1404
|
+
{ int mlen = MINMATCH;
|
1405
|
+
int const matchML = firstMatch.len; /* necessarily < sufficient_len < LZ4_OPT_NUM */
|
1406
|
+
int const offset = firstMatch.off;
|
1407
|
+
assert(matchML < LZ4_OPT_NUM);
|
1408
|
+
for ( ; mlen <= matchML ; mlen++) {
|
1409
|
+
int const cost = LZ4HC_sequencePrice(llen, mlen);
|
1410
|
+
opt[mlen].mlen = mlen;
|
1411
|
+
opt[mlen].off = offset;
|
1412
|
+
opt[mlen].litlen = llen;
|
1413
|
+
opt[mlen].price = cost;
|
1414
|
+
DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i) -- initial setup",
|
1415
|
+
mlen, cost, mlen);
|
1416
|
+
} }
|
1417
|
+
last_match_pos = firstMatch.len;
|
1418
|
+
{ int addLit;
|
1419
|
+
for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {
|
1420
|
+
opt[last_match_pos+addLit].mlen = 1; /* literal */
|
1421
|
+
opt[last_match_pos+addLit].off = 0;
|
1422
|
+
opt[last_match_pos+addLit].litlen = addLit;
|
1423
|
+
opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);
|
1424
|
+
DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup",
|
1425
|
+
last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);
|
1426
|
+
} }
|
1427
|
+
|
1428
|
+
/* check further positions */
|
1429
|
+
for (cur = 1; cur < last_match_pos; cur++) {
|
1430
|
+
const BYTE* const curPtr = ip + cur;
|
1431
|
+
LZ4HC_match_t newMatch;
|
1432
|
+
|
1433
|
+
if (curPtr > mflimit) break;
|
1434
|
+
DEBUGLOG(7, "rPos:%u[%u] vs [%u]%u",
|
1435
|
+
cur, opt[cur].price, opt[cur+1].price, cur+1);
|
1436
|
+
if (fullUpdate) {
|
1437
|
+
/* not useful to search here if next position has same (or lower) cost */
|
1438
|
+
if ( (opt[cur+1].price <= opt[cur].price)
|
1439
|
+
/* in some cases, next position has same cost, but cost rises sharply after, so a small match would still be beneficial */
|
1440
|
+
&& (opt[cur+MINMATCH].price < opt[cur].price + 3/*min seq price*/) )
|
1441
|
+
continue;
|
1442
|
+
} else {
|
1443
|
+
/* not useful to search here if next position has same (or lower) cost */
|
1444
|
+
if (opt[cur+1].price <= opt[cur].price) continue;
|
1445
|
+
}
|
1446
|
+
|
1447
|
+
DEBUGLOG(7, "search at rPos:%u", cur);
|
1448
|
+
if (fullUpdate)
|
1449
|
+
newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);
|
1450
|
+
else
|
1451
|
+
/* only test matches of minimum length; slightly faster, but misses a few bytes */
|
1452
|
+
newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, last_match_pos - cur, nbSearches, dict, favorDecSpeed);
|
1453
|
+
if (!newMatch.len) continue;
|
1454
|
+
|
1455
|
+
if ( ((size_t)newMatch.len > sufficient_len)
|
1456
|
+
|| (newMatch.len + cur >= LZ4_OPT_NUM) ) {
|
1457
|
+
/* immediate encoding */
|
1458
|
+
best_mlen = newMatch.len;
|
1459
|
+
best_off = newMatch.off;
|
1460
|
+
last_match_pos = cur + 1;
|
1461
|
+
goto encode;
|
1462
|
+
}
|
1463
|
+
|
1464
|
+
/* before match : set price with literals at beginning */
|
1465
|
+
{ int const baseLitlen = opt[cur].litlen;
|
1466
|
+
int litlen;
|
1467
|
+
for (litlen = 1; litlen < MINMATCH; litlen++) {
|
1468
|
+
int const price = opt[cur].price - LZ4HC_literalsPrice(baseLitlen) + LZ4HC_literalsPrice(baseLitlen+litlen);
|
1469
|
+
int const pos = cur + litlen;
|
1470
|
+
if (price < opt[pos].price) {
|
1471
|
+
opt[pos].mlen = 1; /* literal */
|
1472
|
+
opt[pos].off = 0;
|
1473
|
+
opt[pos].litlen = baseLitlen+litlen;
|
1474
|
+
opt[pos].price = price;
|
1475
|
+
DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)",
|
1476
|
+
pos, price, opt[pos].litlen);
|
1477
|
+
} } }
|
1478
|
+
|
1479
|
+
/* set prices using match at position = cur */
|
1480
|
+
{ int const matchML = newMatch.len;
|
1481
|
+
int ml = MINMATCH;
|
1482
|
+
|
1483
|
+
assert(cur + newMatch.len < LZ4_OPT_NUM);
|
1484
|
+
for ( ; ml <= matchML ; ml++) {
|
1485
|
+
int const pos = cur + ml;
|
1486
|
+
int const offset = newMatch.off;
|
1487
|
+
int price;
|
1488
|
+
int ll;
|
1489
|
+
DEBUGLOG(7, "testing price rPos %i (last_match_pos=%i)",
|
1490
|
+
pos, last_match_pos);
|
1491
|
+
if (opt[cur].mlen == 1) {
|
1492
|
+
ll = opt[cur].litlen;
|
1493
|
+
price = ((cur > ll) ? opt[cur - ll].price : 0)
|
1494
|
+
+ LZ4HC_sequencePrice(ll, ml);
|
1495
|
+
} else {
|
1496
|
+
ll = 0;
|
1497
|
+
price = opt[cur].price + LZ4HC_sequencePrice(0, ml);
|
1498
|
+
}
|
1499
|
+
|
1500
|
+
assert((U32)favorDecSpeed <= 1);
|
1501
|
+
if (pos > last_match_pos+TRAILING_LITERALS
|
1502
|
+
|| price <= opt[pos].price - (int)favorDecSpeed) {
|
1503
|
+
DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i)",
|
1504
|
+
pos, price, ml);
|
1505
|
+
assert(pos < LZ4_OPT_NUM);
|
1506
|
+
if ( (ml == matchML) /* last pos of last match */
|
1507
|
+
&& (last_match_pos < pos) )
|
1508
|
+
last_match_pos = pos;
|
1509
|
+
opt[pos].mlen = ml;
|
1510
|
+
opt[pos].off = offset;
|
1511
|
+
opt[pos].litlen = ll;
|
1512
|
+
opt[pos].price = price;
|
1513
|
+
} } }
|
1514
|
+
/* complete following positions with literals */
|
1515
|
+
{ int addLit;
|
1516
|
+
for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {
|
1517
|
+
opt[last_match_pos+addLit].mlen = 1; /* literal */
|
1518
|
+
opt[last_match_pos+addLit].off = 0;
|
1519
|
+
opt[last_match_pos+addLit].litlen = addLit;
|
1520
|
+
opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);
|
1521
|
+
DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)", last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);
|
1522
|
+
} }
|
1523
|
+
} /* for (cur = 1; cur <= last_match_pos; cur++) */
|
1524
|
+
|
1525
|
+
assert(last_match_pos < LZ4_OPT_NUM + TRAILING_LITERALS);
|
1526
|
+
best_mlen = opt[last_match_pos].mlen;
|
1527
|
+
best_off = opt[last_match_pos].off;
|
1528
|
+
cur = last_match_pos - best_mlen;
|
1529
|
+
|
1530
|
+
encode: /* cur, last_match_pos, best_mlen, best_off must be set */
|
1531
|
+
assert(cur < LZ4_OPT_NUM);
|
1532
|
+
assert(last_match_pos >= 1); /* == 1 when only one candidate */
|
1533
|
+
DEBUGLOG(6, "reverse traversal, looking for shortest path (last_match_pos=%i)", last_match_pos);
|
1534
|
+
{ int candidate_pos = cur;
|
1535
|
+
int selected_matchLength = best_mlen;
|
1536
|
+
int selected_offset = best_off;
|
1537
|
+
while (1) { /* from end to beginning */
|
1538
|
+
int const next_matchLength = opt[candidate_pos].mlen; /* can be 1, means literal */
|
1539
|
+
int const next_offset = opt[candidate_pos].off;
|
1540
|
+
DEBUGLOG(7, "pos %i: sequence length %i", candidate_pos, selected_matchLength);
|
1541
|
+
opt[candidate_pos].mlen = selected_matchLength;
|
1542
|
+
opt[candidate_pos].off = selected_offset;
|
1543
|
+
selected_matchLength = next_matchLength;
|
1544
|
+
selected_offset = next_offset;
|
1545
|
+
if (next_matchLength > candidate_pos) break; /* last match elected, first match to encode */
|
1546
|
+
assert(next_matchLength > 0); /* can be 1, means literal */
|
1547
|
+
candidate_pos -= next_matchLength;
|
1548
|
+
} }
|
1549
|
+
|
1550
|
+
/* encode all recorded sequences in order */
|
1551
|
+
{ int rPos = 0; /* relative position (to ip) */
|
1552
|
+
while (rPos < last_match_pos) {
|
1553
|
+
int const ml = opt[rPos].mlen;
|
1554
|
+
int const offset = opt[rPos].off;
|
1555
|
+
if (ml == 1) { ip++; rPos++; continue; } /* literal; note: can end up with several literals, in which case, skip them */
|
1556
|
+
rPos += ml;
|
1557
|
+
assert(ml >= MINMATCH);
|
1558
|
+
assert((offset >= 1) && (offset <= LZ4_DISTANCE_MAX));
|
1559
|
+
opSaved = op;
|
1560
|
+
if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ip - offset, limit, oend) ) { /* updates ip, op and anchor */
|
1561
|
+
ovml = ml;
|
1562
|
+
ovref = ip - offset;
|
1563
|
+
goto _dest_overflow;
|
1564
|
+
} } }
|
1565
|
+
} /* while (ip <= mflimit) */
|
1566
|
+
|
1567
|
+
_last_literals:
|
1568
|
+
/* Encode Last Literals */
|
1569
|
+
{ size_t lastRunSize = (size_t)(iend - anchor); /* literals */
|
1570
|
+
size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;
|
1571
|
+
size_t const totalSize = 1 + llAdd + lastRunSize;
|
1572
|
+
if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */
|
1573
|
+
if (limit && (op + totalSize > oend)) {
|
1574
|
+
if (limit == limitedOutput) { /* Check output limit */
|
1575
|
+
retval = 0;
|
1576
|
+
goto _return_label;
|
1577
|
+
}
|
1578
|
+
/* adapt lastRunSize to fill 'dst' */
|
1579
|
+
lastRunSize = (size_t)(oend - op) - 1 /*token*/;
|
1580
|
+
llAdd = (lastRunSize + 256 - RUN_MASK) / 256;
|
1581
|
+
lastRunSize -= llAdd;
|
1582
|
+
}
|
1583
|
+
DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);
|
1584
|
+
ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */
|
1585
|
+
|
1586
|
+
if (lastRunSize >= RUN_MASK) {
|
1587
|
+
size_t accumulator = lastRunSize - RUN_MASK;
|
1588
|
+
*op++ = (RUN_MASK << ML_BITS);
|
1589
|
+
for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;
|
1590
|
+
*op++ = (BYTE) accumulator;
|
1591
|
+
} else {
|
1592
|
+
*op++ = (BYTE)(lastRunSize << ML_BITS);
|
1593
|
+
}
|
1594
|
+
LZ4_memcpy(op, anchor, lastRunSize);
|
1595
|
+
op += lastRunSize;
|
1596
|
+
}
|
1597
|
+
|
1598
|
+
/* End */
|
1599
|
+
*srcSizePtr = (int) (((const char*)ip) - source);
|
1600
|
+
retval = (int) ((char*)op-dst);
|
1601
|
+
goto _return_label;
|
1602
|
+
|
1603
|
+
_dest_overflow:
|
1604
|
+
if (limit == fillOutput) {
|
1605
|
+
/* Assumption : ip, anchor, ovml and ovref must be set correctly */
|
1606
|
+
size_t const ll = (size_t)(ip - anchor);
|
1607
|
+
size_t const ll_addbytes = (ll + 240) / 255;
|
1608
|
+
size_t const ll_totalCost = 1 + ll_addbytes + ll;
|
1609
|
+
BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */
|
1610
|
+
DEBUGLOG(6, "Last sequence overflowing (only %i bytes remaining)", (int)(oend-1-opSaved));
|
1611
|
+
op = opSaved; /* restore correct out pointer */
|
1612
|
+
if (op + ll_totalCost <= maxLitPos) {
|
1613
|
+
/* ll validated; now adjust match length */
|
1614
|
+
size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));
|
1615
|
+
size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);
|
1616
|
+
assert(maxMlSize < INT_MAX); assert(ovml >= 0);
|
1617
|
+
if ((size_t)ovml > maxMlSize) ovml = (int)maxMlSize;
|
1618
|
+
if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ovml >= MFLIMIT) {
|
1619
|
+
DEBUGLOG(6, "Space to end : %i + ml (%i)", (int)((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1), ovml);
|
1620
|
+
DEBUGLOG(6, "Before : ip = %p, anchor = %p", ip, anchor);
|
1621
|
+
LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ovml, ovref, notLimited, oend);
|
1622
|
+
DEBUGLOG(6, "After : ip = %p, anchor = %p", ip, anchor);
|
1623
|
+
} }
|
1624
|
+
goto _last_literals;
|
1625
|
+
}
|
1626
|
+
_return_label:
|
1627
|
+
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
|
1628
|
+
FREEMEM(opt);
|
1629
|
+
#endif
|
1630
|
+
return retval;
|
893
1631
|
}
|