Coverage Report

Created: 2026-04-09 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/brotli/c/enc/backward_references_hq.c
Line
Count
Source
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_hq.h"
10
11
#include "../common/constants.h"
12
#include "../common/context.h"
13
#include "../common/platform.h"
14
#include "command.h"
15
#include "compound_dictionary.h"
16
#include "encoder_dict.h"
17
#include "fast_log.h"
18
#include "find_match_length.h"
19
#include "hash.h"
20
#include "literal_cost.h"
21
#include "memory.h"
22
#include "params.h"
23
#include "prefix.h"
24
#include "quality.h"
25
26
#if defined(__cplusplus) || defined(c_plusplus)
27
extern "C" {
28
#endif
29
30
/* BrotliCalculateDistanceCodeLimit(BROTLI_MAX_ALLOWED_DISTANCE, 3, 120). */
31
#define BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE 544
32
33
static const float kInfinity = 1.7e38f;  /* ~= 2 ^ 127 */
34
35
static const BROTLI_MODEL("small") uint32_t kDistanceCacheIndex[] = {
36
  0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
37
};
38
static const BROTLI_MODEL("small") int kDistanceCacheOffset[] = {
39
  0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3
40
};
41
42
0
void BrotliInitZopfliNodes(ZopfliNode* array, size_t length) {
43
0
  ZopfliNode stub;
44
0
  size_t i;
45
0
  stub.length = 1;
46
0
  stub.distance = 0;
47
0
  stub.dcode_insert_length = 0;
48
0
  stub.u.cost = kInfinity;
49
0
  for (i = 0; i < length; ++i) array[i] = stub;
50
0
}
51
52
0
static BROTLI_INLINE uint32_t ZopfliNodeCopyLength(const ZopfliNode* self) {
53
0
  return self->length & 0x1FFFFFF;
54
0
}
55
56
0
static BROTLI_INLINE uint32_t ZopfliNodeLengthCode(const ZopfliNode* self) {
57
0
  const uint32_t modifier = self->length >> 25;
58
0
  return ZopfliNodeCopyLength(self) + 9u - modifier;
59
0
}
60
61
0
static BROTLI_INLINE uint32_t ZopfliNodeCopyDistance(const ZopfliNode* self) {
62
0
  return self->distance;
63
0
}
64
65
0
static BROTLI_INLINE uint32_t ZopfliNodeDistanceCode(const ZopfliNode* self) {
66
0
  const uint32_t short_code = self->dcode_insert_length >> 27;
67
0
  return short_code == 0 ?
68
0
      ZopfliNodeCopyDistance(self) + BROTLI_NUM_DISTANCE_SHORT_CODES - 1 :
69
0
      short_code - 1;
70
0
}
71
72
0
static BROTLI_INLINE uint32_t ZopfliNodeCommandLength(const ZopfliNode* self) {
73
0
  return ZopfliNodeCopyLength(self) + (self->dcode_insert_length & 0x7FFFFFF);
74
0
}
75
76
/* Temporary data for ZopfliCostModelSetFromCommands. */
77
typedef struct ZopfliCostModelArena {
78
  uint32_t histogram_literal[BROTLI_NUM_LITERAL_SYMBOLS];
79
  uint32_t histogram_cmd[BROTLI_NUM_COMMAND_SYMBOLS];
80
  uint32_t histogram_dist[BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE];
81
  float cost_literal[BROTLI_NUM_LITERAL_SYMBOLS];
82
} ZopfliCostModelArena;
83
84
/* Histogram based cost model for zopflification. */
85
typedef struct ZopfliCostModel {
86
  /* The insert and copy length symbols. */
87
  float cost_cmd_[BROTLI_NUM_COMMAND_SYMBOLS];
88
  float* cost_dist_;
89
  uint32_t distance_histogram_size;
90
  /* Cumulative costs of literals per position in the stream. */
91
  float* literal_costs_;
92
  float min_cost_cmd_;
93
  size_t num_bytes_;
94
95
  /* Temporary data. */
96
  union {
97
    size_t literal_histograms[3 * 256];
98
    ZopfliCostModelArena arena;
99
  };
100
} ZopfliCostModel;
101
102
static void InitZopfliCostModel(
103
    MemoryManager* m, ZopfliCostModel* self, const BrotliDistanceParams* dist,
104
0
    size_t num_bytes) {
105
0
  self->num_bytes_ = num_bytes;
106
0
  self->literal_costs_ = BROTLI_ALLOC(m, float, num_bytes + 2);
107
0
  self->cost_dist_ = BROTLI_ALLOC(m, float, dist->alphabet_size_limit);
108
0
  self->distance_histogram_size = dist->alphabet_size_limit;
109
0
  if (BROTLI_IS_OOM(m)) return;
110
0
}
111
112
0
static void CleanupZopfliCostModel(MemoryManager* m, ZopfliCostModel* self) {
113
0
  BROTLI_FREE(m, self->literal_costs_);
114
0
  BROTLI_FREE(m, self->cost_dist_);
115
0
}
116
117
static void SetCost(const uint32_t* histogram, size_t histogram_size,
118
0
                    BROTLI_BOOL literal_histogram, float* cost) {
119
0
  size_t sum = 0;
120
0
  size_t missing_symbol_sum;
121
0
  float log2sum;
122
0
  float missing_symbol_cost;
123
0
  size_t i;
124
0
  for (i = 0; i < histogram_size; i++) {
125
0
    sum += histogram[i];
126
0
  }
127
0
  log2sum = (float)FastLog2(sum);
128
0
  missing_symbol_sum = sum;
129
0
  if (!literal_histogram) {
130
0
    for (i = 0; i < histogram_size; i++) {
131
0
      if (histogram[i] == 0) missing_symbol_sum++;
132
0
    }
133
0
  }
134
0
  missing_symbol_cost = (float)FastLog2(missing_symbol_sum) + 2;
135
0
  for (i = 0; i < histogram_size; i++) {
136
0
    if (histogram[i] == 0) {
137
0
      cost[i] = missing_symbol_cost;
138
0
      continue;
139
0
    }
140
141
    /* Shannon bits for this symbol. */
142
0
    cost[i] = log2sum - (float)FastLog2(histogram[i]);
143
144
    /* Cannot be coded with less than 1 bit */
145
0
    if (cost[i] < 1) cost[i] = 1;
146
0
  }
147
0
}
148
149
static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
150
                                           size_t position,
151
                                           const uint8_t* ringbuffer,
152
                                           size_t ringbuffer_mask,
153
                                           const Command* commands,
154
                                           size_t num_commands,
155
0
                                           size_t last_insert_len) {
156
0
  ZopfliCostModelArena* arena = &self->arena;
157
0
  size_t pos = position - last_insert_len;
158
0
  float min_cost_cmd = kInfinity;
159
0
  size_t i;
160
0
  float* cost_cmd = self->cost_cmd_;
161
162
0
  memset(arena->histogram_literal, 0, sizeof(arena->histogram_literal));
163
0
  memset(arena->histogram_cmd, 0, sizeof(arena->histogram_cmd));
164
0
  memset(arena->histogram_dist, 0, sizeof(arena->histogram_dist));
165
166
0
  for (i = 0; i < num_commands; i++) {
167
0
    size_t inslength = commands[i].insert_len_;
168
0
    size_t copylength = CommandCopyLen(&commands[i]);
169
0
    size_t distcode = commands[i].dist_prefix_ & 0x3FF;
170
0
    size_t cmdcode = commands[i].cmd_prefix_;
171
0
    size_t j;
172
173
0
    arena->histogram_cmd[cmdcode]++;
174
0
    if (cmdcode >= 128) arena->histogram_dist[distcode]++;
175
176
0
    for (j = 0; j < inslength; j++) {
177
0
      arena->histogram_literal[ringbuffer[(pos + j) & ringbuffer_mask]]++;
178
0
    }
179
180
0
    pos += inslength + copylength;
181
0
  }
182
183
0
  SetCost(arena->histogram_literal, BROTLI_NUM_LITERAL_SYMBOLS, BROTLI_TRUE,
184
0
          arena->cost_literal);
185
0
  SetCost(arena->histogram_cmd, BROTLI_NUM_COMMAND_SYMBOLS, BROTLI_FALSE,
186
0
          cost_cmd);
187
0
  SetCost(arena->histogram_dist, self->distance_histogram_size, BROTLI_FALSE,
188
0
          self->cost_dist_);
189
190
0
  for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
191
0
    min_cost_cmd = BROTLI_MIN(float, min_cost_cmd, cost_cmd[i]);
192
0
  }
