Coverage Report

Created: 2025-08-28 07:58

/src/duckdb/third_party/brotli/enc/backward_references.cpp
Line
Count
Source (jump to first uncovered line)
1
/* Copyright 2013 Google Inc. All Rights Reserved.
2
3
   Distributed under MIT license.
4
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
5
*/
6
7
/* Function to find backward reference copies. */
8
9
#include "backward_references.h"
10
11
#include <brotli/types.h>
12
13
#include "../common/brotli_constants.h"
14
#include "../common/dictionary.h"
15
#include "../common/brotli_platform.h"
16
#include "command.h"
17
#include "compound_dictionary.h"
18
#include "dictionary_hash.h"
19
#include "encoder_dict.h"
20
#include "memory.h"
21
#include "quality.h"
22
23
using namespace duckdb_brotli;
24
25
static BROTLI_INLINE size_t ComputeDistanceCode(size_t distance,
26
                                                size_t max_distance,
27
0
                                                const int* dist_cache) {
28
0
  if (distance <= max_distance) {
29
0
    size_t distance_plus_3 = distance + 3;
30
0
    size_t offset0 = distance_plus_3 - (size_t)dist_cache[0];
31
0
    size_t offset1 = distance_plus_3 - (size_t)dist_cache[1];
32
0
    if (distance == (size_t)dist_cache[0]) {
33
0
      return 0;
34
0
    } else if (distance == (size_t)dist_cache[1]) {
35
0
      return 1;
36
0
    } else if (offset0 < 7) {
37
0
      return (0x9750468 >> (4 * offset0)) & 0xF;
38
0
    } else if (offset1 < 7) {
39
0
      return (0xFDB1ACE >> (4 * offset1)) & 0xF;
40
0
    } else if (distance == (size_t)dist_cache[2]) {
41
0
      return 2;
42
0
    } else if (distance == (size_t)dist_cache[3]) {
43
0
      return 3;
44
0
    }
45
0
  }
46
0
  return distance + BROTLI_NUM_DISTANCE_SHORT_CODES - 1;
47
0
}
48
49
0
#define EXPAND_CAT(a, b) CAT(a, b)
50
0
#define CAT(a, b) a ## b
51
0
#define FN(X) EXPAND_CAT(X, HASHER())
52
#define EXPORT_FN(X) EXPAND_CAT(X, EXPAND_CAT(PREFIX(), HASHER()))
53
54
#define PREFIX() N
55
0
#define ENABLE_COMPOUND_DICTIONARY 0
56
57
0
#define HASHER() H2
58
/* NOLINTNEXTLINE(build/include) */
59
/* NOLINT(build/header_guard) */
60
/* Copyright 2013 Google Inc. All Rights Reserved.
61
62
   Distributed under MIT license.
63
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
64
*/
65
66
/* template parameters: EXPORT_FN, FN */
67
68
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
69
    size_t num_bytes, size_t position,
70
    const uint8_t* ringbuffer, size_t ringbuffer_mask,
71
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
72
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
73
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
74
0
  HASHER()* privat = &hasher->privat.FN(_);
75
  /* Set maximum distance, see section 9.1. of the spec. */
76
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
77
0
  const size_t position_offset = params->stream_offset;
78
79
0
  const Command* const orig_commands = commands;
80
0
  size_t insert_length = *last_insert_len;
81
0
  const size_t pos_end = position + num_bytes;
82
0
  const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
83
0
      position + num_bytes - FN(StoreLookahead)() + 1 : position;
84
85
  /* For speed up heuristics for random data. */
86
0
  const size_t random_heuristics_window_size =
87
0
      LiteralSpreeLengthForSparseSearch(params);
88
0
  size_t apply_random_heuristics = position + random_heuristics_window_size;
89
0
  const size_t gap = params->dictionary.compound.total_size;
90
91
  /* Minimum score to accept a backward reference. */
92
0
  const score_t kMinScore = BROTLI_SCORE_BASE + 100;
93
94
0
  FN(PrepareDistanceCache)(privat, dist_cache);
95
96
0
  while (position + FN(HashTypeLength)() < pos_end) {
97
0
    size_t max_length = pos_end - position;
98
0
    size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
99
0
    size_t dictionary_start = BROTLI_MIN(size_t,
100
0
        position + position_offset, max_backward_limit);
101
0
    HasherSearchResult sr;
102
0
    int dict_id = 0;
103
0
    uint8_t p1 = 0;
104
0
    uint8_t p2 = 0;
105
0
    if (params->dictionary.contextual.context_based) {
106
0
      p1 = position >= 1 ?
107
0
          ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
108
0
      p2 = position >= 2 ?
109
0
          ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
110
0
      dict_id = params->dictionary.contextual.context_map[
111
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
112
0
    }
113
0
    sr.len = 0;
114
0
    sr.len_code_delta = 0;
115
0
    sr.distance = 0;
116
0
    sr.score = kMinScore;
117
0
    FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
118
0
        ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
119
0
        max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
120
0
    if (ENABLE_COMPOUND_DICTIONARY) {
121
0
      LookupCompoundDictionaryMatch(&params->dictionary.compound, ringbuffer,
122
0
          ringbuffer_mask, dist_cache, position, max_length,
123
0
          dictionary_start, params->dist.max_distance, &sr);
124
0
    }
125
0
    if (sr.score > kMinScore) {
126
      /* Found a match. Let's look for something even better ahead. */
127
0
      int delayed_backward_references_in_row = 0;
128
0
      --max_length;
129
0
      for (;; --max_length) {
130
0
        const score_t cost_diff_lazy = 175;
131
0
        HasherSearchResult sr2;
132
0
        sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
133
0
            BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
134
0
        sr2.len_code_delta = 0;
135
0
        sr2.distance = 0;
136
0
        sr2.score = kMinScore;
137
0
        max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
138
0
        dictionary_start = BROTLI_MIN(size_t,
139
0
            position + 1 + position_offset, max_backward_limit);
140
0
        if (params->dictionary.contextual.context_based) {
141
0
          p2 = p1;
142
0
          p1 = ringbuffer[position & ringbuffer_mask];
143
0
          dict_id = params->dictionary.contextual.context_map[
144
0
              BROTLI_CONTEXT(p1, p2, literal_context_lut)];
145
0
        }
146
0
        FN(FindLongestMatch)(privat,
147
0
            params->dictionary.contextual.dict[dict_id],
148
0
            ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
149
0
            max_distance, dictionary_start + gap, params->dist.max_distance,
150
0
            &sr2);
151
0
        if (ENABLE_COMPOUND_DICTIONARY) {
152
0
          LookupCompoundDictionaryMatch(
153
0
              &params->dictionary.compound, ringbuffer,
154
0
              ringbuffer_mask, dist_cache, position + 1, max_length,
155
0
              dictionary_start, params->dist.max_distance, &sr2);
156
0
        }
157
0
        if (sr2.score >= sr.score + cost_diff_lazy) {
158
          /* Ok, let's just write one byte for now and start a match from the
159
             next byte. */
160
0
          ++position;
161
0
          ++insert_length;
162
0
          sr = sr2;
163
0
          if (++delayed_backward_references_in_row < 4 &&
164
0
              position + FN(HashTypeLength)() < pos_end) {
165
0
            continue;
166
0
          }
167
0
        }
168
0
        break;
169
0
      }
170
0
      apply_random_heuristics =
171
0
          position + 2 * sr.len + random_heuristics_window_size;
172
0
      dictionary_start = BROTLI_MIN(size_t,
173
0
          position + position_offset, max_backward_limit);
174
0
      {
175
        /* The first 16 codes are special short-codes,
176
           and the minimum offset is 1. */
177
0
        size_t distance_code = ComputeDistanceCode(
178
0
            sr.distance, dictionary_start + gap, dist_cache);
179
0
        if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
180
0
          dist_cache[3] = dist_cache[2];
181
0
          dist_cache[2] = dist_cache[1];
182
0
          dist_cache[1] = dist_cache[0];
183
0
          dist_cache[0] = (int)sr.distance;
184
0
          FN(PrepareDistanceCache)(privat, dist_cache);
185
0
        }
186
0
        InitCommand(commands++, &params->dist, insert_length,
187
0
            sr.len, sr.len_code_delta, distance_code);
188
0
      }
189
0
      *num_literals += insert_length;
190
0
      insert_length = 0;
191
      /* Put the hash keys into the table, if there are enough bytes left.
192
         Depending on the hasher implementation, it can push all positions
193
         in the given range or only a subset of them.
194
         Avoid hash poisoning with RLE data. */
195
0
      {
196
0
        size_t range_start = position + 2;
197
0
        size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
198
0
        if (sr.distance < (sr.len >> 2)) {
199
0
          range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
200
0
              range_start, position + sr.len - (sr.distance << 2)));
201
0
        }
202
0
        FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
203
0
                       range_end);
204
0
      }
205
0
      position += sr.len;
206
0
    } else {
207
0
      ++insert_length;
208
0
      ++position;
209
      /* If we have not seen matches for a long time, we can skip some
210
         match lookups. Unsuccessful match lookups are very very expensive
211
         and this kind of a heuristic speeds up compression quite
212
         a lot. */
213
0
      if (position > apply_random_heuristics) {
214
        /* Going through uncompressible data, jump. */
215
0
        if (position >
216
0
            apply_random_heuristics + 4 * random_heuristics_window_size) {
217
          /* It is quite a long time since we saw a copy, so we assume
218
             that this data is not compressible, and store hashes less
219
             often. Hashes of non compressible data are less likely to
220
             turn out to be useful in the future, too, so we store less of
221
             them to not to flood out the hash table of good compressible
222
             data. */
223
0
          const size_t kMargin =
224
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
225
0
          size_t pos_jump =
226
0
              BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
227
0
          for (; position < pos_jump; position += 4) {
228
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
229
0
            insert_length += 4;
230
0
          }
231
0
        } else {
232
0
          const size_t kMargin =
233
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
234
0
          size_t pos_jump =
235
0
              BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
236
0
          for (; position < pos_jump; position += 2) {
237
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
238
0
            insert_length += 2;
239
0
          }
240
0
        }
241
0
      }
242
0
    }
243
0
  }
244
0
  insert_length += pos_end - position;
245
0
  *last_insert_len = insert_length;
246
0
  *num_commands += (size_t)(commands - orig_commands);
247
0
}
248
#undef HASHER
249
250
0
#define HASHER() H3
251
/* NOLINTNEXTLINE(build/include) */
252
/* NOLINT(build/header_guard) */
253
/* Copyright 2013 Google Inc. All Rights Reserved.
254
255
   Distributed under MIT license.
256
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
257
*/
258
259
/* template parameters: EXPORT_FN, FN */
260
261
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
262
    size_t num_bytes, size_t position,
263
    const uint8_t* ringbuffer, size_t ringbuffer_mask,
264
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
265
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
266
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
267
0
  HASHER()* privat = &hasher->privat.FN(_);
268
  /* Set maximum distance, see section 9.1. of the spec. */
269
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
270
0
  const size_t position_offset = params->stream_offset;
271
272
0
  const Command* const orig_commands = commands;
273
0
  size_t insert_length = *last_insert_len;
274
0
  const size_t pos_end = position + num_bytes;
275
0
  const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
276
0
      position + num_bytes - FN(StoreLookahead)() + 1 : position;
277
278
  /* For speed up heuristics for random data. */
279
0
  const size_t random_heuristics_window_size =
280
0
      LiteralSpreeLengthForSparseSearch(params);
281
0
  size_t apply_random_heuristics = position + random_heuristics_window_size;
282
0
  const size_t gap = params->dictionary.compound.total_size;
283
284
  /* Minimum score to accept a backward reference. */
285
0
  const score_t kMinScore = BROTLI_SCORE_BASE + 100;
286
287
0
  FN(PrepareDistanceCache)(privat, dist_cache);
288
289
0
  while (position + FN(HashTypeLength)() < pos_end) {
290
0
    size_t max_length = pos_end - position;
291
0
    size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
292
0
    size_t dictionary_start = BROTLI_MIN(size_t,
293
0
        position + position_offset, max_backward_limit);
294
0
    HasherSearchResult sr;
295
0
    int dict_id = 0;
296
0
    uint8_t p1 = 0;
297
0
    uint8_t p2 = 0;
298
0
    if (params->dictionary.contextual.context_based) {
299
0
      p1 = position >= 1 ?
300
0
          ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
301
0
      p2 = position >= 2 ?
302
0
          ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
303
0
      dict_id = params->dictionary.contextual.context_map[
304
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
305
0
    }
306
0
    sr.len = 0;
307
0
    sr.len_code_delta = 0;
308
0
    sr.distance = 0;
309
0
    sr.score = kMinScore;
310
0
    FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
311
0
        ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
312
0
        max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
313
0
    if (ENABLE_COMPOUND_DICTIONARY) {
314
0
      LookupCompoundDictionaryMatch(&params->dictionary.compound, ringbuffer,
315
0
          ringbuffer_mask, dist_cache, position, max_length,
316
0
          dictionary_start, params->dist.max_distance, &sr);
317
0
    }
318
0
    if (sr.score > kMinScore) {
319
      /* Found a match. Let's look for something even better ahead. */
320
0
      int delayed_backward_references_in_row = 0;
321
0
      --max_length;
322
0
      for (;; --max_length) {
323
0
        const score_t cost_diff_lazy = 175;
324
0
        HasherSearchResult sr2;
325
0
        sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
326
0
            BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
327
0
        sr2.len_code_delta = 0;
328
0
        sr2.distance = 0;
329
0
        sr2.score = kMinScore;
330
0
        max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
331
0
        dictionary_start = BROTLI_MIN(size_t,
332
0
            position + 1 + position_offset, max_backward_limit);
333
0
        if (params->dictionary.contextual.context_based) {
334
0
          p2 = p1;
335
0
          p1 = ringbuffer[position & ringbuffer_mask];
336
0
          dict_id = params->dictionary.contextual.context_map[
337
0
              BROTLI_CONTEXT(p1, p2, literal_context_lut)];
338
0
        }
339
0
        FN(FindLongestMatch)(privat,
340
0
            params->dictionary.contextual.dict[dict_id],
341
0
            ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
342
0
            max_distance, dictionary_start + gap, params->dist.max_distance,
343
0
            &sr2);
344
0
        if (ENABLE_COMPOUND_DICTIONARY) {
345
0
          LookupCompoundDictionaryMatch(
346
0
              &params->dictionary.compound, ringbuffer,
347
0
              ringbuffer_mask, dist_cache, position + 1, max_length,
348
0
              dictionary_start, params->dist.max_distance, &sr2);
349
0
        }
350
0
        if (sr2.score >= sr.score + cost_diff_lazy) {
351
          /* Ok, let's just write one byte for now and start a match from the
352
             next byte. */
353
0
          ++position;
354
0
          ++insert_length;
355
0
          sr = sr2;
356
0
          if (++delayed_backward_references_in_row < 4 &&
357
0
              position + FN(HashTypeLength)() < pos_end) {
358
0
            continue;
359
0
          }
360
0
        }
361
0
        break;
362
0
      }
363
0
      apply_random_heuristics =
364
0
          position + 2 * sr.len + random_heuristics_window_size;
365
0
      dictionary_start = BROTLI_MIN(size_t,
366
0
          position + position_offset, max_backward_limit);
367
0
      {
368
        /* The first 16 codes are special short-codes,
369
           and the minimum offset is 1. */
370
0
        size_t distance_code = ComputeDistanceCode(
371
0
            sr.distance, dictionary_start + gap, dist_cache);
372
0
        if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
373
0
          dist_cache[3] = dist_cache[2];
374
0
          dist_cache[2] = dist_cache[1];
375
0
          dist_cache[1] = dist_cache[0];
376
0
          dist_cache[0] = (int)sr.distance;
377
0
          FN(PrepareDistanceCache)(privat, dist_cache);
378
0
        }
379
0
        InitCommand(commands++, &params->dist, insert_length,
380
0
            sr.len, sr.len_code_delta, distance_code);
381
0
      }
382
0
      *num_literals += insert_length;
383
0
      insert_length = 0;
384
      /* Put the hash keys into the table, if there are enough bytes left.
385
         Depending on the hasher implementation, it can push all positions
386
         in the given range or only a subset of them.
387
         Avoid hash poisoning with RLE data. */
388
0
      {
389
0
        size_t range_start = position + 2;
390
0
        size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
391
0
        if (sr.distance < (sr.len >> 2)) {
392
0
          range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
393
0
              range_start, position + sr.len - (sr.distance << 2)));
394
0
        }
395
0
        FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
396
0
                       range_end);
397
0
      }
398
0
      position += sr.len;
399
0
    } else {
400
0
      ++insert_length;
401
0
      ++position;
402
      /* If we have not seen matches for a long time, we can skip some
403
         match lookups. Unsuccessful match lookups are very very expensive
404
         and this kind of a heuristic speeds up compression quite
405
         a lot. */
406
0
      if (position > apply_random_heuristics) {
407
        /* Going through uncompressible data, jump. */
408
0
        if (position >
409
0
            apply_random_heuristics + 4 * random_heuristics_window_size) {
410
          /* It is quite a long time since we saw a copy, so we assume
411
             that this data is not compressible, and store hashes less
412
             often. Hashes of non compressible data are less likely to
413
             turn out to be useful in the future, too, so we store less of
414
             them to not to flood out the hash table of good compressible
415
             data. */
416
0
          const size_t kMargin =
417
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
418
0
          size_t pos_jump =
419
0
              BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
420
0
          for (; position < pos_jump; position += 4) {
421
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
422
0
            insert_length += 4;
423
0
          }
424
0
        } else {
425
0
          const size_t kMargin =
426
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
427
0
          size_t pos_jump =
428
0
              BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
429
0
          for (; position < pos_jump; position += 2) {
430
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
431
0
            insert_length += 2;
432
0
          }
433
0
        }
434
0
      }
435
0
    }
436
0
  }
437
0
  insert_length += pos_end - position;
438
0
  *last_insert_len = insert_length;
439
0
  *num_commands += (size_t)(commands - orig_commands);
440
0
}
441
#undef HASHER
442
443
0
#define HASHER() H4
444
/* NOLINTNEXTLINE(build/include) */
445
/* NOLINT(build/header_guard) */
446
/* Copyright 2013 Google Inc. All Rights Reserved.
447
448
   Distributed under MIT license.
449
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
450
*/
451
452
/* template parameters: EXPORT_FN, FN */
453
454
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
455
    size_t num_bytes, size_t position,
456
    const uint8_t* ringbuffer, size_t ringbuffer_mask,
457
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
458
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
459
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
460
0
  HASHER()* privat = &hasher->privat.FN(_);
461
  /* Set maximum distance, see section 9.1. of the spec. */
462
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
463
0
  const size_t position_offset = params->stream_offset;
464
465
0
  const Command* const orig_commands = commands;
466
0
  size_t insert_length = *last_insert_len;
467
0
  const size_t pos_end = position + num_bytes;
468
0
  const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
469
0
      position + num_bytes - FN(StoreLookahead)() + 1 : position;
470
471
  /* For speed up heuristics for random data. */
472
0
  const size_t random_heuristics_window_size =
473
0
      LiteralSpreeLengthForSparseSearch(params);
474
0
  size_t apply_random_heuristics = position + random_heuristics_window_size;
475
0
  const size_t gap = params->dictionary.compound.total_size;
476
477
  /* Minimum score to accept a backward reference. */
478
0
  const score_t kMinScore = BROTLI_SCORE_BASE + 100;
479
480
0
  FN(PrepareDistanceCache)(privat, dist_cache);
