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