193
0
  self->min_cost_cmd_ = min_cost_cmd;
194
195
0
  {
196
0
    float* literal_costs = self->literal_costs_;
197
0
    float literal_carry = 0.0;
198
0
    size_t num_bytes = self->num_bytes_;
199
0
    literal_costs[0] = 0.0;
200
0
    for (i = 0; i < num_bytes; ++i) {
201
0
      literal_carry +=
202
0
          arena->cost_literal[ringbuffer[(position + i) & ringbuffer_mask]];
203
0
      literal_costs[i + 1] = literal_costs[i] + literal_carry;
204
0
      literal_carry -= literal_costs[i + 1] - literal_costs[i];
205
0
    }
206
0
  }
207
0
}
208
209
static void ZopfliCostModelSetFromLiteralCosts(ZopfliCostModel* self,
210
                                               size_t position,
211
                                               const uint8_t* ringbuffer,
212
0
                                               size_t ringbuffer_mask) {
213
0
  float* literal_costs = self->literal_costs_;
214
0
  float literal_carry = 0.0;
215
0
  float* cost_dist = self->cost_dist_;
216
0
  float* cost_cmd = self->cost_cmd_;
217
0
  size_t num_bytes = self->num_bytes_;
218
0
  size_t i;
219
0
  BrotliEstimateBitCostsForLiterals(position, num_bytes, ringbuffer_mask,
220
0
                                    ringbuffer, self->literal_histograms,
221
0
                                    &literal_costs[1]);
222
0
  literal_costs[0] = 0.0;
223
0
  for (i = 0; i < num_bytes; ++i) {
224
0
    literal_carry += literal_costs[i + 1];
225
0
    literal_costs[i + 1] = literal_costs[i] + literal_carry;
226
0
    literal_carry -= literal_costs[i + 1] - literal_costs[i];
227
0
  }
228
0
  for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
229
0
    cost_cmd[i] = (float)FastLog2(11 + (uint32_t)i);
230
0
  }
231
0
  for (i = 0; i < self->distance_histogram_size; ++i) {
232
0
    cost_dist[i] = (float)FastLog2(20 + (uint32_t)i);
233
0
  }
234
0
  self->min_cost_cmd_ = (float)FastLog2(11);