481
482
0
  while (position + FN(HashTypeLength)() < pos_end) {
483
0
    size_t max_length = pos_end - position;
484
0
    size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
485
0
    size_t dictionary_start = BROTLI_MIN(size_t,
486
0
        position + position_offset, max_backward_limit);
487
0
    HasherSearchResult sr;
488
0
    int dict_id = 0;
489
0
    uint8_t p1 = 0;
490
0
    uint8_t p2 = 0;
491
0
    if (params->dictionary.contextual.context_based) {
492
0
      p1 = position >= 1 ?
493
0
          ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
494
0
      p2 = position >= 2 ?
495
0
          ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
496
0
      dict_id = params->dictionary.contextual.context_map[
497
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
498
0
    }
499
0
    sr.len = 0;
500
0
    sr.len_code_delta = 0;
501
0
    sr.distance = 0;
502
0
    sr.score = kMinScore;
503
0
    FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
504
0
        ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
505
0
        max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
506
0
    if (ENABLE_COMPOUND_DICTIONARY) {
507
0
      LookupCompoundDictionaryMatch(&params->dictionary.compound, ringbuffer,
508
0
          ringbuffer_mask, dist_cache, position, max_length,
509
0
          dictionary_start, params->dist.max_distance, &sr);
510
0
    }
511
0
    if (sr.score > kMinScore) {
512
      /* Found a match. Let's look for something even better ahead. */
513
0
      int delayed_backward_references_in_row = 0;
514
0
      --max_length;
515
0
      for (;; --max_length) {
516
0
        const score_t cost_diff_lazy = 175;
517
0
        HasherSearchResult sr2;
518
0
        sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
519
0
            BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
520
0
        sr2.len_code_delta = 0;
521
0
        sr2.distance = 0;
522
0
        sr2.score = kMinScore;
523
0
        max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
524
0
        dictionary_start = BROTLI_MIN(size_t,
525
0
            position + 1 + position_offset, max_backward_limit);
526
0
        if (params->dictionary.contextual.context_based) {
527
0
          p2 = p1;
528
0
          p1 = ringbuffer[position & ringbuffer_mask];
529
0
          dict_id = params->dictionary.contextual.context_map[
530
0
              BROTLI_CONTEXT(p1, p2, literal_context_lut)];
531
0
        }
532
0
        FN(FindLongestMatch)(privat,
533
0
            params->dictionary.contextual.dict[dict_id],
534
0
            ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
535
0
            max_distance, dictionary_start + gap, params->dist.max_distance,
536
0
            &sr2);
537
0
        if (ENABLE_COMPOUND_DICTIONARY) {
538
0
          LookupCompoundDictionaryMatch(
539
0
              &params->dictionary.compound, ringbuffer,
540
0
              ringbuffer_mask, dist_cache, position + 1, max_length,
541
0
              dictionary_start, params->dist.max_distance, &sr2);
542
0
        }
543
0
        if (sr2.score >= sr.score + cost_diff_lazy) {
544
          /* Ok, let's just write one byte for now and start a match from the
545
             next byte. */
546
0
          ++position;
547
0
          ++insert_length;
548
0
          sr = sr2;
549
0
          if (++delayed_backward_references_in_row < 4 &&
550
0
              position + FN(HashTypeLength)() < pos_end) {
551
0
            continue;
552
0
          }
553
0
        }
554
0
        break;
555
0
      }
556
0
      apply_random_heuristics =
557
0
          position + 2 * sr.len + random_heuristics_window_size;
558
0
      dictionary_start = BROTLI_MIN(size_t,
559
0
          position + position_offset, max_backward_limit);
560
0
      {
561
        /* The first 16 codes are special short-codes,
562
           and the minimum offset is 1. */
563
0
        size_t distance_code = ComputeDistanceCode(
564
0
            sr.distance, dictionary_start + gap, dist_cache);
565
0
        if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
566
0
          dist_cache[3] = dist_cache[2];
567
0
          dist_cache[2] = dist_cache[1];
568
0
          dist_cache[1] = dist_cache[0];
569
0
          dist_cache[0] = (int)sr.distance;
570
0
          FN(PrepareDistanceCache)(privat, dist_cache);
571
0
        }
572
0
        InitCommand(commands++, &params->dist, insert_length,
573
0
            sr.len, sr.len_code_delta, distance_code);
574
0
      }
575
0
      *num_literals += insert_length;
576
0
      insert_length = 0;
577
      /* Put the hash keys into the table, if there are enough bytes left.
578
         Depending on the hasher implementation, it can push all positions
579
         in the given range or only a subset of them.
580
         Avoid hash poisoning with RLE data. */
581
0
      {
582
0
        size_t range_start = position + 2;
583
0
        size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
584
0
        if (sr.distance < (sr.len >> 2)) {
585
0
          range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
586
0
              range_start, position + sr.len - (sr.distance << 2)));
587
0
        }
588
0
        FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
589
0
                       range_end);
590
0
      }
591
0
      position += sr.len;
592
0
    } else {
593
0
      ++insert_length;
594
0
      ++position;
595
      /* If we have not seen matches for a long time, we can skip some
596
         match lookups. Unsuccessful match lookups are very very expensive
597
         and this kind of a heuristic speeds up compression quite
598
         a lot. */
599
0
      if (position > apply_random_heuristics) {
600
        /* Going through uncompressible data, jump. */
601
0
        if (position >
602
0
            apply_random_heuristics + 4 * random_heuristics_window_size) {
603
          /* It is quite a long time since we saw a copy, so we assume
604
             that this data is not compressible, and store hashes less
605
             often. Hashes of non compressible data are less likely to
606
             turn out to be useful in the future, too, so we store less of
607
             them to not to flood out the hash table of good compressible
608
             data. */
609
0
          const size_t kMargin =
610
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
611
0
          size_t pos_jump =
612
0
              BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
613
0
          for (; position < pos_jump; position += 4) {
614
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
615
0
            insert_length += 4;
616
0
          }
617
0
        } else {
618
0
          const size_t kMargin =
619
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
620
0
          size_t pos_jump =
621
0
              BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
622
0
          for (; position < pos_jump; position += 2) {
623
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
624
0
            insert_length += 2;
625
0
          }
626
0
        }
627
0
      }
628
0
    }
629
0
  }
630
0
  insert_length += pos_end - position;
631
0
  *last_insert_len = insert_length;
632
0
  *num_commands += (size_t)(commands - orig_commands);
633
0
}
634
#undef HASHER
635
636
0
#define HASHER() H5
637
/* NOLINTNEXTLINE(build/include) */
638
/* NOLINT(build/header_guard) */
639
/* Copyright 2013 Google Inc. All Rights Reserved.
640
641
   Distributed under MIT license.
642
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
643
*/
644
645
/* template parameters: EXPORT_FN, FN */
646
647
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
648
    size_t num_bytes, size_t position,
649
    const uint8_t* ringbuffer, size_t ringbuffer_mask,
650
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
651
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
652
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
653
0
  HASHER()* privat = &hasher->privat.FN(_);
654
  /* Set maximum distance, see section 9.1. of the spec. */
655
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
656
0
  const size_t position_offset = params->stream_offset;
657
658
0
  const Command* const orig_commands = commands;
659
0
  size_t insert_length = *last_insert_len;
660
0
  const size_t pos_end = position + num_bytes;
661
0
  const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
662
0
      position + num_bytes - FN(StoreLookahead)() + 1 : position;
663
664
  /* For speed up heuristics for random data. */
665
0
  const size_t random_heuristics_window_size =
666
0
      LiteralSpreeLengthForSparseSearch(params);
667
0
  size_t apply_random_heuristics = position + random_heuristics_window_size;
668
0
  const size_t gap = params->dictionary.compound.total_size;
669
670
  /* Minimum score to accept a backward reference. */
671
0
  const score_t kMinScore = BROTLI_SCORE_BASE + 100;
672
673
0
  FN(PrepareDistanceCache)(privat, dist_cache);
674
675
0
  while (position + FN(HashTypeLength)() < pos_end) {
676
0
    size_t max_length = pos_end - position;
677
0
    size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
678
0
    size_t dictionary_start = BROTLI_MIN(size_t,
679
0
        position + position_offset, max_backward_limit);
680
0
    HasherSearchResult sr;
681
0
    int dict_id = 0;
682
0
    uint8_t p1 = 0;
683
0
    uint8_t p2 = 0;
684
0
    if (params->dictionary.contextual.context_based) {
685
0
      p1 = position >= 1 ?
686
0
          ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
687
0
      p2 = position >= 2 ?
688
0
          ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
689
0
      dict_id = params->dictionary.contextual.context_map[
690
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
691
0
    }
692
0
    sr.len = 0;
693
0
    sr.len_code_delta = 0;
694
0
    sr.distance = 0;
695
0
    sr.score = kMinScore;
696
0
    FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
697
0
        ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
698
0
        max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
699
0
    if (ENABLE_COMPOUND_DICTIONARY) {
700
0
      LookupCompoundDictionaryMatch(&params->dictionary.compound, ringbuffer,
701
0
          ringbuffer_mask, dist_cache, position, max_length,
702
0
          dictionary_start, params->dist.max_distance, &sr);
703
0
    }
704
0
    if (sr.score > kMinScore) {
705
      /* Found a match. Let's look for something even better ahead. */
706
0
      int delayed_backward_references_in_row = 0;
707
0
      --max_length;
708
0
      for (;; --max_length) {
709
0
        const score_t cost_diff_lazy = 175;
710
0
        HasherSearchResult sr2;
711
0
        sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
712
0
            BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
713
0
        sr2.len_code_delta = 0;
714
0
        sr2.distance = 0;
715
0
        sr2.score = kMinScore;
716
0
        max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
717
0
        dictionary_start = BROTLI_MIN(size_t,
718
0
            position + 1 + position_offset, max_backward_limit);
719
0
        if (params->dictionary.contextual.context_based) {
720
0
          p2 = p1;
721
0
          p1 = ringbuffer[position & ringbuffer_mask];
722
0
          dict_id = params->dictionary.contextual.context_map[
723
0
              BROTLI_CONTEXT(p1, p2, literal_context_lut)];
724
0
        }
725
0
        FN(FindLongestMatch)(privat,
726
0
            params->dictionary.contextual.dict[dict_id],
727
0
            ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
728
0
            max_distance, dictionary_start + gap, params->dist.max_distance,
729
0
            &sr2);
730
0
        if (ENABLE_COMPOUND_DICTIONARY) {
731
0
          LookupCompoundDictionaryMatch(
732
0
              &params->dictionary.compound, ringbuffer,
733
0
              ringbuffer_mask, dist_cache, position + 1, max_length,
734
0
              dictionary_start, params->dist.max_distance, &sr2);
735
0
        }
736
0
        if (sr2.score >= sr.score + cost_diff_lazy) {
737
          /* Ok, let's just write one byte for now and start a match from the
738
             next byte. */
739
0
          ++position;
740
0
          ++insert_length;
741
0
          sr = sr2;
742
0
          if (++delayed_backward_references_in_row < 4 &&
743
0
              position + FN(HashTypeLength)() < pos_end) {
744
0
            continue;
745
0
          }
746
0
        }
747
0
        break;
748
0
      }
749
0
      apply_random_heuristics =
750
0
          position + 2 * sr.len + random_heuristics_window_size;
751
0
      dictionary_start = BROTLI_MIN(size_t,
752
0
          position + position_offset, max_backward_limit);
753
0
      {
754
        /* The first 16 codes are special short-codes,
755
           and the minimum offset is 1. */
756
0
        size_t distance_code = ComputeDistanceCode(
757
0
            sr.distance, dictionary_start + gap, dist_cache);
758
0
        if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
759
0
          dist_cache[3] = dist_cache[2];
760
0
          dist_cache[2] = dist_cache[1];
761
0
          dist_cache[1] = dist_cache[0];
762
0
          dist_cache[0] = (int)sr.distance;
763
0
          FN(PrepareDistanceCache)(privat, dist_cache);
764
0
        }
765
0
        InitCommand(commands++, &params->dist, insert_length,
766
0
            sr.len, sr.len_code_delta, distance_code);
767
0
      }
768
0
      *num_literals += insert_length;
769
0
      insert_length = 0;
770
      /* Put the hash keys into the table, if there are enough bytes left.
771
         Depending on the hasher implementation, it can push all positions
772
         in the given range or only a subset of them.
773
         Avoid hash poisoning with RLE data. */
774
0
      {
775
0
        size_t range_start = position + 2;
776
0
        size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
777
0
        if (sr.distance < (sr.len >> 2)) {
778
0
          range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
779
0
              range_start, position + sr.len - (sr.distance << 2)));
780
0
        }
781
0
        FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
782
0
                       range_end);
783
0
      }
784
0
      position += sr.len;
785
0
    } else {
786
0
      ++insert_length;
787
0
      ++position;
788
      /* If we have not seen matches for a long time, we can skip some
789
         match lookups. Unsuccessful match lookups are very very expensive
790
         and this kind of a heuristic speeds up compression quite
791
         a lot. */
792
0
      if (position > apply_random_heuristics) {
793
        /* Going through uncompressible data, jump. */
794
0
        if (position >
795
0
            apply_random_heuristics + 4 * random_heuristics_window_size) {
796
          /* It is quite a long time since we saw a copy, so we assume
797
             that this data is not compressible, and store hashes less
798
             often. Hashes of non compressible data are less likely to
799
             turn out to be useful in the future, too, so we store less of
800
             them to not to flood out the hash table of good compressible
801
             data. */
802
0
          const size_t kMargin =
803
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
804
0
          size_t pos_jump =
805
0
              BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
806
0
          for (; position < pos_jump; position += 4) {
807
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
808
0
            insert_length += 4;
809
0
          }
810
0
        } else {
811
0
          const size_t kMargin =
812
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
813
0
          size_t pos_jump =
814
0
              BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
815
0
          for (; position < pos_jump; position += 2) {
816
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
817
0
            insert_length += 2;
818
0
          }
819
0
        }
820
0
      }
821
0
    }
822
0
  }
823
0
  insert_length += pos_end - position;
824
0
  *last_insert_len = insert_length;
825
0
  *num_commands += (size_t)(commands - orig_commands);
826
0
}
827
#undef HASHER
828
829
0
#define HASHER() H6
830
/* NOLINTNEXTLINE(build/include) */
831
/* NOLINT(build/header_guard) */
832
/* Copyright 2013 Google Inc. All Rights Reserved.
833
834
   Distributed under MIT license.
835
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
836
*/
837
838
/* template parameters: EXPORT_FN, FN */
839
840
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
841
    size_t num_bytes, size_t position,
842
    const uint8_t* ringbuffer, size_t ringbuffer_mask,
843
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
844
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
845
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
846
0
  HASHER()* privat = &hasher->privat.FN(_);
847
  /* Set maximum distance, see section 9.1. of the spec. */
848
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
849
0
  const size_t position_offset = params->stream_offset;
850
851
0
  const Command* const orig_commands = commands;
852
0
  size_t insert_length = *last_insert_len;
853
0
  const size_t pos_end = position + num_bytes;
854
0
  const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
855
0
      position + num_bytes - FN(StoreLookahead)() + 1 : position;
856
857
  /* For speed up heuristics for random data. */
858
0
  const size_t random_heuristics_window_size =
859
0
      LiteralSpreeLengthForSparseSearch(params);
860
0
  size_t apply_random_heuristics = position + random_heuristics_window_size;
861
0
  const size_t gap = params->dictionary.compound.total_size;
862
863
  /* Minimum score to accept a backward reference. */
864
0
  const score_t kMinScore = BROTLI_SCORE_BASE + 100;
865
866
0
  FN(PrepareDistanceCache)(privat, dist_cache);
867
868
0
  while (position + FN(HashTypeLength)() < pos_end) {
869
0
    size_t max_length = pos_end - position;
870
0
    size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
871
0
    size_t dictionary_start = BROTLI_MIN(size_t,
872
0
        position + position_offset, max_backward_limit);
873
0
    HasherSearchResult sr;
874
0
    int dict_id = 0;
875
0
    uint8_t p1 = 0;
876
0
    uint8_t p2 = 0;
877
0
    if (params->dictionary.contextual.context_based) {
878
0
      p1 = position >= 1 ?
879
0
          ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
880
0
      p2 = position >= 2 ?
881
0
          ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
882
0
      dict_id = params->dictionary.contextual.context_map[
883
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
884
0
    }
885
0
    sr.len = 0;
886
0
    sr.len_code_delta = 0;
887
0
    sr.distance = 0;
888
0
    sr.score = kMinScore;
889
0
    FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
890
0
        ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
891
0
        max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
892
0
    if (ENABLE_COMPOUND_DICTIONARY) {
893
0
      LookupCompoundDictionaryMatch(&params->dictionary.compound, ringbuffer,
894
0
          ringbuffer_mask, dist_cache, position, max_length,
895
0
          dictionary_start, params->dist.max_distance, &sr);
896
0
    }
897
0
    if (sr.score > kMinScore) {
898
      /* Found a match. Let's look for something even better ahead. */
899
0
      int delayed_backward_references_in_row = 0;
900
0
      --max_length;
901
0
      for (;; --max_length) {
902
0
        const score_t cost_diff_lazy = 175;
903
0
        HasherSearchResult sr2;
904
0
        sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
905
0
            BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
906
0
        sr2.len_code_delta = 0;
907
0
        sr2.distance = 0;
908
0
        sr2.score = kMinScore;
909
0
        max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
910
0
        dictionary_start = BROTLI_MIN(size_t,
911
0
            position + 1 + position_offset, max_backward_limit);
912
0
        if (params->dictionary.contextual.context_based) {
913
0
          p2 = p1;
914
0
          p1 = ringbuffer[position & ringbuffer_mask];
915
0
          dict_id = params->dictionary.contextual.context_map[
916
0
              BROTLI_CONTEXT(p1, p2, literal_context_lut)];
917
0
        }
918
0
        FN(FindLongestMatch)(privat,
919
0
            params->dictionary.contextual.dict[dict_id],
920
0
            ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
921
0
            max_distance, dictionary_start + gap, params->dist.max_distance,
922
0
            &sr2);
923
0
        if (ENABLE_COMPOUND_DICTIONARY) {
924
0
          LookupCompoundDictionaryMatch(
925
0
              &params->dictionary.compound, ringbuffer,
926
0
              ringbuffer_mask, dist_cache, position + 1, max_length,
927
0
              dictionary_start, params->dist.max_distance, &sr2);
928
0
        }
929
0
        if (sr2.score >= sr.score + cost_diff_lazy) {
930
          /* Ok, let's just write one byte for now and start a match from the
931
             next byte. */
932
0
          ++position;
933
0
          ++insert_length;
934
0
          sr = sr2;
935
0
          if (++delayed_backward_references_in_row < 4 &&
936
0
              position + FN(HashTypeLength)() < pos_end) {
937
0
            continue;
938
0
          }
939
0
        }
940
0
        break;
941
0
      }
942
0
      apply_random_heuristics =
943
0
          position + 2 * sr.len + random_heuristics_window_size;
944
0
      dictionary_start = BROTLI_MIN(size_t,
945
0
          position + position_offset, max_backward_limit);
946
0
      {
947
        /* The first 16 codes are special short-codes,
948
           and the minimum offset is 1. */
949
0
        size_t distance_code = ComputeDistanceCode(
950
0
            sr.distance, dictionary_start + gap, dist_cache);
951
0
        if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
952
0
          dist_cache[3] = dist_cache[2];
953
0
          dist_cache[2] = dist_cache[1];
954
0
          dist_cache[1] = dist_cache[0];
955
0
          dist_cache[0] = (int)sr.distance;
956
0
          FN(PrepareDistanceCache)(privat, dist_cache);
957
0
        }
958
0
        InitCommand(commands++, &params->dist, insert_length,
959
0
            sr.len, sr.len_code_delta, distance_code);
960
0
      }
961
0
      *num_literals += insert_length;
962
0
      insert_length = 0;
963
      /* Put the hash keys into the table, if there are enough bytes left.
964
         Depending on the hasher implementation, it can push all positions
965
         in the given range or only a subset of them.
966
         Avoid hash poisoning with RLE data. */
967
0
      {
968
0
        size_t range_start = position + 2;
969
0
        size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
970
0
        if (sr.distance < (sr.len >> 2)) {
971
0
          range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
972
0
              range_start, position + sr.len - (sr.distance << 2)));
973
0
        }
974
0
        FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
975
0
                       range_end);
