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 = ¶ms->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], ¶ms->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 = ¶ms->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, ¶ms->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 = ¶ms->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, ¶ms->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