235
0
}
236
237
static BROTLI_INLINE float ZopfliCostModelGetCommandCost(
238
0
    const ZopfliCostModel* self, uint16_t cmdcode) {
239
0
  return self->cost_cmd_[cmdcode];
240
0
}
241
242
static BROTLI_INLINE float ZopfliCostModelGetDistanceCost(
243
0
    const ZopfliCostModel* self, size_t distcode) {
244
0
  return self->cost_dist_[distcode];
245
0
}
246
247
static BROTLI_INLINE float ZopfliCostModelGetLiteralCosts(
248
0
    const ZopfliCostModel* self, size_t from, size_t to) {
249
0
  return self->literal_costs_[to] - self->literal_costs_[from];
250
0
}
251
252
static BROTLI_INLINE float ZopfliCostModelGetMinCostCmd(
253
0
    const ZopfliCostModel* self) {
254
0
  return self->min_cost_cmd_;
255
0
}
256
257
/* REQUIRES: len >= 2, start_pos <= pos */
258
/* REQUIRES: cost < kInfinity, nodes[start_pos].cost < kInfinity */
259
/* Maintains the "ZopfliNode array invariant". */
260
static BROTLI_INLINE void UpdateZopfliNode(ZopfliNode* nodes, size_t pos,
261
    size_t start_pos, size_t len, size_t len_code, size_t dist,
262
0
    size_t short_code, float cost) {
263
0
  ZopfliNode* next = &nodes[pos + len];
264
0
  next->length = (uint32_t)(len | ((len + 9u - len_code) << 25));
265
0
  next->distance = (uint32_t)dist;
266
0
  next->dcode_insert_length = (uint32_t)(
267
0
      (short_code << 27) | (pos - start_pos));
268
0
  next->u.cost = cost;
269
0
}
270
271
typedef struct PosData {
272
  size_t pos;
273
  int distance_cache[4];
274
  float costdiff;
275
  float cost;
276
} PosData;
277
278
/* Maintains the smallest 8 cost difference together with their positions */
279
typedef struct StartPosQueue {
280
  PosData q_[8];
281
  size_t idx_;
282
} StartPosQueue;
283
284
0
static BROTLI_INLINE void InitStartPosQueue(StartPosQueue* self) {
285
0
  self->idx_ = 0;
286
0
}
287
288
0
static size_t StartPosQueueSize(const StartPosQueue* self) {
289
0
  return BROTLI_MIN(size_t, self->idx_, 8);
290
0
}
291
292
0
static void StartPosQueuePush(StartPosQueue* self, const PosData* posdata) {
293
0
  size_t offset = ~(self->idx_++) & 7;
294
0
  size_t len = StartPosQueueSize(self);
295
0
  size_t i;
296
0
  PosData* q = self->q_;
297
0
  q[offset] = *posdata;
298
  /* Restore the sorted order. In the list of |len| items at most |len - 1|
299
     adjacent element comparisons / swaps are required. */
300
0
  for (i = 1; i < len; ++i) {
301
0
    if (q[offset & 7].costdiff > q[(offset + 1) & 7].costdiff) {
302
0
      BROTLI_SWAP(PosData, q, offset & 7, (offset + 1) & 7);
303
0
    }
304
0
    ++offset;
305
0
  }
306
0
}
307
308
0
static const PosData* StartPosQueueAt(const StartPosQueue* self, size_t k) {
309
0
  return &self->q_[(k - self->idx_) & 7];
310
0
}
311
312
/* Returns the minimum possible copy length that can improve the cost of any */
313
/* future position. */
314
static size_t ComputeMinimumCopyLength(const float start_cost,
315
                                       const ZopfliNode* nodes,
316
                                       const size_t num_bytes,
317
0
                                       const size_t pos) {
318
  /* Compute the minimum possible cost of reaching any future position. */
319
0
  float min_cost = start_cost;
320
0
  size_t len = 2;
321
0
  size_t next_len_bucket = 4;
322
0
  size_t next_len_offset = 10;
323
0
  while (pos + len <= num_bytes && nodes[pos + len].u.cost <= min_cost) {
324
    /* We already reached (pos + len) with no more cost than the minimum
325
       possible cost of reaching anything from this pos, so there is no point in
326
       looking for lengths <= len. */
327
0
    ++len;
328
0
    if (len == next_len_offset) {
329
      /* We reached the next copy length code bucket, so we add one more
330
         extra bit to the minimum cost. */
331
0
      min_cost += 1.0f;
332
0
      next_len_offset += next_len_bucket;
333
0
      next_len_bucket *= 2;
334
0
    }
335
0
  }
336
0
  return len;
337
0
}
338
339
/* REQUIRES: nodes[pos].cost < kInfinity
340
   REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
341
static uint32_t ComputeDistanceShortcut(const size_t block_start,
342
                                        const size_t pos,
343
                                        const size_t max_backward_limit,
344
                                        const size_t gap,
345
0
                                        const ZopfliNode* nodes) {
346
0
  const size_t c_len = ZopfliNodeCopyLength(&nodes[pos]);
347
0
  const size_t i_len = nodes[pos].dcode_insert_length & 0x7FFFFFF;
348
0
  const size_t dist = ZopfliNodeCopyDistance(&nodes[pos]);
349
  /* Since |block_start + pos| is the end position of the command, the copy part
350
     starts from |block_start + pos - c_len|. Distances that are greater than
351
     this or greater than |max_backward_limit| + |gap| are static dictionary
352
     references, and do not update the last distances.
353
     Also distance code 0 (last distance) does not update the last distances. */
354
0
  if (pos == 0) {
355
0
    return 0;
356
0
  } else if (dist + c_len <= block_start + pos + gap &&
357
0
             dist <= max_backward_limit + gap &&
358
0
             ZopfliNodeDistanceCode(&nodes[pos]) > 0) {
359
0
    return (uint32_t)pos;
360
0
  } else {
361
0
    return nodes[pos - c_len - i_len].u.shortcut;
362
0
  }
363
0
}
364
365
/* Fills in dist_cache[0..3] with the last four distances (as defined by
366
   Section 4. of the Spec) that would be used at (block_start + pos) if we
367
   used the shortest path of commands from block_start, computed from
368
   nodes[0..pos]. The last four distances at block_start are in
369
   starting_dist_cache[0..3].
370
   REQUIRES: nodes[pos].cost < kInfinity
371
   REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
372
static void ComputeDistanceCache(const size_t pos,
373
                                 const int* starting_dist_cache,
374
                                 const ZopfliNode* nodes,
375
0
                                 int* dist_cache) {
376
0
  int idx = 0;
377
0
  size_t p = nodes[pos].u.shortcut;
378
0
  while (idx < 4 && p > 0) {
379
0
    const size_t i_len = nodes[p].dcode_insert_length & 0x7FFFFFF;
380
0
    const size_t c_len = ZopfliNodeCopyLength(&nodes[p]);
381
0
    const size_t dist = ZopfliNodeCopyDistance(&nodes[p]);
382
0
    dist_cache[idx++] = (int)dist;
383
    /* Because of prerequisite, p >= c_len + i_len >= 2. */
