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