976
0
      }
977
0
      position += sr.len;
978
0
    } else {
979
0
      ++insert_length;
980
0
      ++position;
981
      /* If we have not seen matches for a long time, we can skip some
982
         match lookups. Unsuccessful match lookups are very very expensive
983
         and this kind of a heuristic speeds up compression quite
984
         a lot. */
985
0
      if (position > apply_random_heuristics) {
986
        /* Going through uncompressible data, jump. */
987
0
        if (position >
988
0
            apply_random_heuristics + 4 * random_heuristics_window_size) {
989
          /* It is quite a long time since we saw a copy, so we assume
990
             that this data is not compressible, and store hashes less
991
             often. Hashes of non compressible data are less likely to
992
             turn out to be useful in the future, too, so we store less of
993
             them to not to flood out the hash table of good compressible
994
             data. */
995
0
          const size_t kMargin =
996
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
997
0
          size_t pos_jump =
998
0
              BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
999
0
          for (; position < pos_jump; position += 4) {
1000
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
1001
0
            insert_length += 4;
1002
0
          }
1003
0
        } else {
1004
0
          const size_t kMargin =
1005
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
1006
0
          size_t pos_jump =
1007
0
              BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
1008
0
          for (; position < pos_jump; position += 2) {
1009
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
1010
0
            insert_length += 2;
1011
0
          }
1012
0
        }
1013
0
      }
1014
0
    }
1015
0
  }
1016
0
  insert_length += pos_end - position;
1017
0
  *last_insert_len = insert_length;
1018
0
  *num_commands += (size_t)(commands - orig_commands);
1019
0
}
1020
#undef HASHER
1021
1022
0
#define HASHER() H40
1023
/* NOLINTNEXTLINE(build/include) */
1024
/* NOLINT(build/header_guard) */
1025
/* Copyright 2013 Google Inc. All Rights Reserved.
1026
1027
   Distributed under MIT license.
1028
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
1029
*/
1030
1031
/* template parameters: EXPORT_FN, FN */
1032
1033
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
1034
    size_t num_bytes, size_t position,
1035
    const uint8_t* ringbuffer, size_t ringbuffer_mask,
1036
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
1037
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
1038
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
1039
0
  HASHER()* privat = &hasher->privat.FN(_);
1040
  /* Set maximum distance, see section 9.1. of the spec. */
1041
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
1042
0
  const size_t position_offset = params->stream_offset;
1043
1044
0
  const Command* const orig_commands = commands;
1045
0
  size_t insert_length = *last_insert_len;
1046
0
  const size_t pos_end = position + num_bytes;
1047
0
  const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
1048
0
      position + num_bytes - FN(StoreLookahead)() + 1 : position;
1049
1050
  /* For speed up heuristics for random data. */
1051
0
  const size_t random_heuristics_window_size =
1052
0
      LiteralSpreeLengthForSparseSearch(params);
1053
0
  size_t apply_random_heuristics = position + random_heuristics_window_size;
1054
0
  const size_t gap = params->dictionary.compound.total_size;
1055
1056
  /* Minimum score to accept a backward reference. */
1057
0
  const score_t kMinScore = BROTLI_SCORE_BASE + 100;
1058
1059
0
  FN(PrepareDistanceCache)(privat, dist_cache);
1060
1061
0
  while (position + FN(HashTypeLength)() < pos_end) {
1062
0
    size_t max_length = pos_end - position;
1063
0
    size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
1064
0
    size_t dictionary_start = BROTLI_MIN(size_t,
1065
0
        position + position_offset, max_backward_limit);
1066
0
    HasherSearchResult sr;
1067
0
    int dict_id = 0;
1068
0
    uint8_t p1 = 0;
1069
0
    uint8_t p2 = 0;
1070
0
    if (params->dictionary.contextual.context_based) {
1071
0
      p1 = position >= 1 ?
1072
0
          ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
1073
0
      p2 = position >= 2 ?
1074
0
          ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
1075
0
      dict_id = params->dictionary.contextual.context_map[
1076
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
1077
0
    }
1078
0
    sr.len = 0;
1079
0
    sr.len_code_delta = 0;
1080
0
    sr.distance = 0;
1081
0
    sr.score = kMinScore;
1082
0
    FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
1083
0
        ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
1084
0
        max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
1085
0
    if (ENABLE_COMPOUND_DICTIONARY) {
1086
0
      LookupCompoundDictionaryMatch(&params->dictionary.compound, ringbuffer,
1087
0
          ringbuffer_mask, dist_cache, position, max_length,
1088
0
          dictionary_start, params->dist.max_distance, &sr);
1089
0
    }
1090
0
    if (sr.score > kMinScore) {
1091
      /* Found a match. Let's look for something even better ahead. */
1092
0
      int delayed_backward_references_in_row = 0;
1093
0
      --max_length;
1094
0
      for (;; --max_length) {
1095
0
        const score_t cost_diff_lazy = 175;
1096
0
        HasherSearchResult sr2;
1097
0
        sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
1098
0
            BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
1099
0
        sr2.len_code_delta = 0;
1100
0
        sr2.distance = 0;
1101
0
        sr2.score = kMinScore;
1102
0
        max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
1103
0
        dictionary_start = BROTLI_MIN(size_t,
1104
0
            position + 1 + position_offset, max_backward_limit);
1105
0
        if (params->dictionary.contextual.context_based) {
1106
0
          p2 = p1;
1107
0
          p1 = ringbuffer[position & ringbuffer_mask];
1108
0
          dict_id = params->dictionary.contextual.context_map[
1109
0
              BROTLI_CONTEXT(p1, p2, literal_context_lut)];
1110
0
        }
1111
0
        FN(FindLongestMatch)(privat,
1112
0
            params->dictionary.contextual.dict[dict_id],
1113
0
            ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
1114
0
            max_distance, dictionary_start + gap, params->dist.max_distance,
1115
0
            &sr2);
1116
0
        if (ENABLE_COMPOUND_DICTIONARY) {
1117
0
          LookupCompoundDictionaryMatch(
1118
0
              &params->dictionary.compound, ringbuffer,
1119
0
              ringbuffer_mask, dist_cache, position + 1, max_length,
1120
0
              dictionary_start, params->dist.max_distance, &sr2);
1121
0
        }
1122
0
        if (sr2.score >= sr.score + cost_diff_lazy) {
1123
          /* Ok, let's just write one byte for now and start a match from the
1124
             next byte. */
1125
0
          ++position;
1126
0
          ++insert_length;
1127
0
          sr = sr2;
1128
0
          if (++delayed_backward_references_in_row < 4 &&
1129
0
              position + FN(HashTypeLength)() < pos_end) {
1130
0
            continue;
1131
0
          }
1132
0
        }
1133
0
        break;
1134
0
      }
1135
0
      apply_random_heuristics =
1136
0
          position + 2 * sr.len + random_heuristics_window_size;
1137
0
      dictionary_start = BROTLI_MIN(size_t,
1138
0
          position + position_offset, max_backward_limit);
1139
0
      {
1140
        /* The first 16 codes are special short-codes,
1141
           and the minimum offset is 1. */
1142
0
        size_t distance_code = ComputeDistanceCode(
1143
0
            sr.distance, dictionary_start + gap, dist_cache);
1144
0
        if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
1145
0
          dist_cache[3] = dist_cache[2];
1146
0
          dist_cache[2] = dist_cache[1];
1147
0
          dist_cache[1] = dist_cache[0];
1148
0
          dist_cache[0] = (int)sr.distance;
1149
0
          FN(PrepareDistanceCache)(privat, dist_cache);
1150
0
        }
1151
0
        InitCommand(commands++, &params->dist, insert_length,
1152
0
            sr.len, sr.len_code_delta, distance_code);
1153
0
      }
1154
0
      *num_literals += insert_length;
1155
0
      insert_length = 0;
1156
      /* Put the hash keys into the table, if there are enough bytes left.
1157
         Depending on the hasher implementation, it can push all positions
1158
         in the given range or only a subset of them.
1159
         Avoid hash poisoning with RLE data. */
1160
0
      {
1161
0
        size_t range_start = position + 2;
1162
0
        size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
1163
0
        if (sr.distance < (sr.len >> 2)) {
1164
0
          range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
1165
0
              range_start, position + sr.len - (sr.distance << 2)));
1166
0
        }
1167
0
        FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
1168
0
                       range_end);
1169
0
      }
1170
0
      position += sr.len;
1171
0
    } else {
1172
0
      ++insert_length;
1173
0
      ++position;
1174
      /* If we have not seen matches for a long time, we can skip some
1175
         match lookups. Unsuccessful match lookups are very very expensive
1176
         and this kind of a heuristic speeds up compression quite
1177
         a lot. */
1178
0
      if (position > apply_random_heuristics) {
1179
        /* Going through uncompressible data, jump. */
1180
0
        if (position >
1181
0
            apply_random_heuristics + 4 * random_heuristics_window_size) {
1182
          /* It is quite a long time since we saw a copy, so we assume
1183
             that this data is not compressible, and store hashes less
1184
             often. Hashes of non compressible data are less likely to
1185
             turn out to be useful in the future, too, so we store less of
1186
             them to not to flood out the hash table of good compressible
1187
             data. */
1188
0
          const size_t kMargin =
1189
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
1190
0
          size_t pos_jump =
1191
0
              BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
1192
0
          for (; position < pos_jump; position += 4) {
1193
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
1194
0
            insert_length += 4;
1195
0
          }
1196
0
        } else {
1197
0
          const size_t kMargin =
1198
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
1199
0
          size_t pos_jump =
1200
0
              BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
1201
0
          for (; position < pos_jump; position += 2) {
1202
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
1203
0
            insert_length += 2;
1204
0
          }
1205
0
        }
1206
0
      }
1207
0
    }
1208
0
  }
1209
0
  insert_length += pos_end - position;
1210
0
  *last_insert_len = insert_length;
1211
0
  *num_commands += (size_t)(commands - orig_commands);
1212
0
}
1213
#undef HASHER
1214
1215
0
#define HASHER() H41
1216
/* NOLINTNEXTLINE(build/include) */
1217
/* NOLINT(build/header_guard) */
1218
/* Copyright 2013 Google Inc. All Rights Reserved.
1219
1220
   Distributed under MIT license.
1221
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
1222
*/
1223
1224
/* template parameters: EXPORT_FN, FN */
1225
1226
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
1227
    size_t num_bytes, size_t position,
1228
    const uint8_t* ringbuffer, size_t ringbuffer_mask,
1229
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
1230
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
1231
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
1232
0
  HASHER()* privat = &hasher->privat.FN(_);
1233
  /* Set maximum distance, see section 9.1. of the spec. */
1234
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
1235
0
  const size_t position_offset = params->stream_offset;
1236
1237
0
  const Command* const orig_commands = commands;
1238
0
  size_t insert_length = *last_insert_len;
1239
0
  const size_t pos_end = position + num_bytes;
1240
0
  const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
1241
0
      position + num_bytes - FN(StoreLookahead)() + 1 : position;
1242
1243
  /* For speed up heuristics for random data. */
1244
0
  const size_t random_heuristics_window_size =
1245
0
      LiteralSpreeLengthForSparseSearch(params);
1246
0
  size_t apply_random_heuristics = position + random_heuristics_window_size;
1247
0
  const size_t gap = params->dictionary.compound.total_size;
1248
1249
  /* Minimum score to accept a backward reference. */
1250
0
  const score_t kMinScore = BROTLI_SCORE_BASE + 100;
1251
1252
0
  FN(PrepareDistanceCache)(privat, dist_cache);
1253
1254
0
  while (position + FN(HashTypeLength)() < pos_end) {
1255
0
    size_t max_length = pos_end - position;
1256
0
    size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
1257
0
    size_t dictionary_start = BROTLI_MIN(size_t,
1258
0
        position + position_offset, max_backward_limit);
1259
0
    HasherSearchResult sr;
1260
0
    int dict_id = 0;
1261
0
    uint8_t p1 = 0;
1262
0
    uint8_t p2 = 0;
1263
0
    if (params->dictionary.contextual.context_based) {
1264
0
      p1 = position >= 1 ?
1265
0
          ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
1266
0
      p2 = position >= 2 ?
1267
0
          ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
1268
0
      dict_id = params->dictionary.contextual.context_map[
1269
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
1270
0
    }
1271
0
    sr.len = 0;
1272
0
    sr.len_code_delta = 0;
1273
0
    sr.distance = 0;
1274
0
    sr.score = kMinScore;
1275
0
    FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
1276
0
        ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
1277
0
        max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
1278
0
    if (ENABLE_COMPOUND_DICTIONARY) {
1279
0
      LookupCompoundDictionaryMatch(&params->dictionary.compound, ringbuffer,
1280
0
          ringbuffer_mask, dist_cache, position, max_length,
1281
0
          dictionary_start, params->dist.max_distance, &sr);
1282
0
    }
1283
0
    if (sr.score > kMinScore) {
1284
      /* Found a match. Let's look for something even better ahead. */
1285
0
      int delayed_backward_references_in_row = 0;
1286
0
      --max_length;
1287
0
      for (;; --max_length) {
1288
0
        const score_t cost_diff_lazy = 175;
1289
0
        HasherSearchResult sr2;
1290
0
        sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
1291
0
            BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
1292
0
        sr2.len_code_delta = 0;
1293
0
        sr2.distance = 0;
1294
0
        sr2.score = kMinScore;
1295
0
        max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
1296
0
        dictionary_start = BROTLI_MIN(size_t,
1297
0
            position + 1 + position_offset, max_backward_limit);
1298
0
        if (params->dictionary.contextual.context_based) {
1299
0
          p2 = p1;
1300
0
          p1 = ringbuffer[position & ringbuffer_mask];
1301
0
          dict_id = params->dictionary.contextual.context_map[
1302
0
              BROTLI_CONTEXT(p1, p2, literal_context_lut)];
1303
0
        }
1304
0
        FN(FindLongestMatch)(privat,
1305
0
            params->dictionary.contextual.dict[dict_id],
1306
0
            ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
1307
0
            max_distance, dictionary_start + gap, params->dist.max_distance,
1308
0
            &sr2);
1309
0
        if (ENABLE_COMPOUND_DICTIONARY) {
1310
0
          LookupCompoundDictionaryMatch(
1311
0
              &params->dictionary.compound, ringbuffer,
1312
0
              ringbuffer_mask, dist_cache, position + 1, max_length,
1313
0
              dictionary_start, params->dist.max_distance, &sr2);
1314
0
        }
1315
0
        if (sr2.score >= sr.score + cost_diff_lazy) {
1316
          /* Ok, let's just write one byte for now and start a match from the
1317
             next byte. */
1318
0
          ++position;
1319
0
          ++insert_length;
1320
0
          sr = sr2;
1321
0
          if (++delayed_backward_references_in_row < 4 &&
1322
0
              position + FN(HashTypeLength)() < pos_end) {
1323
0
            continue;
1324
0
          }
1325
0
        }
1326
0
        break;
1327
0
      }
1328
0
      apply_random_heuristics =
1329
0
          position + 2 * sr.len + random_heuristics_window_size;
1330
0
      dictionary_start = BROTLI_MIN(size_t,
1331
0
          position + position_offset, max_backward_limit);
1332
0
      {
1333
        /* The first 16 codes are special short-codes,
1334
           and the minimum offset is 1. */
1335
0
        size_t distance_code = ComputeDistanceCode(
1336
0
            sr.distance, dictionary_start + gap, dist_cache);
1337
0
        if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
1338
0
          dist_cache[3] = dist_cache[2];
1339
0
          dist_cache[2] = dist_cache[1];
1340
0
          dist_cache[1] = dist_cache[0];
1341
0
          dist_cache[0] = (int)sr.distance;
1342
0
          FN(PrepareDistanceCache)(privat, dist_cache);
1343
0
        }
1344
0
        InitCommand(commands++, &params->dist, insert_length,
1345
0
            sr.len, sr.len_code_delta, distance_code);
1346
0
      }
1347
0
      *num_literals += insert_length;
1348
0
      insert_length = 0;
1349
      /* Put the hash keys into the table, if there are enough bytes left.
1350
         Depending on the hasher implementation, it can push all positions
1351
         in the given range or only a subset of them.
1352
         Avoid hash poisoning with RLE data. */
1353
0
      {
1354
0
        size_t range_start = position + 2;
1355
0
        size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
1356
0
        if (sr.distance < (sr.len >> 2)) {
1357
0
          range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
1358
0
              range_start, position + sr.len - (sr.distance << 2)));
1359
0
        }
1360
0
        FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
1361
0
                       range_end);
1362
0
      }
1363
0
      position += sr.len;
1364
0
    } else {
1365
0
      ++insert_length;
1366
0
      ++position;
1367
      /* If we have not seen matches for a long time, we can skip some
1368
         match lookups. Unsuccessful match lookups are very very expensive
1369
         and this kind of a heuristic speeds up compression quite
1370
         a lot. */
1371
0
      if (position > apply_random_heuristics) {
1372
        /* Going through uncompressible data, jump. */
1373
0
        if (position >
1374
0
            apply_random_heuristics + 4 * random_heuristics_window_size) {
1375
          /* It is quite a long time since we saw a copy, so we assume
1376
             that this data is not compressible, and store hashes less
1377
             often. Hashes of non compressible data are less likely to
1378
             turn out to be useful in the future, too, so we store less of
1379
             them to not to flood out the hash table of good compressible
1380
             data. */
1381
0
          const size_t kMargin =
1382
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
1383
0
          size_t pos_jump =
1384
0
              BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
1385
0
          for (; position < pos_jump; position += 4) {
1386
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
1387
0
            insert_length += 4;
1388
0
          }
1389
0
        } else {
1390
0
          const size_t kMargin =
1391
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
1392
0
          size_t pos_jump =
1393
0
              BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
1394
0
          for (; position < pos_jump; position += 2) {
1395
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
1396
0
            insert_length += 2;
1397
0
          }
1398
0
        }
1399
0
      }
1400
0
    }
1401
0
  }
1402
0
  insert_length += pos_end - position;
1403
0
  *last_insert_len = insert_length;
1404
0
  *num_commands += (size_t)(commands - orig_commands);
1405
0
}
1406
#undef HASHER
1407
1408
0
#define HASHER() H42
1409
/* NOLINTNEXTLINE(build/include) */
1410
/* NOLINT(build/header_guard) */
1411
/* Copyright 2013 Google Inc. All Rights Reserved.
1412
1413
   Distributed under MIT license.
1414
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
1415
*/
1416
1417
/* template parameters: EXPORT_FN, FN */
1418
1419
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
1420
    size_t num_bytes, size_t position,
1421
    const uint8_t* ringbuffer, size_t ringbuffer_mask,
1422
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
1423
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
1424
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
1425
0
  HASHER()* privat = &hasher->privat.FN(_);
1426
  /* Set maximum distance, see section 9.1. of the spec. */
1427
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
1428
0
  const size_t position_offset = params->stream_offset;
1429
1430
0
  const Command* const orig_commands = commands;
1431
0
  size_t insert_length = *last_insert_len;
1432
0
  const size_t pos_end = position + num_bytes;
1433
0
  const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
1434
0
      position + num_bytes - FN(StoreLookahead)() + 1 : position;
1435
1436
  /* For speed up heuristics for random data. */
1437
0
  const size_t random_heuristics_window_size =
1438
0
      LiteralSpreeLengthForSparseSearch(params);
1439
0
  size_t apply_random_heuristics = position + random_heuristics_window_size;
1440
0
  const size_t gap = params->dictionary.compound.total_size;
1441
1442
  /* Minimum score to accept a backward reference. */
1443
0
  const score_t kMinScore = BROTLI_SCORE_BASE + 100;
1444
1445
0
  FN(PrepareDistanceCache)(privat, dist_cache);