384
0
    p = nodes[p - c_len - i_len].u.shortcut;
385
0
  }
386
0
  for (; idx < 4; ++idx) {
387
0
    dist_cache[idx] = *starting_dist_cache++;
388
0
  }
389
0
}
390
391
/* Maintains "ZopfliNode array invariant" and pushes node to the queue, if it
392
   is eligible. */
393
static void EvaluateNode(
394
    const size_t block_start, const size_t pos, const size_t max_backward_limit,
395
    const size_t gap, const int* starting_dist_cache,
396
0
    const ZopfliCostModel* model, StartPosQueue* queue, ZopfliNode* nodes) {
397
  /* Save cost, because ComputeDistanceCache invalidates it. */
398
0
  float node_cost = nodes[pos].u.cost;
399
0
  nodes[pos].u.shortcut = ComputeDistanceShortcut(
400
0
      block_start, pos, max_backward_limit, gap, nodes);
401
0
  if (node_cost <= ZopfliCostModelGetLiteralCosts(model, 0, pos)) {
402
0
    PosData posdata;
403
0
    posdata.pos = pos;
404
0
    posdata.cost = node_cost;
405
0
    posdata.costdiff = node_cost -
406
0
        ZopfliCostModelGetLiteralCosts(model, 0, pos);
407
0
    ComputeDistanceCache(
408
0
        pos, starting_dist_cache, nodes, posdata.distance_cache);
409
0
    StartPosQueuePush(queue, &posdata);
410
0
  }
411
0
}
412
413
/* Returns longest copy length. */
414
static size_t UpdateNodes(
415
    const size_t num_bytes, const size_t block_start, const size_t pos,
416
    const uint8_t* ringbuffer, const size_t ringbuffer_mask,
417
    const BrotliEncoderParams* params, const size_t max_backward_limit,
418
    const int* starting_dist_cache, const size_t num_matches,
419
    const BackwardMatch* matches, const ZopfliCostModel* model,
420
0
    StartPosQueue* queue, ZopfliNode* nodes) {
421
0
  const size_t stream_offset = params->stream_offset;
422
0
  const size_t cur_ix = block_start + pos;
423
0
  const size_t cur_ix_masked = cur_ix & ringbuffer_mask;
424
0
  const size_t max_distance = BROTLI_MIN(size_t, cur_ix, max_backward_limit);
425
0
  const size_t dictionary_start = BROTLI_MIN(size_t,
426
0
      cur_ix + stream_offset, max_backward_limit);
427
0
  const size_t max_len = num_bytes - pos;
428
0
  const size_t max_zopfli_len = MaxZopfliLen(params);
429
0
  const size_t max_iters = MaxZopfliCandidates(params);
430
0
  size_t min_len;
431
0
  size_t result = 0;
432
0
  size_t k;
433
0
  const CompoundDictionary* addon = &params->dictionary.compound;
434
0
  size_t gap = addon->total_size;
435
436
0
  BROTLI_DCHECK(cur_ix_masked + max_len <= ringbuffer_mask + 1);
437
438
0
  EvaluateNode(block_start + stream_offset, pos, max_backward_limit, gap,
439
0
      starting_dist_cache, model, queue, nodes);
440
441
0
  {
442
0
    const PosData* posdata = StartPosQueueAt(queue, 0);
443
0
    float min_cost = (posdata->cost + ZopfliCostModelGetMinCostCmd(model) +
444
0
        ZopfliCostModelGetLiteralCosts(model, posdata->pos, pos));
445
0
    min_len = ComputeMinimumCopyLength(min_cost, nodes, num_bytes, pos);
446
0
  }
447
448
  /* Go over the command starting positions in order of increasing cost
449
     difference. */
450
0
  for (k = 0; k < max_iters && k < StartPosQueueSize(queue); ++k) {
451
0
    const PosData* posdata = StartPosQueueAt(queue, k);
452
0
    const size_t start = posdata->pos;
453
0
    const uint16_t inscode = GetInsertLengthCode(pos - start);
454
0
    const float start_costdiff = posdata->costdiff;
455
0
    const float base_cost = start_costdiff + (float)GetInsertExtra(inscode) +
456
0
        ZopfliCostModelGetLiteralCosts(model, 0, pos);
457
458
    /* Look for last distance matches using the distance cache from this
459
       starting position. */
460
0
    size_t best_len = min_len - 1;
461
0
    size_t j = 0;
462
0
    for (; j < BROTLI_NUM_DISTANCE_SHORT_CODES && best_len < max_len; ++j) {
463
0
      const size_t idx = kDistanceCacheIndex[j];
464
0
      const size_t backward =
465
0
          (size_t)(posdata->distance_cache[idx] + kDistanceCacheOffset[j]);
466
0
      size_t prev_ix = cur_ix - backward;
467
0
      size_t len = 0;
468
0
      uint8_t continuation = ringbuffer[cur_ix_masked + best_len];
469
0
      if (cur_ix_masked + best_len > ringbuffer_mask) {
470
0
        break;
471
0
      }
472
0
      if (BROTLI_PREDICT_FALSE(backward > dictionary_start + gap)) {
473
        /* Word dictionary -> ignore. */
474
0
        continue;
475
0
      }
476
0
      if (backward <= max_distance) {
477
        /* Regular backward reference. */
478
0
        if (prev_ix >= cur_ix) {
479
0
          continue;
480
0
        }
481
482
0
        prev_ix &= ringbuffer_mask;
483
0
        if (prev_ix + best_len > ringbuffer_mask ||
484
0
            continuation != ringbuffer[prev_ix + best_len]) {
485
0
          continue;
486
0
        }
487
0
        len = FindMatchLengthWithLimit(&ringbuffer[prev_ix],
488
0
                                       &ringbuffer[cur_ix_masked],
489
0
                                       max_len);
490
0
      } else if (backward > dictionary_start) {
491
0
        size_t d = 0;
492
0
        size_t offset;
493
0
        size_t limit;
494
0
        const uint8_t* source;
495
0
        offset = dictionary_start + 1 + addon->total_size - 1;
496
0
        while (offset >= backward + addon->chunk_offsets[d + 1]) d++;
497
0
        source = addon->chunk_source[d];
498
0
        offset = offset - addon->chunk_offsets[d] - backward;
499
0
        limit = addon->chunk_offsets[d + 1] - addon->chunk_offsets[d] - offset;
500
0
        limit = limit > max_len ? max_len : limit;
501
0
        if (best_len >= limit ||
502
0
            continuation != source[offset + best_len]) {
503
0
          continue;
504
0
        }
505
0
        len = FindMatchLengthWithLimit(&source[offset],
506
0
                                       &ringbuffer[cur_ix_masked],
507
0
                                       limit);
508
0
      } else {
509
        /* "Gray" area. It is addressable by decoder, but this encoder
510
           instance does not have that data -> should not touch it. */
511
0
        continue;
512
0
      }
513
0
      {
514
0
        const float dist_cost = base_cost +
515
0
            ZopfliCostModelGetDistanceCost(model, j);
516
0
        size_t l;
517
0
        for (l = best_len + 1; l <= len; ++l) {
518
0
          const uint16_t copycode = GetCopyLengthCode(l);
519
0
          const uint16_t cmdcode =
520
0
              CombineLengthCodes(inscode, copycode, j == 0);
521
0
          const float cost = (cmdcode < 128 ? base_cost : dist_cost) +
522
0
              (float)GetCopyExtra(copycode) +
523
0
              ZopfliCostModelGetCommandCost(model, cmdcode);
524
0
          if (cost < nodes[pos + l].u.cost) {
525
0
            UpdateZopfliNode(nodes, pos, start, l, l, backward, j + 1, cost);
526
0
            result = BROTLI_MAX(size_t, result, l);
527
0
          }
528
0
          best_len = l;
529
0
        }
530
0
      }
531
0
    }
532
533
    /* At higher iterations look only for new last distance matches, since
534
       looking only for new command start positions with the same distances
535
       does not help much. */
536
0
    if (k >= 2) continue;
537
538
0
    {
539
      /* Loop through all possible copy lengths at this position. */
540
0
      size_t len = min_len;
541
0
      for (j = 0; j < num_matches; ++j) {
542
0
        BackwardMatch match = matches[j];
543
0
        size_t dist = match.distance;
544
0
        BROTLI_BOOL is_dictionary_match =
545
0
            TO_BROTLI_BOOL(dist > dictionary_start + gap);
546
        /* We already tried all possible last distance matches, so we can use
547
           normal distance code here. */
548
0
        size_t dist_code = dist + BROTLI_NUM_DISTANCE_SHORT_CODES - 1;
549
0
        uint16_t dist_symbol;
550
0
        uint32_t distextra;
551
0
        uint32_t distnumextra;
552
0
        float dist_cost;
553
0
        size_t max_match_len;
554
0
        PrefixEncodeCopyDistance(
555
0
            dist_code, params->dist.num_direct_distance_codes,
556
0
            params->dist.distance_postfix_bits, &dist_symbol, &distextra);
557
0
        distnumextra = dist_symbol >> 10;
558
0
        dist_cost = base_cost + (float)distnumextra +
559
0
            ZopfliCostModelGetDistanceCost(model, dist_symbol & 0x3FF);
560
561
        /* Try all copy lengths up until the maximum copy length corresponding
562
           to this distance. If the distance refers to the static dictionary, or
563
           the maximum length is long enough, try only one maximum length. */
564
0
        max_match_len = BackwardMatchLength(&match);
565
0
        if (len < max_match_len &&
566
0
            (is_dictionary_match || max_match_len > max_zopfli_len)) {
567
0
          len = max_match_len;
568
0
        }
569
0
        for (; len <= max_match_len; ++len) {
570
0
          const size_t len_code =
571
0
              is_dictionary_match ? BackwardMatchLengthCode(&match) : len;
572
0
          const uint16_t copycode = GetCopyLengthCode(len_code);
573
0
          const uint16_t cmdcode = CombineLengthCodes(inscode, copycode, 0);
574
0
          const float cost = dist_cost + (float)GetCopyExtra(copycode) +
575
0
              ZopfliCostModelGetCommandCost(model, cmdcode);
576
0
          if (cost < nodes[pos + len].u.cost) {
577
0
            UpdateZopfliNode(nodes, pos, start, len, len_code, dist, 0, cost);
578
0
            result = BROTLI_MAX(size_t, result, len);
579
0
          }
580
0
        }
581
0
      }
582
0
    }
583
0
  }
584
0
  return result;
585
0
}
586
587
static size_t ComputeShortestPathFromNodes(size_t num_bytes,
588
0
    ZopfliNode* nodes) {
589
0
  size_t index = num_bytes;
590
0
  size_t num_commands = 0;
591
0
  while ((nodes[index].dcode_insert_length & 0x7FFFFFF) == 0 &&
592
0
      nodes[index].length == 1) --index;
593
0
  nodes[index].u.next = BROTLI_UINT32_MAX;
594
0
  while (index != 0) {
595
0
    size_t len = ZopfliNodeCommandLength(&nodes[index]);
596
0
    index -= len;
597
0
    nodes[index].u.next = (uint32_t)len;
598
0
    num_commands++;
599
0
  }
600
0
  return num_commands;
601
0
}
602
603
/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
604
void BrotliZopfliCreateCommands(const size_t num_bytes,
605
    const size_t block_start, const ZopfliNode* nodes, int* dist_cache,
606
    size_t* last_insert_len, const BrotliEncoderParams* params,
607
0
    Command* commands, size_t* num_literals) {
608
0
  const size_t stream_offset = params->stream_offset;
609
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
610
0
  size_t pos = 0;
611
0
  uint32_t offset = nodes[0].u.next;
612
0
  size_t i;
613
0
  size_t gap = params->dictionary.compound.total_size;
614
0
  for (i = 0; offset != BROTLI_UINT32_MAX; i++) {
615
0
    const ZopfliNode* next = &nodes[pos + offset];
616
0
    size_t copy_length = ZopfliNodeCopyLength(next);
617
0
    size_t insert_length = next->dcode_insert_length & 0x7FFFFFF;
618
0
    pos += insert_length;
619
0
    offset = next->u.next;
620
0
    if (i == 0) {
621
0
      insert_length += *last_insert_len;
622
0
      *last_insert_len = 0;
623
0
    }
624
0
    {
625
0
      size_t distance = ZopfliNodeCopyDistance(next);
626
0
      size_t len_code = ZopfliNodeLengthCode(next);
627
0
      size_t dictionary_start = BROTLI_MIN(size_t,
628
0
          block_start + pos + stream_offset, max_backward_limit);
629
0
      BROTLI_BOOL is_dictionary =
630
0
          TO_BROTLI_BOOL(distance > dictionary_start + gap);
631
0
      size_t dist_code = ZopfliNodeDistanceCode(next);
632
0
      InitCommand(&commands[i], &params->dist, insert_length,
633
0
          copy_length, (int)len_code - (int)copy_length, dist_code);
634
635
0
      if (!is_dictionary && dist_code > 0) {
636
0
        dist_cache[3] = dist_cache[2];
637
0
        dist_cache[2] = dist_cache[1];
638
0
        dist_cache[1] = dist_cache[0];
639
0
        dist_cache[0] = (int)distance;
640
0
      }
641
0
    }
642
643
0
    *num_literals += insert_length;
644
0
    pos += copy_length;
645
0
  }
646
0
  *last_insert_len += num_bytes - pos;
647
0
}
648
649
static size_t ZopfliIterate(size_t num_bytes, size_t position,
650
    const uint8_t* ringbuffer, size_t ringbuffer_mask,
651
    const BrotliEncoderParams* params, const size_t gap, const int* dist_cache,
652
    const ZopfliCostModel* model, const uint32_t* num_matches,
653
0
    const BackwardMatch* matches, ZopfliNode* nodes) {
654
0
  const size_t stream_offset = params->stream_offset;
655
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
656
0
  const size_t max_zopfli_len = MaxZopfliLen(params);
657
0
  StartPosQueue queue;
658
0
  size_t cur_match_pos = 0;
659
0
  size_t i;
660
0
  nodes[0].length = 0;
661
0
  nodes[0].u.cost = 0;
662
0
  InitStartPosQueue(&queue);
663
0
  for (i = 0; i + 3 < num_bytes; i++) {
664
0
    size_t skip = UpdateNodes(num_bytes, position, i, ringbuffer,
665
0
        ringbuffer_mask, params, max_backward_limit, dist_cache,
666
0
        num_matches[i], &matches[cur_match_pos], model, &queue, nodes);
667
0
    if (skip < BROTLI_LONG_COPY_QUICK_STEP) skip = 0;
668
0
    cur_match_pos += num_matches[i];
669
0
    if (num_matches[i] == 1 &&
670
0
        BackwardMatchLength(&matches[cur_match_pos - 1]) > max_zopfli_len) {
671
0
      skip = BROTLI_MAX(size_t,
672
0
          BackwardMatchLength(&matches[cur_match_pos - 1]), skip);
673
0
    }
674
0
    if (skip > 1) {
675
0
      skip--;
676
0
      while (skip) {
677
0
        i++;
678
0
        if (i + 3 >= num_bytes) break;
679
0
        EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
680
0
            dist_cache, model, &queue, nodes);
681
0
        cur_match_pos += num_matches[i];
682
0
        skip--;
683
0
      }
684
0
    }
685
0
  }
