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