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