1446
1447
0
  while (position + FN(HashTypeLength)() < pos_end) {
1448
0
    size_t max_length = pos_end - position;
1449
0
    size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
1450
0
    size_t dictionary_start = BROTLI_MIN(size_t,
1451
0
        position + position_offset, max_backward_limit);
1452
0
    HasherSearchResult sr;
1453
0
    int dict_id = 0;
1454
0
    uint8_t p1 = 0;
1455
0
    uint8_t p2 = 0;
1456
0
    if (params->dictionary.contextual.context_based) {
1457
0
      p1 = position >= 1 ?
1458
0
          ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
1459
0
      p2 = position >= 2 ?
1460
0
          ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
1461
0
      dict_id = params->dictionary.contextual.context_map[
1462
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
1463
0
    }
1464
0
    sr.len = 0;
1465
0
    sr.len_code_delta = 0;
1466
0
    sr.distance = 0;
1467
0
    sr.score = kMinScore;
1468
0
    FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
1469
0
        ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
1470
0
        max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
1471
0
    if (ENABLE_COMPOUND_DICTIONARY) {
1472
0
      LookupCompoundDictionaryMatch(&params->dictionary.compound, ringbuffer,
1473
0
          ringbuffer_mask, dist_cache, position, max_length,
1474
0
          dictionary_start, params->dist.max_distance, &sr);
1475
0
    }
1476
0
    if (sr.score > kMinScore) {
1477
      /* Found a match. Let's look for something even better ahead. */
1478
0
      int delayed_backward_references_in_row = 0;
1479
0
      --max_length;
1480
0
      for (;; --max_length) {
1481
0
        const score_t cost_diff_lazy = 175;
1482
0
        HasherSearchResult sr2;
1483
0
        sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
1484
0
            BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
1485
0
        sr2.len_code_delta = 0;
1486
0
        sr2.distance = 0;
1487
0
        sr2.score = kMinScore;
1488
0
        max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
1489
0
        dictionary_start = BROTLI_MIN(size_t,
1490
0
            position + 1 + position_offset, max_backward_limit);
1491
0
        if (params->dictionary.contextual.context_based) {
1492
0
          p2 = p1;
1493
0
          p1 = ringbuffer[position & ringbuffer_mask];
1494
0
          dict_id = params->dictionary.contextual.context_map[
1495
0
              BROTLI_CONTEXT(p1, p2, literal_context_lut)];
1496
0
        }
1497
0
        FN(FindLongestMatch)(privat,
1498
0
            params->dictionary.contextual.dict[dict_id],
1499
0
            ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
1500
0
            max_distance, dictionary_start + gap, params->dist.max_distance,
1501
0
            &sr2);
1502
0
        if (ENABLE_COMPOUND_DICTIONARY) {
1503
0
          LookupCompoundDictionaryMatch(
1504
0
              &params->dictionary.compound, ringbuffer,
1505
0
              ringbuffer_mask, dist_cache, position + 1, max_length,
1506
0
              dictionary_start, params->dist.max_distance, &sr2);
1507
0
        }
1508
0
        if (sr2.score >= sr.score + cost_diff_lazy) {
1509
          /* Ok, let's just write one byte for now and start a match from the
1510
             next byte. */
1511
0
          ++position;
1512
0
          ++insert_length;
1513
0
          sr = sr2;
1514
0
          if (++delayed_backward_references_in_row < 4 &&
1515
0
              position + FN(HashTypeLength)() < pos_end) {
1516
0
            continue;
1517
0
          }
1518
0
        }
1519
0
        break;
1520
0
      }
1521
0
      apply_random_heuristics =
1522
0
          position + 2 * sr.len + random_heuristics_window_size;
1523
0
      dictionary_start = BROTLI_MIN(size_t,
1524
0
          position + position_offset, max_backward_limit);
1525
0
      {
1526
        /* The first 16 codes are special short-codes,
1527
           and the minimum offset is 1. */
1528
0
        size_t distance_code = ComputeDistanceCode(
1529
0
            sr.distance, dictionary_start + gap, dist_cache);
1530
0
        if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
1531
0
          dist_cache[3] = dist_cache[2];
1532
0
          dist_cache[2] = dist_cache[1];
1533
0
          dist_cache[1] = dist_cache[0];
1534
0
          dist_cache[0] = (int)sr.distance;
1535
0
          FN(PrepareDistanceCache)(privat, dist_cache);
1536
0
        }
1537
0
        InitCommand(commands++, &params->dist, insert_length,
1538
0
            sr.len, sr.len_code_delta, distance_code);
1539
0
      }
1540
0
      *num_literals += insert_length;
1541
0
      insert_length = 0;
1542
      /* Put the hash keys into the table, if there are enough bytes left.
1543
         Depending on the hasher implementation, it can push all positions
1544
         in the given range or only a subset of them.
1545
         Avoid hash poisoning with RLE data. */
1546
0
      {
1547
0
        size_t range_start = position + 2;
1548
0
        size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
1549
0
        if (sr.distance < (sr.len >> 2)) {
1550
0
          range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
1551
0
              range_start, position + sr.len - (sr.distance << 2)));
1552
0
        }
1553
0
        FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
1554
0
                       range_end);
1555
0
      }
1556
0
      position += sr.len;
1557
0
    } else {
1558
0
      ++insert_length;
1559
0
      ++position;
1560
      /* If we have not seen matches for a long time, we can skip some
1561
         match lookups. Unsuccessful match lookups are very very expensive
1562
         and this kind of a heuristic speeds up compression quite
1563
         a lot. */
1564
0
      if (position > apply_random_heuristics) {
1565
        /* Going through uncompressible data, jump. */
1566
0
        if (position >
1567
0
            apply_random_heuristics + 4 * random_heuristics_window_size) {
1568
          /* It is quite a long time since we saw a copy, so we assume
1569
             that this data is not compressible, and store hashes less
1570
             often. Hashes of non compressible data are less likely to
1571
             turn out to be useful in the future, too, so we store less of
1572
             them to not to flood out the hash table of good compressible
1573
             data. */
1574
0
          const size_t kMargin =
1575
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
1576
0
          size_t pos_jump =
1577
0
              BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
1578
0
          for (; position < pos_jump; position += 4) {
1579
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
1580
0
            insert_length += 4;
1581
0
          }
1582
0
        } else {
1583
0
          const size_t kMargin =
1584
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
1585
0
          size_t pos_jump =
1586
0
              BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
1587
0
          for (; position < pos_jump; position += 2) {
1588
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
1589
0
            insert_length += 2;
1590
0
          }
1591
0
        }
1592
0
      }
1593
0
    }
1594
0
  }
1595
0
  insert_length += pos_end - position;
1596
0
  *last_insert_len = insert_length;
1597
0
  *num_commands += (size_t)(commands - orig_commands);
1598
0
}
1599
#undef HASHER
1600
1601
0
#define HASHER() H54
1602
/* NOLINTNEXTLINE(build/include) */
1603
/* NOLINT(build/header_guard) */
1604
/* Copyright 2013 Google Inc. All Rights Reserved.
1605
1606
   Distributed under MIT license.
1607
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
1608
*/
1609
1610
/* template parameters: EXPORT_FN, FN */
1611
1612
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
1613
    size_t num_bytes, size_t position,
1614
    const uint8_t* ringbuffer, size_t ringbuffer_mask,
1615
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
1616
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
1617
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
1618
0
  HASHER()* privat = &hasher->privat.FN(_);
1619
  /* Set maximum distance, see section 9.1. of the spec. */
1620
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
1621
0
  const size_t position_offset = params->stream_offset;
1622
1623
0
  const Command* const orig_commands = commands;
1624
0
  size_t insert_length = *last_insert_len;
1625
0
  const size_t pos_end = position + num_bytes;
1626
0
  const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
1627
0
      position + num_bytes - FN(StoreLookahead)() + 1 : position;
1628
1629
  /* For speed up heuristics for random data. */
1630
0
  const size_t random_heuristics_window_size =
1631
0
      LiteralSpreeLengthForSparseSearch(params);
1632
0
  size_t apply_random_heuristics = position + random_heuristics_window_size;
1633
0
  const size_t gap = params->dictionary.compound.total_size;
1634
1635
  /* Minimum score to accept a backward reference. */
1636
0
  const score_t kMinScore = BROTLI_SCORE_BASE + 100;
1637
1638
0
  FN(PrepareDistanceCache)(privat, dist_cache);
1639
1640
0
  while (position + FN(HashTypeLength)() < pos_end) {
1641
0
    size_t max_length = pos_end - position;
1642
0
    size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
1643
0
    size_t dictionary_start = BROTLI_MIN(size_t,
1644
0
        position + position_offset, max_backward_limit);
1645
0
    HasherSearchResult sr;
1646
0
    int dict_id = 0;
1647
0
    uint8_t p1 = 0;
1648
0
    uint8_t p2 = 0;
1649
0
    if (params->dictionary.contextual.context_based) {
1650
0
      p1 = position >= 1 ?
1651
0
          ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
1652
0
      p2 = position >= 2 ?
1653
0
          ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
1654
0
      dict_id = params->dictionary.contextual.context_map[
1655
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
1656
0
    }
1657
0
    sr.len = 0;
1658
0
    sr.len_code_delta = 0;
1659
0
    sr.distance = 0;
1660
0
    sr.score = kMinScore;
1661
0
    FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
1662
0
        ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
1663
0
        max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
1664
0
    if (ENABLE_COMPOUND_DICTIONARY) {
1665
0
      LookupCompoundDictionaryMatch(&params->dictionary.compound, ringbuffer,
1666
0
          ringbuffer_mask, dist_cache, position, max_length,
1667
0
          dictionary_start, params->dist.max_distance, &sr);
1668
0
    }
1669
0
    if (sr.score > kMinScore) {
1670
      /* Found a match. Let's look for something even better ahead. */
1671
0
      int delayed_backward_references_in_row = 0;
1672
0
      --max_length;
1673
0
      for (;; --max_length) {
1674
0
        const score_t cost_diff_lazy = 175;
1675
0
        HasherSearchResult sr2;
1676
0
        sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
1677
0
            BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
1678
0
        sr2.len_code_delta = 0;
1679
0
        sr2.distance = 0;
1680
0
        sr2.score = kMinScore;
1681
0
        max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
1682
0
        dictionary_start = BROTLI_MIN(size_t,
1683
0
            position + 1 + position_offset, max_backward_limit);
1684
0
        if (params->dictionary.contextual.context_based) {
1685
0
          p2 = p1;
1686
0
          p1 = ringbuffer[position & ringbuffer_mask];
1687
0
          dict_id = params->dictionary.contextual.context_map[
1688
0
              BROTLI_CONTEXT(p1, p2, literal_context_lut)];
1689
0
        }
1690
0
        FN(FindLongestMatch)(privat,
1691
0
            params->dictionary.contextual.dict[dict_id],
1692
0
            ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
1693
0
            max_distance, dictionary_start + gap, params->dist.max_distance,
1694
0
            &sr2);
1695
0
        if (ENABLE_COMPOUND_DICTIONARY) {
1696
0
          LookupCompoundDictionaryMatch(
1697
0
              &params->dictionary.compound, ringbuffer,
1698
0
              ringbuffer_mask, dist_cache, position + 1, max_length,
1699
0
              dictionary_start, params->dist.max_distance, &sr2);
1700
0
        }
1701
0
        if (sr2.score >= sr.score + cost_diff_lazy) {
1702
          /* Ok, let's just write one byte for now and start a match from the
1703
             next byte. */
1704
0
          ++position;
1705
0
          ++insert_length;
1706
0
          sr = sr2;
1707
0
          if (++delayed_backward_references_in_row < 4 &&
1708
0
              position + FN(HashTypeLength)() < pos_end) {
1709
0
            continue;
1710
0
          }
1711
0
        }
1712
0
        break;
1713
0
      }
1714
0
      apply_random_heuristics =
1715
0
          position + 2 * sr.len + random_heuristics_window_size;
1716
0
      dictionary_start = BROTLI_MIN(size_t,
1717
0
          position + position_offset, max_backward_limit);
1718
0
      {
1719
        /* The first 16 codes are special short-codes,
1720
           and the minimum offset is 1. */
1721
0
        size_t distance_code = ComputeDistanceCode(
1722
0
            sr.distance, dictionary_start + gap, dist_cache);
1723
0
        if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
1724
0
          dist_cache[3] = dist_cache[2];
1725
0
          dist_cache[2] = dist_cache[1];
1726
0
          dist_cache[1] = dist_cache[0];
1727
0
          dist_cache[0] = (int)sr.distance;
1728
0
          FN(PrepareDistanceCache)(privat, dist_cache);
1729
0
        }
1730
0
        InitCommand(commands++, &params->dist, insert_length,
1731
0
            sr.len, sr.len_code_delta, distance_code);
1732
0
      }
1733
0
      *num_literals += insert_length;
1734
0
      insert_length = 0;
1735
      /* Put the hash keys into the table, if there are enough bytes left.
1736
         Depending on the hasher implementation, it can push all positions
1737
         in the given range or only a subset of them.
1738
         Avoid hash poisoning with RLE data. */
1739
0
      {
1740
0
        size_t range_start = position + 2;
1741
0
        size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
1742
0
        if (sr.distance < (sr.len >> 2)) {
1743
0
          range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
1744
0
              range_start, position + sr.len - (sr.distance << 2)));
1745
0
        }
1746
0
        FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
1747
0
                       range_end);
1748
0
      }
1749
0
      position += sr.len;
1750
0
    } else {
1751
0
      ++insert_length;
1752
0
      ++position;
1753
      /* If we have not seen matches for a long time, we can skip some
1754
         match lookups. Unsuccessful match lookups are very very expensive
1755
         and this kind of a heuristic speeds up compression quite
1756
         a lot. */
1757
0
      if (position > apply_random_heuristics) {
1758
        /* Going through uncompressible data, jump. */
1759
0
        if (position >
1760
0
            apply_random_heuristics + 4 * random_heuristics_window_size) {
1761
          /* It is quite a long time since we saw a copy, so we assume
1762
             that this data is not compressible, and store hashes less
1763
             often. Hashes of non compressible data are less likely to
1764
             turn out to be useful in the future, too, so we store less of
1765
             them to not to flood out the hash table of good compressible
1766
             data. */
1767
0
          const size_t kMargin =
1768
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
1769
0
          size_t pos_jump =
1770
0
              BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
1771
0
          for (; position < pos_jump; position += 4) {
1772
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
1773
0
            insert_length += 4;
1774
0
          }
1775
0
        } else {
1776
0
          const size_t kMargin =
1777
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
1778
0
          size_t pos_jump =
1779
0
              BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
1780
0
          for (; position < pos_jump; position += 2) {
1781
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
1782
0
            insert_length += 2;
1783
0
          }
1784
0
        }
1785
0
      }
1786
0
    }
1787
0
  }
1788
0
  insert_length += pos_end - position;
1789
0
  *last_insert_len = insert_length;
1790
0
  *num_commands += (size_t)(commands - orig_commands);
1791
0
}
1792
#undef HASHER
1793
1794
0
#define HASHER() H35
1795
/* NOLINTNEXTLINE(build/include) */
1796
/* NOLINT(build/header_guard) */
1797
/* Copyright 2013 Google Inc. All Rights Reserved.
1798
1799
   Distributed under MIT license.
1800
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
1801
*/
1802
1803
/* template parameters: EXPORT_FN, FN */
1804
1805
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
1806
    size_t num_bytes, size_t position,
1807
    const uint8_t* ringbuffer, size_t ringbuffer_mask,
1808
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
1809
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
1810
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
1811
0
  HASHER()* privat = &hasher->privat.FN(_);
1812
  /* Set maximum distance, see section 9.1. of the spec. */
1813
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
1814
0
  const size_t position_offset = params->stream_offset;
1815
1816
0
  const Command* const orig_commands = commands;
1817
0
  size_t insert_length = *last_insert_len;
1818
0
  const size_t pos_end = position + num_bytes;
1819
0
  const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
1820
0
      position + num_bytes - FN(StoreLookahead)() + 1 : position;
1821
1822
  /* For speed up heuristics for random data. */
1823
0
  const size_t random_heuristics_window_size =
1824
0
      LiteralSpreeLengthForSparseSearch(params);
1825
0
  size_t apply_random_heuristics = position + random_heuristics_window_size;
1826
0
  const size_t gap = params->dictionary.compound.total_size;
1827
1828
  /* Minimum score to accept a backward reference. */
1829
0
  const score_t kMinScore = BROTLI_SCORE_BASE + 100;
1830
1831
0
  FN(PrepareDistanceCache)(privat, dist_cache);
1832
1833
0
  while (position + FN(HashTypeLength)() < pos_end) {
1834
0
    size_t max_length = pos_end - position;
1835
0
    size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
1836
0
    size_t dictionary_start = BROTLI_MIN(size_t,
1837
0
        position + position_offset, max_backward_limit);
1838
0
    HasherSearchResult sr;
1839
0
    int dict_id = 0;
1840
0
    uint8_t p1 = 0;
1841
0
    uint8_t p2 = 0;
1842
0
    if (params->dictionary.contextual.context_based) {
1843
0
      p1 = position >= 1 ?
1844
0
          ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
1845
0
      p2 = position >= 2 ?
1846
0
          ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
1847
0
      dict_id = params->dictionary.contextual.context_map[
1848
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
1849
0
    }
1850
0
    sr.len = 0;
1851
0
    sr.len_code_delta = 0;
1852
0
    sr.distance = 0;
1853
0
    sr.score = kMinScore;
1854
0
    FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
1855
0
        ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
1856
0
        max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
1857
0
    if (ENABLE_COMPOUND_DICTIONARY) {
1858
0
      LookupCompoundDictionaryMatch(&params->dictionary.compound, ringbuffer,
1859
0
          ringbuffer_mask, dist_cache, position, max_length,
1860
0
          dictionary_start, params->dist.max_distance, &sr);
1861
0
    }
1862
0
    if (sr.score > kMinScore) {
1863
      /* Found a match. Let's look for something even better ahead. */
1864
0
      int delayed_backward_references_in_row = 0;
1865
0
      --max_length;
1866
0
      for (;; --max_length) {
1867
0
        const score_t cost_diff_lazy = 175;
1868
0
        HasherSearchResult sr2;
1869
0
        sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
1870
0
            BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
1871
0
        sr2.len_code_delta = 0;
1872
0
        sr2.distance = 0;
1873
0
        sr2.score = kMinScore;
1874
0
        max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
1875
0
        dictionary_start = BROTLI_MIN(size_t,
1876
0
            position + 1 + position_offset, max_backward_limit);
1877
0
        if (params->dictionary.contextual.context_based) {
1878
0
          p2 = p1;
1879
0
          p1 = ringbuffer[position & ringbuffer_mask];
1880
0
          dict_id = params->dictionary.contextual.context_map[
1881
0
              BROTLI_CONTEXT(p1, p2, literal_context_lut)];
1882
0
        }
1883
0
        FN(FindLongestMatch)(privat,
1884
0
            params->dictionary.contextual.dict[dict_id],
1885
0
            ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
1886
0
            max_distance, dictionary_start + gap, params->dist.max_distance,
1887
0
            &sr2);
1888
0
        if (ENABLE_COMPOUND_DICTIONARY) {
1889
0
          LookupCompoundDictionaryMatch(
1890
0
              &params->dictionary.compound, ringbuffer,
1891
0
              ringbuffer_mask, dist_cache, position + 1, max_length,
1892
0
              dictionary_start, params->dist.max_distance, &sr2);
1893
0
        }
1894
0
        if (sr2.score >= sr.score + cost_diff_lazy) {
1895
          /* Ok, let's just write one byte for now and start a match from the
1896
             next byte. */
1897
0
          ++position;
1898
0
          ++insert_length;
1899
0
          sr = sr2;
1900
0
          if (++delayed_backward_references_in_row < 4 &&
1901
0
              position + FN(HashTypeLength)() < pos_end) {
1902
0
            continue;
1903
0
          }
1904
0
        }
1905
0
        break;
1906
0
      }
1907
0
      apply_random_heuristics =
1908
0
          position + 2 * sr.len + random_heuristics_window_size;
1909
0
      dictionary_start = BROTLI_MIN(size_t,
1910
0
          position + position_offset, max_backward_limit);
1911
0
      {
1912
        /* The first 16 codes are special short-codes,
1913
           and the minimum offset is 1. */
1914
0
        size_t distance_code = ComputeDistanceCode(
1915
0
            sr.distance, dictionary_start + gap, dist_cache);
1916
0
        if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
1917
0
          dist_cache[3] = dist_cache[2];
1918
0
          dist_cache[2] = dist_cache[1];
1919
0
          dist_cache[1] = dist_cache[0];
1920
0
          dist_cache[0] = (int)sr.distance;
1921
0
          FN(PrepareDistanceCache)(privat, dist_cache);
1922
0
        }
1923
0
        InitCommand(commands++, &params->dist, insert_length,
1924
0
            sr.len, sr.len_code_delta, distance_code);
1925
0
      }
1926
0
      *num_literals += insert_length;
1927
0
      insert_length = 0;
1928
      /* Put the hash keys into the table, if there are enough bytes left.
1929
         Depending on the hasher implementation, it can push all positions
1930
         in the given range or only a subset of them.
1931
         Avoid hash poisoning with RLE data. */
1932
0
      {
1933
0
        size_t range_start = position + 2;
1934
0
        size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
1935
0
        if (sr.distance < (sr.len >> 2)) {
1936
0
          range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
1937
0
              range_start, position + sr.len - (sr.distance << 2)));
1938
0
        }
1939
0
        FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
1940
0
                       range_end);