686
0
  return ComputeShortestPathFromNodes(num_bytes, nodes);
687
0
}
688
689
static void MergeMatches(BackwardMatch* dst,
690
0
    BackwardMatch* src1, size_t len1, BackwardMatch* src2, size_t len2) {
691
0
  while (len1 > 0 && len2 > 0) {
692
0
    size_t l1 = BackwardMatchLength(src1);
693
0
    size_t l2 = BackwardMatchLength(src2);
694
0
    if (l1 < l2 || ((l1 == l2) && (src1->distance < src2->distance))) {
695
0
      *dst++ = *src1++;
696
0
      len1--;
697
0
    } else {
698
0
      *dst++ = *src2++;
699
0
      len2--;
700
0
    }
701
0
  }
702
0
  while (len1-- > 0) *dst++ = *src1++;
703
0
  while (len2-- > 0) *dst++ = *src2++;
704
0
}
705
706
/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
707
size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
708
    size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
709
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
710
0
    const int* dist_cache, Hasher* hasher, ZopfliNode* nodes) {
711
0
  const size_t stream_offset = params->stream_offset;
712
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
713
0
  const size_t max_zopfli_len = MaxZopfliLen(params);
714
0
  StartPosQueue queue;
715
0
  BackwardMatch* BROTLI_RESTRICT matches =
716
0
      BROTLI_ALLOC(m, BackwardMatch, 2 * (MAX_NUM_MATCHES_H10 + 64));
717
0
  const size_t store_end = num_bytes >= StoreLookaheadH10() ?
718
0
      position + num_bytes - StoreLookaheadH10() + 1 : position;
719
0
  size_t i;
720
0
  const CompoundDictionary* addon = &params->dictionary.compound;
721
0
  size_t gap = addon->total_size;
722
0
  size_t lz_matches_offset =
723
0
      (addon->num_chunks != 0) ? (MAX_NUM_MATCHES_H10 + 128) : 0;
724
0
  ZopfliCostModel* model = BROTLI_ALLOC(m, ZopfliCostModel, 1);
725
0
  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(model) || BROTLI_IS_NULL(matches)) {
726
0
    return 0;
727
0
  }
