Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/brotli/c/enc/backward_references_hq.c
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_hq.h"
10
11
#include <string.h>  /* memcpy, memset */
12
13
#include <brotli/types.h>
14
15
#include "../common/constants.h"
16
#include "../common/platform.h"
17
#include "command.h"
18
#include "compound_dictionary.h"
19
#include "encoder_dict.h"
20
#include "fast_log.h"
21
#include "find_match_length.h"
22
#include "literal_cost.h"
23
#include "memory.h"
24
#include "params.h"
25
#include "prefix.h"
26
#include "quality.h"
27
28
#if defined(__cplusplus) || defined(c_plusplus)
29
extern "C" {
30
#endif
31
32
/* BrotliCalculateDistanceCodeLimit(BROTLI_MAX_ALLOWED_DISTANCE, 3, 120). */
33
#define BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE 544
34
35
static const float kInfinity = 1.7e38f;  /* ~= 2 ^ 127 */
36
37
static const uint32_t kDistanceCacheIndex[] = {
38
  0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
39
};
40
static const int kDistanceCacheOffset[] = {
41
  0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3
42
};
43
44
0
void BrotliInitZopfliNodes(ZopfliNode* array, size_t length) {
45
0
  ZopfliNode stub;
46
0
  size_t i;
47
0
  stub.length = 1;
48
0
  stub.distance = 0;
49
0
  stub.dcode_insert_length = 0;
50
0
  stub.u.cost = kInfinity;
51
0
  for (i = 0; i < length; ++i) array[i] = stub;
52
0
}
53
54
0
static BROTLI_INLINE uint32_t ZopfliNodeCopyLength(const ZopfliNode* self) {
55
0
  return self->length & 0x1FFFFFF;
56
0
}
57
58
0
static BROTLI_INLINE uint32_t ZopfliNodeLengthCode(const ZopfliNode* self) {
59
0
  const uint32_t modifier = self->length >> 25;
60
0
  return ZopfliNodeCopyLength(self) + 9u - modifier;
61
0
}
62
63
0
static BROTLI_INLINE uint32_t ZopfliNodeCopyDistance(const ZopfliNode* self) {
64
0
  return self->distance;
65
0
}
66
67
0
static BROTLI_INLINE uint32_t ZopfliNodeDistanceCode(const ZopfliNode* self) {
68
0
  const uint32_t short_code = self->dcode_insert_length >> 27;
69
0
  return short_code == 0 ?
70
0
      ZopfliNodeCopyDistance(self) + BROTLI_NUM_DISTANCE_SHORT_CODES - 1 :
71
0
      short_code - 1;
72
0
}
73
74
0
static BROTLI_INLINE uint32_t ZopfliNodeCommandLength(const ZopfliNode* self) {
75
0
  return ZopfliNodeCopyLength(self) + (self->dcode_insert_length & 0x7FFFFFF);
76
0
}
77
78
/* Temporary data for ZopfliCostModelSetFromCommands. */
79
typedef struct ZopfliCostModelArena {
80
  uint32_t histogram_literal[BROTLI_NUM_LITERAL_SYMBOLS];
81
  uint32_t histogram_cmd[BROTLI_NUM_COMMAND_SYMBOLS];
82
  uint32_t histogram_dist[BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE];
83
  float cost_literal[BROTLI_NUM_LITERAL_SYMBOLS];
84
} ZopfliCostModelArena;
85
86
/* Histogram based cost model for zopflification. */
87
typedef struct ZopfliCostModel {
88
  /* The insert and copy length symbols. */
89
  float cost_cmd_[BROTLI_NUM_COMMAND_SYMBOLS];
90
  float* cost_dist_;
91
  uint32_t distance_histogram_size;
92
  /* Cumulative costs of literals per position in the stream. */
93
  float* literal_costs_;
94
  float min_cost_cmd_;
95
  size_t num_bytes_;
96
97
  /* Temporary data. */
98
  union {
99
    size_t literal_histograms[3 * 256];
100
    ZopfliCostModelArena arena;
101
  };
102
} ZopfliCostModel;
103
104
static void InitZopfliCostModel(
105
    MemoryManager* m, ZopfliCostModel* self, const BrotliDistanceParams* dist,
106
0
    size_t num_bytes) {
107
0
  self->num_bytes_ = num_bytes;
108
0
  self->literal_costs_ = BROTLI_ALLOC(m, float, num_bytes + 2);
109
0
  self->cost_dist_ = BROTLI_ALLOC(m, float, dist->alphabet_size_limit);
110
0
  self->distance_histogram_size = dist->alphabet_size_limit;
111
0
  if (BROTLI_IS_OOM(m)) return;
112
0
}
113
114
0
static void CleanupZopfliCostModel(MemoryManager* m, ZopfliCostModel* self) {
115
0
  BROTLI_FREE(m, self->literal_costs_);
116
0
  BROTLI_FREE(m, self->cost_dist_);
117
0
}
118
119
static void SetCost(const uint32_t* histogram, size_t histogram_size,
120
0
                    BROTLI_BOOL literal_histogram, float* cost) {
121
0
  size_t sum = 0;
122
0
  size_t missing_symbol_sum;
123
0
  float log2sum;
124
0
  float missing_symbol_cost;
125
0
  size_t i;
126
0
  for (i = 0; i < histogram_size; i++) {
127
0
    sum += histogram[i];
128
0
  }
129
0
  log2sum = (float)FastLog2(sum);
130
0
  missing_symbol_sum = sum;
131
0
  if (!literal_histogram) {
132
0
    for (i = 0; i < histogram_size; i++) {
133
0
      if (histogram[i] == 0) missing_symbol_sum++;
134
0
    }
135
0
  }
136
0
  missing_symbol_cost = (float)FastLog2(missing_symbol_sum) + 2;
137
0
  for (i = 0; i < histogram_size; i++) {
138
0
    if (histogram[i] == 0) {
139
0
      cost[i] = missing_symbol_cost;
140
0
      continue;
141
0
    }
142
143
    /* Shannon bits for this symbol. */
144
0
    cost[i] = log2sum - (float)FastLog2(histogram[i]);
145
146
    /* Cannot be coded with less than 1 bit */
147
0
    if (cost[i] < 1) cost[i] = 1;
148
0
  }
149
0
}
150
151
static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
152
                                           size_t position,
153
                                           const uint8_t* ringbuffer,
154
                                           size_t ringbuffer_mask,
155
                                           const Command* commands,
156
                                           size_t num_commands,
157
0
                                           size_t last_insert_len) {
158
0
  ZopfliCostModelArena* arena = &self->arena;
159
0
  size_t pos = position - last_insert_len;
160
0
  float min_cost_cmd = kInfinity;
161
0
  size_t i;
162
0
  float* cost_cmd = self->cost_cmd_;
163
164
0
  memset(arena->histogram_literal, 0, sizeof(arena->histogram_literal));
165
0
  memset(arena->histogram_cmd, 0, sizeof(arena->histogram_cmd));
166
0
  memset(arena->histogram_dist, 0, sizeof(arena->histogram_dist));
167
168
0
  for (i = 0; i < num_commands; i++) {
169
0
    size_t inslength = commands[i].insert_len_;
170
0
    size_t copylength = CommandCopyLen(&commands[i]);
171
0
    size_t distcode = commands[i].dist_prefix_ & 0x3FF;
172
0
    size_t cmdcode = commands[i].cmd_prefix_;
173
0
    size_t j;
174
175
0
    arena->histogram_cmd[cmdcode]++;
176
0
    if (cmdcode >= 128) arena->histogram_dist[distcode]++;
177
178
0
    for (j = 0; j < inslength; j++) {
179
0
      arena->histogram_literal[ringbuffer[(pos + j) & ringbuffer_mask]]++;
180
0
    }
181
182
0
    pos += inslength + copylength;
183
0
  }
184
185
0
  SetCost(arena->histogram_literal, BROTLI_NUM_LITERAL_SYMBOLS, BROTLI_TRUE,
186
0
          arena->cost_literal);
187
0
  SetCost(arena->histogram_cmd, BROTLI_NUM_COMMAND_SYMBOLS, BROTLI_FALSE,
188
0
          cost_cmd);
189
0
  SetCost(arena->histogram_dist, self->distance_histogram_size, BROTLI_FALSE,
190
0
          self->cost_dist_);
191
192
0
  for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
193
0
    min_cost_cmd = BROTLI_MIN(float, min_cost_cmd, cost_cmd[i]);
194
0
  }