1941
0
      }
1942
0
      position += sr.len;
1943
0
    } else {
1944
0
      ++insert_length;
1945
0
      ++position;
1946
      /* If we have not seen matches for a long time, we can skip some
1947
         match lookups. Unsuccessful match lookups are very very expensive
1948
         and this kind of a heuristic speeds up compression quite
1949
         a lot. */
1950
0
      if (position > apply_random_heuristics) {
1951
        /* Going through uncompressible data, jump. */
1952
0
        if (position >
1953
0
            apply_random_heuristics + 4 * random_heuristics_window_size) {
1954
          /* It is quite a long time since we saw a copy, so we assume
1955
             that this data is not compressible, and store hashes less
1956
             often. Hashes of non compressible data are less likely to
1957
             turn out to be useful in the future, too, so we store less of
1958
             them to not to flood out the hash table of good compressible
1959
             data. */
1960
0
          const size_t kMargin =
1961
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
1962
0
          size_t pos_jump =
1963
0
              BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
1964
0
          for (; position < pos_jump; position += 4) {
1965
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
1966
0
            insert_length += 4;
1967
0
          }
1968
0
        } else {
1969
0
          const size_t kMargin =
1970
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
1971
0
          size_t pos_jump =
1972
0
              BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
1973
0
          for (; position < pos_jump; position += 2) {
1974
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
1975
0
            insert_length += 2;
1976
0
          }
1977
0
        }
1978
0
      }
1979
0
    }
1980
0
  }
1981
0
  insert_length += pos_end - position;
1982
0
  *last_insert_len = insert_length;
1983
0
  *num_commands += (size_t)(commands - orig_commands);
1984
0
}
1985
#undef HASHER
1986
1987
0
#define HASHER() H55
1988
/* NOLINTNEXTLINE(build/include) */
1989
/* NOLINT(build/header_guard) */
1990
/* Copyright 2013 Google Inc. All Rights Reserved.
1991
1992
   Distributed under MIT license.
1993
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
1994
*/
1995
1996
/* template parameters: EXPORT_FN, FN */
1997
1998
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
1999
    size_t num_bytes, size_t position,
2000
    const uint8_t* ringbuffer, size_t ringbuffer_mask,
2001
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
2002
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
2003
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
2004
0
  HASHER()* privat = &hasher->privat.FN(_);
2005
  /* Set maximum distance, see section 9.1. of the spec. */
2006
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
2007
0
  const size_t position_offset = params->stream_offset;
2008
2009
0
  const Command* const orig_commands = commands;
2010
0
  size_t insert_length = *last_insert_len;
2011
0
  const size_t pos_end = position + num_bytes;
2012
0
  const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
2013
0
      position + num_bytes - FN(StoreLookahead)() + 1 : position;
2014
2015
  /* For speed up heuristics for random data. */
2016
0
  const size_t random_heuristics_window_size =
2017
0
      LiteralSpreeLengthForSparseSearch(params);
2018
0
  size_t apply_random_heuristics = position + random_heuristics_window_size;
2019
0
  const size_t gap = params->dictionary.compound.total_size;
2020
2021
  /* Minimum score to accept a backward reference. */
2022
0
  const score_t kMinScore = BROTLI_SCORE_BASE + 100;
2023
2024
0
  FN(PrepareDistanceCache)(privat, dist_cache);
2025
2026
0
  while (position + FN(HashTypeLength)() < pos_end) {
2027
0
    size_t max_length = pos_end - position;
2028
0
    size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
2029
0
    size_t dictionary_start = BROTLI_MIN(size_t,
2030
0
        position + position_offset, max_backward_limit);
2031
0
    HasherSearchResult sr;
2032
0
    int dict_id = 0;
2033
0
    uint8_t p1 = 0;
2034
0
    uint8_t p2 = 0;
2035
0
    if (params->dictionary.contextual.context_based) {
2036
0
      p1 = position >= 1 ?
2037
0
          ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
2038
0
      p2 = position >= 2 ?
2039
0
          ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
2040
0
      dict_id = params->dictionary.contextual.context_map[
2041
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
2042
0
    }
2043
0
    sr.len = 0;
2044
0
    sr.len_code_delta = 0;
2045
0
    sr.distance = 0;
2046
0
    sr.score = kMinScore;
2047
0
    FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
2048
0
        ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
2049
0
        max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
2050
0
    if (ENABLE_COMPOUND_DICTIONARY) {
2051
0
      LookupCompoundDictionaryMatch(&params->dictionary.compound, ringbuffer,
2052
0
          ringbuffer_mask, dist_cache, position, max_length,
2053
0
          dictionary_start, params->dist.max_distance, &sr);
2054
0
    }
2055
0
    if (sr.score > kMinScore) {
2056
      /* Found a match. Let's look for something even better ahead. */
2057
0
      int delayed_backward_references_in_row = 0;
2058
0
      --max_length;
2059
0
      for (;; --max_length) {
2060
0
        const score_t cost_diff_lazy = 175;
2061
0
        HasherSearchResult sr2;
2062
0
        sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
2063
0
            BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
2064
0
        sr2.len_code_delta = 0;
2065
0
        sr2.distance = 0;
2066
0
        sr2.score = kMinScore;
2067
0
        max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
2068
0
        dictionary_start = BROTLI_MIN(size_t,
2069
0
            position + 1 + position_offset, max_backward_limit);
2070
0
        if (params->dictionary.contextual.context_based) {
2071
0
          p2 = p1;
2072
0
          p1 = ringbuffer[position & ringbuffer_mask];
2073
0
          dict_id = params->dictionary.contextual.context_map[
2074
0
              BROTLI_CONTEXT(p1, p2, literal_context_lut)];
2075
0
        }
2076
0
        FN(FindLongestMatch)(privat,
2077
0
            params->dictionary.contextual.dict[dict_id],
2078
0
            ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
2079
0
            max_distance, dictionary_start + gap, params->dist.max_distance,
2080
0
            &sr2);
2081
0
        if (ENABLE_COMPOUND_DICTIONARY) {
2082
0
          LookupCompoundDictionaryMatch(
2083
0
              &params->dictionary.compound, ringbuffer,
2084
0
              ringbuffer_mask, dist_cache, position + 1, max_length,
2085
0
              dictionary_start, params->dist.max_distance, &sr2);
2086
0
        }
2087
0
        if (sr2.score >= sr.score + cost_diff_lazy) {
2088
          /* Ok, let's just write one byte for now and start a match from the
2089
             next byte. */
2090
0
          ++position;
2091
0
          ++insert_length;
2092
0
          sr = sr2;
2093
0
          if (++delayed_backward_references_in_row < 4 &&
2094
0
              position + FN(HashTypeLength)() < pos_end) {
2095
0
            continue;
2096
0
          }
2097
0
        }
2098
0
        break;
2099
0
      }
2100
0
      apply_random_heuristics =
2101
0
          position + 2 * sr.len + random_heuristics_window_size;
2102
0
      dictionary_start = BROTLI_MIN(size_t,
2103
0
          position + position_offset, max_backward_limit);
2104
0
      {
2105
        /* The first 16 codes are special short-codes,
2106
           and the minimum offset is 1. */
2107
0
        size_t distance_code = ComputeDistanceCode(
2108
0
            sr.distance, dictionary_start + gap, dist_cache);
2109
0
        if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
2110
0
          dist_cache[3] = dist_cache[2];
2111
0
          dist_cache[2] = dist_cache[1];
2112
0
          dist_cache[1] = dist_cache[0];
2113
0
          dist_cache[0] = (int)sr.distance;
2114
0
          FN(PrepareDistanceCache)(privat, dist_cache);
2115
0
        }
2116
0
        InitCommand(commands++, &params->dist, insert_length,
2117
0
            sr.len, sr.len_code_delta, distance_code);
2118
0
      }
2119
0
      *num_literals += insert_length;
2120
0
      insert_length = 0;
2121
      /* Put the hash keys into the table, if there are enough bytes left.
2122
         Depending on the hasher implementation, it can push all positions
2123
         in the given range or only a subset of them.
2124
         Avoid hash poisoning with RLE data. */
2125
0
      {
2126
0
        size_t range_start = position + 2;
2127
0
        size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
2128
0
        if (sr.distance < (sr.len >> 2)) {
2129
0
          range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
2130
0
              range_start, position + sr.len - (sr.distance << 2)));
2131
0
        }
2132
0
        FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
2133
0
                       range_end);
2134
0
      }
2135
0
      position += sr.len;
2136
0
    } else {
2137
0
      ++insert_length;
2138
0
      ++position;
2139
      /* If we have not seen matches for a long time, we can skip some
2140
         match lookups. Unsuccessful match lookups are very very expensive
2141
         and this kind of a heuristic speeds up compression quite
2142
         a lot. */
2143
0
      if (position > apply_random_heuristics) {
2144
        /* Going through uncompressible data, jump. */
2145
0
        if (position >
2146
0
            apply_random_heuristics + 4 * random_heuristics_window_size) {
2147
          /* It is quite a long time since we saw a copy, so we assume
2148
             that this data is not compressible, and store hashes less
2149
             often. Hashes of non compressible data are less likely to
2150
             turn out to be useful in the future, too, so we store less of
2151
             them to not to flood out the hash table of good compressible
2152
             data. */
2153
0
          const size_t kMargin =
2154
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
2155
0
          size_t pos_jump =
2156
0
              BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
2157
0
          for (; position < pos_jump; position += 4) {
2158
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
2159
0
            insert_length += 4;
2160
0
          }
2161
0
        } else {
2162
0
          const size_t kMargin =
2163
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
2164
0
          size_t pos_jump =
2165
0
              BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
2166
0
          for (; position < pos_jump; position += 2) {
2167
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
2168
0
            insert_length += 2;
2169
0
          }
2170
0
        }
2171
0
      }
2172
0
    }
2173
0
  }
2174
0
  insert_length += pos_end - position;
2175
0
  *last_insert_len = insert_length;
2176
0
  *num_commands += (size_t)(commands - orig_commands);
2177
0
}
2178
#undef HASHER
2179
2180
0
#define HASHER() H65
2181
/* NOLINTNEXTLINE(build/include) */
2182
/* NOLINT(build/header_guard) */
2183
/* Copyright 2013 Google Inc. All Rights Reserved.
2184
2185
   Distributed under MIT license.
2186
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
2187
*/
2188
2189
/* template parameters: EXPORT_FN, FN */
2190
2191
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
2192
    size_t num_bytes, size_t position,
2193
    const uint8_t* ringbuffer, size_t ringbuffer_mask,
2194
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
2195
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
2196
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
2197
0
  HASHER()* privat = &hasher->privat.FN(_);
2198
  /* Set maximum distance, see section 9.1. of the spec. */
2199
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
2200
0
  const size_t position_offset = params->stream_offset;
2201
2202
0
  const Command* const orig_commands = commands;
2203
0
  size_t insert_length = *last_insert_len;
2204
0
  const size_t pos_end = position + num_bytes;
2205
0
  const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
2206
0
      position + num_bytes - FN(StoreLookahead)() + 1 : position;
2207
2208
  /* For speed up heuristics for random data. */
2209
0
  const size_t random_heuristics_window_size =
2210
0
      LiteralSpreeLengthForSparseSearch(params);
2211
0
  size_t apply_random_heuristics = position + random_heuristics_window_size;
2212
0
  const size_t gap = params->dictionary.compound.total_size;
2213
2214
  /* Minimum score to accept a backward reference. */
2215
0
  const score_t kMinScore = BROTLI_SCORE_BASE + 100;
2216
2217
0
  FN(PrepareDistanceCache)(privat, dist_cache);
2218
2219
0
  while (position + FN(HashTypeLength)() < pos_end) {
2220
0
    size_t max_length = pos_end - position;
2221
0
    size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
2222
0
    size_t dictionary_start = BROTLI_MIN(size_t,
2223
0
        position + position_offset, max_backward_limit);
2224
0
    HasherSearchResult sr;
2225
0
    int dict_id = 0;
2226
0
    uint8_t p1 = 0;
2227
0
    uint8_t p2 = 0;
2228
0
    if (params->dictionary.contextual.context_based) {
2229
0
      p1 = position >= 1 ?
2230
0
          ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
2231
0
      p2 = position >= 2 ?
2232
0
          ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
2233
0
      dict_id = params->dictionary.contextual.context_map[
2234
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
2235
0
    }
2236
0
    sr.len = 0;
2237
0
    sr.len_code_delta = 0;
2238
0
    sr.distance = 0;
2239
0
    sr.score = kMinScore;
2240
0
    FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
2241
0
        ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
2242
0
        max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
2243
0
    if (ENABLE_COMPOUND_DICTIONARY) {
2244
0
      LookupCompoundDictionaryMatch(&params->dictionary.compound, ringbuffer,
2245
0
          ringbuffer_mask, dist_cache, position, max_length,
2246
0
          dictionary_start, params->dist.max_distance, &sr);
2247
0
    }
2248
0
    if (sr.score > kMinScore) {
2249
      /* Found a match. Let's look for something even better ahead. */
2250
0
      int delayed_backward_references_in_row = 0;
2251
0
      --max_length;
2252
0
      for (;; --max_length) {
2253
0
        const score_t cost_diff_lazy = 175;
2254
0
        HasherSearchResult sr2;
2255
0
        sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
2256
0
            BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
2257
0
        sr2.len_code_delta = 0;
2258
0
        sr2.distance = 0;
2259
0
        sr2.score = kMinScore;
2260
0
        max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
2261
0
        dictionary_start = BROTLI_MIN(size_t,
2262
0
            position + 1 + position_offset, max_backward_limit);
2263
0
        if (params->dictionary.contextual.context_based) {
2264
0
          p2 = p1;
2265
0
          p1 = ringbuffer[position & ringbuffer_mask];
2266
0
          dict_id = params->dictionary.contextual.context_map[
2267
0
              BROTLI_CONTEXT(p1, p2, literal_context_lut)];
2268
0
        }
2269
0
        FN(FindLongestMatch)(privat,
2270
0
            params->dictionary.contextual.dict[dict_id],
2271
0
            ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
2272
0
            max_distance, dictionary_start + gap, params->dist.max_distance,
2273
0
            &sr2);
2274
0
        if (ENABLE_COMPOUND_DICTIONARY) {
2275
0
          LookupCompoundDictionaryMatch(
2276
0
              &params->dictionary.compound, ringbuffer,
2277
0
              ringbuffer_mask, dist_cache, position + 1, max_length,
2278
0
              dictionary_start, params->dist.max_distance, &sr2);
2279
0
        }
2280
0
        if (sr2.score >= sr.score + cost_diff_lazy) {
2281
          /* Ok, let's just write one byte for now and start a match from the
2282
             next byte. */
2283
0
          ++position;
2284
0
          ++insert_length;
2285
0
          sr = sr2;
2286
0
          if (++delayed_backward_references_in_row < 4 &&
2287
0
              position + FN(HashTypeLength)() < pos_end) {
2288
0
            continue;
2289
0
          }
2290
0
        }
2291
0
        break;
2292
0
      }
2293
0
      apply_random_heuristics =
2294
0
          position + 2 * sr.len + random_heuristics_window_size;
2295
0
      dictionary_start = BROTLI_MIN(size_t,
2296
0
          position + position_offset, max_backward_limit);
2297
0
      {
2298
        /* The first 16 codes are special short-codes,
2299
           and the minimum offset is 1. */
2300
0
        size_t distance_code = ComputeDistanceCode(
2301
0
            sr.distance, dictionary_start + gap, dist_cache);
2302
0
        if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
2303
0
          dist_cache[3] = dist_cache[2];
2304
0
          dist_cache[2] = dist_cache[1];
2305
0
          dist_cache[1] = dist_cache[0];
2306
0
          dist_cache[0] = (int)sr.distance;
2307
0
          FN(PrepareDistanceCache)(privat, dist_cache);
2308
0
        }
2309
0
        InitCommand(commands++, &params->dist, insert_length,
2310
0
            sr.len, sr.len_code_delta, distance_code);
2311
0
      }
2312
0
      *num_literals += insert_length;
2313
0
      insert_length = 0;
2314
      /* Put the hash keys into the table, if there are enough bytes left.
2315
         Depending on the hasher implementation, it can push all positions
2316
         in the given range or only a subset of them.
2317
         Avoid hash poisoning with RLE data. */
2318
0
      {
2319
0
        size_t range_start = position + 2;
2320
0
        size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
2321
0
        if (sr.distance < (sr.len >> 2)) {
2322
0
          range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
2323
0
              range_start, position + sr.len - (sr.distance << 2)));
2324
0
        }
2325
0
        FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
2326
0
                       range_end);
2327
0
      }
2328
0
      position += sr.len;
2329
0
    } else {
2330
0
      ++insert_length;
2331
0
      ++position;
2332
      /* If we have not seen matches for a long time, we can skip some
2333
         match lookups. Unsuccessful match lookups are very very expensive
2334
         and this kind of a heuristic speeds up compression quite
2335
         a lot. */
2336
0
      if (position > apply_random_heuristics) {
2337
        /* Going through uncompressible data, jump. */
2338
0
        if (position >
2339
0
            apply_random_heuristics + 4 * random_heuristics_window_size) {
2340
          /* It is quite a long time since we saw a copy, so we assume
2341
             that this data is not compressible, and store hashes less
2342
             often. Hashes of non compressible data are less likely to
2343
             turn out to be useful in the future, too, so we store less of
2344
             them to not to flood out the hash table of good compressible
2345
             data. */
2346
0
          const size_t kMargin =
2347
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
2348
0
          size_t pos_jump =
2349
0
              BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
2350
0
          for (; position < pos_jump; position += 4) {
2351
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
2352
0
            insert_length += 4;
2353
0
          }
2354
0
        } else {
2355
0
          const size_t kMargin =
2356
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
2357
0
          size_t pos_jump =
2358
0
              BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
2359
0
          for (; position < pos_jump; position += 2) {
2360
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
2361
0
            insert_length += 2;
2362
0
          }
2363
0
        }
2364
0
      }
2365
0
    }
2366
0
  }
2367
0
  insert_length += pos_end - position;
2368
0
  *last_insert_len = insert_length;
2369
0
  *num_commands += (size_t)(commands - orig_commands);
