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