195
0
  self->min_cost_cmd_ = min_cost_cmd;
196
197
0
  {
198
0
    float* literal_costs = self->literal_costs_;
199
0
    float literal_carry = 0.0;
200
0
    size_t num_bytes = self->num_bytes_;
201
0
    literal_costs[0] = 0.0;
202
0
    for (i = 0; i < num_bytes; ++i) {
203
0
      literal_carry +=
204
0
          arena->cost_literal[ringbuffer[(position + i) & ringbuffer_mask]];
205
0
      literal_costs[i + 1] = literal_costs[i] + literal_carry;
206
0
      literal_carry -= literal_costs[i + 1] - literal_costs[i];
207
0
    }
208
0
  }
209
0
}
210
211
static void ZopfliCostModelSetFromLiteralCosts(ZopfliCostModel* self,
212
                                               size_t position,
213
                                               const uint8_t* ringbuffer,
214
0
                                               size_t ringbuffer_mask) {
215
0
  float* literal_costs = self->literal_costs_;
216
0
  float literal_carry = 0.0;
217
0
  float* cost_dist = self->cost_dist_;
218
0
  float* cost_cmd = self->cost_cmd_;
219
0
  size_t num_bytes = self->num_bytes_;
220
0
  size_t i;
221
0
  BrotliEstimateBitCostsForLiterals(position, num_bytes, ringbuffer_mask,
222
0
                                    ringbuffer, self->literal_histograms,
223
0
                                    &literal_costs[1]);
224
0
  literal_costs[0] = 0.0;
225
0
  for (i = 0; i < num_bytes; ++i) {
226
0
    literal_carry += literal_costs[i + 1];
227
0
    literal_costs[i + 1] = literal_costs[i] + literal_carry;
228
0
    literal_carry -= literal_costs[i + 1] - literal_costs[i];
229
0
  }
230
0
  for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
231
0
    cost_cmd[i] = (float)FastLog2(11 + (uint32_t)i);
232
0
  }