2370
0
}
2371
#undef HASHER
2372
2373
#undef ENABLE_COMPOUND_DICTIONARY
2374
#undef PREFIX
2375
#define PREFIX() D
2376
0
#define ENABLE_COMPOUND_DICTIONARY 1
2377
2378
0
#define HASHER() H5
2379
/* NOLINTNEXTLINE(build/include) */
2380
/* NOLINT(build/header_guard) */
2381
/* Copyright 2013 Google Inc. All Rights Reserved.
2382
2383
   Distributed under MIT license.
2384
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
2385
*/
2386
2387
/* template parameters: EXPORT_FN, FN */
2388
2389
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
2390
    size_t num_bytes, size_t position,
2391
    const uint8_t* ringbuffer, size_t ringbuffer_mask,
2392
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
2393
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
2394
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
2395
0
  HASHER()* privat = &hasher->privat.FN(_);
2396
  /* Set maximum distance, see section 9.1. of the spec. */
2397
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
2398
0
  const size_t position_offset = params->stream_offset;
2399
2400
0
  const Command* const orig_commands = commands;
2401
0
  size_t insert_length = *last_insert_len;
2402
0
  const size_t pos_end = position + num_bytes;
2403
0
  const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
2404
0
      position + num_bytes - FN(StoreLookahead)() + 1 : position;
2405
2406
  /* For speed up heuristics for random data. */
2407
0
  const size_t random_heuristics_window_size =
2408
0
      LiteralSpreeLengthForSparseSearch(params);
2409
0
  size_t apply_random_heuristics = position + random_heuristics_window_size;
2410
0
  const size_t gap = params->dictionary.compound.total_size;
2411
2412
  /* Minimum score to accept a backward reference. */
2413
0
  const score_t kMinScore = BROTLI_SCORE_BASE + 100;
2414
2415
0
  FN(PrepareDistanceCache)(privat, dist_cache);
2416
2417
0
  while (position + FN(HashTypeLength)() < pos_end) {
2418
0
    size_t max_length = pos_end - position;
2419
0
    size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
2420
0
    size_t dictionary_start = BROTLI_MIN(size_t,
2421
0
        position + position_offset, max_backward_limit);
2422
0
    HasherSearchResult sr;
2423
0
    int dict_id = 0;
2424
0
    uint8_t p1 = 0;
2425
0
    uint8_t p2 = 0;
2426
0
    if (params->dictionary.contextual.context_based) {
2427
0
      p1 = position >= 1 ?
2428
0
          ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
2429
0
      p2 = position >= 2 ?
2430
0
          ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
2431
0
      dict_id = params->dictionary.contextual.context_map[
2432
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
2433
0
    }
2434
0
    sr.len = 0;
2435
0
    sr.len_code_delta = 0;
2436
0
    sr.distance = 0;
2437
0
    sr.score = kMinScore;
2438
0
    FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
2439
0
        ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
2440
0
        max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
2441
0
    if (ENABLE_COMPOUND_DICTIONARY) {
2442
0
      LookupCompoundDictionaryMatch(&params->dictionary.compound, ringbuffer,
2443
0
          ringbuffer_mask, dist_cache, position, max_length,
2444
0
          dictionary_start, params->dist.max_distance, &sr);
2445
0
    }
2446
0
    if (sr.score > kMinScore) {
2447
      /* Found a match. Let's look for something even better ahead. */
2448
0
      int delayed_backward_references_in_row = 0;
2449
0
      --max_length;
2450
0
      for (;; --max_length) {
2451
0
        const score_t cost_diff_lazy = 175;
2452
0
        HasherSearchResult sr2;
2453
0
        sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
2454
0
            BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
2455
0
        sr2.len_code_delta = 0;
2456
0
        sr2.distance = 0;
2457
0
        sr2.score = kMinScore;
2458
0
        max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
2459
0
        dictionary_start = BROTLI_MIN(size_t,
2460
0
            position + 1 + position_offset, max_backward_limit);
2461
0
        if (params->dictionary.contextual.context_based) {
2462
0
          p2 = p1;
2463
0
          p1 = ringbuffer[position & ringbuffer_mask];
2464
0
          dict_id = params->dictionary.contextual.context_map[
2465
0
              BROTLI_CONTEXT(p1, p2, literal_context_lut)];
2466
0
        }
2467
0
        FN(FindLongestMatch)(privat,
2468
0
            params->dictionary.contextual.dict[dict_id],
2469
0
            ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
2470
0
            max_distance, dictionary_start + gap, params->dist.max_distance,
2471
0
            &sr2);
2472
0
        if (ENABLE_COMPOUND_DICTIONARY) {
2473
0
          LookupCompoundDictionaryMatch(
2474
0
              &params->dictionary.compound, ringbuffer,
2475
0
              ringbuffer_mask, dist_cache, position + 1, max_length,
2476
0
              dictionary_start, params->dist.max_distance, &sr2);
2477
0
        }
2478
0
        if (sr2.score >= sr.score + cost_diff_lazy) {
2479
          /* Ok, let's just write one byte for now and start a match from the
2480
             next byte. */
2481
0
          ++position;
2482
0
          ++insert_length;
2483
0
          sr = sr2;
2484
0
          if (++delayed_backward_references_in_row < 4 &&
2485
0
              position + FN(HashTypeLength)() < pos_end) {
2486
0
            continue;
2487
0
          }
2488
0
        }
2489
0
        break;
2490
0
      }
2491
0
      apply_random_heuristics =
2492
0
          position + 2 * sr.len + random_heuristics_window_size;
2493
0
      dictionary_start = BROTLI_MIN(size_t,
2494
0
          position + position_offset, max_backward_limit);
2495
0
      {
2496
        /* The first 16 codes are special short-codes,
2497
           and the minimum offset is 1. */
2498
0
        size_t distance_code = ComputeDistanceCode(
2499
0
            sr.distance, dictionary_start + gap, dist_cache);
2500
0
        if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
2501
0
          dist_cache[3] = dist_cache[2];
2502
0
          dist_cache[2] = dist_cache[1];
2503
0
          dist_cache[1] = dist_cache[0];
2504
0
          dist_cache[0] = (int)sr.distance;
2505
0
          FN(PrepareDistanceCache)(privat, dist_cache);
2506
0
        }
2507
0
        InitCommand(commands++, &params->dist, insert_length,
2508
0
            sr.len, sr.len_code_delta, distance_code);
2509
0
      }
2510
0
      *num_literals += insert_length;
2511
0
      insert_length = 0;
2512
      /* Put the hash keys into the table, if there are enough bytes left.
2513
         Depending on the hasher implementation, it can push all positions
2514
         in the given range or only a subset of them.
2515
         Avoid hash poisoning with RLE data. */
2516
0
      {
2517
0
        size_t range_start = position + 2;
2518
0
        size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
2519
0
        if (sr.distance < (sr.len >> 2)) {
2520
0
          range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
2521
0
              range_start, position + sr.len - (sr.distance << 2)));
2522
0
        }
2523
0
        FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
2524
0
                       range_end);
2525
0
      }
2526
0
      position += sr.len;
2527
0
    } else {
2528
0
      ++insert_length;
2529
0
      ++position;
2530
      /* If we have not seen matches for a long time, we can skip some
2531
         match lookups. Unsuccessful match lookups are very very expensive
2532
         and this kind of a heuristic speeds up compression quite
2533
         a lot. */
2534
0
      if (position > apply_random_heuristics) {
2535
        /* Going through uncompressible data, jump. */
2536
0
        if (position >
2537
0
            apply_random_heuristics + 4 * random_heuristics_window_size) {
2538
          /* It is quite a long time since we saw a copy, so we assume
2539
             that this data is not compressible, and store hashes less
2540
             often. Hashes of non compressible data are less likely to
2541
             turn out to be useful in the future, too, so we store less of
2542
             them to not to flood out the hash table of good compressible
2543
             data. */
2544
0
          const size_t kMargin =
2545
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
2546
0
          size_t pos_jump =
2547
0
              BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
2548
0
          for (; position < pos_jump; position += 4) {
2549
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
2550
0
            insert_length += 4;
2551
0
          }
2552
0
        } else {
2553
0
          const size_t kMargin =
2554
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
2555
0
          size_t pos_jump =
2556
0
              BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
2557
0
          for (; position < pos_jump; position += 2) {
2558
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
2559
0
            insert_length += 2;
2560
0
          }
2561
0
        }
2562
0
      }
2563
0
    }
2564
0
  }
2565
0
  insert_length += pos_end - position;
2566
0
  *last_insert_len = insert_length;
2567
0
  *num_commands += (size_t)(commands - orig_commands);
2568
0
}
2569
#undef HASHER
2570
0
#define HASHER() H6
2571
/* NOLINTNEXTLINE(build/include) */
2572
/* NOLINT(build/header_guard) */
2573
/* Copyright 2013 Google Inc. All Rights Reserved.
2574
2575
   Distributed under MIT license.
2576
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
2577
*/
2578
2579
/* template parameters: EXPORT_FN, FN */
2580
2581
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
2582
    size_t num_bytes, size_t position,
2583
    const uint8_t* ringbuffer, size_t ringbuffer_mask,
2584
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
2585
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
2586
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
2587
0
  HASHER()* privat = &hasher->privat.FN(_);
2588
  /* Set maximum distance, see section 9.1. of the spec. */
2589
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
2590
0
  const size_t position_offset = params->stream_offset;
2591
2592
0
  const Command* const orig_commands = commands;
2593
0
  size_t insert_length = *last_insert_len;
2594
0
  const size_t pos_end = position + num_bytes;
2595
0
  const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
2596
0
      position + num_bytes - FN(StoreLookahead)() + 1 : position;
2597
2598
  /* For speed up heuristics for random data. */
2599
0
  const size_t random_heuristics_window_size =
2600
0
      LiteralSpreeLengthForSparseSearch(params);
2601
0
  size_t apply_random_heuristics = position + random_heuristics_window_size;
2602
0
  const size_t gap = params->dictionary.compound.total_size;
2603
2604
  /* Minimum score to accept a backward reference. */
2605
0
  const score_t kMinScore = BROTLI_SCORE_BASE + 100;
2606
2607
0
  FN(PrepareDistanceCache)(privat, dist_cache);
2608
2609
0
  while (position + FN(HashTypeLength)() < pos_end) {
2610
0
    size_t max_length = pos_end - position;
2611
0
    size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
2612
0
    size_t dictionary_start = BROTLI_MIN(size_t,
2613
0
        position + position_offset, max_backward_limit);
2614
0
    HasherSearchResult sr;
2615
0
    int dict_id = 0;
2616
0
    uint8_t p1 = 0;
2617
0
    uint8_t p2 = 0;
2618
0
    if (params->dictionary.contextual.context_based) {
2619
0
      p1 = position >= 1 ?
2620
0
          ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
2621
0
      p2 = position >= 2 ?
2622
0
          ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
2623
0
      dict_id = params->dictionary.contextual.context_map[
2624
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
2625
0
    }
2626
0
    sr.len = 0;
2627
0
    sr.len_code_delta = 0;
2628
0
    sr.distance = 0;
2629
0
    sr.score = kMinScore;
2630
0
    FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
2631
0
        ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
2632
0
        max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
2633
0
    if (ENABLE_COMPOUND_DICTIONARY) {
2634
0
      LookupCompoundDictionaryMatch(&params->dictionary.compound, ringbuffer,
2635
0
          ringbuffer_mask, dist_cache, position, max_length,
2636
0
          dictionary_start, params->dist.max_distance, &sr);
2637
0
    }
2638
0
    if (sr.score > kMinScore) {
2639
      /* Found a match. Let's look for something even better ahead. */
2640
0
      int delayed_backward_references_in_row = 0;
2641
0
      --max_length;
2642
0
      for (;; --max_length) {
2643
0
        const score_t cost_diff_lazy = 175;
2644
0
        HasherSearchResult sr2;
2645
0
        sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
2646
0
            BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
2647
0
        sr2.len_code_delta = 0;
2648
0
        sr2.distance = 0;
2649
0
        sr2.score = kMinScore;
2650
0
        max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
2651
0
        dictionary_start = BROTLI_MIN(size_t,
2652
0
            position + 1 + position_offset, max_backward_limit);
2653
0
        if (params->dictionary.contextual.context_based) {
2654
0
          p2 = p1;
2655
0
          p1 = ringbuffer[position & ringbuffer_mask];
2656
0
          dict_id = params->dictionary.contextual.context_map[
2657
0
              BROTLI_CONTEXT(p1, p2, literal_context_lut)];
2658
0
        }
2659
0
        FN(FindLongestMatch)(privat,
2660
0
            params->dictionary.contextual.dict[dict_id],
2661
0
            ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
2662
0
            max_distance, dictionary_start + gap, params->dist.max_distance,
2663
0
            &sr2);
2664
0
        if (ENABLE_COMPOUND_DICTIONARY) {
2665
0
          LookupCompoundDictionaryMatch(
2666
0
              &params->dictionary.compound, ringbuffer,
2667
0
              ringbuffer_mask, dist_cache, position + 1, max_length,
2668
0
              dictionary_start, params->dist.max_distance, &sr2);
2669
0
        }
2670
0
        if (sr2.score >= sr.score + cost_diff_lazy) {
2671
          /* Ok, let's just write one byte for now and start a match from the
2672
             next byte. */
2673
0
          ++position;
2674
0
          ++insert_length;
2675
0
          sr = sr2;
2676
0
          if (++delayed_backward_references_in_row < 4 &&
2677
0
              position + FN(HashTypeLength)() < pos_end) {
2678
0
            continue;
2679
0
          }
2680
0
        }
2681
0
        break;
2682
0
      }
2683
0
      apply_random_heuristics =
2684
0
          position + 2 * sr.len + random_heuristics_window_size;
2685
0
      dictionary_start = BROTLI_MIN(size_t,
2686
0
          position + position_offset, max_backward_limit);
2687
0
      {
2688
        /* The first 16 codes are special short-codes,
2689
           and the minimum offset is 1. */
2690
0
        size_t distance_code = ComputeDistanceCode(
2691
0
            sr.distance, dictionary_start + gap, dist_cache);
2692
0
        if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
2693
0
          dist_cache[3] = dist_cache[2];
2694
0
          dist_cache[2] = dist_cache[1];
2695
0
          dist_cache[1] = dist_cache[0];
2696
0
          dist_cache[0] = (int)sr.distance;
2697
0
          FN(PrepareDistanceCache)(privat, dist_cache);
2698
0
        }
2699
0
        InitCommand(commands++, &params->dist, insert_length,
2700
0
            sr.len, sr.len_code_delta, distance_code);
2701
0
      }
2702
0
      *num_literals += insert_length;
2703
0
      insert_length = 0;
2704
      /* Put the hash keys into the table, if there are enough bytes left.
2705
         Depending on the hasher implementation, it can push all positions
2706
         in the given range or only a subset of them.
2707
         Avoid hash poisoning with RLE data. */
2708
0
      {
2709
0
        size_t range_start = position + 2;
2710
0
        size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
2711
0
        if (sr.distance < (sr.len >> 2)) {
2712
0
          range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
2713
0
              range_start, position + sr.len - (sr.distance << 2)));
2714
0
        }
2715
0
        FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
2716
0
                       range_end);
2717
0
      }
2718
0
      position += sr.len;
2719
0
    } else {
2720
0
      ++insert_length;
2721
0
      ++position;
2722
      /* If we have not seen matches for a long time, we can skip some
2723
         match lookups. Unsuccessful match lookups are very very expensive
2724
         and this kind of a heuristic speeds up compression quite
2725
         a lot. */
2726
0
      if (position > apply_random_heuristics) {
2727
        /* Going through uncompressible data, jump. */
2728
0
        if (position >
2729
0
            apply_random_heuristics + 4 * random_heuristics_window_size) {
2730
          /* It is quite a long time since we saw a copy, so we assume
2731
             that this data is not compressible, and store hashes less
2732
             often. Hashes of non compressible data are less likely to
2733
             turn out to be useful in the future, too, so we store less of
2734
             them to not to flood out the hash table of good compressible
2735
             data. */
2736
0
          const size_t kMargin =
2737
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
2738
0
          size_t pos_jump =
2739
0
              BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
2740
0
          for (; position < pos_jump; position += 4) {
2741
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
2742
0
            insert_length += 4;
2743
0
          }
2744
0
        } else {
2745
0
          const size_t kMargin =
2746
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
2747
0
          size_t pos_jump =
2748
0
              BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
2749
0
          for (; position < pos_jump; position += 2) {
2750
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
2751
0
            insert_length += 2;
2752
0
          }
2753
0
        }
2754
0
      }
2755
0
    }
2756
0
  }
2757
0
  insert_length += pos_end - position;
2758
0
  *last_insert_len = insert_length;
2759
0
  *num_commands += (size_t)(commands - orig_commands);
2760
0
}
2761
#undef HASHER
2762
0
#define HASHER() H40
2763
/* NOLINTNEXTLINE(build/include) */
2764
/* NOLINT(build/header_guard) */
2765
/* Copyright 2013 Google Inc. All Rights Reserved.
2766
2767
   Distributed under MIT license.
2768
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
2769
*/
2770
2771
/* template parameters: EXPORT_FN, FN */
2772
2773
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
2774
    size_t num_bytes, size_t position,
2775
    const uint8_t* ringbuffer, size_t ringbuffer_mask,
2776
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
2777
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
2778
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
2779
0
  HASHER()* privat = &hasher->privat.FN(_);
2780
  /* Set maximum distance, see section 9.1. of the spec. */
2781
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
2782
0
  const size_t position_offset = params->stream_offset;
2783
2784
0
  const Command* const orig_commands = commands;
2785
0
  size_t insert_length = *last_insert_len;
2786
0
  const size_t pos_end = position + num_bytes;
2787
0
  const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
2788
0
      position + num_bytes - FN(StoreLookahead)() + 1 : position;
2789
2790
  /* For speed up heuristics for random data. */
2791
0
  const size_t random_heuristics_window_size =
2792
0
      LiteralSpreeLengthForSparseSearch(params);
2793
0
  size_t apply_random_heuristics = position + random_heuristics_window_size;
2794
0
  const size_t gap = params->dictionary.compound.total_size;
2795
2796
  /* Minimum score to accept a backward reference. */
2797
0
  const score_t kMinScore = BROTLI_SCORE_BASE + 100;
2798
2799
0
  FN(PrepareDistanceCache)(privat, dist_cache);
