extlz4 0.2.5 → 0.3
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 +9 -1
- data/README.md +44 -41
- data/contrib/lz4/NEWS +33 -0
- data/contrib/lz4/README.md +30 -24
- data/contrib/lz4/lib/README.md +59 -10
- data/contrib/lz4/lib/lz4.c +1303 -583
- data/contrib/lz4/lib/lz4.h +376 -176
- data/contrib/lz4/lib/lz4frame.c +447 -286
- data/contrib/lz4/lib/lz4frame.h +289 -74
- data/contrib/lz4/lib/lz4frame_static.h +4 -111
- data/contrib/lz4/lib/lz4hc.c +789 -207
- data/contrib/lz4/lib/lz4hc.h +256 -93
- data/contrib/lz4/lib/xxhash.c +376 -240
- data/contrib/lz4/lib/xxhash.h +128 -93
- data/ext/blockapi.c +2 -2
- data/ext/lz4_amalgam.c +0 -23
- data/gemstub.rb +4 -4
- data/lib/extlz4.rb +46 -0
- data/lib/extlz4/version.rb +1 -1
- metadata +33 -10
- data/contrib/lz4/circle.yml +0 -38
- data/contrib/lz4/lib/lz4opt.h +0 -356
@@ -36,119 +36,12 @@
|
|
36
36
|
#ifndef LZ4FRAME_STATIC_H_0398209384
|
37
37
|
#define LZ4FRAME_STATIC_H_0398209384
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
/* lz4frame_static.h should be used solely in the context of static linking.
|
44
|
-
* It contains definitions which are not stable and may change in the future.
|
45
|
-
* Never use it in the context of DLL linking.
|
46
|
-
*
|
47
|
-
* Defining LZ4F_PUBLISH_STATIC_FUNCTIONS allows one to override this. Use at
|
48
|
-
* your own risk.
|
39
|
+
/* The declarations that formerly were made here have been merged into
|
40
|
+
* lz4frame.h, protected by the LZ4F_STATIC_LINKING_ONLY macro. Going forward,
|
41
|
+
* it is recommended to simply include that header directly.
|
49
42
|
*/
|
50
|
-
#ifdef LZ4F_PUBLISH_STATIC_FUNCTIONS
|
51
|
-
#define LZ4FLIB_STATIC_API LZ4FLIB_API
|
52
|
-
#else
|
53
|
-
#define LZ4FLIB_STATIC_API
|
54
|
-
#endif
|
55
|
-
|
56
43
|
|
57
|
-
|
44
|
+
#define LZ4F_STATIC_LINKING_ONLY
|
58
45
|
#include "lz4frame.h"
|
59
46
|
|
60
|
-
|
61
|
-
/* --- Error List --- */
|
62
|
-
#define LZ4F_LIST_ERRORS(ITEM) \
|
63
|
-
ITEM(OK_NoError) \
|
64
|
-
ITEM(ERROR_GENERIC) \
|
65
|
-
ITEM(ERROR_maxBlockSize_invalid) \
|
66
|
-
ITEM(ERROR_blockMode_invalid) \
|
67
|
-
ITEM(ERROR_contentChecksumFlag_invalid) \
|
68
|
-
ITEM(ERROR_compressionLevel_invalid) \
|
69
|
-
ITEM(ERROR_headerVersion_wrong) \
|
70
|
-
ITEM(ERROR_blockChecksum_invalid) \
|
71
|
-
ITEM(ERROR_reservedFlag_set) \
|
72
|
-
ITEM(ERROR_allocation_failed) \
|
73
|
-
ITEM(ERROR_srcSize_tooLarge) \
|
74
|
-
ITEM(ERROR_dstMaxSize_tooSmall) \
|
75
|
-
ITEM(ERROR_frameHeader_incomplete) \
|
76
|
-
ITEM(ERROR_frameType_unknown) \
|
77
|
-
ITEM(ERROR_frameSize_wrong) \
|
78
|
-
ITEM(ERROR_srcPtr_wrong) \
|
79
|
-
ITEM(ERROR_decompressionFailed) \
|
80
|
-
ITEM(ERROR_headerChecksum_invalid) \
|
81
|
-
ITEM(ERROR_contentChecksum_invalid) \
|
82
|
-
ITEM(ERROR_frameDecoding_alreadyStarted) \
|
83
|
-
ITEM(ERROR_maxCode)
|
84
|
-
|
85
|
-
#define LZ4F_GENERATE_ENUM(ENUM) LZ4F_##ENUM,
|
86
|
-
|
87
|
-
/* enum list is exposed, to handle specific errors */
|
88
|
-
typedef enum { LZ4F_LIST_ERRORS(LZ4F_GENERATE_ENUM) } LZ4F_errorCodes;
|
89
|
-
|
90
|
-
LZ4FLIB_STATIC_API LZ4F_errorCodes LZ4F_getErrorCode(size_t functionResult);
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
/**********************************
|
95
|
-
* Bulk processing dictionary API
|
96
|
-
*********************************/
|
97
|
-
typedef struct LZ4F_CDict_s LZ4F_CDict;
|
98
|
-
|
99
|
-
/*! LZ4_createCDict() :
|
100
|
-
* When compressing multiple messages / blocks with the same dictionary, it's recommended to load it just once.
|
101
|
-
* LZ4_createCDict() will create a digested dictionary, ready to start future compression operations without startup delay.
|
102
|
-
* LZ4_CDict can be created once and shared by multiple threads concurrently, since its usage is read-only.
|
103
|
-
* `dictBuffer` can be released after LZ4_CDict creation, since its content is copied within CDict */
|
104
|
-
LZ4FLIB_STATIC_API LZ4F_CDict* LZ4F_createCDict(const void* dictBuffer, size_t dictSize);
|
105
|
-
LZ4FLIB_STATIC_API void LZ4F_freeCDict(LZ4F_CDict* CDict);
|
106
|
-
|
107
|
-
|
108
|
-
/*! LZ4_compressFrame_usingCDict() :
|
109
|
-
* Compress an entire srcBuffer into a valid LZ4 frame using a digested Dictionary.
|
110
|
-
* If cdict==NULL, compress without a dictionary.
|
111
|
-
* dstBuffer MUST be >= LZ4F_compressFrameBound(srcSize, preferencesPtr).
|
112
|
-
* If this condition is not respected, function will fail (@return an errorCode).
|
113
|
-
* The LZ4F_preferences_t structure is optional : you may provide NULL as argument,
|
114
|
-
* but it's not recommended, as it's the only way to provide dictID in the frame header.
|
115
|
-
* @return : number of bytes written into dstBuffer.
|
116
|
-
* or an error code if it fails (can be tested using LZ4F_isError()) */
|
117
|
-
LZ4FLIB_STATIC_API size_t LZ4F_compressFrame_usingCDict(
|
118
|
-
void* dst, size_t dstCapacity,
|
119
|
-
const void* src, size_t srcSize,
|
120
|
-
const LZ4F_CDict* cdict,
|
121
|
-
const LZ4F_preferences_t* preferencesPtr);
|
122
|
-
|
123
|
-
|
124
|
-
/*! LZ4F_compressBegin_usingCDict() :
|
125
|
-
* Inits streaming dictionary compression, and writes the frame header into dstBuffer.
|
126
|
-
* dstCapacity must be >= LZ4F_HEADER_SIZE_MAX bytes.
|
127
|
-
* `prefsPtr` is optional : you may provide NULL as argument,
|
128
|
-
* however, it's the only way to provide dictID in the frame header.
|
129
|
-
* @return : number of bytes written into dstBuffer for the header,
|
130
|
-
* or an error code (which can be tested using LZ4F_isError()) */
|
131
|
-
LZ4FLIB_STATIC_API size_t LZ4F_compressBegin_usingCDict(
|
132
|
-
LZ4F_cctx* cctx,
|
133
|
-
void* dstBuffer, size_t dstCapacity,
|
134
|
-
const LZ4F_CDict* cdict,
|
135
|
-
const LZ4F_preferences_t* prefsPtr);
|
136
|
-
|
137
|
-
|
138
|
-
/*! LZ4F_decompress_usingDict() :
|
139
|
-
* Same as LZ4F_decompress(), using a predefined dictionary.
|
140
|
-
* Dictionary is used "in place", without any preprocessing.
|
141
|
-
* It must remain accessible throughout the entire frame decoding. */
|
142
|
-
LZ4FLIB_STATIC_API size_t LZ4F_decompress_usingDict(
|
143
|
-
LZ4F_dctx* dctxPtr,
|
144
|
-
void* dstBuffer, size_t* dstSizePtr,
|
145
|
-
const void* srcBuffer, size_t* srcSizePtr,
|
146
|
-
const void* dict, size_t dictSize,
|
147
|
-
const LZ4F_decompressOptions_t* decompressOptionsPtr);
|
148
|
-
|
149
|
-
|
150
|
-
#if defined (__cplusplus)
|
151
|
-
}
|
152
|
-
#endif
|
153
|
-
|
154
47
|
#endif /* LZ4FRAME_STATIC_H_0398209384 */
|
data/contrib/lz4/lib/lz4hc.c
CHANGED
@@ -61,12 +61,18 @@
|
|
61
61
|
# pragma clang diagnostic ignored "-Wunused-function"
|
62
62
|
#endif
|
63
63
|
|
64
|
+
/*=== Enums ===*/
|
65
|
+
typedef enum { noDictCtx, usingDictCtxHc } dictCtx_directive;
|
66
|
+
|
67
|
+
|
64
68
|
#define LZ4_COMMONDEFS_ONLY
|
69
|
+
#ifndef LZ4_SRC_INCLUDED
|
65
70
|
#include "lz4.c" /* LZ4_count, constants, mem */
|
66
|
-
|
71
|
+
#endif
|
67
72
|
|
68
73
|
/*=== Constants ===*/
|
69
74
|
#define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH)
|
75
|
+
#define LZ4_OPT_NUM (1<<12)
|
70
76
|
|
71
77
|
|
72
78
|
/*=== Macros ===*/
|
@@ -75,24 +81,35 @@
|
|
75
81
|
#define HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG))
|
76
82
|
#define DELTANEXTMAXD(p) chainTable[(p) & LZ4HC_MAXD_MASK] /* flexible, LZ4HC_MAXD dependent */
|
77
83
|
#define DELTANEXTU16(table, pos) table[(U16)(pos)] /* faster */
|
84
|
+
/* Make fields passed to, and updated by LZ4HC_encodeSequence explicit */
|
85
|
+
#define UPDATABLE(ip, op, anchor) &ip, &op, &anchor
|
78
86
|
|
79
87
|
static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }
|
80
88
|
|
81
89
|
|
82
|
-
|
83
90
|
/**************************************
|
84
91
|
* HC Compression
|
85
92
|
**************************************/
|
86
|
-
static void
|
93
|
+
static void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4)
|
87
94
|
{
|
88
95
|
MEM_INIT((void*)hc4->hashTable, 0, sizeof(hc4->hashTable));
|
89
96
|
MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));
|
90
|
-
|
91
|
-
|
97
|
+
}
|
98
|
+
|
99
|
+
static void LZ4HC_init_internal (LZ4HC_CCtx_internal* hc4, const BYTE* start)
|
100
|
+
{
|
101
|
+
uptrval startingOffset = (uptrval)(hc4->end - hc4->base);
|
102
|
+
if (startingOffset > 1 GB) {
|
103
|
+
LZ4HC_clearTables(hc4);
|
104
|
+
startingOffset = 0;
|
105
|
+
}
|
106
|
+
startingOffset += 64 KB;
|
107
|
+
hc4->nextToUpdate = (U32) startingOffset;
|
108
|
+
hc4->base = start - startingOffset;
|
92
109
|
hc4->end = start;
|
93
|
-
hc4->dictBase = start -
|
94
|
-
hc4->dictLimit =
|
95
|
-
hc4->lowLimit =
|
110
|
+
hc4->dictBase = start - startingOffset;
|
111
|
+
hc4->dictLimit = (U32) startingOffset;
|
112
|
+
hc4->lowLimit = (U32) startingOffset;
|
96
113
|
}
|
97
114
|
|
98
115
|
|
@@ -108,7 +125,7 @@ LZ4_FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip)
|
|
108
125
|
while (idx < target) {
|
109
126
|
U32 const h = LZ4HC_hashPtr(base+idx);
|
110
127
|
size_t delta = idx - hashTable[h];
|
111
|
-
if (delta>
|
128
|
+
if (delta>LZ4_DISTANCE_MAX) delta = LZ4_DISTANCE_MAX;
|
112
129
|
DELTANEXTU16(chainTable, idx) = (U16)delta;
|
113
130
|
hashTable[h] = idx;
|
114
131
|
idx++;
|
@@ -123,17 +140,21 @@ LZ4_FORCE_INLINE
|
|
123
140
|
int LZ4HC_countBack(const BYTE* const ip, const BYTE* const match,
|
124
141
|
const BYTE* const iMin, const BYTE* const mMin)
|
125
142
|
{
|
126
|
-
int back=0;
|
127
|
-
|
128
|
-
|
129
|
-
|
143
|
+
int back = 0;
|
144
|
+
int const min = (int)MAX(iMin - ip, mMin - match);
|
145
|
+
assert(min <= 0);
|
146
|
+
assert(ip >= iMin); assert((size_t)(ip-iMin) < (1U<<31));
|
147
|
+
assert(match >= mMin); assert((size_t)(match - mMin) < (1U<<31));
|
148
|
+
while ( (back > min)
|
149
|
+
&& (ip[back-1] == match[back-1]) )
|
130
150
|
back--;
|
131
151
|
return back;
|
132
152
|
}
|
133
153
|
|
134
154
|
/* LZ4HC_countPattern() :
|
135
155
|
* pattern32 must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!) */
|
136
|
-
static unsigned
|
156
|
+
static unsigned
|
157
|
+
LZ4HC_countPattern(const BYTE* ip, const BYTE* const iEnd, U32 const pattern32)
|
137
158
|
{
|
138
159
|
const BYTE* const iStart = ip;
|
139
160
|
reg_t const pattern = (sizeof(pattern)==8) ? (reg_t)pattern32 + (((reg_t)pattern32) << 32) : pattern32;
|
@@ -165,7 +186,8 @@ static unsigned LZ4HC_countPattern(const BYTE* ip, const BYTE* const iEnd, U32 c
|
|
165
186
|
/* LZ4HC_reverseCountPattern() :
|
166
187
|
* pattern must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!)
|
167
188
|
* read using natural platform endianess */
|
168
|
-
static unsigned
|
189
|
+
static unsigned
|
190
|
+
LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern)
|
169
191
|
{
|
170
192
|
const BYTE* const iStart = ip;
|
171
193
|
|
@@ -182,8 +204,10 @@ static unsigned LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow
|
|
182
204
|
}
|
183
205
|
|
184
206
|
typedef enum { rep_untested, rep_not, rep_confirmed } repeat_state_e;
|
207
|
+
typedef enum { favorCompressionRatio=0, favorDecompressionSpeed } HCfavor_e;
|
185
208
|
|
186
|
-
LZ4_FORCE_INLINE int
|
209
|
+
LZ4_FORCE_INLINE int
|
210
|
+
LZ4HC_InsertAndGetWiderMatch (
|
187
211
|
LZ4HC_CCtx_internal* hc4,
|
188
212
|
const BYTE* const ip,
|
189
213
|
const BYTE* const iLowLimit,
|
@@ -192,17 +216,23 @@ LZ4_FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch (
|
|
192
216
|
const BYTE** matchpos,
|
193
217
|
const BYTE** startpos,
|
194
218
|
const int maxNbAttempts,
|
195
|
-
const int patternAnalysis
|
219
|
+
const int patternAnalysis,
|
220
|
+
const int chainSwap,
|
221
|
+
const dictCtx_directive dict,
|
222
|
+
const HCfavor_e favorDecSpeed)
|
196
223
|
{
|
197
224
|
U16* const chainTable = hc4->chainTable;
|
198
225
|
U32* const HashTable = hc4->hashTable;
|
226
|
+
const LZ4HC_CCtx_internal * const dictCtx = hc4->dictCtx;
|
199
227
|
const BYTE* const base = hc4->base;
|
200
228
|
const U32 dictLimit = hc4->dictLimit;
|
201
229
|
const BYTE* const lowPrefixPtr = base + dictLimit;
|
202
|
-
const U32
|
230
|
+
const U32 ipIndex = (U32)(ip - base);
|
231
|
+
const U32 lowestMatchIndex = (hc4->lowLimit + 64 KB > ipIndex) ? hc4->lowLimit : ipIndex - LZ4_DISTANCE_MAX;
|
203
232
|
const BYTE* const dictBase = hc4->dictBase;
|
204
|
-
int const
|
233
|
+
int const lookBackLength = (int)(ip-iLowLimit);
|
205
234
|
int nbAttempts = maxNbAttempts;
|
235
|
+
U32 matchChainPos = 0;
|
206
236
|
U32 const pattern = LZ4_read32(ip);
|
207
237
|
U32 matchIndex;
|
208
238
|
repeat_state_e repeat = rep_untested;
|
@@ -212,86 +242,142 @@ LZ4_FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch (
|
|
212
242
|
/* First Match */
|
213
243
|
LZ4HC_Insert(hc4, ip);
|
214
244
|
matchIndex = HashTable[LZ4HC_hashPtr(ip)];
|
215
|
-
DEBUGLOG(7, "First match at index %u / %u (
|
216
|
-
matchIndex,
|
245
|
+
DEBUGLOG(7, "First match at index %u / %u (lowestMatchIndex)",
|
246
|
+
matchIndex, lowestMatchIndex);
|
217
247
|
|
218
|
-
while ((matchIndex>=
|
219
|
-
|
248
|
+
while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) {
|
249
|
+
int matchLength=0;
|
220
250
|
nbAttempts--;
|
221
|
-
|
251
|
+
assert(matchIndex < ipIndex);
|
252
|
+
if (favorDecSpeed && (ipIndex - matchIndex < 8)) {
|
253
|
+
/* do nothing */
|
254
|
+
} else if (matchIndex >= dictLimit) { /* within current Prefix */
|
222
255
|
const BYTE* const matchPtr = base + matchIndex;
|
223
|
-
|
256
|
+
assert(matchPtr >= lowPrefixPtr);
|
257
|
+
assert(matchPtr < ip);
|
258
|
+
assert(longest >= 1);
|
259
|
+
if (LZ4_read16(iLowLimit + longest - 1) == LZ4_read16(matchPtr - lookBackLength + longest - 1)) {
|
224
260
|
if (LZ4_read32(matchPtr) == pattern) {
|
225
|
-
int
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
back--;
|
235
|
-
}
|
236
|
-
#endif
|
237
|
-
mlt -= back;
|
238
|
-
|
239
|
-
if (mlt > longest) {
|
240
|
-
longest = mlt;
|
241
|
-
*matchpos = matchPtr+back;
|
242
|
-
*startpos = ip+back;
|
243
|
-
} }
|
244
|
-
}
|
245
|
-
} else { /* matchIndex < dictLimit */
|
261
|
+
int const back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, lowPrefixPtr) : 0;
|
262
|
+
matchLength = MINMATCH + (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit);
|
263
|
+
matchLength -= back;
|
264
|
+
if (matchLength > longest) {
|
265
|
+
longest = matchLength;
|
266
|
+
*matchpos = matchPtr + back;
|
267
|
+
*startpos = ip + back;
|
268
|
+
} } }
|
269
|
+
} else { /* lowestMatchIndex <= matchIndex < dictLimit */
|
246
270
|
const BYTE* const matchPtr = dictBase + matchIndex;
|
247
271
|
if (LZ4_read32(matchPtr) == pattern) {
|
248
|
-
|
272
|
+
const BYTE* const dictStart = dictBase + hc4->lowLimit;
|
249
273
|
int back = 0;
|
250
274
|
const BYTE* vLimit = ip + (dictLimit - matchIndex);
|
251
275
|
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;
|
276
|
+
matchLength = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
|
277
|
+
if ((ip+matchLength == vLimit) && (vLimit < iHighLimit))
|
278
|
+
matchLength += LZ4_count(ip+matchLength, lowPrefixPtr, iHighLimit);
|
279
|
+
back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictStart) : 0;
|
280
|
+
matchLength -= back;
|
281
|
+
if (matchLength > longest) {
|
282
|
+
longest = matchLength;
|
283
|
+
*matchpos = base + matchIndex + back; /* virtual pos, relative to ip, to retrieve offset */
|
263
284
|
*startpos = ip + back;
|
264
285
|
} } }
|
265
286
|
|
266
|
-
{
|
267
|
-
|
268
|
-
if (
|
287
|
+
if (chainSwap && matchLength==longest) { /* better match => select a better chain */
|
288
|
+
assert(lookBackLength==0); /* search forward only */
|
289
|
+
if (matchIndex + (U32)longest <= ipIndex) {
|
290
|
+
U32 distanceToNextMatch = 1;
|
291
|
+
int pos;
|
292
|
+
for (pos = 0; pos <= longest - MINMATCH; pos++) {
|
293
|
+
U32 const candidateDist = DELTANEXTU16(chainTable, matchIndex + (U32)pos);
|
294
|
+
if (candidateDist > distanceToNextMatch) {
|
295
|
+
distanceToNextMatch = candidateDist;
|
296
|
+
matchChainPos = (U32)pos;
|
297
|
+
} }
|
298
|
+
if (distanceToNextMatch > 1) {
|
299
|
+
if (distanceToNextMatch > matchIndex) break; /* avoid overflow */
|
300
|
+
matchIndex -= distanceToNextMatch;
|
301
|
+
continue;
|
302
|
+
} } }
|
303
|
+
|
304
|
+
{ U32 const distNextMatch = DELTANEXTU16(chainTable, matchIndex);
|
305
|
+
if (patternAnalysis && distNextMatch==1 && matchChainPos==0) {
|
306
|
+
U32 const matchCandidateIdx = matchIndex-1;
|
269
307
|
/* may be a repeated pattern */
|
270
308
|
if (repeat == rep_untested) {
|
271
309
|
if ( ((pattern & 0xFFFF) == (pattern >> 16))
|
272
310
|
& ((pattern & 0xFF) == (pattern >> 24)) ) {
|
273
311
|
repeat = rep_confirmed;
|
274
|
-
srcPatternLength = LZ4HC_countPattern(ip+
|
312
|
+
srcPatternLength = LZ4HC_countPattern(ip+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern);
|
275
313
|
} else {
|
276
314
|
repeat = rep_not;
|
277
315
|
} }
|
278
316
|
if ( (repeat == rep_confirmed)
|
279
|
-
&& (
|
280
|
-
const BYTE* const matchPtr = base +
|
317
|
+
&& (matchCandidateIdx >= dictLimit) ) { /* same segment only */
|
318
|
+
const BYTE* const matchPtr = base + matchCandidateIdx;
|
281
319
|
if (LZ4_read32(matchPtr) == pattern) { /* good candidate */
|
282
320
|
size_t const forwardPatternLength = LZ4HC_countPattern(matchPtr+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern);
|
283
|
-
const BYTE* const
|
284
|
-
size_t const backLength = LZ4HC_reverseCountPattern(matchPtr,
|
321
|
+
const BYTE* const lowestMatchPtr = (lowPrefixPtr + LZ4_DISTANCE_MAX >= ip) ? lowPrefixPtr : ip - LZ4_DISTANCE_MAX;
|
322
|
+
size_t const backLength = LZ4HC_reverseCountPattern(matchPtr, lowestMatchPtr, pattern);
|
285
323
|
size_t const currentSegmentLength = backLength + forwardPatternLength;
|
286
324
|
|
287
325
|
if ( (currentSegmentLength >= srcPatternLength) /* current pattern segment large enough to contain full srcPatternLength */
|
288
326
|
&& (forwardPatternLength <= srcPatternLength) ) { /* haven't reached this position yet */
|
289
|
-
matchIndex
|
327
|
+
matchIndex = matchCandidateIdx + (U32)forwardPatternLength - (U32)srcPatternLength; /* best position, full pattern, might be followed by more match */
|
290
328
|
} else {
|
291
|
-
matchIndex
|
292
|
-
|
293
|
-
|
294
|
-
|
329
|
+
matchIndex = matchCandidateIdx - (U32)backLength; /* farthest position in current segment, will find a match of length currentSegmentLength + maybe some back */
|
330
|
+
if (lookBackLength==0) { /* no back possible */
|
331
|
+
size_t const maxML = MIN(currentSegmentLength, srcPatternLength);
|
332
|
+
if ((size_t)longest < maxML) {
|
333
|
+
assert(base + matchIndex < ip);
|
334
|
+
if (ip - (base+matchIndex) > LZ4_DISTANCE_MAX) break;
|
335
|
+
assert(maxML < 2 GB);
|
336
|
+
longest = (int)maxML;
|
337
|
+
*matchpos = base + matchIndex; /* virtual pos, relative to ip, to retrieve offset */
|
338
|
+
*startpos = ip;
|
339
|
+
}
|
340
|
+
{ U32 const distToNextPattern = DELTANEXTU16(chainTable, matchIndex);
|
341
|
+
if (distToNextPattern > matchIndex) break; /* avoid overflow */
|
342
|
+
matchIndex -= distToNextPattern;
|
343
|
+
} } }
|
344
|
+
continue;
|
345
|
+
} }
|
346
|
+
} } /* PA optimization */
|
347
|
+
|
348
|
+
/* follow current chain */
|
349
|
+
matchIndex -= DELTANEXTU16(chainTable, matchIndex + matchChainPos);
|
350
|
+
|
351
|
+
} /* while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) */
|
352
|
+
|
353
|
+
if ( dict == usingDictCtxHc
|
354
|
+
&& nbAttempts
|
355
|
+
&& ipIndex - lowestMatchIndex < LZ4_DISTANCE_MAX) {
|
356
|
+
size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->base);
|
357
|
+
U32 dictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)];
|
358
|
+
assert(dictEndOffset <= 1 GB);
|
359
|
+
matchIndex = dictMatchIndex + lowestMatchIndex - (U32)dictEndOffset;
|
360
|
+
while (ipIndex - matchIndex <= LZ4_DISTANCE_MAX && nbAttempts--) {
|
361
|
+
const BYTE* const matchPtr = dictCtx->base + dictMatchIndex;
|
362
|
+
|
363
|
+
if (LZ4_read32(matchPtr) == pattern) {
|
364
|
+
int mlt;
|
365
|
+
int back = 0;
|
366
|
+
const BYTE* vLimit = ip + (dictEndOffset - dictMatchIndex);
|
367
|
+
if (vLimit > iHighLimit) vLimit = iHighLimit;
|
368
|
+
mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
|
369
|
+
back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->base + dictCtx->dictLimit) : 0;
|
370
|
+
mlt -= back;
|
371
|
+
if (mlt > longest) {
|
372
|
+
longest = mlt;
|
373
|
+
*matchpos = base + matchIndex + back;
|
374
|
+
*startpos = ip + back;
|
375
|
+
} }
|
376
|
+
|
377
|
+
{ U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, dictMatchIndex);
|
378
|
+
dictMatchIndex -= nextOffset;
|
379
|
+
matchIndex -= nextOffset;
|
380
|
+
} } }
|
295
381
|
|
296
382
|
return longest;
|
297
383
|
}
|
@@ -301,23 +387,16 @@ int LZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4, /* Index tabl
|
|
301
387
|
const BYTE* const ip, const BYTE* const iLimit,
|
302
388
|
const BYTE** matchpos,
|
303
389
|
const int maxNbAttempts,
|
304
|
-
const int patternAnalysis
|
390
|
+
const int patternAnalysis,
|
391
|
+
const dictCtx_directive dict)
|
305
392
|
{
|
306
393
|
const BYTE* uselessPtr = ip;
|
307
394
|
/* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),
|
308
395
|
* but this won't be the case here, as we define iLowLimit==ip,
|
309
396
|
* 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);
|
397
|
+
return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, matchpos, &uselessPtr, maxNbAttempts, patternAnalysis, 0 /*chainSwap*/, dict, favorCompressionRatio);
|
311
398
|
}
|
312
399
|
|
313
|
-
|
314
|
-
|
315
|
-
typedef enum {
|
316
|
-
noLimit = 0,
|
317
|
-
limitedOutput = 1,
|
318
|
-
limitedDestSize = 2,
|
319
|
-
} limitedOutput_directive;
|
320
|
-
|
321
400
|
/* LZ4HC_encodeSequence() :
|
322
401
|
* @return : 0 if ok,
|
323
402
|
* 1 if buffer issue detected */
|
@@ -333,7 +412,7 @@ LZ4_FORCE_INLINE int LZ4HC_encodeSequence (
|
|
333
412
|
size_t length;
|
334
413
|
BYTE* const token = (*op)++;
|
335
414
|
|
336
|
-
#if defined(LZ4_DEBUG) && (LZ4_DEBUG >=
|
415
|
+
#if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 6)
|
337
416
|
static const BYTE* start = NULL;
|
338
417
|
static U32 totalCost = 0;
|
339
418
|
U32 const pos = (start==NULL) ? 0 : (U32)(*anchor - start);
|
@@ -342,8 +421,8 @@ LZ4_FORCE_INLINE int LZ4HC_encodeSequence (
|
|
342
421
|
U32 const mlAdd = (matchLength>=19) ? ((matchLength-19) / 255) + 1 : 0;
|
343
422
|
U32 const cost = 1 + llAdd + ll + 2 + mlAdd;
|
344
423
|
if (start==NULL) start = *anchor; /* only works for single segment */
|
345
|
-
|
346
|
-
DEBUGLOG(
|
424
|
+
/* g_debuglog_enable = (pos >= 2228) & (pos <= 2262); */
|
425
|
+
DEBUGLOG(6, "pos:%7u -- literals:%3u, match:%4i, offset:%5u, cost:%3u + %u",
|
347
426
|
pos,
|
348
427
|
(U32)(*ip - *anchor), matchLength, (U32)(*ip-match),
|
349
428
|
cost, totalCost);
|
@@ -352,7 +431,7 @@ LZ4_FORCE_INLINE int LZ4HC_encodeSequence (
|
|
352
431
|
|
353
432
|
/* Encode Literal length */
|
354
433
|
length = (size_t)(*ip - *anchor);
|
355
|
-
if ((limit) && ((*op + (length
|
434
|
+
if ((limit) && ((*op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) return 1; /* Check output limit */
|
356
435
|
if (length >= RUN_MASK) {
|
357
436
|
size_t len = length - RUN_MASK;
|
358
437
|
*token = (RUN_MASK << ML_BITS);
|
@@ -367,12 +446,13 @@ LZ4_FORCE_INLINE int LZ4HC_encodeSequence (
|
|
367
446
|
*op += length;
|
368
447
|
|
369
448
|
/* Encode Offset */
|
449
|
+
assert( (*ip - match) <= LZ4_DISTANCE_MAX ); /* note : consider providing offset as a value, rather than as a pointer difference */
|
370
450
|
LZ4_writeLE16(*op, (U16)(*ip-match)); *op += 2;
|
371
451
|
|
372
452
|
/* Encode MatchLength */
|
373
453
|
assert(matchLength >= MINMATCH);
|
374
|
-
length = (size_t)
|
375
|
-
if ((limit) && (*op + (length
|
454
|
+
length = (size_t)matchLength - MINMATCH;
|
455
|
+
if ((limit) && (*op + (length / 255) + (1 + LASTLITERALS) > oend)) return 1; /* Check output limit */
|
376
456
|
if (length >= ML_MASK) {
|
377
457
|
*token += ML_MASK;
|
378
458
|
length -= ML_MASK;
|
@@ -390,22 +470,19 @@ LZ4_FORCE_INLINE int LZ4HC_encodeSequence (
|
|
390
470
|
return 0;
|
391
471
|
}
|
392
472
|
|
393
|
-
|
394
|
-
#include "lz4opt.h"
|
395
|
-
|
396
|
-
|
397
|
-
static int LZ4HC_compress_hashChain (
|
473
|
+
LZ4_FORCE_INLINE int LZ4HC_compress_hashChain (
|
398
474
|
LZ4HC_CCtx_internal* const ctx,
|
399
475
|
const char* const source,
|
400
476
|
char* const dest,
|
401
477
|
int* srcSizePtr,
|
402
478
|
int const maxOutputSize,
|
403
479
|
unsigned maxNbAttempts,
|
404
|
-
limitedOutput_directive limit
|
480
|
+
const limitedOutput_directive limit,
|
481
|
+
const dictCtx_directive dict
|
405
482
|
)
|
406
483
|
{
|
407
484
|
const int inputSize = *srcSizePtr;
|
408
|
-
const int patternAnalysis = (maxNbAttempts >
|
485
|
+
const int patternAnalysis = (maxNbAttempts > 128); /* levels 9+ */
|
409
486
|
|
410
487
|
const BYTE* ip = (const BYTE*) source;
|
411
488
|
const BYTE* anchor = ip;
|
@@ -417,51 +494,47 @@ static int LZ4HC_compress_hashChain (
|
|
417
494
|
BYTE* op = (BYTE*) dest;
|
418
495
|
BYTE* oend = op + maxOutputSize;
|
419
496
|
|
420
|
-
int ml, ml2, ml3
|
497
|
+
int ml0, ml, ml2, ml3;
|
498
|
+
const BYTE* start0;
|
499
|
+
const BYTE* ref0;
|
421
500
|
const BYTE* ref = NULL;
|
422
501
|
const BYTE* start2 = NULL;
|
423
502
|
const BYTE* ref2 = NULL;
|
424
503
|
const BYTE* start3 = NULL;
|
425
504
|
const BYTE* ref3 = NULL;
|
426
|
-
const BYTE* start0;
|
427
|
-
const BYTE* ref0;
|
428
505
|
|
429
506
|
/* init */
|
430
507
|
*srcSizePtr = 0;
|
431
|
-
if (limit ==
|
508
|
+
if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */
|
432
509
|
if (inputSize < LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
|
433
510
|
|
434
511
|
/* Main Loop */
|
435
|
-
while (ip
|
436
|
-
ml = LZ4HC_InsertAndFindBestMatch
|
512
|
+
while (ip <= mflimit) {
|
513
|
+
ml = LZ4HC_InsertAndFindBestMatch(ctx, ip, matchlimit, &ref, maxNbAttempts, patternAnalysis, dict);
|
437
514
|
if (ml<MINMATCH) { ip++; continue; }
|
438
515
|
|
439
516
|
/* saved, in case we would skip too much */
|
440
|
-
start0 = ip;
|
441
|
-
ref0 = ref;
|
442
|
-
ml0 = ml;
|
517
|
+
start0 = ip; ref0 = ref; ml0 = ml;
|
443
518
|
|
444
519
|
_Search2:
|
445
|
-
if (ip+ml
|
520
|
+
if (ip+ml <= mflimit) {
|
446
521
|
ml2 = LZ4HC_InsertAndGetWiderMatch(ctx,
|
447
522
|
ip + ml - 2, ip + 0, matchlimit, ml, &ref2, &start2,
|
448
|
-
maxNbAttempts, patternAnalysis);
|
449
|
-
else
|
523
|
+
maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);
|
524
|
+
} else {
|
450
525
|
ml2 = ml;
|
526
|
+
}
|
451
527
|
|
452
|
-
if (ml2 == ml) { /* No better match */
|
528
|
+
if (ml2 == ml) { /* No better match => encode ML1 */
|
453
529
|
optr = op;
|
454
|
-
if (LZ4HC_encodeSequence(
|
530
|
+
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
|
455
531
|
continue;
|
456
532
|
}
|
457
533
|
|
458
|
-
if (start0 < ip) {
|
459
|
-
if (start2 < ip + ml0) { /*
|
460
|
-
ip = start0;
|
461
|
-
|
462
|
-
ml = ml0;
|
463
|
-
}
|
464
|
-
}
|
534
|
+
if (start0 < ip) { /* first match was skipped at least once */
|
535
|
+
if (start2 < ip + ml0) { /* squeezing ML1 between ML0(original ML1) and ML2 */
|
536
|
+
ip = start0; ref = ref0; ml = ml0; /* restore initial ML1 */
|
537
|
+
} }
|
465
538
|
|
466
539
|
/* Here, start0==ip */
|
467
540
|
if ((start2 - ip) < 3) { /* First Match too small : removed */
|
@@ -489,22 +562,23 @@ _Search3:
|
|
489
562
|
}
|
490
563
|
/* Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) */
|
491
564
|
|
492
|
-
if (start2 + ml2
|
565
|
+
if (start2 + ml2 <= mflimit) {
|
493
566
|
ml3 = LZ4HC_InsertAndGetWiderMatch(ctx,
|
494
567
|
start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3,
|
495
|
-
maxNbAttempts, patternAnalysis);
|
496
|
-
else
|
568
|
+
maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);
|
569
|
+
} else {
|
497
570
|
ml3 = ml2;
|
571
|
+
}
|
498
572
|
|
499
|
-
if (ml3 == ml2) { /* No better match
|
573
|
+
if (ml3 == ml2) { /* No better match => encode ML1 and ML2 */
|
500
574
|
/* ip & ref are known; Now for ml */
|
501
575
|
if (start2 < ip+ml) ml = (int)(start2 - ip);
|
502
576
|
/* Now, encode 2 sequences */
|
503
577
|
optr = op;
|
504
|
-
if (LZ4HC_encodeSequence(
|
578
|
+
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
|
505
579
|
ip = start2;
|
506
580
|
optr = op;
|
507
|
-
if (LZ4HC_encodeSequence(
|
581
|
+
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml2, ref2, limit, oend)) goto _dest_overflow;
|
508
582
|
continue;
|
509
583
|
}
|
510
584
|
|
@@ -523,7 +597,7 @@ _Search3:
|
|
523
597
|
}
|
524
598
|
|
525
599
|
optr = op;
|
526
|
-
if (LZ4HC_encodeSequence(
|
600
|
+
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
|
527
601
|
ip = start3;
|
528
602
|
ref = ref3;
|
529
603
|
ml = ml3;
|
@@ -541,11 +615,12 @@ _Search3:
|
|
541
615
|
}
|
542
616
|
|
543
617
|
/*
|
544
|
-
* OK, now we have 3 ascending matches;
|
545
|
-
*
|
618
|
+
* OK, now we have 3 ascending matches;
|
619
|
+
* let's write the first one ML1.
|
620
|
+
* ip & ref are known; Now decide ml.
|
546
621
|
*/
|
547
622
|
if (start2 < ip+ml) {
|
548
|
-
if ((start2 - ip) <
|
623
|
+
if ((start2 - ip) < OPTIMAL_ML) {
|
549
624
|
int correction;
|
550
625
|
if (ml > OPTIMAL_ML) ml = OPTIMAL_ML;
|
551
626
|
if (ip + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - ip) + ml2 - MINMATCH;
|
@@ -560,16 +635,15 @@ _Search3:
|
|
560
635
|
}
|
561
636
|
}
|
562
637
|
optr = op;
|
563
|
-
if (LZ4HC_encodeSequence(
|
638
|
+
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
|
564
639
|
|
565
|
-
|
566
|
-
ref = ref2;
|
567
|
-
ml = ml2;
|
640
|
+
/* ML2 becomes ML1 */
|
641
|
+
ip = start2; ref = ref2; ml = ml2;
|
568
642
|
|
569
|
-
|
570
|
-
ref2 = ref3;
|
571
|
-
ml2 = ml3;
|
643
|
+
/* ML3 becomes ML2 */
|
644
|
+
start2 = start3; ref2 = ref3; ml2 = ml3;
|
572
645
|
|
646
|
+
/* let's find a new ML3 */
|
573
647
|
goto _Search3;
|
574
648
|
}
|
575
649
|
|
@@ -578,7 +652,7 @@ _last_literals:
|
|
578
652
|
{ size_t lastRunSize = (size_t)(iend - anchor); /* literals */
|
579
653
|
size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255;
|
580
654
|
size_t const totalSize = 1 + litLength + lastRunSize;
|
581
|
-
if (limit ==
|
655
|
+
if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */
|
582
656
|
if (limit && (op + totalSize > oend)) {
|
583
657
|
if (limit == limitedOutput) return 0; /* Check output limit */
|
584
658
|
/* adapt lastRunSize to fill 'dest' */
|
@@ -605,7 +679,7 @@ _last_literals:
|
|
605
679
|
return (int) (((char*)op)-dest);
|
606
680
|
|
607
681
|
_dest_overflow:
|
608
|
-
if (limit ==
|
682
|
+
if (limit == fillOutput) {
|
609
683
|
op = optr; /* restore correct out pointer */
|
610
684
|
goto _last_literals;
|
611
685
|
}
|
@@ -613,14 +687,24 @@ _dest_overflow:
|
|
613
687
|
}
|
614
688
|
|
615
689
|
|
616
|
-
static int
|
690
|
+
static int LZ4HC_compress_optimal( LZ4HC_CCtx_internal* ctx,
|
691
|
+
const char* const source, char* dst,
|
692
|
+
int* srcSizePtr, int dstCapacity,
|
693
|
+
int const nbSearches, size_t sufficient_len,
|
694
|
+
const limitedOutput_directive limit, int const fullUpdate,
|
695
|
+
const dictCtx_directive dict,
|
696
|
+
HCfavor_e favorDecSpeed);
|
697
|
+
|
698
|
+
|
699
|
+
LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal (
|
617
700
|
LZ4HC_CCtx_internal* const ctx,
|
618
701
|
const char* const src,
|
619
702
|
char* const dst,
|
620
703
|
int* const srcSizePtr,
|
621
704
|
int const dstCapacity,
|
622
705
|
int cLevel,
|
623
|
-
limitedOutput_directive limit
|
706
|
+
const limitedOutput_directive limit,
|
707
|
+
const dictCtx_directive dict
|
624
708
|
)
|
625
709
|
{
|
626
710
|
typedef enum { lz4hc, lz4opt } lz4hc_strat_e;
|
@@ -630,78 +714,173 @@ static int LZ4HC_compress_generic (
|
|
630
714
|
U32 targetLength;
|
631
715
|
} cParams_t;
|
632
716
|
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,
|
717
|
+
{ lz4hc, 2, 16 }, /* 0, unused */
|
718
|
+
{ lz4hc, 2, 16 }, /* 1, unused */
|
719
|
+
{ lz4hc, 2, 16 }, /* 2, unused */
|
720
|
+
{ lz4hc, 4, 16 }, /* 3 */
|
721
|
+
{ lz4hc, 8, 16 }, /* 4 */
|
722
|
+
{ lz4hc, 16, 16 }, /* 5 */
|
723
|
+
{ lz4hc, 32, 16 }, /* 6 */
|
724
|
+
{ lz4hc, 64, 16 }, /* 7 */
|
725
|
+
{ lz4hc, 128, 16 }, /* 8 */
|
726
|
+
{ lz4hc, 256, 16 }, /* 9 */
|
727
|
+
{ lz4opt, 96, 64 }, /*10==LZ4HC_CLEVEL_OPT_MIN*/
|
728
|
+
{ lz4opt, 512,128 }, /*11 */
|
729
|
+
{ lz4opt,16384,LZ4_OPT_NUM }, /* 12==LZ4HC_CLEVEL_MAX */
|
646
730
|
};
|
647
731
|
|
648
|
-
|
649
|
-
|
732
|
+
DEBUGLOG(4, "LZ4HC_compress_generic(ctx=%p, src=%p, srcSize=%d)", ctx, src, *srcSizePtr);
|
733
|
+
|
734
|
+
if (limit == fillOutput && dstCapacity < 1) return 0; /* Impossible to store anything */
|
735
|
+
if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size (too large or negative) */
|
650
736
|
|
651
737
|
ctx->end += *srcSizePtr;
|
652
738
|
if (cLevel < 1) cLevel = LZ4HC_CLEVEL_DEFAULT; /* note : convention is different from lz4frame, maybe something to review */
|
653
739
|
cLevel = MIN(LZ4HC_CLEVEL_MAX, cLevel);
|
654
|
-
assert(cLevel >= 0);
|
655
|
-
assert(cLevel <= LZ4HC_CLEVEL_MAX);
|
656
740
|
{ cParams_t const cParam = clTable[cLevel];
|
657
|
-
|
658
|
-
|
741
|
+
HCfavor_e const favor = ctx->favorDecSpeed ? favorDecompressionSpeed : favorCompressionRatio;
|
742
|
+
int result;
|
743
|
+
|
744
|
+
if (cParam.strat == lz4hc) {
|
745
|
+
result = LZ4HC_compress_hashChain(ctx,
|
746
|
+
src, dst, srcSizePtr, dstCapacity,
|
747
|
+
cParam.nbSearches, limit, dict);
|
748
|
+
} else {
|
749
|
+
assert(cParam.strat == lz4opt);
|
750
|
+
result = LZ4HC_compress_optimal(ctx,
|
659
751
|
src, dst, srcSizePtr, dstCapacity,
|
660
|
-
cParam.nbSearches, limit
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
752
|
+
(int)cParam.nbSearches, cParam.targetLength, limit,
|
753
|
+
cLevel == LZ4HC_CLEVEL_MAX, /* ultra mode */
|
754
|
+
dict, favor);
|
755
|
+
}
|
756
|
+
if (result <= 0) ctx->dirty = 1;
|
757
|
+
return result;
|
666
758
|
}
|
667
759
|
}
|
668
760
|
|
761
|
+
static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock);
|
762
|
+
|
763
|
+
static int
|
764
|
+
LZ4HC_compress_generic_noDictCtx (
|
765
|
+
LZ4HC_CCtx_internal* const ctx,
|
766
|
+
const char* const src,
|
767
|
+
char* const dst,
|
768
|
+
int* const srcSizePtr,
|
769
|
+
int const dstCapacity,
|
770
|
+
int cLevel,
|
771
|
+
limitedOutput_directive limit
|
772
|
+
)
|
773
|
+
{
|
774
|
+
assert(ctx->dictCtx == NULL);
|
775
|
+
return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, noDictCtx);
|
776
|
+
}
|
669
777
|
|
670
|
-
int
|
778
|
+
static int
|
779
|
+
LZ4HC_compress_generic_dictCtx (
|
780
|
+
LZ4HC_CCtx_internal* const ctx,
|
781
|
+
const char* const src,
|
782
|
+
char* const dst,
|
783
|
+
int* const srcSizePtr,
|
784
|
+
int const dstCapacity,
|
785
|
+
int cLevel,
|
786
|
+
limitedOutput_directive limit
|
787
|
+
)
|
788
|
+
{
|
789
|
+
const size_t position = (size_t)(ctx->end - ctx->base) - ctx->lowLimit;
|
790
|
+
assert(ctx->dictCtx != NULL);
|
791
|
+
if (position >= 64 KB) {
|
792
|
+
ctx->dictCtx = NULL;
|
793
|
+
return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
|
794
|
+
} else if (position == 0 && *srcSizePtr > 4 KB) {
|
795
|
+
memcpy(ctx, ctx->dictCtx, sizeof(LZ4HC_CCtx_internal));
|
796
|
+
LZ4HC_setExternalDict(ctx, (const BYTE *)src);
|
797
|
+
ctx->compressionLevel = (short)cLevel;
|
798
|
+
return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
|
799
|
+
} else {
|
800
|
+
return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, usingDictCtxHc);
|
801
|
+
}
|
802
|
+
}
|
671
803
|
|
672
|
-
|
804
|
+
static int
|
805
|
+
LZ4HC_compress_generic (
|
806
|
+
LZ4HC_CCtx_internal* const ctx,
|
807
|
+
const char* const src,
|
808
|
+
char* const dst,
|
809
|
+
int* const srcSizePtr,
|
810
|
+
int const dstCapacity,
|
811
|
+
int cLevel,
|
812
|
+
limitedOutput_directive limit
|
813
|
+
)
|
814
|
+
{
|
815
|
+
if (ctx->dictCtx == NULL) {
|
816
|
+
return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
|
817
|
+
} else {
|
818
|
+
return LZ4HC_compress_generic_dictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
|
819
|
+
}
|
820
|
+
}
|
821
|
+
|
822
|
+
|
823
|
+
int LZ4_sizeofStateHC(void) { return (int)sizeof(LZ4_streamHC_t); }
|
824
|
+
|
825
|
+
#ifndef _MSC_VER /* for some reason, Visual fails the aligment test on 32-bit x86 :
|
826
|
+
* it reports an aligment of 8-bytes,
|
827
|
+
* while actually aligning LZ4_streamHC_t on 4 bytes. */
|
828
|
+
static size_t LZ4_streamHC_t_alignment(void)
|
829
|
+
{
|
830
|
+
struct { char c; LZ4_streamHC_t t; } t_a;
|
831
|
+
return sizeof(t_a) - sizeof(t_a.t);
|
832
|
+
}
|
833
|
+
#endif
|
834
|
+
|
835
|
+
/* state is presumed correctly initialized,
|
836
|
+
* in which case its size and alignment have already been validate */
|
837
|
+
int LZ4_compress_HC_extStateHC_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
|
673
838
|
{
|
674
839
|
LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse;
|
840
|
+
#ifndef _MSC_VER /* for some reason, Visual fails the aligment test on 32-bit x86 :
|
841
|
+
* it reports an aligment of 8-bytes,
|
842
|
+
* while actually aligning LZ4_streamHC_t on 4 bytes. */
|
843
|
+
assert(((size_t)state & (LZ4_streamHC_t_alignment() - 1)) == 0); /* check alignment */
|
844
|
+
#endif
|
675
845
|
if (((size_t)(state)&(sizeof(void*)-1)) != 0) return 0; /* Error : state is not aligned for pointers (32 or 64 bits) */
|
676
|
-
|
846
|
+
LZ4_resetStreamHC_fast((LZ4_streamHC_t*)state, compressionLevel);
|
847
|
+
LZ4HC_init_internal (ctx, (const BYTE*)src);
|
677
848
|
if (dstCapacity < LZ4_compressBound(srcSize))
|
678
849
|
return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, limitedOutput);
|
679
850
|
else
|
680
|
-
return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel,
|
851
|
+
return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, notLimited);
|
852
|
+
}
|
853
|
+
|
854
|
+
int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
|
855
|
+
{
|
856
|
+
LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));
|
857
|
+
if (ctx==NULL) return 0; /* init failure */
|
858
|
+
return LZ4_compress_HC_extStateHC_fastReset(state, src, dst, srcSize, dstCapacity, compressionLevel);
|
681
859
|
}
|
682
860
|
|
683
861
|
int LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
|
684
862
|
{
|
685
863
|
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
|
686
|
-
LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)
|
864
|
+
LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));
|
687
865
|
#else
|
688
866
|
LZ4_streamHC_t state;
|
689
867
|
LZ4_streamHC_t* const statePtr = &state;
|
690
868
|
#endif
|
691
869
|
int const cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel);
|
692
870
|
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
|
693
|
-
|
871
|
+
FREEMEM(statePtr);
|
694
872
|
#endif
|
695
873
|
return cSize;
|
696
874
|
}
|
697
875
|
|
698
|
-
/*
|
699
|
-
*
|
700
|
-
int LZ4_compress_HC_destSize(void* LZ4HC_Data, const char* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel)
|
876
|
+
/* state is presumed sized correctly (>= sizeof(LZ4_streamHC_t)) */
|
877
|
+
int LZ4_compress_HC_destSize(void* state, const char* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel)
|
701
878
|
{
|
702
|
-
|
703
|
-
|
704
|
-
|
879
|
+
LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));
|
880
|
+
if (ctx==NULL) return 0; /* init failure */
|
881
|
+
LZ4HC_init_internal(&ctx->internal_donotuse, (const BYTE*) source);
|
882
|
+
LZ4_setCompressionLevel(ctx, cLevel);
|
883
|
+
return LZ4HC_compress_generic(&ctx->internal_donotuse, source, dest, sourceSizePtr, targetDestSize, cLevel, fillOutput);
|
705
884
|
}
|
706
885
|
|
707
886
|
|
@@ -710,48 +889,114 @@ int LZ4_compress_HC_destSize(void* LZ4HC_Data, const char* source, char* dest, i
|
|
710
889
|
* Streaming Functions
|
711
890
|
**************************************/
|
712
891
|
/* allocation */
|
713
|
-
LZ4_streamHC_t* LZ4_createStreamHC(void)
|
714
|
-
|
892
|
+
LZ4_streamHC_t* LZ4_createStreamHC(void)
|
893
|
+
{
|
894
|
+
LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));
|
895
|
+
if (LZ4_streamHCPtr==NULL) return NULL;
|
896
|
+
LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr)); /* full initialization, malloc'ed buffer can be full of garbage */
|
897
|
+
return LZ4_streamHCPtr;
|
898
|
+
}
|
899
|
+
|
900
|
+
int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr)
|
901
|
+
{
|
902
|
+
DEBUGLOG(4, "LZ4_freeStreamHC(%p)", LZ4_streamHCPtr);
|
715
903
|
if (!LZ4_streamHCPtr) return 0; /* support free on NULL */
|
716
|
-
|
904
|
+
FREEMEM(LZ4_streamHCPtr);
|
717
905
|
return 0;
|
718
906
|
}
|
719
907
|
|
720
908
|
|
721
|
-
|
722
|
-
void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
|
909
|
+
LZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size)
|
723
910
|
{
|
724
|
-
|
911
|
+
LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)buffer;
|
912
|
+
if (buffer == NULL) return NULL;
|
913
|
+
if (size < sizeof(LZ4_streamHC_t)) return NULL;
|
914
|
+
#ifndef _MSC_VER /* for some reason, Visual fails the aligment test on 32-bit x86 :
|
915
|
+
* it reports an aligment of 8-bytes,
|
916
|
+
* while actually aligning LZ4_streamHC_t on 4 bytes. */
|
917
|
+
if (((size_t)buffer) & (LZ4_streamHC_t_alignment() - 1)) return NULL; /* alignment check */
|
918
|
+
#endif
|
919
|
+
/* if compilation fails here, LZ4_STREAMHCSIZE must be increased */
|
920
|
+
LZ4_STATIC_ASSERT(sizeof(LZ4HC_CCtx_internal) <= LZ4_STREAMHCSIZE);
|
921
|
+
DEBUGLOG(4, "LZ4_initStreamHC(%p, %u)", LZ4_streamHCPtr, (unsigned)size);
|
922
|
+
/* end-base will trigger a clearTable on starting compression */
|
923
|
+
LZ4_streamHCPtr->internal_donotuse.end = (const BYTE *)(ptrdiff_t)-1;
|
725
924
|
LZ4_streamHCPtr->internal_donotuse.base = NULL;
|
925
|
+
LZ4_streamHCPtr->internal_donotuse.dictCtx = NULL;
|
926
|
+
LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = 0;
|
927
|
+
LZ4_streamHCPtr->internal_donotuse.dirty = 0;
|
928
|
+
LZ4_setCompressionLevel(LZ4_streamHCPtr, LZ4HC_CLEVEL_DEFAULT);
|
929
|
+
return LZ4_streamHCPtr;
|
930
|
+
}
|
931
|
+
|
932
|
+
/* just a stub */
|
933
|
+
void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
|
934
|
+
{
|
935
|
+
LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
|
936
|
+
LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);
|
937
|
+
}
|
938
|
+
|
939
|
+
void LZ4_resetStreamHC_fast (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
|
940
|
+
{
|
941
|
+
DEBUGLOG(4, "LZ4_resetStreamHC_fast(%p, %d)", LZ4_streamHCPtr, compressionLevel);
|
942
|
+
if (LZ4_streamHCPtr->internal_donotuse.dirty) {
|
943
|
+
LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
|
944
|
+
} else {
|
945
|
+
/* preserve end - base : can trigger clearTable's threshold */
|
946
|
+
LZ4_streamHCPtr->internal_donotuse.end -= (uptrval)LZ4_streamHCPtr->internal_donotuse.base;
|
947
|
+
LZ4_streamHCPtr->internal_donotuse.base = NULL;
|
948
|
+
LZ4_streamHCPtr->internal_donotuse.dictCtx = NULL;
|
949
|
+
}
|
726
950
|
LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);
|
727
951
|
}
|
728
952
|
|
729
953
|
void LZ4_setCompressionLevel(LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
|
730
954
|
{
|
731
|
-
|
955
|
+
DEBUGLOG(5, "LZ4_setCompressionLevel(%p, %d)", LZ4_streamHCPtr, compressionLevel);
|
956
|
+
if (compressionLevel < 1) compressionLevel = LZ4HC_CLEVEL_DEFAULT;
|
732
957
|
if (compressionLevel > LZ4HC_CLEVEL_MAX) compressionLevel = LZ4HC_CLEVEL_MAX;
|
733
|
-
LZ4_streamHCPtr->internal_donotuse.compressionLevel = compressionLevel;
|
958
|
+
LZ4_streamHCPtr->internal_donotuse.compressionLevel = (short)compressionLevel;
|
959
|
+
}
|
960
|
+
|
961
|
+
void LZ4_favorDecompressionSpeed(LZ4_streamHC_t* LZ4_streamHCPtr, int favor)
|
962
|
+
{
|
963
|
+
LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = (favor!=0);
|
734
964
|
}
|
735
965
|
|
736
|
-
|
966
|
+
/* LZ4_loadDictHC() :
|
967
|
+
* LZ4_streamHCPtr is presumed properly initialized */
|
968
|
+
int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr,
|
969
|
+
const char* dictionary, int dictSize)
|
737
970
|
{
|
738
971
|
LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
|
972
|
+
DEBUGLOG(4, "LZ4_loadDictHC(%p, %p, %d)", LZ4_streamHCPtr, dictionary, dictSize);
|
973
|
+
assert(LZ4_streamHCPtr != NULL);
|
739
974
|
if (dictSize > 64 KB) {
|
740
|
-
dictionary += dictSize - 64 KB;
|
975
|
+
dictionary += (size_t)dictSize - 64 KB;
|
741
976
|
dictSize = 64 KB;
|
742
977
|
}
|
743
|
-
|
978
|
+
/* need a full initialization, there are bad side-effects when using resetFast() */
|
979
|
+
{ int const cLevel = ctxPtr->compressionLevel;
|
980
|
+
LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
|
981
|
+
LZ4_setCompressionLevel(LZ4_streamHCPtr, cLevel);
|
982
|
+
}
|
983
|
+
LZ4HC_init_internal (ctxPtr, (const BYTE*)dictionary);
|
744
984
|
ctxPtr->end = (const BYTE*)dictionary + dictSize;
|
745
985
|
if (dictSize >= 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3);
|
746
986
|
return dictSize;
|
747
987
|
}
|
748
988
|
|
989
|
+
void LZ4_attach_HC_dictionary(LZ4_streamHC_t *working_stream, const LZ4_streamHC_t *dictionary_stream) {
|
990
|
+
working_stream->internal_donotuse.dictCtx = dictionary_stream != NULL ? &(dictionary_stream->internal_donotuse) : NULL;
|
991
|
+
}
|
749
992
|
|
750
993
|
/* compression */
|
751
994
|
|
752
995
|
static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock)
|
753
996
|
{
|
754
|
-
|
997
|
+
DEBUGLOG(4, "LZ4HC_setExternalDict(%p, %p)", ctxPtr, newBlock);
|
998
|
+
if (ctxPtr->end >= ctxPtr->base + ctxPtr->dictLimit + 4)
|
999
|
+
LZ4HC_Insert (ctxPtr, ctxPtr->end-3); /* Referencing remaining dictionary content */
|
755
1000
|
|
756
1001
|
/* Only one memory segment for extDict, so any previous extDict is lost at this stage */
|
757
1002
|
ctxPtr->lowLimit = ctxPtr->dictLimit;
|
@@ -768,8 +1013,11 @@ static int LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,
|
|
768
1013
|
limitedOutput_directive limit)
|
769
1014
|
{
|
770
1015
|
LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
|
1016
|
+
DEBUGLOG(4, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d)",
|
1017
|
+
LZ4_streamHCPtr, src, *srcSizePtr);
|
1018
|
+
assert(ctxPtr != NULL);
|
771
1019
|
/* auto-init if forgotten */
|
772
|
-
if (ctxPtr->base == NULL)
|
1020
|
+
if (ctxPtr->base == NULL) LZ4HC_init_internal (ctxPtr, (const BYTE*) src);
|
773
1021
|
|
774
1022
|
/* Check overflow */
|
775
1023
|
if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 GB) {
|
@@ -779,7 +1027,8 @@ static int LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,
|
|
779
1027
|
}
|
780
1028
|
|
781
1029
|
/* Check if blocks follow each other */
|
782
|
-
if ((const BYTE*)src != ctxPtr->end)
|
1030
|
+
if ((const BYTE*)src != ctxPtr->end)
|
1031
|
+
LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src);
|
783
1032
|
|
784
1033
|
/* Check overlapping input/dictionary space */
|
785
1034
|
{ const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr;
|
@@ -800,12 +1049,12 @@ int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src,
|
|
800
1049
|
if (dstCapacity < LZ4_compressBound(srcSize))
|
801
1050
|
return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput);
|
802
1051
|
else
|
803
|
-
return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity,
|
1052
|
+
return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, notLimited);
|
804
1053
|
}
|
805
1054
|
|
806
1055
|
int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int targetDestSize)
|
807
1056
|
{
|
808
|
-
return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize,
|
1057
|
+
return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, fillOutput);
|
809
1058
|
}
|
810
1059
|
|
811
1060
|
|
@@ -816,6 +1065,7 @@ int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictS
|
|
816
1065
|
{
|
817
1066
|
LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse;
|
818
1067
|
int const prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit));
|
1068
|
+
DEBUGLOG(4, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize);
|
819
1069
|
if (dictSize > 64 KB) dictSize = 64 KB;
|
820
1070
|
if (dictSize < 4) dictSize = 0;
|
821
1071
|
if (dictSize > prefixSize) dictSize = prefixSize;
|
@@ -823,19 +1073,21 @@ int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictS
|
|
823
1073
|
{ U32 const endIndex = (U32)(streamPtr->end - streamPtr->base);
|
824
1074
|
streamPtr->end = (const BYTE*)safeBuffer + dictSize;
|
825
1075
|
streamPtr->base = streamPtr->end - endIndex;
|
826
|
-
streamPtr->dictLimit = endIndex - dictSize;
|
827
|
-
streamPtr->lowLimit = endIndex - dictSize;
|
1076
|
+
streamPtr->dictLimit = endIndex - (U32)dictSize;
|
1077
|
+
streamPtr->lowLimit = endIndex - (U32)dictSize;
|
828
1078
|
if (streamPtr->nextToUpdate < streamPtr->dictLimit) streamPtr->nextToUpdate = streamPtr->dictLimit;
|
829
1079
|
}
|
830
1080
|
return dictSize;
|
831
1081
|
}
|
832
1082
|
|
833
1083
|
|
834
|
-
|
1084
|
+
/***************************************************
|
835
1085
|
* Deprecated Functions
|
836
|
-
|
1086
|
+
***************************************************/
|
1087
|
+
|
837
1088
|
/* These functions currently generate deprecation warnings */
|
838
|
-
|
1089
|
+
|
1090
|
+
/* Wrappers for deprecated compression functions */
|
839
1091
|
int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
|
840
1092
|
int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); }
|
841
1093
|
int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
|
@@ -851,25 +1103,26 @@ int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* ctx, const char* src,
|
|
851
1103
|
/* Deprecated streaming functions */
|
852
1104
|
int LZ4_sizeofStreamStateHC(void) { return LZ4_STREAMHCSIZE; }
|
853
1105
|
|
1106
|
+
/* state is presumed correctly sized, aka >= sizeof(LZ4_streamHC_t)
|
1107
|
+
* @return : 0 on success, !=0 if error */
|
854
1108
|
int LZ4_resetStreamStateHC(void* state, char* inputBuffer)
|
855
1109
|
{
|
856
|
-
|
857
|
-
if (
|
858
|
-
|
859
|
-
ctx->inputBuffer = (BYTE*)inputBuffer;
|
1110
|
+
LZ4_streamHC_t* const hc4 = LZ4_initStreamHC(state, sizeof(*hc4));
|
1111
|
+
if (hc4 == NULL) return 1; /* init failed */
|
1112
|
+
LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
|
860
1113
|
return 0;
|
861
1114
|
}
|
862
1115
|
|
863
|
-
void* LZ4_createHC (char* inputBuffer)
|
1116
|
+
void* LZ4_createHC (const char* inputBuffer)
|
864
1117
|
{
|
865
|
-
LZ4_streamHC_t* hc4 = (
|
1118
|
+
LZ4_streamHC_t* const hc4 = LZ4_createStreamHC();
|
866
1119
|
if (hc4 == NULL) return NULL; /* not enough memory */
|
867
|
-
|
868
|
-
hc4->internal_donotuse.inputBuffer = (BYTE*)inputBuffer;
|
1120
|
+
LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
|
869
1121
|
return hc4;
|
870
1122
|
}
|
871
1123
|
|
872
|
-
int LZ4_freeHC (void* LZ4HC_Data)
|
1124
|
+
int LZ4_freeHC (void* LZ4HC_Data)
|
1125
|
+
{
|
873
1126
|
if (!LZ4HC_Data) return 0; /* support free on NULL */
|
874
1127
|
FREEMEM(LZ4HC_Data);
|
875
1128
|
return 0;
|
@@ -877,7 +1130,7 @@ int LZ4_freeHC (void* LZ4HC_Data) {
|
|
877
1130
|
|
878
1131
|
int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)
|
879
1132
|
{
|
880
|
-
return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel,
|
1133
|
+
return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited);
|
881
1134
|
}
|
882
1135
|
|
883
1136
|
int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel)
|
@@ -887,7 +1140,336 @@ int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, c
|
|
887
1140
|
|
888
1141
|
char* LZ4_slideInputBufferHC(void* LZ4HC_Data)
|
889
1142
|
{
|
890
|
-
|
891
|
-
|
892
|
-
|
1143
|
+
LZ4_streamHC_t *ctx = (LZ4_streamHC_t*)LZ4HC_Data;
|
1144
|
+
const BYTE *bufferStart = ctx->internal_donotuse.base + ctx->internal_donotuse.lowLimit;
|
1145
|
+
LZ4_resetStreamHC_fast(ctx, ctx->internal_donotuse.compressionLevel);
|
1146
|
+
/* avoid const char * -> char * conversion warning :( */
|
1147
|
+
return (char *)(uptrval)bufferStart;
|
1148
|
+
}
|
1149
|
+
|
1150
|
+
|
1151
|
+
/* ================================================
|
1152
|
+
* LZ4 Optimal parser (levels [LZ4HC_CLEVEL_OPT_MIN - LZ4HC_CLEVEL_MAX])
|
1153
|
+
* ===============================================*/
|
1154
|
+
typedef struct {
|
1155
|
+
int price;
|
1156
|
+
int off;
|
1157
|
+
int mlen;
|
1158
|
+
int litlen;
|
1159
|
+
} LZ4HC_optimal_t;
|
1160
|
+
|
1161
|
+
/* price in bytes */
|
1162
|
+
LZ4_FORCE_INLINE int LZ4HC_literalsPrice(int const litlen)
|
1163
|
+
{
|
1164
|
+
int price = litlen;
|
1165
|
+
assert(litlen >= 0);
|
1166
|
+
if (litlen >= (int)RUN_MASK)
|
1167
|
+
price += 1 + ((litlen-(int)RUN_MASK) / 255);
|
1168
|
+
return price;
|
1169
|
+
}
|
1170
|
+
|
1171
|
+
|
1172
|
+
/* requires mlen >= MINMATCH */
|
1173
|
+
LZ4_FORCE_INLINE int LZ4HC_sequencePrice(int litlen, int mlen)
|
1174
|
+
{
|
1175
|
+
int price = 1 + 2 ; /* token + 16-bit offset */
|
1176
|
+
assert(litlen >= 0);
|
1177
|
+
assert(mlen >= MINMATCH);
|
1178
|
+
|
1179
|
+
price += LZ4HC_literalsPrice(litlen);
|
1180
|
+
|
1181
|
+
if (mlen >= (int)(ML_MASK+MINMATCH))
|
1182
|
+
price += 1 + ((mlen-(int)(ML_MASK+MINMATCH)) / 255);
|
1183
|
+
|
1184
|
+
return price;
|
1185
|
+
}
|
1186
|
+
|
1187
|
+
|
1188
|
+
typedef struct {
|
1189
|
+
int off;
|
1190
|
+
int len;
|
1191
|
+
} LZ4HC_match_t;
|
1192
|
+
|
1193
|
+
LZ4_FORCE_INLINE LZ4HC_match_t
|
1194
|
+
LZ4HC_FindLongerMatch(LZ4HC_CCtx_internal* const ctx,
|
1195
|
+
const BYTE* ip, const BYTE* const iHighLimit,
|
1196
|
+
int minLen, int nbSearches,
|
1197
|
+
const dictCtx_directive dict,
|
1198
|
+
const HCfavor_e favorDecSpeed)
|
1199
|
+
{
|
1200
|
+
LZ4HC_match_t match = { 0 , 0 };
|
1201
|
+
const BYTE* matchPtr = NULL;
|
1202
|
+
/* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),
|
1203
|
+
* but this won't be the case here, as we define iLowLimit==ip,
|
1204
|
+
* so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */
|
1205
|
+
int matchLength = LZ4HC_InsertAndGetWiderMatch(ctx, ip, ip, iHighLimit, minLen, &matchPtr, &ip, nbSearches, 1 /*patternAnalysis*/, 1 /*chainSwap*/, dict, favorDecSpeed);
|
1206
|
+
if (matchLength <= minLen) return match;
|
1207
|
+
if (favorDecSpeed) {
|
1208
|
+
if ((matchLength>18) & (matchLength<=36)) matchLength=18; /* favor shortcut */
|
1209
|
+
}
|
1210
|
+
match.len = matchLength;
|
1211
|
+
match.off = (int)(ip-matchPtr);
|
1212
|
+
return match;
|
893
1213
|
}
|
1214
|
+
|
1215
|
+
|
1216
|
+
static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,
|
1217
|
+
const char* const source,
|
1218
|
+
char* dst,
|
1219
|
+
int* srcSizePtr,
|
1220
|
+
int dstCapacity,
|
1221
|
+
int const nbSearches,
|
1222
|
+
size_t sufficient_len,
|
1223
|
+
const limitedOutput_directive limit,
|
1224
|
+
int const fullUpdate,
|
1225
|
+
const dictCtx_directive dict,
|
1226
|
+
const HCfavor_e favorDecSpeed)
|
1227
|
+
{
|
1228
|
+
#define TRAILING_LITERALS 3
|
1229
|
+
LZ4HC_optimal_t opt[LZ4_OPT_NUM + TRAILING_LITERALS]; /* ~64 KB, which is a bit large for stack... */
|
1230
|
+
|
1231
|
+
const BYTE* ip = (const BYTE*) source;
|
1232
|
+
const BYTE* anchor = ip;
|
1233
|
+
const BYTE* const iend = ip + *srcSizePtr;
|
1234
|
+
const BYTE* const mflimit = iend - MFLIMIT;
|
1235
|
+
const BYTE* const matchlimit = iend - LASTLITERALS;
|
1236
|
+
BYTE* op = (BYTE*) dst;
|
1237
|
+
BYTE* opSaved = (BYTE*) dst;
|
1238
|
+
BYTE* oend = op + dstCapacity;
|
1239
|
+
|
1240
|
+
/* init */
|
1241
|
+
DEBUGLOG(5, "LZ4HC_compress_optimal(dst=%p, dstCapa=%u)", dst, (unsigned)dstCapacity);
|
1242
|
+
*srcSizePtr = 0;
|
1243
|
+
if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */
|
1244
|
+
if (sufficient_len >= LZ4_OPT_NUM) sufficient_len = LZ4_OPT_NUM-1;
|
1245
|
+
|
1246
|
+
/* Main Loop */
|
1247
|
+
assert(ip - anchor < LZ4_MAX_INPUT_SIZE);
|
1248
|
+
while (ip <= mflimit) {
|
1249
|
+
int const llen = (int)(ip - anchor);
|
1250
|
+
int best_mlen, best_off;
|
1251
|
+
int cur, last_match_pos = 0;
|
1252
|
+
|
1253
|
+
LZ4HC_match_t const firstMatch = LZ4HC_FindLongerMatch(ctx, ip, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);
|
1254
|
+
if (firstMatch.len==0) { ip++; continue; }
|
1255
|
+
|
1256
|
+
if ((size_t)firstMatch.len > sufficient_len) {
|
1257
|
+
/* good enough solution : immediate encoding */
|
1258
|
+
int const firstML = firstMatch.len;
|
1259
|
+
const BYTE* const matchPos = ip - firstMatch.off;
|
1260
|
+
opSaved = op;
|
1261
|
+
if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, matchPos, limit, oend) ) /* updates ip, op and anchor */
|
1262
|
+
goto _dest_overflow;
|
1263
|
+
continue;
|
1264
|
+
}
|
1265
|
+
|
1266
|
+
/* set prices for first positions (literals) */
|
1267
|
+
{ int rPos;
|
1268
|
+
for (rPos = 0 ; rPos < MINMATCH ; rPos++) {
|
1269
|
+
int const cost = LZ4HC_literalsPrice(llen + rPos);
|
1270
|
+
opt[rPos].mlen = 1;
|
1271
|
+
opt[rPos].off = 0;
|
1272
|
+
opt[rPos].litlen = llen + rPos;
|
1273
|
+
opt[rPos].price = cost;
|
1274
|
+
DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup",
|
1275
|
+
rPos, cost, opt[rPos].litlen);
|
1276
|
+
} }
|
1277
|
+
/* set prices using initial match */
|
1278
|
+
{ int mlen = MINMATCH;
|
1279
|
+
int const matchML = firstMatch.len; /* necessarily < sufficient_len < LZ4_OPT_NUM */
|
1280
|
+
int const offset = firstMatch.off;
|
1281
|
+
assert(matchML < LZ4_OPT_NUM);
|
1282
|
+
for ( ; mlen <= matchML ; mlen++) {
|
1283
|
+
int const cost = LZ4HC_sequencePrice(llen, mlen);
|
1284
|
+
opt[mlen].mlen = mlen;
|
1285
|
+
opt[mlen].off = offset;
|
1286
|
+
opt[mlen].litlen = llen;
|
1287
|
+
opt[mlen].price = cost;
|
1288
|
+
DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i) -- initial setup",
|
1289
|
+
mlen, cost, mlen);
|
1290
|
+
} }
|
1291
|
+
last_match_pos = firstMatch.len;
|
1292
|
+
{ int addLit;
|
1293
|
+
for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {
|
1294
|
+
opt[last_match_pos+addLit].mlen = 1; /* literal */
|
1295
|
+
opt[last_match_pos+addLit].off = 0;
|
1296
|
+
opt[last_match_pos+addLit].litlen = addLit;
|
1297
|
+
opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);
|
1298
|
+
DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup",
|
1299
|
+
last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);
|
1300
|
+
} }
|
1301
|
+
|
1302
|
+
/* check further positions */
|
1303
|
+
for (cur = 1; cur < last_match_pos; cur++) {
|
1304
|
+
const BYTE* const curPtr = ip + cur;
|
1305
|
+
LZ4HC_match_t newMatch;
|
1306
|
+
|
1307
|
+
if (curPtr > mflimit) break;
|
1308
|
+
DEBUGLOG(7, "rPos:%u[%u] vs [%u]%u",
|
1309
|
+
cur, opt[cur].price, opt[cur+1].price, cur+1);
|
1310
|
+
if (fullUpdate) {
|
1311
|
+
/* not useful to search here if next position has same (or lower) cost */
|
1312
|
+
if ( (opt[cur+1].price <= opt[cur].price)
|
1313
|
+
/* in some cases, next position has same cost, but cost rises sharply after, so a small match would still be beneficial */
|
1314
|
+
&& (opt[cur+MINMATCH].price < opt[cur].price + 3/*min seq price*/) )
|
1315
|
+
continue;
|
1316
|
+
} else {
|
1317
|
+
/* not useful to search here if next position has same (or lower) cost */
|
1318
|
+
if (opt[cur+1].price <= opt[cur].price) continue;
|
1319
|
+
}
|
1320
|
+
|
1321
|
+
DEBUGLOG(7, "search at rPos:%u", cur);
|
1322
|
+
if (fullUpdate)
|
1323
|
+
newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);
|
1324
|
+
else
|
1325
|
+
/* only test matches of minimum length; slightly faster, but misses a few bytes */
|
1326
|
+
newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, last_match_pos - cur, nbSearches, dict, favorDecSpeed);
|
1327
|
+
if (!newMatch.len) continue;
|
1328
|
+
|
1329
|
+
if ( ((size_t)newMatch.len > sufficient_len)
|
1330
|
+
|| (newMatch.len + cur >= LZ4_OPT_NUM) ) {
|
1331
|
+
/* immediate encoding */
|
1332
|
+
best_mlen = newMatch.len;
|
1333
|
+
best_off = newMatch.off;
|
1334
|
+
last_match_pos = cur + 1;
|
1335
|
+
goto encode;
|
1336
|
+
}
|
1337
|
+
|
1338
|
+
/* before match : set price with literals at beginning */
|
1339
|
+
{ int const baseLitlen = opt[cur].litlen;
|
1340
|
+
int litlen;
|
1341
|
+
for (litlen = 1; litlen < MINMATCH; litlen++) {
|
1342
|
+
int const price = opt[cur].price - LZ4HC_literalsPrice(baseLitlen) + LZ4HC_literalsPrice(baseLitlen+litlen);
|
1343
|
+
int const pos = cur + litlen;
|
1344
|
+
if (price < opt[pos].price) {
|
1345
|
+
opt[pos].mlen = 1; /* literal */
|
1346
|
+
opt[pos].off = 0;
|
1347
|
+
opt[pos].litlen = baseLitlen+litlen;
|
1348
|
+
opt[pos].price = price;
|
1349
|
+
DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)",
|
1350
|
+
pos, price, opt[pos].litlen);
|
1351
|
+
} } }
|
1352
|
+
|
1353
|
+
/* set prices using match at position = cur */
|
1354
|
+
{ int const matchML = newMatch.len;
|
1355
|
+
int ml = MINMATCH;
|
1356
|
+
|
1357
|
+
assert(cur + newMatch.len < LZ4_OPT_NUM);
|
1358
|
+
for ( ; ml <= matchML ; ml++) {
|
1359
|
+
int const pos = cur + ml;
|
1360
|
+
int const offset = newMatch.off;
|
1361
|
+
int price;
|
1362
|
+
int ll;
|
1363
|
+
DEBUGLOG(7, "testing price rPos %i (last_match_pos=%i)",
|
1364
|
+
pos, last_match_pos);
|
1365
|
+
if (opt[cur].mlen == 1) {
|
1366
|
+
ll = opt[cur].litlen;
|
1367
|
+
price = ((cur > ll) ? opt[cur - ll].price : 0)
|
1368
|
+
+ LZ4HC_sequencePrice(ll, ml);
|
1369
|
+
} else {
|
1370
|
+
ll = 0;
|
1371
|
+
price = opt[cur].price + LZ4HC_sequencePrice(0, ml);
|
1372
|
+
}
|
1373
|
+
|
1374
|
+
assert((U32)favorDecSpeed <= 1);
|
1375
|
+
if (pos > last_match_pos+TRAILING_LITERALS
|
1376
|
+
|| price <= opt[pos].price - (int)favorDecSpeed) {
|
1377
|
+
DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i)",
|
1378
|
+
pos, price, ml);
|
1379
|
+
assert(pos < LZ4_OPT_NUM);
|
1380
|
+
if ( (ml == matchML) /* last pos of last match */
|
1381
|
+
&& (last_match_pos < pos) )
|
1382
|
+
last_match_pos = pos;
|
1383
|
+
opt[pos].mlen = ml;
|
1384
|
+
opt[pos].off = offset;
|
1385
|
+
opt[pos].litlen = ll;
|
1386
|
+
opt[pos].price = price;
|
1387
|
+
} } }
|
1388
|
+
/* complete following positions with literals */
|
1389
|
+
{ int addLit;
|
1390
|
+
for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {
|
1391
|
+
opt[last_match_pos+addLit].mlen = 1; /* literal */
|
1392
|
+
opt[last_match_pos+addLit].off = 0;
|
1393
|
+
opt[last_match_pos+addLit].litlen = addLit;
|
1394
|
+
opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);
|
1395
|
+
DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)", last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);
|
1396
|
+
} }
|
1397
|
+
} /* for (cur = 1; cur <= last_match_pos; cur++) */
|
1398
|
+
|
1399
|
+
best_mlen = opt[last_match_pos].mlen;
|
1400
|
+
best_off = opt[last_match_pos].off;
|
1401
|
+
cur = last_match_pos - best_mlen;
|
1402
|
+
|
1403
|
+
encode: /* cur, last_match_pos, best_mlen, best_off must be set */
|
1404
|
+
assert(cur < LZ4_OPT_NUM);
|
1405
|
+
assert(last_match_pos >= 1); /* == 1 when only one candidate */
|
1406
|
+
DEBUGLOG(6, "reverse traversal, looking for shortest path (last_match_pos=%i)", last_match_pos);
|
1407
|
+
{ int candidate_pos = cur;
|
1408
|
+
int selected_matchLength = best_mlen;
|
1409
|
+
int selected_offset = best_off;
|
1410
|
+
while (1) { /* from end to beginning */
|
1411
|
+
int const next_matchLength = opt[candidate_pos].mlen; /* can be 1, means literal */
|
1412
|
+
int const next_offset = opt[candidate_pos].off;
|
1413
|
+
DEBUGLOG(7, "pos %i: sequence length %i", candidate_pos, selected_matchLength);
|
1414
|
+
opt[candidate_pos].mlen = selected_matchLength;
|
1415
|
+
opt[candidate_pos].off = selected_offset;
|
1416
|
+
selected_matchLength = next_matchLength;
|
1417
|
+
selected_offset = next_offset;
|
1418
|
+
if (next_matchLength > candidate_pos) break; /* last match elected, first match to encode */
|
1419
|
+
assert(next_matchLength > 0); /* can be 1, means literal */
|
1420
|
+
candidate_pos -= next_matchLength;
|
1421
|
+
} }
|
1422
|
+
|
1423
|
+
/* encode all recorded sequences in order */
|
1424
|
+
{ int rPos = 0; /* relative position (to ip) */
|
1425
|
+
while (rPos < last_match_pos) {
|
1426
|
+
int const ml = opt[rPos].mlen;
|
1427
|
+
int const offset = opt[rPos].off;
|
1428
|
+
if (ml == 1) { ip++; rPos++; continue; } /* literal; note: can end up with several literals, in which case, skip them */
|
1429
|
+
rPos += ml;
|
1430
|
+
assert(ml >= MINMATCH);
|
1431
|
+
assert((offset >= 1) && (offset <= LZ4_DISTANCE_MAX));
|
1432
|
+
opSaved = op;
|
1433
|
+
if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ip - offset, limit, oend) ) /* updates ip, op and anchor */
|
1434
|
+
goto _dest_overflow;
|
1435
|
+
} }
|
1436
|
+
} /* while (ip <= mflimit) */
|
1437
|
+
|
1438
|
+
_last_literals:
|
1439
|
+
/* Encode Last Literals */
|
1440
|
+
{ size_t lastRunSize = (size_t)(iend - anchor); /* literals */
|
1441
|
+
size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255;
|
1442
|
+
size_t const totalSize = 1 + litLength + lastRunSize;
|
1443
|
+
if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */
|
1444
|
+
if (limit && (op + totalSize > oend)) {
|
1445
|
+
if (limit == limitedOutput) return 0; /* Check output limit */
|
1446
|
+
/* adapt lastRunSize to fill 'dst' */
|
1447
|
+
lastRunSize = (size_t)(oend - op) - 1;
|
1448
|
+
litLength = (lastRunSize + 255 - RUN_MASK) / 255;
|
1449
|
+
lastRunSize -= litLength;
|
1450
|
+
}
|
1451
|
+
ip = anchor + lastRunSize;
|
1452
|
+
|
1453
|
+
if (lastRunSize >= RUN_MASK) {
|
1454
|
+
size_t accumulator = lastRunSize - RUN_MASK;
|
1455
|
+
*op++ = (RUN_MASK << ML_BITS);
|
1456
|
+
for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;
|
1457
|
+
*op++ = (BYTE) accumulator;
|
1458
|
+
} else {
|
1459
|
+
*op++ = (BYTE)(lastRunSize << ML_BITS);
|
1460
|
+
}
|
1461
|
+
memcpy(op, anchor, lastRunSize);
|
1462
|
+
op += lastRunSize;
|
1463
|
+
}
|
1464
|
+
|
1465
|
+
/* End */
|
1466
|
+
*srcSizePtr = (int) (((const char*)ip) - source);
|
1467
|
+
return (int) ((char*)op-dst);
|
1468
|
+
|
1469
|
+
_dest_overflow:
|
1470
|
+
if (limit == fillOutput) {
|
1471
|
+
op = opSaved; /* restore correct out pointer */
|
1472
|
+
goto _last_literals;
|
1473
|
+
}
|
1474
|
+
return 0;
|
1475
|
+
}
|