233
0
  for (i = 0; i < self->distance_histogram_size; ++i) {
234
0
    cost_dist[i] = (float)FastLog2(20 + (uint32_t)i);
235
0
  }
236
0
  self->min_cost_cmd_ = (float)FastLog2(11);
237
0
}
238
239
static BROTLI_INLINE float ZopfliCostModelGetCommandCost(
240
0
    const ZopfliCostModel* self, uint16_t cmdcode) {
241
0
  return self->cost_cmd_[cmdcode];
242
0
}
243
244
static BROTLI_INLINE float ZopfliCostModelGetDistanceCost(
245
0
    const ZopfliCostModel* self, size_t distcode) {
246
0
  return self->cost_dist_[distcode];
247
0
}
248
249
static BROTLI_INLINE float ZopfliCostModelGetLiteralCosts(
250
0
    const ZopfliCostModel* self, size_t from, size_t to) {
251
0
  return self->literal_costs_[to] - self->literal_costs_[from];
252
0
}
253
254
static BROTLI_INLINE float ZopfliCostModelGetMinCostCmd(
255
0
    const ZopfliCostModel* self) {
256
0
  return self->min_cost_cmd_;
257
0
}
258
259
/* REQUIRES: len >= 2, start_pos <= pos */
260
/* REQUIRES: cost < kInfinity, nodes[start_pos].cost < kInfinity */
261
/* Maintains the "ZopfliNode array invariant". */
262
static BROTLI_INLINE void UpdateZopfliNode(ZopfliNode* nodes, size_t pos,
263
    size_t start_pos, size_t len, size_t len_code, size_t dist,
264
0
    size_t short_code, float cost) {
265
0
  ZopfliNode* next = &nodes[pos + len];
266
0
  next->length = (uint32_t)(len | ((len + 9u - len_code) << 25));
267
0
  next->distance = (uint32_t)dist;
268
0
  next->dcode_insert_length = (uint32_t)(
269
0
      (short_code << 27) | (pos - start_pos));
270
0
  next->u.cost = cost;
271
0
}
272
273
typedef struct PosData {
274
  size_t pos;
275
  int distance_cache[4];
276
  float costdiff;
277
  float cost;
278
} PosData;
279
280
/* Maintains the smallest 8 cost difference together with their positions */
281
typedef struct StartPosQueue {
282
  PosData q_[8];
283
  size_t idx_;
284
} StartPosQueue;
285
286
0
static BROTLI_INLINE void InitStartPosQueue(StartPosQueue* self) {
287
0
  self->idx_ = 0;
288
0
}
289
290
0
static size_t StartPosQueueSize(const StartPosQueue* self) {
291
0
  return BROTLI_MIN(size_t, self->idx_, 8);
292
0
}
293
294
0
static void StartPosQueuePush(StartPosQueue* self, const PosData* posdata) {
295
0
  size_t offset = ~(self->idx_++) & 7;
296
0
  size_t len = StartPosQueueSize(self);
297
0
  size_t i;
298
0
  PosData* q = self->q_;
299
0
  q[offset] = *posdata;
300
  /* Restore the sorted order. In the list of |len| items at most |len - 1|
301
     adjacent element comparisons / swaps are required. */
302
0
  for (i = 1; i < len; ++i) {
303
0
    if (q[offset & 7].costdiff > q[(offset + 1) & 7].costdiff) {
304
0
      BROTLI_SWAP(PosData, q, offset & 7, (offset + 1) & 7);
305
0
    }
306
0
    ++offset;
307
0
  }
308
0
}
309
310
0
static const PosData* StartPosQueueAt(const StartPosQueue* self, size_t k) {
311
0
  return &self->q_[(k - self->idx_) & 7];
312
0
}
313
314
/* Returns the minimum possible copy length that can improve the cost of any */
315
/* future position. */
316
static size_t ComputeMinimumCopyLength(const float start_cost,
317
                                       const ZopfliNode* nodes,
318
                                       const size_t num_bytes,
319
0
                                       const size_t pos) {
320
  /* Compute the minimum possible cost of reaching any future position. */
321
0
  float min_cost = start_cost;
322
0
  size_t len = 2;
323
0
  size_t next_len_bucket = 4;
324
0
  size_t next_len_offset = 10;
325
0
  while (pos + len <= num_bytes && nodes[pos + len].u.cost <= min_cost) {
326
    /* We already reached (pos + len) with no more cost than the minimum
327
       possible cost of reaching anything from this pos, so there is no point in
328
       looking for lengths <= len. */
329
0
    ++len;
330
0
    if (len == next_len_offset) {
331
      /* We reached the next copy length code bucket, so we add one more
332
         extra bit to the minimum cost. */
333
0
      min_cost += 1.0f;
334
0
      next_len_offset += next_len_bucket;
335
0
      next_len_bucket *= 2;
336
0
    }
337
0
  }
338
0
  return len;
339
0
}
340
341
/* REQUIRES: nodes[pos].cost < kInfinity
342
   REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
343
static uint32_t ComputeDistanceShortcut(const size_t block_start,
344
                                        const size_t pos,
345
                                        const size_t max_backward_limit,
346
                                        const size_t gap,
347
0
                                        const ZopfliNode* nodes) {
348
0
  const size_t clen = ZopfliNodeCopyLength(&nodes[pos]);
349
0
  const size_t ilen = nodes[pos].dcode_insert_length & 0x7FFFFFF;
350
0
  const size_t dist = ZopfliNodeCopyDistance(&nodes[pos]);
351
  /* Since |block_start + pos| is the end position of the command, the copy part
352
     starts from |block_start + pos - clen|. Distances that are greater than
353
     this or greater than |max_backward_limit| + |gap| are static dictionary
354
     references, and do not update the last distances.
355
     Also distance code 0 (last distance) does not update the last distances. */