2800
2801
0
  while (position + FN(HashTypeLength)() < pos_end) {
2802
0
    size_t max_length = pos_end - position;
2803
0
    size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
2804
0
    size_t dictionary_start = BROTLI_MIN(size_t,
2805
0
        position + position_offset, max_backward_limit);
2806
0
    HasherSearchResult sr;
2807
0
    int dict_id = 0;
2808
0
    uint8_t p1 = 0;
2809
0
    uint8_t p2 = 0;
2810
0
    if (params->dictionary.contextual.context_based) {
2811
0
      p1 = position >= 1 ?
2812
0
          ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
2813
0
      p2 = position >= 2 ?
2814
0
          ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
2815
0
      dict_id = params->dictionary.contextual.context_map[
2816
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
2817
0
    }
2818
0
    sr.len = 0;
2819
0
    sr.len_code_delta = 0;
2820
0
    sr.distance = 0;
2821
0
    sr.score = kMinScore;
2822
0
    FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
2823
0
        ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
2824
0
        max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
2825
0
    if (ENABLE_COMPOUND_DICTIONARY) {
2826
0
      LookupCompoundDictionaryMatch(&params->dictionary.compound, ringbuffer,
2827
0
          ringbuffer_mask, dist_cache, position, max_length,
2828
0
          dictionary_start, params->dist.max_distance, &sr);
2829
0
    }
2830
0
    if (sr.score > kMinScore) {
2831
      /* Found a match. Let's look for something even better ahead. */
2832
0
      int delayed_backward_references_in_row = 0;
2833
0
      --max_length;
2834
0
      for (;; --max_length) {
2835
0
        const score_t cost_diff_lazy = 175;
2836
0
        HasherSearchResult sr2;
2837
0
        sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
2838
0
            BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
2839
0
        sr2.len_code_delta = 0;
2840
0
        sr2.distance = 0;
2841
0
        sr2.score = kMinScore;
2842
0
        max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
2843
0
        dictionary_start = BROTLI_MIN(size_t,
2844
0
            position + 1 + position_offset, max_backward_limit);
2845
0
        if (params->dictionary.contextual.context_based) {
2846
0
          p2 = p1;
2847
0
          p1 = ringbuffer[position & ringbuffer_mask];
2848
0
          dict_id = params->dictionary.contextual.context_map[
2849
0
              BROTLI_CONTEXT(p1, p2, literal_context_lut)];
2850
0
        }
2851
0
        FN(FindLongestMatch)(privat,
2852
0
            params->dictionary.contextual.dict[dict_id],
2853
0
            ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
2854
0
            max_distance, dictionary_start + gap, params->dist.max_distance,
2855
0
            &sr2);
2856
0
        if (ENABLE_COMPOUND_DICTIONARY) {
2857
0
          LookupCompoundDictionaryMatch(
2858
0
              &params->dictionary.compound, ringbuffer,
2859
0
              ringbuffer_mask, dist_cache, position + 1, max_length,
2860
0
              dictionary_start, params->dist.max_distance, &sr2);
2861
0
        }
2862
0
        if (sr2.score >= sr.score + cost_diff_lazy) {
2863
          /* Ok, let's just write one byte for now and start a match from the
2864
             next byte. */
2865
0
          ++position;
2866
0
          ++insert_length;
2867
0
          sr = sr2;
2868
0
          if (++delayed_backward_references_in_row < 4 &&
2869
0
              position + FN(HashTypeLength)() < pos_end) {
2870
0
            continue;
2871
0
          }
2872
0
        }
2873
0
        break;
2874
0
      }
2875
0
      apply_random_heuristics =
2876
0
          position + 2 * sr.len + random_heuristics_window_size;
2877
0
      dictionary_start = BROTLI_MIN(size_t,
2878
0
          position + position_offset, max_backward_limit);
2879
0
      {
2880
        /* The first 16 codes are special short-codes,
2881
           and the minimum offset is 1. */
2882
0
        size_t distance_code = ComputeDistanceCode(
2883
0
            sr.distance, dictionary_start + gap, dist_cache);
2884
0
        if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
2885
0
          dist_cache[3] = dist_cache[2];
2886
0
          dist_cache[2] = dist_cache[1];
2887
0
          dist_cache[1] = dist_cache[0];
2888
0
          dist_cache[0] = (int)sr.distance;
2889
0
          FN(PrepareDistanceCache)(privat, dist_cache);
2890
0
        }
2891
0
        InitCommand(commands++, &params->dist, insert_length,
2892
0
            sr.len, sr.len_code_delta, distance_code);
2893
0
      }
2894
0
      *num_literals += insert_length;
2895
0
      insert_length = 0;
2896
      /* Put the hash keys into the table, if there are enough bytes left.
2897
         Depending on the hasher implementation, it can push all positions
2898
         in the given range or only a subset of them.
2899
         Avoid hash poisoning with RLE data. */
2900
0
      {
2901
0
        size_t range_start = position + 2;
2902
0
        size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
2903
0
        if (sr.distance < (sr.len >> 2)) {
2904
0
          range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
2905
0
              range_start, position + sr.len - (sr.distance << 2)));
2906
0
        }
2907
0
        FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
2908
0
                       range_end);
2909
0
      }
2910
0
      position += sr.len;
2911
0
    } else {
2912
0
      ++insert_length;
2913
0
      ++position;
2914
      /* If we have not seen matches for a long time, we can skip some
2915
         match lookups. Unsuccessful match lookups are very very expensive
2916
         and this kind of a heuristic speeds up compression quite
2917
         a lot. */
2918
0
      if (position > apply_random_heuristics) {
2919
        /* Going through uncompressible data, jump. */
2920
0
        if (position >
2921
0
            apply_random_heuristics + 4 * random_heuristics_window_size) {
2922
          /* It is quite a long time since we saw a copy, so we assume
2923
             that this data is not compressible, and store hashes less
2924
             often. Hashes of non compressible data are less likely to
2925
             turn out to be useful in the future, too, so we store less of
2926
             them to not to flood out the hash table of good compressible
2927
             data. */
2928
0
          const size_t kMargin =
2929
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
2930
0
          size_t pos_jump =
2931
0
              BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
2932
0
          for (; position < pos_jump; position += 4) {
2933
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
2934
0
            insert_length += 4;
2935
0
          }
2936
0
        } else {
2937
0
          const size_t kMargin =
2938
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
2939
0
          size_t pos_jump =
2940
0
              BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
2941
0
          for (; position < pos_jump; position += 2) {
2942
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
2943
0
            insert_length += 2;
2944
0
          }
2945
0
        }
2946
0
      }
2947
0
    }
2948
0
  }
2949
0
  insert_length += pos_end - position;
2950
0
  *last_insert_len = insert_length;
2951
0
  *num_commands += (size_t)(commands - orig_commands);
2952
0
}
2953
#undef HASHER
2954
0
#define HASHER() H41
2955
/* NOLINTNEXTLINE(build/include) */
2956
/* NOLINT(build/header_guard) */
2957
/* Copyright 2013 Google Inc. All Rights Reserved.
2958
2959
   Distributed under MIT license.
2960
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
2961
*/
2962
2963
/* template parameters: EXPORT_FN, FN */
2964
2965
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
2966
    size_t num_bytes, size_t position,
2967
    const uint8_t* ringbuffer, size_t ringbuffer_mask,
2968
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
2969
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
2970
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
2971
0
  HASHER()* privat = &hasher->privat.FN(_);
2972
  /* Set maximum distance, see section 9.1. of the spec. */
2973
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
2974
0
  const size_t position_offset = params->stream_offset;
2975
2976
0
  const Command* const orig_commands = commands;
2977
0
  size_t insert_length = *last_insert_len;
2978
0
  const size_t pos_end = position + num_bytes;
2979
0
  const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
2980
0
      position + num_bytes - FN(StoreLookahead)() + 1 : position;
2981
2982
  /* For speed up heuristics for random data. */
2983
0
  const size_t random_heuristics_window_size =
2984
0
      LiteralSpreeLengthForSparseSearch(params);
2985
0
  size_t apply_random_heuristics = position + random_heuristics_window_size;
2986
0
  const size_t gap = params->dictionary.compound.total_size;
2987
2988
  /* Minimum score to accept a backward reference. */
2989
0
  const score_t kMinScore = BROTLI_SCORE_BASE + 100;
2990
2991
0
  FN(PrepareDistanceCache)(privat, dist_cache);
2992
2993
0
  while (position + FN(HashTypeLength)() < pos_end) {
2994
0
    size_t max_length = pos_end - position;
2995
0
    size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
2996
0
    size_t dictionary_start = BROTLI_MIN(size_t,
2997
0
        position + position_offset, max_backward_limit);
2998
0
    HasherSearchResult sr;
2999
0
    int dict_id = 0;
3000
0
    uint8_t p1 = 0;
3001
0
    uint8_t p2 = 0;
3002
0
    if (params->dictionary.contextual.context_based) {
3003
0
      p1 = position >= 1 ?
3004
0
          ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
3005
0
      p2 = position >= 2 ?
3006
0
          ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
3007
0
      dict_id = params->dictionary.contextual.context_map[
3008
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
3009
0
    }
3010
0
    sr.len = 0;
3011
0
    sr.len_code_delta = 0;
3012
0
    sr.distance = 0;
3013
0
    sr.score = kMinScore;
3014
0
    FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
3015
0
        ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
3016
0
        max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
3017
0
    if (ENABLE_COMPOUND_DICTIONARY) {
3018
0
      LookupCompoundDictionaryMatch(&params->dictionary.compound, ringbuffer,
3019
0
          ringbuffer_mask, dist_cache, position, max_length,
3020
0
          dictionary_start, params->dist.max_distance, &sr);
3021
0
    }
3022
0
    if (sr.score > kMinScore) {
3023
      /* Found a match. Let's look for something even better ahead. */
3024
0
      int delayed_backward_references_in_row = 0;
3025
0
      --max_length;
3026
0
      for (;; --max_length) {
3027
0
        const score_t cost_diff_lazy = 175;
3028
0
        HasherSearchResult sr2;
3029
0
        sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
3030
0
            BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
3031
0
        sr2.len_code_delta = 0;
3032
0
        sr2.distance = 0;
3033
0
        sr2.score = kMinScore;
3034
0
        max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
3035
0
        dictionary_start = BROTLI_MIN(size_t,
3036
0
            position + 1 + position_offset, max_backward_limit);
3037
0
        if (params->dictionary.contextual.context_based) {
3038
0
          p2 = p1;
3039
0
          p1 = ringbuffer[position & ringbuffer_mask];
3040
0
          dict_id = params->dictionary.contextual.context_map[
3041
0
              BROTLI_CONTEXT(p1, p2, literal_context_lut)];
3042
0
        }
3043
0
        FN(FindLongestMatch)(privat,
3044
0
            params->dictionary.contextual.dict[dict_id],
3045
0
            ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
3046
0
            max_distance, dictionary_start + gap, params->dist.max_distance,
3047
0
            &sr2);
3048
0
        if (ENABLE_COMPOUND_DICTIONARY) {
3049
0
          LookupCompoundDictionaryMatch(
3050
0
              &params->dictionary.compound, ringbuffer,
3051
0
              ringbuffer_mask, dist_cache, position + 1, max_length,
3052
0
              dictionary_start, params->dist.max_distance, &sr2);
3053
0
        }
3054
0
        if (sr2.score >= sr.score + cost_diff_lazy) {
3055
          /* Ok, let's just write one byte for now and start a match from the
3056
             next byte. */
3057
0
          ++position;
3058
0
          ++insert_length;
3059
0
          sr = sr2;
3060
0
          if (++delayed_backward_references_in_row < 4 &&
3061
0
              position + FN(HashTypeLength)() < pos_end) {
3062
0
            continue;
3063
0
          }
3064
0
        }
3065
0
        break;
3066
0
      }
3067
0
      apply_random_heuristics =
3068
0
          position + 2 * sr.len + random_heuristics_window_size;
3069
0
      dictionary_start = BROTLI_MIN(size_t,
3070
0
          position + position_offset, max_backward_limit);
3071
0
      {
3072
        /* The first 16 codes are special short-codes,
3073
           and the minimum offset is 1. */
3074
0
        size_t distance_code = ComputeDistanceCode(
3075
0
            sr.distance, dictionary_start + gap, dist_cache);
3076
0
        if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
3077
0
          dist_cache[3] = dist_cache[2];
3078
0
          dist_cache[2] = dist_cache[1];
3079
0
          dist_cache[1] = dist_cache[0];
3080
0
          dist_cache[0] = (int)sr.distance;
3081
0
          FN(PrepareDistanceCache)(privat, dist_cache);
3082
0
        }
3083
0
        InitCommand(commands++, &params->dist, insert_length,
3084
0
            sr.len, sr.len_code_delta, distance_code);
3085
0
      }
3086
0
      *num_literals += insert_length;
3087
0
      insert_length = 0;
3088
      /* Put the hash keys into the table, if there are enough bytes left.
3089
         Depending on the hasher implementation, it can push all positions
3090
         in the given range or only a subset of them.
3091
         Avoid hash poisoning with RLE data. */
3092
0
      {
3093
0
        size_t range_start = position + 2;
3094
0
        size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
3095
0
        if (sr.distance < (sr.len >> 2)) {
3096
0
          range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
3097
0
              range_start, position + sr.len - (sr.distance << 2)));
3098
0
        }
3099
0
        FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
3100
0
                       range_end);
3101
0
      }
3102
0
      position += sr.len;
3103
0
    } else {
3104
0
      ++insert_length;
3105
0
      ++position;
3106
      /* If we have not seen matches for a long time, we can skip some
3107
         match lookups. Unsuccessful match lookups are very very expensive
3108
         and this kind of a heuristic speeds up compression quite
3109
         a lot. */
3110
0
      if (position > apply_random_heuristics) {
3111
        /* Going through uncompressible data, jump. */
3112
0
        if (position >
3113
0
            apply_random_heuristics + 4 * random_heuristics_window_size) {
3114
          /* It is quite a long time since we saw a copy, so we assume
3115
             that this data is not compressible, and store hashes less
3116
             often. Hashes of non compressible data are less likely to
3117
             turn out to be useful in the future, too, so we store less of
3118
             them to not to flood out the hash table of good compressible
3119
             data. */
3120
0
          const size_t kMargin =
3121
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
3122
0
          size_t pos_jump =
3123
0
              BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
3124
0
          for (; position < pos_jump; position += 4) {
3125
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
3126
0
            insert_length += 4;
3127
0
          }
3128
0
        } else {
3129
0
          const size_t kMargin =
3130
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
3131
0
          size_t pos_jump =
3132
0
              BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
3133
0
          for (; position < pos_jump; position += 2) {
3134
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
3135
0
            insert_length += 2;
3136
0
          }
3137
0
        }
3138
0
      }
3139
0
    }
3140
0
  }
3141
0
  insert_length += pos_end - position;
3142
0
  *last_insert_len = insert_length;
3143
0
  *num_commands += (size_t)(commands - orig_commands);
3144
0
}
3145
#undef HASHER
3146
0
#define HASHER() H42
3147
/* NOLINTNEXTLINE(build/include) */
3148
/* NOLINT(build/header_guard) */
3149
/* Copyright 2013 Google Inc. All Rights Reserved.
3150
3151
   Distributed under MIT license.
3152
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
3153
*/
3154
3155
/* template parameters: EXPORT_FN, FN */
3156
3157
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
3158
    size_t num_bytes, size_t position,
3159
    const uint8_t* ringbuffer, size_t ringbuffer_mask,
3160
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
3161
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
3162
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
3163
0
  HASHER()* privat = &hasher->privat.FN(_);
3164
  /* Set maximum distance, see section 9.1. of the spec. */
3165
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
3166
0
  const size_t position_offset = params->stream_offset;
3167
3168
0
  const Command* const orig_commands = commands;
3169
0
  size_t insert_length = *last_insert_len;
3170
0
  const size_t pos_end = position + num_bytes;
3171
0
  const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
3172
0
      position + num_bytes - FN(StoreLookahead)() + 1 : position;
3173
3174
  /* For speed up heuristics for random data. */
3175
0
  const size_t random_heuristics_window_size =
3176
0
      LiteralSpreeLengthForSparseSearch(params);
3177
0
  size_t apply_random_heuristics = position + random_heuristics_window_size;
3178
0
  const size_t gap = params->dictionary.compound.total_size;
3179
3180
  /* Minimum score to accept a backward reference. */
3181
0
  const score_t kMinScore = BROTLI_SCORE_BASE + 100;
3182
3183
0
  FN(PrepareDistanceCache)(privat, dist_cache);
3184
3185
0
  while (position + FN(HashTypeLength)() < pos_end) {
3186
0
    size_t max_length = pos_end - position;
3187
0
    size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
3188
0
    size_t dictionary_start = BROTLI_MIN(size_t,
3189
0
        position + position_offset, max_backward_limit);
3190
0
    HasherSearchResult sr;
3191
0
    int dict_id = 0;
3192
0
    uint8_t p1 = 0;
3193
0
    uint8_t p2 = 0;
3194
0
    if (params->dictionary.contextual.context_based) {
3195
0
      p1 = position >= 1 ?
3196
0
          ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
3197
0
      p2 = position >= 2 ?
3198
0
          ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
3199
0
      dict_id = params->dictionary.contextual.context_map[
3200
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
3201
0
    }
3202
0
    sr.len = 0;
3203
0
    sr.len_code_delta = 0;
3204
0
    sr.distance = 0;
3205
0
    sr.score = kMinScore;
3206
0
    FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
3207
0
        ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
3208
0
        max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
3209
0
    if (ENABLE_COMPOUND_DICTIONARY) {
3210
0
      LookupCompoundDictionaryMatch(&params->dictionary.compound, ringbuffer,
3211
0
          ringbuffer_mask, dist_cache, position, max_length,
3212
0
          dictionary_start, params->dist.max_distance, &sr);
3213
0
    }
3214
0
    if (sr.score > kMinScore) {
3215
      /* Found a match. Let's look for something even better ahead. */
3216
0
      int delayed_backward_references_in_row = 0;
3217
0
      --max_length;
3218
0
      for (;; --max_length) {
3219
0
        const score_t cost_diff_lazy = 175;
3220
0
        HasherSearchResult sr2;
3221
0
        sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
3222
0
            BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
3223
0
        sr2.len_code_delta = 0;
3224
0
        sr2.distance = 0;
3225
0
        sr2.score = kMinScore;
3226
0
        max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
3227
0
        dictionary_start = BROTLI_MIN(size_t,
3228
0
            position + 1 + position_offset, max_backward_limit);
3229
0
        if (params->dictionary.contextual.context_based) {
3230
0
          p2 = p1;
3231
0
          p1 = ringbuffer[position & ringbuffer_mask];
3232
0
          dict_id = params->dictionary.contextual.context_map[
3233
0
              BROTLI_CONTEXT(p1, p2, literal_context_lut)];
3234
0
        }
3235
0
        FN(FindLongestMatch)(privat,
3236
0
            params->dictionary.contextual.dict[dict_id],
3237
0
            ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
3238
0
            max_distance, dictionary_start + gap, params->dist.max_distance,
3239
0
            &sr2);
3240
0
        if (ENABLE_COMPOUND_DICTIONARY) {
3241
0
          LookupCompoundDictionaryMatch(
3242
0
              &params->dictionary.compound, ringbuffer,
3243
0
              ringbuffer_mask, dist_cache, position + 1, max_length,
3244
0
              dictionary_start, params->dist.max_distance, &sr2);
3245
0
        }
3246
0
        if (sr2.score >= sr.score + cost_diff_lazy) {
3247
          /* Ok, let's just write one byte for now and start a match from the
3248
             next byte. */
3249
0
          ++position;
3250
0
          ++insert_length;
3251
0
          sr = sr2;
3252
0
          if (++delayed_backward_references_in_row < 4 &&
3253
0
              position + FN(HashTypeLength)() < pos_end) {
3254
0
            continue;
3255
0
          }
3256
0
        }
3257
0
        break;
3258
0
      }
3259
0
      apply_random_heuristics =
3260
0
          position + 2 * sr.len + random_heuristics_window_size;
3261
0
      dictionary_start = BROTLI_MIN(size_t,
3262
0
          position + position_offset, max_backward_limit);
3263
0
      {
3264
        /* The first 16 codes are special short-codes,
3265
           and the minimum offset is 1. */
3266
0
        size_t distance_code = ComputeDistanceCode(
3267
0
            sr.distance, dictionary_start + gap, dist_cache);
3268
0
        if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
3269
0
          dist_cache[3] = dist_cache[2];
3270
0
          dist_cache[2] = dist_cache[1];
3271
0
          dist_cache[1] = dist_cache[0];
3272
0
          dist_cache[0] = (int)sr.distance;
3273
0
          FN(PrepareDistanceCache)(privat, dist_cache);
3274
0
        }
3275
0
        InitCommand(commands++, &params->dist, insert_length,
3276
0
            sr.len, sr.len_code_delta, distance_code);
3277
0
      }
3278
0
      *num_literals += insert_length;
3279
0
      insert_length = 0;
3280
      /* Put the hash keys into the table, if there are enough bytes left.
3281
         Depending on the hasher implementation, it can push all positions
3282
         in the given range or only a subset of them.
3283
         Avoid hash poisoning with RLE data. */
3284
0
      {
3285
0
        size_t range_start = position + 2;
3286
0
        size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
3287
0
        if (sr.distance < (sr.len >> 2)) {
3288
0
          range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
3289
0
              range_start, position + sr.len - (sr.distance << 2)));
3290
0
        }
3291
0
        FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
3292
0
                       range_end);
3293
0
      }
3294
0
      position += sr.len;
