isomorfeus-ferret 0.12.7 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +101 -19
  3. data/README.md +54 -1
  4. data/ext/isomorfeus_ferret_ext/bm_bitvector.c +22 -30
  5. data/ext/isomorfeus_ferret_ext/bm_hash.c +6 -12
  6. data/ext/isomorfeus_ferret_ext/bm_micro_string.c +3 -6
  7. data/ext/isomorfeus_ferret_ext/bm_store.c +11 -22
  8. data/ext/isomorfeus_ferret_ext/brotli_common_dictionary.c +1 -1
  9. data/ext/isomorfeus_ferret_ext/brotli_dec_decode.c +1 -1
  10. data/ext/isomorfeus_ferret_ext/bzip_blocksort.c +1094 -0
  11. data/ext/isomorfeus_ferret_ext/bzip_huffman.c +205 -0
  12. data/ext/isomorfeus_ferret_ext/bzlib.c +1572 -0
  13. data/ext/isomorfeus_ferret_ext/bzlib.h +282 -0
  14. data/ext/isomorfeus_ferret_ext/bzlib_compress.c +672 -0
  15. data/ext/isomorfeus_ferret_ext/bzlib_crctable.c +104 -0
  16. data/ext/isomorfeus_ferret_ext/bzlib_decompress.c +652 -0
  17. data/ext/isomorfeus_ferret_ext/bzlib_private.h +509 -0
  18. data/ext/isomorfeus_ferret_ext/bzlib_randtable.c +84 -0
  19. data/ext/isomorfeus_ferret_ext/fio_tmpfile.h +53 -53
  20. data/ext/isomorfeus_ferret_ext/frb_analysis.c +785 -1192
  21. data/ext/isomorfeus_ferret_ext/frb_index.c +492 -474
  22. data/ext/isomorfeus_ferret_ext/frb_qparser.c +48 -60
  23. data/ext/isomorfeus_ferret_ext/frb_search.c +1520 -1002
  24. data/ext/isomorfeus_ferret_ext/frb_store.c +96 -96
  25. data/ext/isomorfeus_ferret_ext/frb_threading.h +0 -1
  26. data/ext/isomorfeus_ferret_ext/frb_utils.c +147 -196
  27. data/ext/isomorfeus_ferret_ext/frt_analysis.c +695 -1090
  28. data/ext/isomorfeus_ferret_ext/frt_analysis.h +174 -170
  29. data/ext/isomorfeus_ferret_ext/frt_array.c +2 -4
  30. data/ext/isomorfeus_ferret_ext/frt_bitvector.c +9 -16
  31. data/ext/isomorfeus_ferret_ext/frt_bitvector.h +32 -81
  32. data/ext/isomorfeus_ferret_ext/frt_document.c +15 -20
  33. data/ext/isomorfeus_ferret_ext/frt_document.h +10 -10
  34. data/ext/isomorfeus_ferret_ext/frt_except.c +5 -12
  35. data/ext/isomorfeus_ferret_ext/frt_field_index.c +3 -3
  36. data/ext/isomorfeus_ferret_ext/frt_field_index.h +6 -7
  37. data/ext/isomorfeus_ferret_ext/frt_filter.c +35 -46
  38. data/ext/isomorfeus_ferret_ext/frt_fs_store.c +1 -0
  39. data/ext/isomorfeus_ferret_ext/frt_global.c +105 -63
  40. data/ext/isomorfeus_ferret_ext/frt_global.h +7 -3
  41. data/ext/isomorfeus_ferret_ext/frt_hash.c +1 -2
  42. data/ext/isomorfeus_ferret_ext/frt_ind.c +32 -35
  43. data/ext/isomorfeus_ferret_ext/frt_ind.h +9 -9
  44. data/ext/isomorfeus_ferret_ext/frt_index.c +580 -399
  45. data/ext/isomorfeus_ferret_ext/frt_index.h +272 -291
  46. data/ext/isomorfeus_ferret_ext/frt_mempool.c +1 -2
  47. data/ext/isomorfeus_ferret_ext/frt_multimapper.c +4 -7
  48. data/ext/isomorfeus_ferret_ext/frt_q_boolean.c +67 -91
  49. data/ext/isomorfeus_ferret_ext/frt_q_const_score.c +35 -38
  50. data/ext/isomorfeus_ferret_ext/frt_q_filtered_query.c +53 -72
  51. data/ext/isomorfeus_ferret_ext/frt_q_fuzzy.c +25 -32
  52. data/ext/isomorfeus_ferret_ext/frt_q_match_all.c +21 -23
  53. data/ext/isomorfeus_ferret_ext/frt_q_multi_term.c +66 -103
  54. data/ext/isomorfeus_ferret_ext/frt_q_parser.c +207 -195
  55. data/ext/isomorfeus_ferret_ext/frt_q_phrase.c +20 -16
  56. data/ext/isomorfeus_ferret_ext/frt_q_prefix.c +17 -14
  57. data/ext/isomorfeus_ferret_ext/frt_q_range.c +102 -131
  58. data/ext/isomorfeus_ferret_ext/frt_q_span.c +179 -178
  59. data/ext/isomorfeus_ferret_ext/frt_q_term.c +47 -60
  60. data/ext/isomorfeus_ferret_ext/frt_q_wildcard.c +18 -16
  61. data/ext/isomorfeus_ferret_ext/frt_ram_store.c +45 -84
  62. data/ext/isomorfeus_ferret_ext/frt_search.c +105 -146
  63. data/ext/isomorfeus_ferret_ext/frt_search.h +331 -320
  64. data/ext/isomorfeus_ferret_ext/frt_similarity.c +5 -13
  65. data/ext/isomorfeus_ferret_ext/frt_similarity.h +7 -12
  66. data/ext/isomorfeus_ferret_ext/frt_sort.c +105 -149
  67. data/ext/isomorfeus_ferret_ext/frt_store.c +13 -7
  68. data/ext/isomorfeus_ferret_ext/frt_store.h +10 -2
  69. data/ext/isomorfeus_ferret_ext/frt_threading.h +0 -1
  70. data/ext/isomorfeus_ferret_ext/isomorfeus_ferret.c +21 -109
  71. data/ext/isomorfeus_ferret_ext/isomorfeus_ferret.h +2 -32
  72. data/ext/isomorfeus_ferret_ext/lz4.c +2495 -0
  73. data/ext/isomorfeus_ferret_ext/lz4.h +774 -0
  74. data/ext/isomorfeus_ferret_ext/lz4frame.c +1899 -0
  75. data/ext/isomorfeus_ferret_ext/lz4frame.h +623 -0
  76. data/ext/isomorfeus_ferret_ext/lz4hc.c +1615 -0
  77. data/ext/isomorfeus_ferret_ext/lz4hc.h +413 -0
  78. data/ext/isomorfeus_ferret_ext/lz4xxhash.c +1030 -0
  79. data/ext/isomorfeus_ferret_ext/lz4xxhash.h +328 -0
  80. data/ext/isomorfeus_ferret_ext/stem_modules.h +0 -86
  81. data/ext/isomorfeus_ferret_ext/test.c +1 -2
  82. data/ext/isomorfeus_ferret_ext/test_1710.c +11 -12
  83. data/ext/isomorfeus_ferret_ext/test_analysis.c +590 -583
  84. data/ext/isomorfeus_ferret_ext/test_compound_io.c +1 -1
  85. data/ext/isomorfeus_ferret_ext/test_document.c +19 -15
  86. data/ext/isomorfeus_ferret_ext/test_except.c +1 -2
  87. data/ext/isomorfeus_ferret_ext/test_fields.c +59 -60
  88. data/ext/isomorfeus_ferret_ext/test_file_deleter.c +10 -27
  89. data/ext/isomorfeus_ferret_ext/test_filter.c +11 -8
  90. data/ext/isomorfeus_ferret_ext/test_hash.c +2 -2
  91. data/ext/isomorfeus_ferret_ext/test_hashset.c +1 -1
  92. data/ext/isomorfeus_ferret_ext/test_highlighter.c +15 -11
  93. data/ext/isomorfeus_ferret_ext/test_index.c +372 -365
  94. data/ext/isomorfeus_ferret_ext/test_q_const_score.c +5 -3
  95. data/ext/isomorfeus_ferret_ext/test_q_filtered.c +5 -3
  96. data/ext/isomorfeus_ferret_ext/test_q_fuzzy.c +13 -10
  97. data/ext/isomorfeus_ferret_ext/test_q_parser.c +45 -7
  98. data/ext/isomorfeus_ferret_ext/test_q_span.c +15 -12
  99. data/ext/isomorfeus_ferret_ext/test_ram_store.c +3 -3
  100. data/ext/isomorfeus_ferret_ext/test_search.c +60 -62
  101. data/ext/isomorfeus_ferret_ext/test_segments.c +5 -4
  102. data/ext/isomorfeus_ferret_ext/test_sort.c +17 -14
  103. data/ext/isomorfeus_ferret_ext/test_store.c +2 -0
  104. data/ext/isomorfeus_ferret_ext/test_term.c +3 -1
  105. data/ext/isomorfeus_ferret_ext/test_term_vectors.c +9 -10
  106. data/ext/isomorfeus_ferret_ext/test_test.c +1 -2
  107. data/ext/isomorfeus_ferret_ext/test_threading.c +9 -10
  108. data/ext/isomorfeus_ferret_ext/testhelper.c +1 -2
  109. data/lib/isomorfeus/ferret/version.rb +1 -1
  110. metadata +27 -57
  111. data/ext/isomorfeus_ferret_ext/email.rl +0 -21
  112. data/ext/isomorfeus_ferret_ext/frt_scanner.c +0 -900
  113. data/ext/isomorfeus_ferret_ext/frt_scanner.h +0 -28
  114. data/ext/isomorfeus_ferret_ext/frt_scanner_mb.c +0 -6706
  115. data/ext/isomorfeus_ferret_ext/frt_scanner_utf8.c +0 -4420
  116. data/ext/isomorfeus_ferret_ext/scanner.h +0 -28
  117. data/ext/isomorfeus_ferret_ext/scanner.in +0 -43
  118. data/ext/isomorfeus_ferret_ext/scanner.rl +0 -84
  119. data/ext/isomorfeus_ferret_ext/scanner_mb.rl +0 -200
  120. data/ext/isomorfeus_ferret_ext/scanner_utf8.rl +0 -85
  121. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_basque.c +0 -1167
  122. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_basque.h +0 -6
  123. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_catalan.c +0 -1433
  124. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_catalan.h +0 -6
  125. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_danish.c +0 -301
  126. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_danish.h +0 -6
  127. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_dutch.c +0 -590
  128. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_dutch.h +0 -6
  129. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_english.c +0 -1049
  130. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_english.h +0 -6
  131. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_finnish.c +0 -705
  132. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_finnish.h +0 -6
  133. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_french.c +0 -1239
  134. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_french.h +0 -6
  135. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_german.c +0 -477
  136. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_german.h +0 -6
  137. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_hungarian.c +0 -1217
  138. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_hungarian.h +0 -7
  139. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_indonesian.c +0 -394
  140. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_indonesian.h +0 -6
  141. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_irish.c +0 -457
  142. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_irish.h +0 -6
  143. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_italian.c +0 -1009
  144. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_italian.h +0 -6
  145. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_norwegian.c +0 -259
  146. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_norwegian.h +0 -6
  147. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_porter.c +0 -704
  148. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_porter.h +0 -6
  149. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_portuguese.c +0 -948
  150. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_portuguese.h +0 -6
  151. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_spanish.c +0 -1028
  152. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_spanish.h +0 -6
  153. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_swedish.c +0 -275
  154. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_1_swedish.h +0 -6
  155. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_2_hungarian.c +0 -849
  156. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_2_hungarian.h +0 -6
  157. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_2_romanian.c +0 -952
  158. data/ext/isomorfeus_ferret_ext/stem_ISO_8859_2_romanian.h +0 -6
  159. data/ext/isomorfeus_ferret_ext/stem_KOI8_R_russian.c +0 -669
  160. data/ext/isomorfeus_ferret_ext/stem_KOI8_R_russian.h +0 -6
  161. data/ext/isomorfeus_ferret_ext/stem_modules.txt +0 -63
  162. data/ext/isomorfeus_ferret_ext/uchar-ucs4.rl +0 -1854
  163. data/ext/isomorfeus_ferret_ext/uchar-utf8.rl +0 -1999
  164. data/ext/isomorfeus_ferret_ext/url.rl +0 -27