356
0
  if (pos == 0) {
357
0
    return 0;
358
0
  } else if (dist + clen <= block_start + pos + gap &&
359
0
             dist <= max_backward_limit + gap &&
360
0
             ZopfliNodeDistanceCode(&nodes[pos]) > 0) {
361
0
    return (uint32_t)pos;
362
0
  } else {
363
0
    return nodes[pos - clen - ilen].u.shortcut;
364
0
  }
365
0
}
366
367
/* Fills in dist_cache[0..3] with the last four distances (as defined by
368
   Section 4. of the Spec) that would be used at (block_start + pos) if we
369
   used the shortest path of commands from block_start, computed from
370
   nodes[0..pos]. The last four distances at block_start are in
371
   starting_dist_cache[0..3].
372
   REQUIRES: nodes[pos].cost < kInfinity
373
   REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
374
static void ComputeDistanceCache(const size_t pos,
375
                                 const int* starting_dist_cache,
376
                                 const ZopfliNode* nodes,
377
0
                                 int* dist_cache) {
378
0
  int idx = 0;
379
0
  size_t p = nodes[pos].u.shortcut;
380
0
  while (idx < 4 && p > 0) {
381
0
    const size_t ilen = nodes[p].dcode_insert_length & 0x7FFFFFF;
382
0
    const size_t clen = ZopfliNodeCopyLength(&nodes[p]);
383
0
    const size_t dist = ZopfliNodeCopyDistance(&nodes[p]);
384
0
    dist_cache[idx++] = (int)dist;
385
    /* Because of prerequisite, p >= clen + ilen >= 2. */