3295
0
    } else {
3296
0
      ++insert_length;
3297
0
      ++position;
3298
      /* If we have not seen matches for a long time, we can skip some
3299
         match lookups. Unsuccessful match lookups are very very expensive
3300
         and this kind of a heuristic speeds up compression quite
3301
         a lot. */
3302
0
      if (position > apply_random_heuristics) {
3303
        /* Going through uncompressible data, jump. */
3304
0
        if (position >
3305
0
            apply_random_heuristics + 4 * random_heuristics_window_size) {
3306
          /* It is quite a long time since we saw a copy, so we assume
3307
             that this data is not compressible, and store hashes less
3308
             often. Hashes of non compressible data are less likely to
3309
             turn out to be useful in the future, too, so we store less of
3310
             them to not to flood out the hash table of good compressible
3311
             data. */
3312
0
          const size_t kMargin =
3313
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
3314
0
          size_t pos_jump =
3315
0
              BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
3316
0
          for (; position < pos_jump; position += 4) {
3317
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
3318
0
            insert_length += 4;
3319
0
          }
3320
0
        } else {
3321
0
          const size_t kMargin =
3322
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
3323
0
          size_t pos_jump =
3324
0
              BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
3325
0
          for (; position < pos_jump; position += 2) {
3326
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
3327
0
            insert_length += 2;
3328
0
          }
3329
0
        }
3330
0
      }
3331
0
    }
3332
0
  }
3333
0
  insert_length += pos_end - position;
3334
0
  *last_insert_len = insert_length;
3335
0
  *num_commands += (size_t)(commands - orig_commands);
3336
0
}
3337
#undef HASHER
3338
0
#define HASHER() H55
3339
/* NOLINTNEXTLINE(build/include) */
3340
/* NOLINT(build/header_guard) */
3341
/* Copyright 2013 Google Inc. All Rights Reserved.
3342
3343
   Distributed under MIT license.
3344
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
3345
*/
3346
3347
/* template parameters: EXPORT_FN, FN */
3348
3349
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
3350
    size_t num_bytes, size_t position,
3351
    const uint8_t* ringbuffer, size_t ringbuffer_mask,
3352
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
3353
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
3354
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
3355
0
  HASHER()* privat = &hasher->privat.FN(_);
3356
  /* Set maximum distance, see section 9.1. of the spec. */
3357
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
3358
0
  const size_t position_offset = params->stream_offset;
3359
3360
0
  const Command* const orig_commands = commands;
3361
0
  size_t insert_length = *last_insert_len;
3362
0
  const size_t pos_end = position + num_bytes;
3363
0
  const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
3364
0
      position + num_bytes - FN(StoreLookahead)() + 1 : position;
3365
3366
  /* For speed up heuristics for random data. */
3367
0
  const size_t random_heuristics_window_size =
3368
0
      LiteralSpreeLengthForSparseSearch(params);
3369
0
  size_t apply_random_heuristics = position + random_heuristics_window_size;
3370
0
  const size_t gap = params->dictionary.compound.total_size;
3371
3372
  /* Minimum score to accept a backward reference. */
3373
0
  const score_t kMinScore = BROTLI_SCORE_BASE + 100;
3374
3375
0
  FN(PrepareDistanceCache)(privat, dist_cache);
3376
3377
0
  while (position + FN(HashTypeLength)() < pos_end) {
3378
0
    size_t max_length = pos_end - position;
3379
0
    size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
3380
0
    size_t dictionary_start = BROTLI_MIN(size_t,
3381
0
        position + position_offset, max_backward_limit);
3382
0
    HasherSearchResult sr;
3383
0
    int dict_id = 0;
3384
0
    uint8_t p1 = 0;
3385
0
    uint8_t p2 = 0;
3386
0
    if (params->dictionary.contextual.context_based) {
3387
0
      p1 = position >= 1 ?
3388
0
          ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
3389
0
      p2 = position >= 2 ?
3390
0
          ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
3391
0
      dict_id = params->dictionary.contextual.context_map[
3392
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
3393
0
    }
3394
0
    sr.len = 0;
3395
0
    sr.len_code_delta = 0;
3396
0
    sr.distance = 0;
3397
0
    sr.score = kMinScore;
3398
0
    FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
3399
0
        ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
3400
0
        max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
3401
0
    if (ENABLE_COMPOUND_DICTIONARY) {
3402
0
      LookupCompoundDictionaryMatch(&params->dictionary.compound, ringbuffer,
3403
0
          ringbuffer_mask, dist_cache, position, max_length,
3404
0
          dictionary_start, params->dist.max_distance, &sr);
3405
0
    }
3406
0
    if (sr.score > kMinScore) {
3407
      /* Found a match. Let's look for something even better ahead. */
3408
0
      int delayed_backward_references_in_row = 0;
3409
0
      --max_length;
3410
0
      for (;; --max_length) {
3411
0
        const score_t cost_diff_lazy = 175;
3412
0
        HasherSearchResult sr2;
3413
0
        sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
3414
0
            BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
3415
0
        sr2.len_code_delta = 0;
3416
0
        sr2.distance = 0;
3417
0
        sr2.score = kMinScore;
3418
0
        max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
3419
0
        dictionary_start = BROTLI_MIN(size_t,
3420
0
            position + 1 + position_offset, max_backward_limit);
3421
0
        if (params->dictionary.contextual.context_based) {
3422
0
          p2 = p1;
3423
0
          p1 = ringbuffer[position & ringbuffer_mask];
3424
0
          dict_id = params->dictionary.contextual.context_map[
3425
0
              BROTLI_CONTEXT(p1, p2, literal_context_lut)];
3426
0
        }
3427
0
        FN(FindLongestMatch)(privat,
3428
0
            params->dictionary.contextual.dict[dict_id],
3429
0
            ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
3430
0
            max_distance, dictionary_start + gap, params->dist.max_distance,
3431
0
            &sr2);
3432
0
        if (ENABLE_COMPOUND_DICTIONARY) {
3433
0
          LookupCompoundDictionaryMatch(
3434
0
              &params->dictionary.compound, ringbuffer,
3435
0
              ringbuffer_mask, dist_cache, position + 1, max_length,
3436
0
              dictionary_start, params->dist.max_distance, &sr2);
3437
0
        }
3438
0
        if (sr2.score >= sr.score + cost_diff_lazy) {
3439
          /* Ok, let's just write one byte for now and start a match from the
3440
             next byte. */
3441
0
          ++position;
3442
0
          ++insert_length;
3443
0
          sr = sr2;
3444
0
          if (++delayed_backward_references_in_row < 4 &&
3445
0
              position + FN(HashTypeLength)() < pos_end) {
3446
0
            continue;
3447
0
          }
3448
0
        }
3449
0
        break;
3450
0
      }
3451
0
      apply_random_heuristics =
3452
0
          position + 2 * sr.len + random_heuristics_window_size;
3453
0
      dictionary_start = BROTLI_MIN(size_t,
3454
0
          position + position_offset, max_backward_limit);
3455
0
      {
3456
        /* The first 16 codes are special short-codes,
3457
           and the minimum offset is 1. */
3458
0
        size_t distance_code = ComputeDistanceCode(
3459
0
            sr.distance, dictionary_start + gap, dist_cache);
3460
0
        if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
3461
0
          dist_cache[3] = dist_cache[2];
3462
0
          dist_cache[2] = dist_cache[1];
3463
0
          dist_cache[1] = dist_cache[0];
3464
0
          dist_cache[0] = (int)sr.distance;
3465
0
          FN(PrepareDistanceCache)(privat, dist_cache);
3466
0
        }
3467
0
        InitCommand(commands++, &params->dist, insert_length,
3468
0
            sr.len, sr.len_code_delta, distance_code);
3469
0
      }
3470
0
      *num_literals += insert_length;
3471
0
      insert_length = 0;
3472
      /* Put the hash keys into the table, if there are enough bytes left.
3473
         Depending on the hasher implementation, it can push all positions
3474
         in the given range or only a subset of them.
3475
         Avoid hash poisoning with RLE data. */
3476
0
      {
3477
0
        size_t range_start = position + 2;
3478
0
        size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
3479
0
        if (sr.distance < (sr.len >> 2)) {
3480
0
          range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
3481
0
              range_start, position + sr.len - (sr.distance << 2)));
3482
0
        }
3483
0
        FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
3484
0
                       range_end);
3485
0
      }
3486
0
      position += sr.len;
3487
0
    } else {
3488
0
      ++insert_length;
3489
0
      ++position;
3490
      /* If we have not seen matches for a long time, we can skip some
3491
         match lookups. Unsuccessful match lookups are very very expensive
3492
         and this kind of a heuristic speeds up compression quite
3493
         a lot. */
3494
0
      if (position > apply_random_heuristics) {
3495
        /* Going through uncompressible data, jump. */
3496
0
        if (position >
3497
0
            apply_random_heuristics + 4 * random_heuristics_window_size) {
3498
          /* It is quite a long time since we saw a copy, so we assume
3499
             that this data is not compressible, and store hashes less
3500
             often. Hashes of non compressible data are less likely to
3501
             turn out to be useful in the future, too, so we store less of
3502
             them to not to flood out the hash table of good compressible
3503
             data. */
3504
0
          const size_t kMargin =
3505
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
3506
0
          size_t pos_jump =
3507
0
              BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
3508
0
          for (; position < pos_jump; position += 4) {
3509
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
3510
0
            insert_length += 4;
3511
0
          }
3512
0
        } else {
3513
0
          const size_t kMargin =
3514
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
3515
0
          size_t pos_jump =
3516
0
              BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
3517
0
          for (; position < pos_jump; position += 2) {
3518
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
3519
0
            insert_length += 2;
3520
0
          }
3521
0
        }
3522
0
      }
3523
0
    }
3524
0
  }
3525
0
  insert_length += pos_end - position;
3526
0
  *last_insert_len = insert_length;
3527
0
  *num_commands += (size_t)(commands - orig_commands);
3528
0
}
3529
#undef HASHER
3530
0
#define HASHER() H65
3531
/* NOLINTNEXTLINE(build/include) */
3532
/* NOLINT(build/header_guard) */
3533
/* Copyright 2013 Google Inc. All Rights Reserved.
3534
3535
   Distributed under MIT license.
3536
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
3537
*/
3538
3539
/* template parameters: EXPORT_FN, FN */
3540
3541
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
3542
    size_t num_bytes, size_t position,
3543
    const uint8_t* ringbuffer, size_t ringbuffer_mask,
3544
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
3545
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
3546
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
3547
0
  HASHER()* privat = &hasher->privat.FN(_);
3548
  /* Set maximum distance, see section 9.1. of the spec. */
3549
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
3550
0
  const size_t position_offset = params->stream_offset;
3551
3552
0
  const Command* const orig_commands = commands;
3553
0
  size_t insert_length = *last_insert_len;
3554
0
  const size_t pos_end = position + num_bytes;
3555
0
  const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
3556
0
      position + num_bytes - FN(StoreLookahead)() + 1 : position;
3557
3558
  /* For speed up heuristics for random data. */
3559
0
  const size_t random_heuristics_window_size =
3560
0
      LiteralSpreeLengthForSparseSearch(params);
3561
0
  size_t apply_random_heuristics = position + random_heuristics_window_size;
3562
0
  const size_t gap = params->dictionary.compound.total_size;
3563
3564
  /* Minimum score to accept a backward reference. */
3565
0
  const score_t kMinScore = BROTLI_SCORE_BASE + 100;
3566
3567
0
  FN(PrepareDistanceCache)(privat, dist_cache);
3568
3569
0
  while (position + FN(HashTypeLength)() < pos_end) {
3570
0
    size_t max_length = pos_end - position;
3571
0
    size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
3572
0
    size_t dictionary_start = BROTLI_MIN(size_t,
3573
0
        position + position_offset, max_backward_limit);
3574
0
    HasherSearchResult sr;
3575
0
    int dict_id = 0;
3576
0
    uint8_t p1 = 0;
3577
0
    uint8_t p2 = 0;
3578
0
    if (params->dictionary.contextual.context_based) {
3579
0
      p1 = position >= 1 ?
3580
0
          ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
3581
0
      p2 = position >= 2 ?
3582
0
          ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
3583
0
      dict_id = params->dictionary.contextual.context_map[
3584
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
3585
0
    }
3586
0
    sr.len = 0;
3587
0
    sr.len_code_delta = 0;
3588
0
    sr.distance = 0;
3589
0
    sr.score = kMinScore;
3590
0
    FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
3591
0
        ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
3592
0
        max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
3593
0
    if (ENABLE_COMPOUND_DICTIONARY) {
3594
0
      LookupCompoundDictionaryMatch(&params->dictionary.compound, ringbuffer,
3595
0
          ringbuffer_mask, dist_cache, position, max_length,
3596
0
          dictionary_start, params->dist.max_distance, &sr);
3597
0
    }
3598
0
    if (sr.score > kMinScore) {
3599
      /* Found a match. Let's look for something even better ahead. */
3600
0
      int delayed_backward_references_in_row = 0;
3601
0
      --max_length;
3602
0
      for (;; --max_length) {
3603
0
        const score_t cost_diff_lazy = 175;
3604
0
        HasherSearchResult sr2;
3605
0
        sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
3606
0
            BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
3607
0
        sr2.len_code_delta = 0;
3608
0
        sr2.distance = 0;
3609
0
        sr2.score = kMinScore;
3610
0
        max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
3611
0
        dictionary_start = BROTLI_MIN(size_t,
3612
0
            position + 1 + position_offset, max_backward_limit);
3613
0
        if (params->dictionary.contextual.context_based) {
3614
0
          p2 = p1;
3615
0
          p1 = ringbuffer[position & ringbuffer_mask];
3616
0
          dict_id = params->dictionary.contextual.context_map[
3617
0
              BROTLI_CONTEXT(p1, p2, literal_context_lut)];
3618
0
        }
3619
0
        FN(FindLongestMatch)(privat,
3620
0
            params->dictionary.contextual.dict[dict_id],
3621
0
            ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
3622
0
            max_distance, dictionary_start + gap, params->dist.max_distance,
3623
0
            &sr2);
3624
0
        if (ENABLE_COMPOUND_DICTIONARY) {
3625
0
          LookupCompoundDictionaryMatch(
3626
0
              &params->dictionary.compound, ringbuffer,
3627
0
              ringbuffer_mask, dist_cache, position + 1, max_length,
3628
0
              dictionary_start, params->dist.max_distance, &sr2);
3629
0
        }
3630
0
        if (sr2.score >= sr.score + cost_diff_lazy) {
3631
          /* Ok, let's just write one byte for now and start a match from the
3632
             next byte. */
3633
0
          ++position;
3634
0
          ++insert_length;
3635
0
          sr = sr2;
3636
0
          if (++delayed_backward_references_in_row < 4 &&
3637
0
              position + FN(HashTypeLength)() < pos_end) {
3638
0
            continue;
3639
0
          }
3640
0
        }
3641
0
        break;
3642
0
      }
3643
0
      apply_random_heuristics =
3644
0
          position + 2 * sr.len + random_heuristics_window_size;
3645
0
      dictionary_start = BROTLI_MIN(size_t,
3646
0
          position + position_offset, max_backward_limit);
3647
0
      {
3648
        /* The first 16 codes are special short-codes,
3649
           and the minimum offset is 1. */
3650
0
        size_t distance_code = ComputeDistanceCode(
3651
0
            sr.distance, dictionary_start + gap, dist_cache);
3652
0
        if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
3653
0
          dist_cache[3] = dist_cache[2];
3654
0
          dist_cache[2] = dist_cache[1];
3655
0
          dist_cache[1] = dist_cache[0];
3656
0
          dist_cache[0] = (int)sr.distance;
3657
0
          FN(PrepareDistanceCache)(privat, dist_cache);
3658
0
        }
3659
0
        InitCommand(commands++, &params->dist, insert_length,
3660
0
            sr.len, sr.len_code_delta, distance_code);
3661
0
      }
3662
0
      *num_literals += insert_length;
3663
0
      insert_length = 0;
3664
      /* Put the hash keys into the table, if there are enough bytes left.
3665
         Depending on the hasher implementation, it can push all positions
3666
         in the given range or only a subset of them.
3667
         Avoid hash poisoning with RLE data. */
3668
0
      {
3669
0
        size_t range_start = position + 2;
3670
0
        size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
3671
0
        if (sr.distance < (sr.len >> 2)) {
3672
0
          range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
3673
0
              range_start, position + sr.len - (sr.distance << 2)));
3674
0
        }
3675
0
        FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
3676
0
                       range_end);
3677
0
      }
3678
0
      position += sr.len;
3679
0
    } else {
3680
0
      ++insert_length;
3681
0
      ++position;
3682
      /* If we have not seen matches for a long time, we can skip some
3683
         match lookups. Unsuccessful match lookups are very very expensive
3684
         and this kind of a heuristic speeds up compression quite
3685
         a lot. */
3686
0
      if (position > apply_random_heuristics) {
3687
        /* Going through uncompressible data, jump. */
3688
0
        if (position >
3689
0
            apply_random_heuristics + 4 * random_heuristics_window_size) {
3690
          /* It is quite a long time since we saw a copy, so we assume
3691
             that this data is not compressible, and store hashes less
3692
             often. Hashes of non compressible data are less likely to
3693
             turn out to be useful in the future, too, so we store less of
3694
             them to not to flood out the hash table of good compressible
3695
             data. */
3696
0
          const size_t kMargin =
3697
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
3698
0
          size_t pos_jump =
3699
0
              BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
3700
0
          for (; position < pos_jump; position += 4) {
3701
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
3702
0
            insert_length += 4;
3703
0
          }
3704
0
        } else {
3705
0
          const size_t kMargin =
3706
0
              BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
3707
0
          size_t pos_jump =
3708
0
              BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
3709
0
          for (; position < pos_jump; position += 2) {
3710
0
            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
3711
0
            insert_length += 2;
3712
0
          }
3713
0
        }
3714
0
      }
3715
0
    }
3716
0
  }
3717
0
  insert_length += pos_end - position;
3718
0
  *last_insert_len = insert_length;
3719
0
  *num_commands += (size_t)(commands - orig_commands);
3720
0
}
3721
#undef HASHER
3722
3723
#undef ENABLE_COMPOUND_DICTIONARY
3724
#undef PREFIX
3725
3726
#undef EXPORT_FN
3727
#undef FN
3728
#undef CAT
3729
#undef EXPAND_CAT
3730
3731
void duckdb_brotli::BrotliCreateBackwardReferences(size_t num_bytes,
3732
    size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
3733
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
3734
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
3735
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
3736
0
  if (params->dictionary.compound.num_chunks != 0) {
3737
0
    switch (params->hasher.type) {
3738
0
#define CASE_(N)                                                    \
3739
0
      case N:                                                       \
3740
0
        CreateBackwardReferencesDH ## N(num_bytes,                  \
3741
0
            position, ringbuffer, ringbuffer_mask,                  \
3742
0
            literal_context_lut, params, hasher, dist_cache,        \
3743
0
            last_insert_len, commands, num_commands, num_literals); \
3744
0
        return;
3745
0
      CASE_(5)
3746
0
      CASE_(6)
3747
0
      CASE_(40)
3748
0
      CASE_(41)
3749
0
      CASE_(42)
3750
0
      CASE_(55)
3751
0
      CASE_(65)
3752
0
#undef CASE_
3753
0
      default:
3754
0
        BROTLI_DCHECK(false);
3755
0
        break;
3756
0
    }
3757
0
  }
3758
3759
0
  switch (params->hasher.type) {
3760
0
#define CASE_(N)                                                  \
3761
0
    case N:                                                       \
3762
0
      CreateBackwardReferencesNH ## N(num_bytes,                  \
3763
0
          position, ringbuffer, ringbuffer_mask,                  \
3764
0
          literal_context_lut, params, hasher, dist_cache,        \
3765
0
          last_insert_len, commands, num_commands, num_literals); \
3766
0
      return;
3767
0
    FOR_GENERIC_HASHERS(CASE_)
3768
0
#undef CASE_
3769
0
    default:
3770
0
      BROTLI_DCHECK(false);
3771
0
      break;
3772
0
  }
3773
0
}
3774
3775