@@ -0,0 +1,1615 @@
1
+ /*
2
+ LZ4 HC - High Compression Mode of LZ4
3
+ Copyright (C) 2011-2017, Yann Collet.
4
+
5
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6
+
7
+ Redistribution and use in source and binary forms, with or without
8
+ modification, are permitted provided that the following conditions are
9
+ met:
10
+
11
+ * Redistributions of source code must retain the above copyright
12
+ notice, this list of conditions and the following disclaimer.
13
+ * Redistributions in binary form must reproduce the above
14
+ copyright notice, this list of conditions and the following disclaimer
15
+ in the documentation and/or other materials provided with the
16
+ distribution.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ You can contact the author at :
31
+ - LZ4 source repository : https://github.com/lz4/lz4
32
+ - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
33
+ */
34
+ /* note : lz4hc is not an independent module, it requires lz4.h/lz4.c for proper compilation */
35
+
36
+
37
+ /* *************************************
38
+ * Tuning Parameter
39
+ ***************************************/
40
+
41
+ /*! HEAPMODE :
42
+ * Select how default compression function will allocate workplace memory,
43
+ * in stack (0:fastest), or in heap (1:requires malloc()).
44
+ * Since workplace is rather large, heap mode is recommended.
45
+ */
46
+ #ifndef LZ4HC_HEAPMODE
47
+ # define LZ4HC_HEAPMODE 1
48
+ #endif
49
+
50
+
51
+ /*=== Dependency ===*/
52
+ #define LZ4_HC_STATIC_LINKING_ONLY
53
+ #include "lz4hc.h"
54
+
55
+
56
+ /*=== Common definitions ===*/
57
+ #if defined(__GNUC__)
58
+ # pragma GCC diagnostic ignored "-Wunused-function"
59
+ #endif
60
+ #if defined (__clang__)
61
+ # pragma clang diagnostic ignored "-Wunused-function"
62
+ #endif
63
+
64
+ #define LZ4_COMMONDEFS_ONLY
65
+ #ifndef LZ4_SRC_INCLUDED
66
+ #include "lz4.c" /* LZ4_count, constants, mem */
67
+ #endif
68
+
69
+
70
+ /*=== Enums ===*/
71
+ typedef enum { noDictCtx, usingDictCtxHc } dictCtx_directive;
72
+
73
+
74
+ /*=== Constants ===*/
75
+ #define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH)
76
+ #define LZ4_OPT_NUM (1<<12)
77
+
78
+
79
+ /*=== Macros ===*/
80
+ #define MIN(a,b) ( (a) < (b) ? (a) : (b) )
81
+ #define MAX(a,b) ( (a) > (b) ? (a) : (b) )
82
+ #define HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG))
83
+ #define DELTANEXTMAXD(p) chainTable[(p) & LZ4HC_MAXD_MASK] /* flexible, LZ4HC_MAXD dependent */
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
87
+
88
+ static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }
89
+
90
+
91
+ /**************************************
92
+ * HC Compression
93
+ **************************************/
94
+ static void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4)
95
+ {
96
+ MEM_INIT(hc4->hashTable, 0, sizeof(hc4->hashTable));
97
+ MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));
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;
110
+ hc4->end = start;
111
+ hc4->dictBase = start - startingOffset;
112
+ hc4->dictLimit = (U32) startingOffset;
113
+ hc4->lowLimit = (U32) startingOffset;
114
+ }
115
+
116
+
117
+ /* Update chains up to ip (excluded) */
118
+ LZ4_FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip)
119
+ {
120
+ U16* const chainTable = hc4->chainTable;
121
+ U32* const hashTable = hc4->hashTable;
122
+ const BYTE* const base = hc4->base;
123
+ U32 const target = (U32)(ip - base);
124
+ U32 idx = hc4->nextToUpdate;
125
+
126
+ while (idx < target) {
127
+ U32 const h = LZ4HC_hashPtr(base+idx);
128
+ size_t delta = idx - hashTable[h];
129
+ if (delta>LZ4_DISTANCE_MAX) delta = LZ4_DISTANCE_MAX;
130
+ DELTANEXTU16(chainTable, idx) = (U16)delta;
131
+ hashTable[h] = idx;
132
+ idx++;
133
+ }
134
+
135
+ hc4->nextToUpdate = target;
136
+ }
137
+
138
+ /** LZ4HC_countBack() :
139
+ * @return : negative value, nb of common bytes before ip/match */
140
+ LZ4_FORCE_INLINE
141
+ int LZ4HC_countBack(const BYTE* const ip, const BYTE* const match,
142
+ const BYTE* const iMin, const BYTE* const mMin)
143
+ {
144
+ int back = 0;
145
+ int const min = (int)MAX(iMin - ip, mMin - match);
146
+ assert(min <= 0);
147
+ assert(ip >= iMin); assert((size_t)(ip-iMin) < (1U<<31));
148
+ assert(match >= mMin); assert((size_t)(match - mMin) < (1U<<31));
149
+ while ( (back > min)
150
+ && (ip[back-1] == match[back-1]) )
151
+ back--;
152
+ return back;
153
+ }
154
+
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)
163
+ {
164
+ size_t const bitsToRotate = (rotate & (sizeof(pattern) - 1)) << 3;
165
+ if (bitsToRotate == 0) return pattern;
166
+ return LZ4HC_rotl32(pattern, (int)bitsToRotate);
167
+ }
168
+
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
+ }
184
+
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;
196
+ }
197
+ }
198
+
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);
230
+ }
231
+
232
+ typedef enum { rep_untested, rep_not, rep_confirmed } repeat_state_e;
233
+ typedef enum { favorCompressionRatio=0, favorDecompressionSpeed } HCfavor_e;
234
+
235
+ LZ4_FORCE_INLINE int
236
+ LZ4HC_InsertAndGetWiderMatch (
237
+ LZ4HC_CCtx_internal* hc4,
238
+ const BYTE* const ip,
239
+ const BYTE* const iLowLimit,
240
+ const BYTE* const iHighLimit,
241
+ int longest,
242
+ const BYTE** matchpos,
243
+ const BYTE** startpos,
244
+ const int maxNbAttempts,
245
+ const int patternAnalysis,
246
+ const int chainSwap,
247
+ const dictCtx_directive dict,
248
+ const HCfavor_e favorDecSpeed)
249
+ {
250
+ U16* const chainTable = hc4->chainTable;
251
+ U32* const HashTable = hc4->hashTable;
252
+ const LZ4HC_CCtx_internal * const dictCtx = hc4->dictCtx;
253
+ const BYTE* const base = hc4->base;
254
+ const U32 dictLimit = hc4->dictLimit;
255
+ const BYTE* const lowPrefixPtr = base + dictLimit;
256
+ const U32 ipIndex = (U32)(ip - base);
257
+ const U32 lowestMatchIndex = (hc4->lowLimit + (LZ4_DISTANCE_MAX + 1) > ipIndex) ? hc4->lowLimit : ipIndex - LZ4_DISTANCE_MAX;
258
+ const BYTE* const dictBase = hc4->dictBase;
259
+ int const lookBackLength = (int)(ip-iLowLimit);
260
+ int nbAttempts = maxNbAttempts;
261
+ U32 matchChainPos = 0;
262
+ U32 const pattern = LZ4_read32(ip);
263
+ U32 matchIndex;
264
+ repeat_state_e repeat = rep_untested;
265
+ size_t srcPatternLength = 0;
266
+
267
+ DEBUGLOG(7, "LZ4HC_InsertAndGetWiderMatch");
268
+ /* First Match */
269
+ LZ4HC_Insert(hc4, ip);
270
+ matchIndex = HashTable[LZ4HC_hashPtr(ip)];
271
+ DEBUGLOG(7, "First match at index %u / %u (lowestMatchIndex)",
272
+ matchIndex, lowestMatchIndex);
273
+
274
+ while ((matchIndex>=lowestMatchIndex) && (nbAttempts>0)) {
275
+ int matchLength=0;
276
+ nbAttempts--;
277
+ assert(matchIndex < ipIndex);
278
+ if (favorDecSpeed && (ipIndex - matchIndex < 8)) {
279
+ /* do nothing */
280
+ } else if (matchIndex >= dictLimit) { /* within current Prefix */
281
+ const BYTE* const matchPtr = base + matchIndex;
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;
294
+ } } }
295
+ } else { /* lowestMatchIndex <= matchIndex < dictLimit */
296
+ const BYTE* const matchPtr = dictBase + matchIndex;
297
+ if (LZ4_read32(matchPtr) == pattern) {
298
+ const BYTE* const dictStart = dictBase + hc4->lowLimit;
299
+ int back = 0;
300
+ const BYTE* vLimit = ip + (dictLimit - matchIndex);
301
+ if (vLimit > iHighLimit) vLimit = iHighLimit;
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;
430
+ mlt -= back;
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
+ } } }
441
+
442
+ return longest;
443
+ }
444
+
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
+ }
459
+
460
+ /* LZ4HC_encodeSequence() :
461
+ * @return : 0 if ok,
462
+ * 1 if buffer issue detected */
463
+ LZ4_FORCE_INLINE int LZ4HC_encodeSequence (
464
+ const BYTE** _ip,
465
+ BYTE** _op,
466
+ const BYTE** _anchor,
467
+ int matchLength,
468
+ const BYTE* const match,
469
+ limitedOutput_directive limit,
470
+ BYTE* oend)
471
+ {
472
+ #define ip (*_ip)
473
+ #define op (*_op)
474
+ #define anchor (*_anchor)
475
+
476
+ size_t length;
477
+ BYTE* const token = op++;
478
+
479
+ #if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 6)
480
+ static const BYTE* start = NULL;
481
+ static U32 totalCost = 0;
482
+ U32 const pos = (start==NULL) ? 0 : (U32)(anchor - start);
483
+ U32 const ll = (U32)(ip - anchor);
484
+ U32 const llAdd = (ll>=15) ? ((ll-15) / 255) + 1 : 0;
485
+ U32 const mlAdd = (matchLength>=19) ? ((matchLength-19) / 255) + 1 : 0;
486
+ U32 const cost = 1 + llAdd + ll + 2 + mlAdd;
487
+ if (start==NULL) start = anchor; /* only works for single segment */
488
+ /* g_debuglog_enable = (pos >= 2228) & (pos <= 2262); */
489
+ DEBUGLOG(6, "pos:%7u -- literals:%4u, match:%4i, offset:%5u, cost:%4u + %5u",
490
+ pos,
491
+ (U32)(ip - anchor), matchLength, (U32)(ip-match),
492
+ cost, totalCost);
493
+ totalCost += cost;
494
+ #endif
495
+
496
+ /* Encode Literal length */
497
+ length = (size_t)(ip - anchor);
498
+ LZ4_STATIC_ASSERT(notLimited == 0);
499
+ /* Check output limit */
500
+ if (limit && ((op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) {
501
+ DEBUGLOG(6, "Not enough room to write %i literals (%i bytes remaining)",
502
+ (int)length, (int)(oend - op));
503
+ return 1;
504
+ }
505
+ if (length >= RUN_MASK) {
506
+ size_t len = length - RUN_MASK;
507
+ *token = (RUN_MASK << ML_BITS);
508
+ for(; len >= 255 ; len -= 255) *op++ = 255;
509
+ *op++ = (BYTE)len;
510
+ } else {
511
+ *token = (BYTE)(length << ML_BITS);
512
+ }
513
+
514
+ /* Copy Literals */
515
+ LZ4_wildCopy8(op, anchor, op + length);
516
+ op += length;
517
+
518
+ /* Encode Offset */
519
+ assert( (ip - match) <= LZ4_DISTANCE_MAX ); /* note : consider providing offset as a value, rather than as a pointer difference */
520
+ LZ4_writeLE16(op, (U16)(ip - match)); op += 2;
521
+
522
+ /* Encode MatchLength */
523
+ assert(matchLength >= MINMATCH);
524
+ length = (size_t)matchLength - MINMATCH;
525
+ if (limit && (op + (length / 255) + (1 + LASTLITERALS) > oend)) {
526
+ DEBUGLOG(6, "Not enough room to write match length");
527
+ return 1; /* Check output limit */
528
+ }
529
+ if (length >= ML_MASK) {
530
+ *token += ML_MASK;
531
+ length -= ML_MASK;
532
+ for(; length >= 510 ; length -= 510) { *op++ = 255; *op++ = 255; }
533
+ if (length >= 255) { length -= 255; *op++ = 255; }
534
+ *op++ = (BYTE)length;
535
+ } else {
536
+ *token += (BYTE)(length);
537
+ }
538
+
539
+ /* Prepare next loop */
540
+ ip += matchLength;
541
+ anchor = ip;
542
+
543
+ return 0;
544
+ }
545
+ #undef ip
546
+ #undef op
547
+ #undef anchor
548
+
549
+ LZ4_FORCE_INLINE int LZ4HC_compress_hashChain (
550
+ LZ4HC_CCtx_internal* const ctx,
551
+ const char* const source,
552
+ char* const dest,
553
+ int* srcSizePtr,
554
+ int const maxOutputSize,
555
+ int maxNbAttempts,
556
+ const limitedOutput_directive limit,
557
+ const dictCtx_directive dict
558
+ )
559
+ {
560
+ const int inputSize = *srcSizePtr;
561
+ const int patternAnalysis = (maxNbAttempts > 128); /* levels 9+ */
562
+
563
+ const BYTE* ip = (const BYTE*) source;
564
+ const BYTE* anchor = ip;
565
+ const BYTE* const iend = ip + inputSize;
566
+ const BYTE* const mflimit = iend - MFLIMIT;
567
+ const BYTE* const matchlimit = (iend - LASTLITERALS);
568
+
569
+ BYTE* optr = (BYTE*) dest;
570
+ BYTE* op = (BYTE*) dest;
571
+ BYTE* oend = op + maxOutputSize;
572
+
573
+ int ml0, ml, ml2, ml3;
574
+ const BYTE* start0;
575
+ const BYTE* ref0;
576
+ const BYTE* ref = NULL;
577
+ const BYTE* start2 = NULL;
578
+ const BYTE* ref2 = NULL;
579
+ const BYTE* start3 = NULL;
580
+ const BYTE* ref3 = NULL;
581
+
582
+ /* init */
583
+ *srcSizePtr = 0;
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) */
586
+
587
+ /* Main Loop */
588
+ while (ip <= mflimit) {
589
+ ml = LZ4HC_InsertAndFindBestMatch(ctx, ip, matchlimit, &ref, maxNbAttempts, patternAnalysis, dict);
590
+ if (ml<MINMATCH) { ip++; continue; }
591
+
592
+ /* saved, in case we would skip too much */
593
+ start0 = ip; ref0 = ref; ml0 = ml;
594
+
595
+ _Search2:
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 {
601
+ ml2 = ml;
602
+ }
603
+
604
+ if (ml2 == ml) { /* No better match => encode ML1 */
605
+ optr = op;
606
+ if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
607
+ continue;
608
+ }
609
+
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
+ } }
614
+
615
+ /* Here, start0==ip */
616
+ if ((start2 - ip) < 3) { /* First Match too small : removed */
617
+ ml = ml2;
618
+ ip = start2;
619
+ ref =ref2;
620
+ goto _Search2;
621
+ }
622
+
623
+ _Search3:
624
+ /* At this stage, we have :
625
+ * ml2 > ml1, and
626
+ * ip1+3 <= ip2 (usually < ip1+ml1) */
627
+ if ((start2 - ip) < OPTIMAL_ML) {
628
+ int correction;
629
+ int new_ml = ml;
630
+ if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;
631
+ if (ip+new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - ip) + ml2 - MINMATCH;
632
+ correction = new_ml - (int)(start2 - ip);
633
+ if (correction > 0) {
634
+ start2 += correction;
635
+ ref2 += correction;
636
+ ml2 -= correction;
637
+ }
638
+ }
639
+ /* Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) */
640
+
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 {
646
+ ml3 = ml2;
647
+ }
648
+
649
+ if (ml3 == ml2) { /* No better match => encode ML1 and ML2 */
650
+ /* ip & ref are known; Now for ml */
651
+ if (start2 < ip+ml) ml = (int)(start2 - ip);
652
+ /* Now, encode 2 sequences */
653
+ optr = op;
654
+ if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
655
+ ip = start2;
656
+ optr = op;
657
+ if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml2, ref2, limit, oend)) {
658
+ ml = ml2;
659
+ ref = ref2;
660
+ goto _dest_overflow;
661
+ }
662
+ continue;
663
+ }
664
+
665
+ if (start3 < ip+ml+3) { /* Not enough space for match 2 : remove it */
666
+ if (start3 >= (ip+ml)) { /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */
667
+ if (start2 < ip+ml) {
668
+ int correction = (int)(ip+ml - start2);
669
+ start2 += correction;
670
+ ref2 += correction;
671
+ ml2 -= correction;
672
+ if (ml2 < MINMATCH) {
673
+ start2 = start3;
674
+ ref2 = ref3;
675
+ ml2 = ml3;
676
+ }
677
+ }
678
+
679
+ optr = op;
680
+ if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
681
+ ip = start3;
682
+ ref = ref3;
683
+ ml = ml3;
684
+
685
+ start0 = start2;
686
+ ref0 = ref2;
687
+ ml0 = ml2;
688
+ goto _Search2;
689
+ }
690
+
691
+ start2 = start3;
692
+ ref2 = ref3;
693
+ ml2 = ml3;
694
+ goto _Search3;
695
+ }
696
+
697
+ /*
698
+ * OK, now we have 3 ascending matches;
699
+ * let's write the first one ML1.
700
+ * ip & ref are known; Now decide ml.
701
+ */
702
+ if (start2 < ip+ml) {
703
+ if ((start2 - ip) < OPTIMAL_ML) {
704
+ int correction;
705
+ if (ml > OPTIMAL_ML) ml = OPTIMAL_ML;
706
+ if (ip + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - ip) + ml2 - MINMATCH;
707
+ correction = ml - (int)(start2 - ip);
708
+ if (correction > 0) {
709
+ start2 += correction;
710
+ ref2 += correction;
711
+ ml2 -= correction;
712
+ }
713
+ } else {
714
+ ml = (int)(start2 - ip);
715
+ }
716
+ }
717
+ optr = op;
718
+ if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
719
+
720
+ /* ML2 becomes ML1 */
721
+ ip = start2; ref = ref2; ml = ml2;
722
+
723
+ /* ML3 becomes ML2 */
724
+ start2 = start3; ref2 = ref3; ml2 = ml3;
725
+
726
+ /* let's find a new ML3 */
727
+ goto _Search3;
728
+ }
729
+
730
+ _last_literals:
731
+ /* Encode Last Literals */
732
+ { size_t lastRunSize = (size_t)(iend - anchor); /* literals */
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 */
736
+ if (limit && (op + totalSize > oend)) {
737
+ if (limit == limitedOutput) return 0;
738
+ /* adapt lastRunSize to fill 'dest' */
739
+ lastRunSize = (size_t)(oend - op) - 1 /*token*/;
740
+ llAdd = (lastRunSize + 256 - RUN_MASK) / 256;
741
+ lastRunSize -= llAdd;
742
+ }
743
+ DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);
744
+ ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */
745
+
746
+ if (lastRunSize >= RUN_MASK) {
747
+ size_t accumulator = lastRunSize - RUN_MASK;
748
+ *op++ = (RUN_MASK << ML_BITS);
749
+ for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;
750
+ *op++ = (BYTE) accumulator;
751
+ } else {
752
+ *op++ = (BYTE)(lastRunSize << ML_BITS);
753
+ }
754
+ memcpy(op, anchor, lastRunSize);
755
+ op += lastRunSize;
756
+ }
757
+
758
+ /* End */
759
+ *srcSizePtr = (int) (((const char*)ip) - source);
760
+ return (int) (((char*)op)-dest);
761
+
762
+ _dest_overflow:
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");
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
+ } }
780
+ goto _last_literals;
781
+ }
782
+ /* compression failed */
783
+ return 0;
784
+ }
785
+
786
+
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 (
797
+ LZ4HC_CCtx_internal* const ctx,
798
+ const char* const src,
799
+ char* const dst,
800
+ int* const srcSizePtr,
801
+ int const dstCapacity,
802
+ int cLevel,
803
+ const limitedOutput_directive limit,
804
+ const dictCtx_directive dict
805
+ )
806
+ {
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);
853
+ }
854
+ if (result <= 0) ctx->dirty = 1;
855
+ return result;
856
+ }
857
+ }
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
+ }
875
+
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
+ }
901
+
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)
936
+ {
937
+ LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse;
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);
941
+ if (dstCapacity < LZ4_compressBound(srcSize))
942
+ return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, limitedOutput);
943
+ else
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);
952
+ }
953
+
954
+ int LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
955
+ {
956
+ #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
957
+ LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));
958
+ #else
959
+ LZ4_streamHC_t state;
960
+ LZ4_streamHC_t* const statePtr = &state;
961
+ #endif
962
+ int const cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel);
963
+ #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
964
+ FREEMEM(statePtr);
965
+ #endif
966
+ return cSize;
967
+ }
968
+
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)
971
+ {
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);
977
+ }
978
+
979
+
980
+
981
+ /**************************************
982
+ * Streaming Functions
983
+ **************************************/
984
+ /* allocation */
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);
997
+ if (!LZ4_streamHCPtr) return 0; /* support free on NULL */
998
+ FREEMEM(LZ4_streamHCPtr);
999
+ return 0;
1000
+ }
1001
+
1002
+
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 */
1021
+ void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
1022
+ {
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);
1039
+ }
1040
+
1041
+ void LZ4_setCompressionLevel(LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
1042
+ {
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);
1052
+ }
1053
+
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)
1058
+ {
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);
1062
+ if (dictSize > 64 KB) {
1063
+ dictionary += (size_t)dictSize - 64 KB;
1064
+ dictSize = 64 KB;
1065
+ }
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);
1072
+ ctxPtr->end = (const BYTE*)dictionary + dictSize;
1073
+ if (dictSize >= 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3);
1074
+ return dictSize;
1075
+ }
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
+ }
1080
+
1081
+ /* compression */
1082
+
1083
+ static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock)
1084
+ {
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 */
1088
+
1089
+ /* Only one memory segment for extDict, so any previous extDict is lost at this stage */
1090
+ ctxPtr->lowLimit = ctxPtr->dictLimit;
1091
+ ctxPtr->dictLimit = (U32)(ctxPtr->end - ctxPtr->base);
1092
+ ctxPtr->dictBase = ctxPtr->base;
1093
+ ctxPtr->base = newBlock - ctxPtr->dictLimit;
1094
+ ctxPtr->end = newBlock;
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;
1099
+ }
1100
+
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)
1106
+ {
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);
1111
+ /* auto-init if forgotten */
1112
+ if (ctxPtr->base == NULL) LZ4HC_init_internal (ctxPtr, (const BYTE*) src);
1113
+
1114
+ /* Check overflow */
1115
+ if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 GB) {
1116
+ size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->base) - ctxPtr->dictLimit;
1117
+ if (dictSize > 64 KB) dictSize = 64 KB;
1118
+ LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize);
1119
+ }
1120
+
1121
+ /* Check if blocks follow each other */
1122
+ if ((const BYTE*)src != ctxPtr->end)
1123
+ LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src);
1124
+
1125
+ /* Check overlapping input/dictionary space */
1126
+ { const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr;
1127
+ const BYTE* const dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit;
1128
+ const BYTE* const dictEnd = ctxPtr->dictBase + ctxPtr->dictLimit;
1129
+ if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) {
1130
+ if (sourceEnd > dictEnd) sourceEnd = dictEnd;
1131
+ ctxPtr->lowLimit = (U32)(sourceEnd - ctxPtr->dictBase);
1132
+ if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) ctxPtr->lowLimit = ctxPtr->dictLimit;
1133
+ } }
1134
+
1135
+ return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit);
1136
+ }
1137
+
1138
+ int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int srcSize, int dstCapacity)
1139
+ {
1140
+ if (dstCapacity < LZ4_compressBound(srcSize))
1141
+ return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput);
1142
+ else
1143
+ return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, notLimited);
1144
+ }
1145
+
1146
+ int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int targetDestSize)
1147
+ {
1148
+ return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, fillOutput);
1149
+ }
1150
+
1151
+
1152
+
1153
+ /* LZ4_saveDictHC :
1154
+ * save history content
1155
+ * into a user-provided buffer
1156
+ * which is then used to continue compression
1157
+ */
1158
+ int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)
1159
+ {
1160
+ LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse;
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);
1164
+ if (dictSize > 64 KB) dictSize = 64 KB;
1165
+ if (dictSize < 4) dictSize = 0;
1166
+ if (dictSize > prefixSize) dictSize = prefixSize;
1167
+ if (safeBuffer == NULL) assert(dictSize == 0);
1168
+ if (dictSize > 0)
1169
+ memmove(safeBuffer, streamPtr->end - dictSize, dictSize);
1170
+ { U32 const endIndex = (U32)(streamPtr->end - streamPtr->base);
1171
+ streamPtr->end = (const BYTE*)safeBuffer + dictSize;
1172
+ streamPtr->base = streamPtr->end - endIndex;
1173
+ streamPtr->dictLimit = endIndex - (U32)dictSize;
1174
+ streamPtr->lowLimit = endIndex - (U32)dictSize;
1175
+ if (streamPtr->nextToUpdate < streamPtr->dictLimit)
1176
+ streamPtr->nextToUpdate = streamPtr->dictLimit;
1177
+ }
1178
+ return dictSize;
1179
+ }
1180
+
1181
+
1182
+ /***************************************************
1183
+ * Deprecated Functions
1184
+ ***************************************************/
1185
+
1186
+ /* These functions currently generate deprecation warnings */
1187
+
1188
+ /* Wrappers for deprecated compression functions */
1189
+ int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
1190
+ int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); }
1191
+ int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
1192
+ int LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); }
1193
+ int LZ4_compressHC_withStateHC (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
1194
+ int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, maxDstSize, 0); }
1195
+ int LZ4_compressHC2_withStateHC (void* state, const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
1196
+ int LZ4_compressHC2_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, maxDstSize, cLevel); }
1197
+ int LZ4_compressHC_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, LZ4_compressBound(srcSize)); }
1198
+ int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, maxDstSize); }
1199
+
1200
+
1201
+ /* Deprecated streaming functions */
1202
+ int LZ4_sizeofStreamStateHC(void) { return LZ4_STREAMHCSIZE; }
1203
+
1204
+ /* state is presumed correctly sized, aka >= sizeof(LZ4_streamHC_t)
1205
+ * @return : 0 on success, !=0 if error */
1206
+ int LZ4_resetStreamStateHC(void* state, char* inputBuffer)
1207
+ {
1208
+ LZ4_streamHC_t* const hc4 = LZ4_initStreamHC(state, sizeof(*hc4));
1209
+ if (hc4 == NULL) return 1; /* init failed */
1210
+ LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
1211
+ return 0;
1212
+ }
1213
+
1214
+ void* LZ4_createHC (const char* inputBuffer)
1215
+ {
1216
+ LZ4_streamHC_t* const hc4 = LZ4_createStreamHC();
1217
+ if (hc4 == NULL) return NULL; /* not enough memory */
1218
+ LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
1219
+ return hc4;
1220
+ }
1221
+
1222
+ int LZ4_freeHC (void* LZ4HC_Data)
1223
+ {
1224
+ if (!LZ4HC_Data) return 0; /* support free on NULL */
1225
+ FREEMEM(LZ4HC_Data);
1226
+ return 0;
1227
+ }
1228
+
1229
+ int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)
1230
+ {
1231
+ return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited);
1232
+ }
1233
+
1234
+ int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel)
1235
+ {
1236
+ return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput);
1237
+ }
1238
+
1239
+ char* LZ4_slideInputBufferHC(void* LZ4HC_Data)
1240
+ {
1241
+ LZ4_streamHC_t *ctx = (LZ4_streamHC_t*)LZ4HC_Data;
1242
+ const BYTE *bufferStart = ctx->internal_donotuse.base + ctx->internal_donotuse.lowLimit;
1243
+ LZ4_resetStreamHC_fast(ctx, ctx->internal_donotuse.compressionLevel);
1244
+ /* avoid const char * -> char * conversion warning :( */
1245
+ return (char *)(uptrval)bufferStart;
1246
+ }
1247
+
1248
+
1249
+ /* ================================================
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;
1615
+ }