386
0
    p = nodes[p - clen - ilen].u.shortcut;
387
0
  }
388
0
  for (; idx < 4; ++idx) {
389
0
    dist_cache[idx] = *starting_dist_cache++;
390
0
  }
391
0
}
392
393
/* Maintains "ZopfliNode array invariant" and pushes node to the queue, if it
394
   is eligible. */
395
static void EvaluateNode(
396
    const size_t block_start, const size_t pos, const size_t max_backward_limit,
397
    const size_t gap, const int* starting_dist_cache,
398
0
    const ZopfliCostModel* model, StartPosQueue* queue, ZopfliNode* nodes) {
399
  /* Save cost, because ComputeDistanceCache invalidates it. */
400
0
  float node_cost = nodes[pos].u.cost;
401
0
  nodes[pos].u.shortcut = ComputeDistanceShortcut(
402
0
      block_start, pos, max_backward_limit, gap, nodes);
403
0
  if (node_cost <= ZopfliCostModelGetLiteralCosts(model, 0, pos)) {
404
0
    PosData posdata;
405
0
    posdata.pos = pos;
406
0
    posdata.cost = node_cost;
407
0
    posdata.costdiff = node_cost -
408
0
        ZopfliCostModelGetLiteralCosts(model, 0, pos);
409
0
    ComputeDistanceCache(
410
0
        pos, starting_dist_cache, nodes, posdata.distance_cache);
411
0
    StartPosQueuePush(queue, &posdata);
412
0
  }
413
0
}
414
415
/* Returns longest copy length. */
416
static size_t UpdateNodes(
417
    const size_t num_bytes, const size_t block_start, const size_t pos,
418
    const uint8_t* ringbuffer, const size_t ringbuffer_mask,
419
    const BrotliEncoderParams* params, const size_t max_backward_limit,
420
    const int* starting_dist_cache, const size_t num_matches,
421
    const BackwardMatch* matches, const ZopfliCostModel* model,
422
0
    StartPosQueue* queue, ZopfliNode* nodes) {
423
0
  const size_t stream_offset = params->stream_offset;
424
0
  const size_t cur_ix = block_start + pos;
425
0
  const size_t cur_ix_masked = cur_ix & ringbuffer_mask;
426
0
  const size_t max_distance = BROTLI_MIN(size_t, cur_ix, max_backward_limit);
427
0
  const size_t dictionary_start = BROTLI_MIN(size_t,
428
0
      cur_ix + stream_offset, max_backward_limit);
429
0
  const size_t max_len = num_bytes - pos;
430
0
  const size_t max_zopfli_len = MaxZopfliLen(params);
431
0
  const size_t max_iters = MaxZopfliCandidates(params);
432
0
  size_t min_len;
433
0
  size_t result = 0;
434
0
  size_t k;
435
0
  const CompoundDictionary* addon = &params->dictionary.compound;
436
0
  size_t gap = addon->total_size;
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
0
  BROTLI_FREE(m, num_matches);
935
0
}
936
937
#if defined(__cplusplus) || defined(c_plusplus)
938
}  /* extern "C" */
939
#endif