728
0
  nodes[0].length = 0;
729
0
  nodes[0].u.cost = 0;
730
0
  InitZopfliCostModel(m, model, &params->dist, num_bytes);
731
0
  if (BROTLI_IS_OOM(m)) return 0;
732
0
  ZopfliCostModelSetFromLiteralCosts(
733
0
      model, position, ringbuffer, ringbuffer_mask);
734
0
  InitStartPosQueue(&queue);
735
0
  for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; i++) {
736
0
    const size_t pos = position + i;
737
0
    const size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
738
0
    const size_t dictionary_start = BROTLI_MIN(size_t,
739
0
        pos + stream_offset, max_backward_limit);
740
0
    size_t skip;
741
0
    size_t num_matches;
742
0
    int dict_id = 0;
743
0
    if (params->dictionary.contextual.context_based) {
744
0
      uint8_t p1 = pos >= 1 ?
745
0
          ringbuffer[(size_t)(pos - 1) & ringbuffer_mask] : 0;
746
0
      uint8_t p2 = pos >= 2 ?
747
0
          ringbuffer[(size_t)(pos - 2) & ringbuffer_mask] : 0;
748
0
      dict_id = params->dictionary.contextual.context_map[
749
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
750
0
    }
751
0
    num_matches = FindAllMatchesH10(&hasher->privat._H10,
752
0
        params->dictionary.contextual.dict[dict_id],
753
0
        ringbuffer, ringbuffer_mask, pos, num_bytes - i, max_distance,
754
0
        dictionary_start + gap, params, &matches[lz_matches_offset]);
755
0
    if (addon->num_chunks != 0) {
756
0
      size_t cd_matches = LookupAllCompoundDictionaryMatches(addon,
757
0
          ringbuffer, ringbuffer_mask, pos, 3, num_bytes - i,
758
0
          dictionary_start, params->dist.max_distance,
759
0
          &matches[lz_matches_offset - 64], 64);
760
0
      MergeMatches(matches, &matches[lz_matches_offset - 64], cd_matches,
761
0
          &matches[lz_matches_offset], num_matches);
762
0
      num_matches += cd_matches;
763
0
    }
764
0
    if (num_matches > 0 &&
765
0
        BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) {
766
0
      matches[0] = matches[num_matches - 1];
767
0
      num_matches = 1;
768
0
    }
769
0
    skip = UpdateNodes(num_bytes, position, i, ringbuffer, ringbuffer_mask,
770
0
        params, max_backward_limit, dist_cache, num_matches, matches, model,
771
0
        &queue, nodes);
772
0
    if (skip < BROTLI_LONG_COPY_QUICK_STEP) skip = 0;
773
0
    if (num_matches == 1 && BackwardMatchLength(&matches[0]) > max_zopfli_len) {
774
0
      skip = BROTLI_MAX(size_t, BackwardMatchLength(&matches[0]), skip);
775
0
    }
776
0
    if (skip > 1) {
777
      /* Add the tail of the copy to the hasher. */
778
0
      StoreRangeH10(&hasher->privat._H10,
779
0
          ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(
780
0
          size_t, pos + skip, store_end));
781
0
      skip--;
782
0
      while (skip) {
783
0
        i++;
784
0
        if (i + HashTypeLengthH10() - 1 >= num_bytes) break;
785
0
        EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
786
0
            dist_cache, model, &queue, nodes);
787
0
        skip--;
788
0
      }
789
0
    }
790
0
  }
