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