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