791
0
  CleanupZopfliCostModel(m, model);
792
0
  BROTLI_FREE(m, model);
793
0
  BROTLI_FREE(m, matches);
794
0
  return ComputeShortestPathFromNodes(num_bytes, nodes);
795
0
}
796
797
void BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
798
    size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
799
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
800
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
801
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
802
0
  ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
803
0
  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
804
0
  BrotliInitZopfliNodes(nodes, num_bytes + 1);
805
0
  *num_commands += BrotliZopfliComputeShortestPath(m, num_bytes,
806
0
      position, ringbuffer, ringbuffer_mask, literal_context_lut, params,
807
0
      dist_cache, hasher, nodes);
808
0
  if (BROTLI_IS_OOM(m)) return;
809
0
  BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
810
0
      last_insert_len, params, commands, num_literals);
811
0
  BROTLI_FREE(m, nodes);
812
0
}
813
814
void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
815
    size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
816
    ContextLut literal_context_lut, const BrotliEncoderParams* params,
817
    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
818
0
    Command* commands, size_t* num_commands, size_t* num_literals) {
819
0
  const size_t stream_offset = params->stream_offset;
820
0
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
821
0
  uint32_t* num_matches = BROTLI_ALLOC(m, uint32_t, num_bytes);
822
0
  size_t matches_size = 4 * num_bytes;
823
0
  const size_t store_end = num_bytes >= StoreLookaheadH10() ?
824
0
      position + num_bytes - StoreLookaheadH10() + 1 : position;
825
0
  size_t cur_match_pos = 0;
826
0
  size_t i;
827
0
  size_t orig_num_literals;
828
0
  size_t orig_last_insert_len;
829
0
  int orig_dist_cache[4];
830
0
  size_t orig_num_commands;
831
0
  ZopfliCostModel* model = BROTLI_ALLOC(m, ZopfliCostModel, 1);
832
0
  ZopfliNode* nodes;
833
0
  BackwardMatch* matches = BROTLI_ALLOC(m, BackwardMatch, matches_size);
834
0
  const CompoundDictionary* addon = &params->dictionary.compound;
835
0
  size_t gap = addon->total_size;
836
0
  size_t shadow_matches =
837
0
      (addon->num_chunks != 0) ? (MAX_NUM_MATCHES_H10 + 128) : 0;
838
0
  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(model) ||
839
0
      BROTLI_IS_NULL(num_matches) || BROTLI_IS_NULL(matches)) {
840
0
    return;
841
0
  }
842
0
  for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; ++i) {
843
0
    const size_t pos = position + i;
844
0
    size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
845
0
    size_t dictionary_start = BROTLI_MIN(size_t,
846
0
        pos + stream_offset, max_backward_limit);
847
0
    size_t max_length = num_bytes - i;
848
0
    size_t num_found_matches;
849
0
    size_t cur_match_end;
850
0
    size_t j;
851
0
    int dict_id = 0;
852
0
    if (params->dictionary.contextual.context_based) {
853
0
      uint8_t p1 = pos >= 1 ?
854
0
          ringbuffer[(size_t)(pos - 1) & ringbuffer_mask] : 0;
855
0
      uint8_t p2 = pos >= 2 ?
856
0
          ringbuffer[(size_t)(pos - 2) & ringbuffer_mask] : 0;
857
0
      dict_id = params->dictionary.contextual.context_map[
858
0
          BROTLI_CONTEXT(p1, p2, literal_context_lut)];
859
0
    }
860
    /* Ensure that we have enough free slots. */
861
0
    BROTLI_ENSURE_CAPACITY(m, BackwardMatch, matches, matches_size,
862
0
        cur_match_pos + MAX_NUM_MATCHES_H10 + shadow_matches);
863
0
    if (BROTLI_IS_OOM(m)) return;
864
0
    num_found_matches = FindAllMatchesH10(&hasher->privat._H10,
865
0
        params->dictionary.contextual.dict[dict_id],
866
0
        ringbuffer, ringbuffer_mask, pos, max_length,
867
0
        max_distance, dictionary_start + gap, params,
868
0
        &matches[cur_match_pos + shadow_matches]);
869
0
    if (addon->num_chunks != 0) {
870
0
      size_t cd_matches = LookupAllCompoundDictionaryMatches(addon,
871
0
          ringbuffer, ringbuffer_mask, pos, 3, max_length,
872
0
          dictionary_start, params->dist.max_distance,
873
0
          &matches[cur_match_pos + shadow_matches - 64], 64);
874
0
      MergeMatches(&matches[cur_match_pos],
875
0
          &matches[cur_match_pos + shadow_matches - 64], cd_matches,
876
0
          &matches[cur_match_pos + shadow_matches], num_found_matches);
877
0
      num_found_matches += cd_matches;
878
0
    }
879
0
    cur_match_end = cur_match_pos + num_found_matches;
880
0
    for (j = cur_match_pos; j + 1 < cur_match_end; ++j) {
881
0
      BROTLI_DCHECK(BackwardMatchLength(&matches[j]) <=
882
0
          BackwardMatchLength(&matches[j + 1]));
883
0
    }
884
0
    num_matches[i] = (uint32_t)num_found_matches;
885
0
    if (num_found_matches > 0) {
886
0
      const size_t match_len = BackwardMatchLength(&matches[cur_match_end - 1]);
887
0
      if (match_len > MAX_ZOPFLI_LEN_QUALITY_11) {
888
0
        const size_t skip = match_len - 1;
889
0
        matches[cur_match_pos++] = matches[cur_match_end - 1];
890
0
        num_matches[i] = 1;
891
        /* Add the tail of the copy to the hasher. */
892
0
        StoreRangeH10(&hasher->privat._H10,
893
0
                      ringbuffer, ringbuffer_mask, pos + 1,
894
0
                      BROTLI_MIN(size_t, pos + match_len, store_end));
895
0
        memset(&num_matches[i + 1], 0, skip * sizeof(num_matches[0]));
896
0
        i += skip;
897
0
      } else {
898
0
        cur_match_pos = cur_match_end;
899
0
      }
900
0
    }
901
0
  }
902
0
  orig_num_literals = *num_literals;
903
0
  orig_last_insert_len = *last_insert_len;
904
0
  memcpy(orig_dist_cache, dist_cache, 4 * sizeof(dist_cache[0]));
905
0
  orig_num_commands = *num_commands;
906
0
  nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
907
0
  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
908
0
  InitZopfliCostModel(m, model, &params->dist, num_bytes);
909
0
  if (BROTLI_IS_OOM(m)) return;
910
0
  for (i = 0; i < 2; i++) {
911
0
    BrotliInitZopfliNodes(nodes, num_bytes + 1);
912
0
    if (i == 0) {
913
0
      ZopfliCostModelSetFromLiteralCosts(
914
0
          model, position, ringbuffer, ringbuffer_mask);
915
0
    } else {
916
0
      ZopfliCostModelSetFromCommands(model, position, ringbuffer,
917
0
          ringbuffer_mask, commands, *num_commands - orig_num_commands,
918
0
          orig_last_insert_len);
919
0
    }
920
0
    *num_commands = orig_num_commands;
921
0
    *num_literals = orig_num_literals;
922
0
    *last_insert_len = orig_last_insert_len;
923
0
    memcpy(dist_cache, orig_dist_cache, 4 * sizeof(dist_cache[0]));
924
0
    *num_commands += ZopfliIterate(num_bytes, position, ringbuffer,
925
0
        ringbuffer_mask, params, gap, dist_cache, model, num_matches, matches,
926
0
        nodes);
927
0
    BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
928
0
        last_insert_len, params, commands, num_literals);
929
0
  }
930
0
  CleanupZopfliCostModel(m, model);
931
0
  BROTLI_FREE(m, model);
932
0
  BROTLI_FREE(m, nodes);
933
0
  BROTLI_FREE(m, matches);
934
  BROTLI_FREE(m, num_matches);
935
0
}
936
937
#if defined(__cplusplus) || defined(c_plusplus)
938
}  /* extern "C" */
939
#endif