126fa459cSmrg/* Copyright 2013 Google Inc. All Rights Reserved. 226fa459cSmrg 326fa459cSmrg Distributed under MIT license. 426fa459cSmrg See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 526fa459cSmrg*/ 626fa459cSmrg 726fa459cSmrg/* Function to find backward reference copies. */ 826fa459cSmrg 926fa459cSmrg#include "./backward_references_hq.h" 1026fa459cSmrg 1126fa459cSmrg#include <string.h> /* memcpy, memset */ 1226fa459cSmrg 1326fa459cSmrg#include "../common/constants.h" 1426fa459cSmrg#include "../common/context.h" 1526fa459cSmrg#include "../common/platform.h" 1626fa459cSmrg#include <brotli/types.h> 1726fa459cSmrg#include "./command.h" 1826fa459cSmrg#include "./fast_log.h" 1926fa459cSmrg#include "./find_match_length.h" 2026fa459cSmrg#include "./literal_cost.h" 2126fa459cSmrg#include "./memory.h" 2226fa459cSmrg#include "./params.h" 2326fa459cSmrg#include "./prefix.h" 2426fa459cSmrg#include "./quality.h" 2526fa459cSmrg 2626fa459cSmrg#if defined(__cplusplus) || defined(c_plusplus) 2726fa459cSmrgextern "C" { 2826fa459cSmrg#endif 2926fa459cSmrg 3026fa459cSmrg/* BrotliCalculateDistanceCodeLimit(BROTLI_MAX_ALLOWED_DISTANCE, 3, 120). */ 3126fa459cSmrg#define BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE 544 3226fa459cSmrg 3326fa459cSmrgstatic const float kInfinity = 1.7e38f; /* ~= 2 ^ 127 */ 3426fa459cSmrg 3526fa459cSmrgstatic const uint32_t kDistanceCacheIndex[] = { 3626fa459cSmrg 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 3726fa459cSmrg}; 3826fa459cSmrgstatic const int kDistanceCacheOffset[] = { 3926fa459cSmrg 0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3 4026fa459cSmrg}; 4126fa459cSmrg 4226fa459cSmrgvoid BrotliInitZopfliNodes(ZopfliNode* array, size_t length) { 4326fa459cSmrg ZopfliNode stub; 4426fa459cSmrg size_t i; 4526fa459cSmrg stub.length = 1; 4626fa459cSmrg stub.distance = 0; 4726fa459cSmrg stub.dcode_insert_length = 0; 4826fa459cSmrg stub.u.cost = kInfinity; 4926fa459cSmrg for (i = 0; i < length; ++i) array[i] = stub; 5026fa459cSmrg} 5126fa459cSmrg 5226fa459cSmrgstatic BROTLI_INLINE uint32_t ZopfliNodeCopyLength(const ZopfliNode* self) { 5326fa459cSmrg return self->length & 0x1FFFFFF; 5426fa459cSmrg} 5526fa459cSmrg 5626fa459cSmrgstatic BROTLI_INLINE uint32_t ZopfliNodeLengthCode(const ZopfliNode* self) { 5726fa459cSmrg const uint32_t modifier = self->length >> 25; 5826fa459cSmrg return ZopfliNodeCopyLength(self) + 9u - modifier; 5926fa459cSmrg} 6026fa459cSmrg 6126fa459cSmrgstatic BROTLI_INLINE uint32_t ZopfliNodeCopyDistance(const ZopfliNode* self) { 6226fa459cSmrg return self->distance; 6326fa459cSmrg} 6426fa459cSmrg 6526fa459cSmrgstatic BROTLI_INLINE uint32_t ZopfliNodeDistanceCode(const ZopfliNode* self) { 6626fa459cSmrg const uint32_t short_code = self->dcode_insert_length >> 27; 6726fa459cSmrg return short_code == 0 ? 6826fa459cSmrg ZopfliNodeCopyDistance(self) + BROTLI_NUM_DISTANCE_SHORT_CODES - 1 : 6926fa459cSmrg short_code - 1; 7026fa459cSmrg} 7126fa459cSmrg 7226fa459cSmrgstatic BROTLI_INLINE uint32_t ZopfliNodeCommandLength(const ZopfliNode* self) { 7326fa459cSmrg return ZopfliNodeCopyLength(self) + (self->dcode_insert_length & 0x7FFFFFF); 7426fa459cSmrg} 7526fa459cSmrg 7626fa459cSmrg/* Histogram based cost model for zopflification. */ 7726fa459cSmrgtypedef struct ZopfliCostModel { 7826fa459cSmrg /* The insert and copy length symbols. */ 7926fa459cSmrg float cost_cmd_[BROTLI_NUM_COMMAND_SYMBOLS]; 8026fa459cSmrg float* cost_dist_; 8126fa459cSmrg uint32_t distance_histogram_size; 8226fa459cSmrg /* Cumulative costs of literals per position in the stream. */ 8326fa459cSmrg float* literal_costs_; 8426fa459cSmrg float min_cost_cmd_; 8526fa459cSmrg size_t num_bytes_; 8626fa459cSmrg} ZopfliCostModel; 8726fa459cSmrg 8826fa459cSmrgstatic void InitZopfliCostModel( 8926fa459cSmrg MemoryManager* m, ZopfliCostModel* self, const BrotliDistanceParams* dist, 9026fa459cSmrg size_t num_bytes) { 9126fa459cSmrg self->num_bytes_ = num_bytes; 9226fa459cSmrg self->literal_costs_ = BROTLI_ALLOC(m, float, num_bytes + 2); 9326fa459cSmrg self->cost_dist_ = BROTLI_ALLOC(m, float, dist->alphabet_size_limit); 9426fa459cSmrg self->distance_histogram_size = dist->alphabet_size_limit; 9526fa459cSmrg if (BROTLI_IS_OOM(m)) return; 9626fa459cSmrg} 9726fa459cSmrg 9826fa459cSmrgstatic void CleanupZopfliCostModel(MemoryManager* m, ZopfliCostModel* self) { 9926fa459cSmrg BROTLI_FREE(m, self->literal_costs_); 10026fa459cSmrg BROTLI_FREE(m, self->cost_dist_); 10126fa459cSmrg} 10226fa459cSmrg 10326fa459cSmrgstatic void SetCost(const uint32_t* histogram, size_t histogram_size, 10426fa459cSmrg BROTLI_BOOL literal_histogram, float* cost) { 10526fa459cSmrg size_t sum = 0; 10626fa459cSmrg size_t missing_symbol_sum; 10726fa459cSmrg float log2sum; 10826fa459cSmrg float missing_symbol_cost; 10926fa459cSmrg size_t i; 11026fa459cSmrg for (i = 0; i < histogram_size; i++) { 11126fa459cSmrg sum += histogram[i]; 11226fa459cSmrg } 11326fa459cSmrg log2sum = (float)FastLog2(sum); 11426fa459cSmrg missing_symbol_sum = sum; 11526fa459cSmrg if (!literal_histogram) { 11626fa459cSmrg for (i = 0; i < histogram_size; i++) { 11726fa459cSmrg if (histogram[i] == 0) missing_symbol_sum++; 11826fa459cSmrg } 11926fa459cSmrg } 12026fa459cSmrg missing_symbol_cost = (float)FastLog2(missing_symbol_sum) + 2; 12126fa459cSmrg for (i = 0; i < histogram_size; i++) { 12226fa459cSmrg if (histogram[i] == 0) { 12326fa459cSmrg cost[i] = missing_symbol_cost; 12426fa459cSmrg continue; 12526fa459cSmrg } 12626fa459cSmrg 12726fa459cSmrg /* Shannon bits for this symbol. */ 12826fa459cSmrg cost[i] = log2sum - (float)FastLog2(histogram[i]); 12926fa459cSmrg 13026fa459cSmrg /* Cannot be coded with less than 1 bit */ 13126fa459cSmrg if (cost[i] < 1) cost[i] = 1; 13226fa459cSmrg } 13326fa459cSmrg} 13426fa459cSmrg 13526fa459cSmrgstatic void ZopfliCostModelSetFromCommands(ZopfliCostModel* self, 13626fa459cSmrg size_t position, 13726fa459cSmrg const uint8_t* ringbuffer, 13826fa459cSmrg size_t ringbuffer_mask, 13926fa459cSmrg const Command* commands, 14026fa459cSmrg size_t num_commands, 14126fa459cSmrg size_t last_insert_len) { 14226fa459cSmrg uint32_t histogram_literal[BROTLI_NUM_LITERAL_SYMBOLS]; 14326fa459cSmrg uint32_t histogram_cmd[BROTLI_NUM_COMMAND_SYMBOLS]; 14426fa459cSmrg uint32_t histogram_dist[BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE]; 14526fa459cSmrg float cost_literal[BROTLI_NUM_LITERAL_SYMBOLS]; 14626fa459cSmrg size_t pos = position - last_insert_len; 14726fa459cSmrg float min_cost_cmd = kInfinity; 14826fa459cSmrg size_t i; 14926fa459cSmrg float* cost_cmd = self->cost_cmd_; 15026fa459cSmrg 15126fa459cSmrg memset(histogram_literal, 0, sizeof(histogram_literal)); 15226fa459cSmrg memset(histogram_cmd, 0, sizeof(histogram_cmd)); 15326fa459cSmrg memset(histogram_dist, 0, sizeof(histogram_dist)); 15426fa459cSmrg 15526fa459cSmrg for (i = 0; i < num_commands; i++) { 15626fa459cSmrg size_t inslength = commands[i].insert_len_; 15726fa459cSmrg size_t copylength = CommandCopyLen(&commands[i]); 15826fa459cSmrg size_t distcode = commands[i].dist_prefix_ & 0x3FF; 15926fa459cSmrg size_t cmdcode = commands[i].cmd_prefix_; 16026fa459cSmrg size_t j; 16126fa459cSmrg 16226fa459cSmrg histogram_cmd[cmdcode]++; 16326fa459cSmrg if (cmdcode >= 128) histogram_dist[distcode]++; 16426fa459cSmrg 16526fa459cSmrg for (j = 0; j < inslength; j++) { 16626fa459cSmrg histogram_literal[ringbuffer[(pos + j) & ringbuffer_mask]]++; 16726fa459cSmrg } 16826fa459cSmrg 16926fa459cSmrg pos += inslength + copylength; 17026fa459cSmrg } 17126fa459cSmrg 17226fa459cSmrg SetCost(histogram_literal, BROTLI_NUM_LITERAL_SYMBOLS, BROTLI_TRUE, 17326fa459cSmrg cost_literal); 17426fa459cSmrg SetCost(histogram_cmd, BROTLI_NUM_COMMAND_SYMBOLS, BROTLI_FALSE, 17526fa459cSmrg cost_cmd); 17626fa459cSmrg SetCost(histogram_dist, self->distance_histogram_size, BROTLI_FALSE, 17726fa459cSmrg self->cost_dist_); 17826fa459cSmrg 17926fa459cSmrg for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) { 18026fa459cSmrg min_cost_cmd = BROTLI_MIN(float, min_cost_cmd, cost_cmd[i]); 18126fa459cSmrg } 18226fa459cSmrg self->min_cost_cmd_ = min_cost_cmd; 18326fa459cSmrg 18426fa459cSmrg { 18526fa459cSmrg float* literal_costs = self->literal_costs_; 18626fa459cSmrg float literal_carry = 0.0; 18726fa459cSmrg size_t num_bytes = self->num_bytes_; 18826fa459cSmrg literal_costs[0] = 0.0; 18926fa459cSmrg for (i = 0; i < num_bytes; ++i) { 19026fa459cSmrg literal_carry += 19126fa459cSmrg cost_literal[ringbuffer[(position + i) & ringbuffer_mask]]; 19226fa459cSmrg literal_costs[i + 1] = literal_costs[i] + literal_carry; 19326fa459cSmrg literal_carry -= literal_costs[i + 1] - literal_costs[i]; 19426fa459cSmrg } 19526fa459cSmrg } 19626fa459cSmrg} 19726fa459cSmrg 19826fa459cSmrgstatic void ZopfliCostModelSetFromLiteralCosts(ZopfliCostModel* self, 19926fa459cSmrg size_t position, 20026fa459cSmrg const uint8_t* ringbuffer, 20126fa459cSmrg size_t ringbuffer_mask) { 20226fa459cSmrg float* literal_costs = self->literal_costs_; 20326fa459cSmrg float literal_carry = 0.0; 20426fa459cSmrg float* cost_dist = self->cost_dist_; 20526fa459cSmrg float* cost_cmd = self->cost_cmd_; 20626fa459cSmrg size_t num_bytes = self->num_bytes_; 20726fa459cSmrg size_t i; 20826fa459cSmrg BrotliEstimateBitCostsForLiterals(position, num_bytes, ringbuffer_mask, 20926fa459cSmrg ringbuffer, &literal_costs[1]); 21026fa459cSmrg literal_costs[0] = 0.0; 21126fa459cSmrg for (i = 0; i < num_bytes; ++i) { 21226fa459cSmrg literal_carry += literal_costs[i + 1]; 21326fa459cSmrg literal_costs[i + 1] = literal_costs[i] + literal_carry; 21426fa459cSmrg literal_carry -= literal_costs[i + 1] - literal_costs[i]; 21526fa459cSmrg } 21626fa459cSmrg for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) { 21726fa459cSmrg cost_cmd[i] = (float)FastLog2(11 + (uint32_t)i); 21826fa459cSmrg } 21926fa459cSmrg for (i = 0; i < self->distance_histogram_size; ++i) { 22026fa459cSmrg cost_dist[i] = (float)FastLog2(20 + (uint32_t)i); 22126fa459cSmrg } 22226fa459cSmrg self->min_cost_cmd_ = (float)FastLog2(11); 22326fa459cSmrg} 22426fa459cSmrg 22526fa459cSmrgstatic BROTLI_INLINE float ZopfliCostModelGetCommandCost( 22626fa459cSmrg const ZopfliCostModel* self, uint16_t cmdcode) { 22726fa459cSmrg return self->cost_cmd_[cmdcode]; 22826fa459cSmrg} 22926fa459cSmrg 23026fa459cSmrgstatic BROTLI_INLINE float ZopfliCostModelGetDistanceCost( 23126fa459cSmrg const ZopfliCostModel* self, size_t distcode) { 23226fa459cSmrg return self->cost_dist_[distcode]; 23326fa459cSmrg} 23426fa459cSmrg 23526fa459cSmrgstatic BROTLI_INLINE float ZopfliCostModelGetLiteralCosts( 23626fa459cSmrg const ZopfliCostModel* self, size_t from, size_t to) { 23726fa459cSmrg return self->literal_costs_[to] - self->literal_costs_[from]; 23826fa459cSmrg} 23926fa459cSmrg 24026fa459cSmrgstatic BROTLI_INLINE float ZopfliCostModelGetMinCostCmd( 24126fa459cSmrg const ZopfliCostModel* self) { 24226fa459cSmrg return self->min_cost_cmd_; 24326fa459cSmrg} 24426fa459cSmrg 24526fa459cSmrg/* REQUIRES: len >= 2, start_pos <= pos */ 24626fa459cSmrg/* REQUIRES: cost < kInfinity, nodes[start_pos].cost < kInfinity */ 24726fa459cSmrg/* Maintains the "ZopfliNode array invariant". */ 24826fa459cSmrgstatic BROTLI_INLINE void UpdateZopfliNode(ZopfliNode* nodes, size_t pos, 24926fa459cSmrg size_t start_pos, size_t len, size_t len_code, size_t dist, 25026fa459cSmrg size_t short_code, float cost) { 25126fa459cSmrg ZopfliNode* next = &nodes[pos + len]; 25226fa459cSmrg next->length = (uint32_t)(len | ((len + 9u - len_code) << 25)); 25326fa459cSmrg next->distance = (uint32_t)dist; 25426fa459cSmrg next->dcode_insert_length = (uint32_t)( 25526fa459cSmrg (short_code << 27) | (pos - start_pos)); 25626fa459cSmrg next->u.cost = cost; 25726fa459cSmrg} 25826fa459cSmrg 25926fa459cSmrgtypedef struct PosData { 26026fa459cSmrg size_t pos; 26126fa459cSmrg int distance_cache[4]; 26226fa459cSmrg float costdiff; 26326fa459cSmrg float cost; 26426fa459cSmrg} PosData; 26526fa459cSmrg 26626fa459cSmrg/* Maintains the smallest 8 cost difference together with their positions */ 26726fa459cSmrgtypedef struct StartPosQueue { 26826fa459cSmrg PosData q_[8]; 26926fa459cSmrg size_t idx_; 27026fa459cSmrg} StartPosQueue; 27126fa459cSmrg 27226fa459cSmrgstatic BROTLI_INLINE void InitStartPosQueue(StartPosQueue* self) { 27326fa459cSmrg self->idx_ = 0; 27426fa459cSmrg} 27526fa459cSmrg 27626fa459cSmrgstatic size_t StartPosQueueSize(const StartPosQueue* self) { 27726fa459cSmrg return BROTLI_MIN(size_t, self->idx_, 8); 27826fa459cSmrg} 27926fa459cSmrg 28026fa459cSmrgstatic void StartPosQueuePush(StartPosQueue* self, const PosData* posdata) { 28126fa459cSmrg size_t offset = ~(self->idx_++) & 7; 28226fa459cSmrg size_t len = StartPosQueueSize(self); 28326fa459cSmrg size_t i; 28426fa459cSmrg PosData* q = self->q_; 28526fa459cSmrg q[offset] = *posdata; 28626fa459cSmrg /* Restore the sorted order. In the list of |len| items at most |len - 1| 28726fa459cSmrg adjacent element comparisons / swaps are required. */ 28826fa459cSmrg for (i = 1; i < len; ++i) { 28926fa459cSmrg if (q[offset & 7].costdiff > q[(offset + 1) & 7].costdiff) { 29026fa459cSmrg BROTLI_SWAP(PosData, q, offset & 7, (offset + 1) & 7); 29126fa459cSmrg } 29226fa459cSmrg ++offset; 29326fa459cSmrg } 29426fa459cSmrg} 29526fa459cSmrg 29626fa459cSmrgstatic const PosData* StartPosQueueAt(const StartPosQueue* self, size_t k) { 29726fa459cSmrg return &self->q_[(k - self->idx_) & 7]; 29826fa459cSmrg} 29926fa459cSmrg 30026fa459cSmrg/* Returns the minimum possible copy length that can improve the cost of any */ 30126fa459cSmrg/* future position. */ 30226fa459cSmrgstatic size_t ComputeMinimumCopyLength(const float start_cost, 30326fa459cSmrg const ZopfliNode* nodes, 30426fa459cSmrg const size_t num_bytes, 30526fa459cSmrg const size_t pos) { 30626fa459cSmrg /* Compute the minimum possible cost of reaching any future position. */ 30726fa459cSmrg float min_cost = start_cost; 30826fa459cSmrg size_t len = 2; 30926fa459cSmrg size_t next_len_bucket = 4; 31026fa459cSmrg size_t next_len_offset = 10; 31126fa459cSmrg while (pos + len <= num_bytes && nodes[pos + len].u.cost <= min_cost) { 31226fa459cSmrg /* We already reached (pos + len) with no more cost than the minimum 31326fa459cSmrg possible cost of reaching anything from this pos, so there is no point in 31426fa459cSmrg looking for lengths <= len. */ 31526fa459cSmrg ++len; 31626fa459cSmrg if (len == next_len_offset) { 31726fa459cSmrg /* We reached the next copy length code bucket, so we add one more 31826fa459cSmrg extra bit to the minimum cost. */ 31926fa459cSmrg min_cost += 1.0f; 32026fa459cSmrg next_len_offset += next_len_bucket; 32126fa459cSmrg next_len_bucket *= 2; 32226fa459cSmrg } 32326fa459cSmrg } 32426fa459cSmrg return len; 32526fa459cSmrg} 32626fa459cSmrg 32726fa459cSmrg/* REQUIRES: nodes[pos].cost < kInfinity 32826fa459cSmrg REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */ 32926fa459cSmrgstatic uint32_t ComputeDistanceShortcut(const size_t block_start, 33026fa459cSmrg const size_t pos, 33126fa459cSmrg const size_t max_backward_limit, 33226fa459cSmrg const size_t gap, 33326fa459cSmrg const ZopfliNode* nodes) { 33426fa459cSmrg const size_t clen = ZopfliNodeCopyLength(&nodes[pos]); 33526fa459cSmrg const size_t ilen = nodes[pos].dcode_insert_length & 0x7FFFFFF; 33626fa459cSmrg const size_t dist = ZopfliNodeCopyDistance(&nodes[pos]); 33726fa459cSmrg /* Since |block_start + pos| is the end position of the command, the copy part 33826fa459cSmrg starts from |block_start + pos - clen|. Distances that are greater than 33926fa459cSmrg this or greater than |max_backward_limit| + |gap| are static dictionary 34026fa459cSmrg references, and do not update the last distances. 34126fa459cSmrg Also distance code 0 (last distance) does not update the last distances. */ 34226fa459cSmrg if (pos == 0) { 34326fa459cSmrg return 0; 34426fa459cSmrg } else if (dist + clen <= block_start + pos + gap && 34526fa459cSmrg dist <= max_backward_limit + gap && 34626fa459cSmrg ZopfliNodeDistanceCode(&nodes[pos]) > 0) { 34726fa459cSmrg return (uint32_t)pos; 34826fa459cSmrg } else { 34926fa459cSmrg return nodes[pos - clen - ilen].u.shortcut; 35026fa459cSmrg } 35126fa459cSmrg} 35226fa459cSmrg 35326fa459cSmrg/* Fills in dist_cache[0..3] with the last four distances (as defined by 35426fa459cSmrg Section 4. of the Spec) that would be used at (block_start + pos) if we 35526fa459cSmrg used the shortest path of commands from block_start, computed from 35626fa459cSmrg nodes[0..pos]. The last four distances at block_start are in 35726fa459cSmrg starting_dist_cache[0..3]. 35826fa459cSmrg REQUIRES: nodes[pos].cost < kInfinity 35926fa459cSmrg REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */ 36026fa459cSmrgstatic void ComputeDistanceCache(const size_t pos, 36126fa459cSmrg const int* starting_dist_cache, 36226fa459cSmrg const ZopfliNode* nodes, 36326fa459cSmrg int* dist_cache) { 36426fa459cSmrg int idx = 0; 36526fa459cSmrg size_t p = nodes[pos].u.shortcut; 36626fa459cSmrg while (idx < 4 && p > 0) { 36726fa459cSmrg const size_t ilen = nodes[p].dcode_insert_length & 0x7FFFFFF; 36826fa459cSmrg const size_t clen = ZopfliNodeCopyLength(&nodes[p]); 36926fa459cSmrg const size_t dist = ZopfliNodeCopyDistance(&nodes[p]); 37026fa459cSmrg dist_cache[idx++] = (int)dist; 37126fa459cSmrg /* Because of prerequisite, p >= clen + ilen >= 2. */ 37226fa459cSmrg p = nodes[p - clen - ilen].u.shortcut; 37326fa459cSmrg } 37426fa459cSmrg for (; idx < 4; ++idx) { 37526fa459cSmrg dist_cache[idx] = *starting_dist_cache++; 37626fa459cSmrg } 37726fa459cSmrg} 37826fa459cSmrg 37926fa459cSmrg/* Maintains "ZopfliNode array invariant" and pushes node to the queue, if it 38026fa459cSmrg is eligible. */ 38126fa459cSmrgstatic void EvaluateNode( 38226fa459cSmrg const size_t block_start, const size_t pos, const size_t max_backward_limit, 38326fa459cSmrg const size_t gap, const int* starting_dist_cache, 38426fa459cSmrg const ZopfliCostModel* model, StartPosQueue* queue, ZopfliNode* nodes) { 38526fa459cSmrg /* Save cost, because ComputeDistanceCache invalidates it. */ 38626fa459cSmrg float node_cost = nodes[pos].u.cost; 38726fa459cSmrg nodes[pos].u.shortcut = ComputeDistanceShortcut( 38826fa459cSmrg block_start, pos, max_backward_limit, gap, nodes); 38926fa459cSmrg if (node_cost <= ZopfliCostModelGetLiteralCosts(model, 0, pos)) { 39026fa459cSmrg PosData posdata; 39126fa459cSmrg posdata.pos = pos; 39226fa459cSmrg posdata.cost = node_cost; 39326fa459cSmrg posdata.costdiff = node_cost - 39426fa459cSmrg ZopfliCostModelGetLiteralCosts(model, 0, pos); 39526fa459cSmrg ComputeDistanceCache( 39626fa459cSmrg pos, starting_dist_cache, nodes, posdata.distance_cache); 39726fa459cSmrg StartPosQueuePush(queue, &posdata); 39826fa459cSmrg } 39926fa459cSmrg} 40026fa459cSmrg 40126fa459cSmrg/* Returns longest copy length. */ 40226fa459cSmrgstatic size_t UpdateNodes( 40326fa459cSmrg const size_t num_bytes, const size_t block_start, const size_t pos, 40426fa459cSmrg const uint8_t* ringbuffer, const size_t ringbuffer_mask, 40526fa459cSmrg const BrotliEncoderParams* params, const size_t max_backward_limit, 40626fa459cSmrg const int* starting_dist_cache, const size_t num_matches, 40726fa459cSmrg const BackwardMatch* matches, const ZopfliCostModel* model, 40826fa459cSmrg StartPosQueue* queue, ZopfliNode* nodes) { 40926fa459cSmrg const size_t stream_offset = params->stream_offset; 41026fa459cSmrg const size_t cur_ix = block_start + pos; 41126fa459cSmrg const size_t cur_ix_masked = cur_ix & ringbuffer_mask; 41226fa459cSmrg const size_t max_distance = BROTLI_MIN(size_t, cur_ix, max_backward_limit); 41326fa459cSmrg const size_t dictionary_start = BROTLI_MIN(size_t, 41426fa459cSmrg cur_ix + stream_offset, max_backward_limit); 41526fa459cSmrg const size_t max_len = num_bytes - pos; 41626fa459cSmrg const size_t max_zopfli_len = MaxZopfliLen(params); 41726fa459cSmrg const size_t max_iters = MaxZopfliCandidates(params); 41826fa459cSmrg size_t min_len; 41926fa459cSmrg size_t result = 0; 42026fa459cSmrg size_t k; 42126fa459cSmrg size_t gap = 0; 42226fa459cSmrg 42326fa459cSmrg EvaluateNode(block_start + stream_offset, pos, max_backward_limit, gap, 42426fa459cSmrg starting_dist_cache, model, queue, nodes); 42526fa459cSmrg 42626fa459cSmrg { 42726fa459cSmrg const PosData* posdata = StartPosQueueAt(queue, 0); 42826fa459cSmrg float min_cost = (posdata->cost + ZopfliCostModelGetMinCostCmd(model) + 42926fa459cSmrg ZopfliCostModelGetLiteralCosts(model, posdata->pos, pos)); 43026fa459cSmrg min_len = ComputeMinimumCopyLength(min_cost, nodes, num_bytes, pos); 43126fa459cSmrg } 43226fa459cSmrg 43326fa459cSmrg /* Go over the command starting positions in order of increasing cost 43426fa459cSmrg difference. */ 43526fa459cSmrg for (k = 0; k < max_iters && k < StartPosQueueSize(queue); ++k) { 43626fa459cSmrg const PosData* posdata = StartPosQueueAt(queue, k); 43726fa459cSmrg const size_t start = posdata->pos; 43826fa459cSmrg const uint16_t inscode = GetInsertLengthCode(pos - start); 43926fa459cSmrg const float start_costdiff = posdata->costdiff; 44026fa459cSmrg const float base_cost = start_costdiff + (float)GetInsertExtra(inscode) + 44126fa459cSmrg ZopfliCostModelGetLiteralCosts(model, 0, pos); 44226fa459cSmrg 44326fa459cSmrg /* Look for last distance matches using the distance cache from this 44426fa459cSmrg starting position. */ 44526fa459cSmrg size_t best_len = min_len - 1; 44626fa459cSmrg size_t j = 0; 44726fa459cSmrg for (; j < BROTLI_NUM_DISTANCE_SHORT_CODES && best_len < max_len; ++j) { 44826fa459cSmrg const size_t idx = kDistanceCacheIndex[j]; 44926fa459cSmrg const size_t backward = 45026fa459cSmrg (size_t)(posdata->distance_cache[idx] + kDistanceCacheOffset[j]); 45126fa459cSmrg size_t prev_ix = cur_ix - backward; 45226fa459cSmrg size_t len = 0; 45326fa459cSmrg uint8_t continuation = ringbuffer[cur_ix_masked + best_len]; 45426fa459cSmrg if (cur_ix_masked + best_len > ringbuffer_mask) { 45526fa459cSmrg break; 45626fa459cSmrg } 45726fa459cSmrg if (BROTLI_PREDICT_FALSE(backward > dictionary_start + gap)) { 45826fa459cSmrg /* Word dictionary -> ignore. */ 45926fa459cSmrg continue; 46026fa459cSmrg } 46126fa459cSmrg if (backward <= max_distance) { 46226fa459cSmrg /* Regular backward reference. */ 46326fa459cSmrg if (prev_ix >= cur_ix) { 46426fa459cSmrg continue; 46526fa459cSmrg } 46626fa459cSmrg 46726fa459cSmrg prev_ix &= ringbuffer_mask; 46826fa459cSmrg if (prev_ix + best_len > ringbuffer_mask || 46926fa459cSmrg continuation != ringbuffer[prev_ix + best_len]) { 47026fa459cSmrg continue; 47126fa459cSmrg } 47226fa459cSmrg len = FindMatchLengthWithLimit(&ringbuffer[prev_ix], 47326fa459cSmrg &ringbuffer[cur_ix_masked], 47426fa459cSmrg max_len); 47526fa459cSmrg } else { 47626fa459cSmrg /* "Gray" area. It is addressable by decoder, but this encoder 47726fa459cSmrg instance does not have that data -> should not touch it. */ 47826fa459cSmrg continue; 47926fa459cSmrg } 48026fa459cSmrg { 48126fa459cSmrg const float dist_cost = base_cost + 48226fa459cSmrg ZopfliCostModelGetDistanceCost(model, j); 48326fa459cSmrg size_t l; 48426fa459cSmrg for (l = best_len + 1; l <= len; ++l) { 48526fa459cSmrg const uint16_t copycode = GetCopyLengthCode(l); 48626fa459cSmrg const uint16_t cmdcode = 48726fa459cSmrg CombineLengthCodes(inscode, copycode, j == 0); 48826fa459cSmrg const float cost = (cmdcode < 128 ? base_cost : dist_cost) + 48926fa459cSmrg (float)GetCopyExtra(copycode) + 49026fa459cSmrg ZopfliCostModelGetCommandCost(model, cmdcode); 49126fa459cSmrg if (cost < nodes[pos + l].u.cost) { 49226fa459cSmrg UpdateZopfliNode(nodes, pos, start, l, l, backward, j + 1, cost); 49326fa459cSmrg result = BROTLI_MAX(size_t, result, l); 49426fa459cSmrg } 49526fa459cSmrg best_len = l; 49626fa459cSmrg } 49726fa459cSmrg } 49826fa459cSmrg } 49926fa459cSmrg 50026fa459cSmrg /* At higher iterations look only for new last distance matches, since 50126fa459cSmrg looking only for new command start positions with the same distances 50226fa459cSmrg does not help much. */ 50326fa459cSmrg if (k >= 2) continue; 50426fa459cSmrg 50526fa459cSmrg { 50626fa459cSmrg /* Loop through all possible copy lengths at this position. */ 50726fa459cSmrg size_t len = min_len; 50826fa459cSmrg for (j = 0; j < num_matches; ++j) { 50926fa459cSmrg BackwardMatch match = matches[j]; 51026fa459cSmrg size_t dist = match.distance; 51126fa459cSmrg BROTLI_BOOL is_dictionary_match = 51226fa459cSmrg TO_BROTLI_BOOL(dist > dictionary_start + gap); 51326fa459cSmrg /* We already tried all possible last distance matches, so we can use 51426fa459cSmrg normal distance code here. */ 51526fa459cSmrg size_t dist_code = dist + BROTLI_NUM_DISTANCE_SHORT_CODES - 1; 51626fa459cSmrg uint16_t dist_symbol; 51726fa459cSmrg uint32_t distextra; 51826fa459cSmrg uint32_t distnumextra; 51926fa459cSmrg float dist_cost; 52026fa459cSmrg size_t max_match_len; 52126fa459cSmrg PrefixEncodeCopyDistance( 52226fa459cSmrg dist_code, params->dist.num_direct_distance_codes, 52326fa459cSmrg params->dist.distance_postfix_bits, &dist_symbol, &distextra); 52426fa459cSmrg distnumextra = dist_symbol >> 10; 52526fa459cSmrg dist_cost = base_cost + (float)distnumextra + 52626fa459cSmrg ZopfliCostModelGetDistanceCost(model, dist_symbol & 0x3FF); 52726fa459cSmrg 52826fa459cSmrg /* Try all copy lengths up until the maximum copy length corresponding 52926fa459cSmrg to this distance. If the distance refers to the static dictionary, or 53026fa459cSmrg the maximum length is long enough, try only one maximum length. */ 53126fa459cSmrg max_match_len = BackwardMatchLength(&match); 53226fa459cSmrg if (len < max_match_len && 53326fa459cSmrg (is_dictionary_match || max_match_len > max_zopfli_len)) { 53426fa459cSmrg len = max_match_len; 53526fa459cSmrg } 53626fa459cSmrg for (; len <= max_match_len; ++len) { 53726fa459cSmrg const size_t len_code = 53826fa459cSmrg is_dictionary_match ? BackwardMatchLengthCode(&match) : len; 53926fa459cSmrg const uint16_t copycode = GetCopyLengthCode(len_code); 54026fa459cSmrg const uint16_t cmdcode = CombineLengthCodes(inscode, copycode, 0); 54126fa459cSmrg const float cost = dist_cost + (float)GetCopyExtra(copycode) + 54226fa459cSmrg ZopfliCostModelGetCommandCost(model, cmdcode); 54326fa459cSmrg if (cost < nodes[pos + len].u.cost) { 54426fa459cSmrg UpdateZopfliNode(nodes, pos, start, len, len_code, dist, 0, cost); 54526fa459cSmrg result = BROTLI_MAX(size_t, result, len); 54626fa459cSmrg } 54726fa459cSmrg } 54826fa459cSmrg } 54926fa459cSmrg } 55026fa459cSmrg } 55126fa459cSmrg return result; 55226fa459cSmrg} 55326fa459cSmrg 55426fa459cSmrgstatic size_t ComputeShortestPathFromNodes(size_t num_bytes, 55526fa459cSmrg ZopfliNode* nodes) { 55626fa459cSmrg size_t index = num_bytes; 55726fa459cSmrg size_t num_commands = 0; 55826fa459cSmrg while ((nodes[index].dcode_insert_length & 0x7FFFFFF) == 0 && 55926fa459cSmrg nodes[index].length == 1) --index; 56026fa459cSmrg nodes[index].u.next = BROTLI_UINT32_MAX; 56126fa459cSmrg while (index != 0) { 56226fa459cSmrg size_t len = ZopfliNodeCommandLength(&nodes[index]); 56326fa459cSmrg index -= len; 56426fa459cSmrg nodes[index].u.next = (uint32_t)len; 56526fa459cSmrg num_commands++; 56626fa459cSmrg } 56726fa459cSmrg return num_commands; 56826fa459cSmrg} 56926fa459cSmrg 57026fa459cSmrg/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */ 57126fa459cSmrgvoid BrotliZopfliCreateCommands(const size_t num_bytes, 57226fa459cSmrg const size_t block_start, const ZopfliNode* nodes, int* dist_cache, 57326fa459cSmrg size_t* last_insert_len, const BrotliEncoderParams* params, 57426fa459cSmrg Command* commands, size_t* num_literals) { 57526fa459cSmrg const size_t stream_offset = params->stream_offset; 57626fa459cSmrg const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin); 57726fa459cSmrg size_t pos = 0; 57826fa459cSmrg uint32_t offset = nodes[0].u.next; 57926fa459cSmrg size_t i; 58026fa459cSmrg size_t gap = 0; 58126fa459cSmrg for (i = 0; offset != BROTLI_UINT32_MAX; i++) { 58226fa459cSmrg const ZopfliNode* next = &nodes[pos + offset]; 58326fa459cSmrg size_t copy_length = ZopfliNodeCopyLength(next); 58426fa459cSmrg size_t insert_length = next->dcode_insert_length & 0x7FFFFFF; 58526fa459cSmrg pos += insert_length; 58626fa459cSmrg offset = next->u.next; 58726fa459cSmrg if (i == 0) { 58826fa459cSmrg insert_length += *last_insert_len; 58926fa459cSmrg *last_insert_len = 0; 59026fa459cSmrg } 59126fa459cSmrg { 59226fa459cSmrg size_t distance = ZopfliNodeCopyDistance(next); 59326fa459cSmrg size_t len_code = ZopfliNodeLengthCode(next); 59426fa459cSmrg size_t dictionary_start = BROTLI_MIN(size_t, 59526fa459cSmrg block_start + pos + stream_offset, max_backward_limit); 59626fa459cSmrg BROTLI_BOOL is_dictionary = 59726fa459cSmrg TO_BROTLI_BOOL(distance > dictionary_start + gap); 59826fa459cSmrg size_t dist_code = ZopfliNodeDistanceCode(next); 59926fa459cSmrg InitCommand(&commands[i], ¶ms->dist, insert_length, 60026fa459cSmrg copy_length, (int)len_code - (int)copy_length, dist_code); 60126fa459cSmrg 60226fa459cSmrg if (!is_dictionary && dist_code > 0) { 60326fa459cSmrg dist_cache[3] = dist_cache[2]; 60426fa459cSmrg dist_cache[2] = dist_cache[1]; 60526fa459cSmrg dist_cache[1] = dist_cache[0]; 60626fa459cSmrg dist_cache[0] = (int)distance; 60726fa459cSmrg } 60826fa459cSmrg } 60926fa459cSmrg 61026fa459cSmrg *num_literals += insert_length; 61126fa459cSmrg pos += copy_length; 61226fa459cSmrg } 61326fa459cSmrg *last_insert_len += num_bytes - pos; 61426fa459cSmrg} 61526fa459cSmrg 61626fa459cSmrgstatic size_t ZopfliIterate(size_t num_bytes, size_t position, 61726fa459cSmrg const uint8_t* ringbuffer, size_t ringbuffer_mask, 61826fa459cSmrg const BrotliEncoderParams* params, const size_t gap, const int* dist_cache, 61926fa459cSmrg const ZopfliCostModel* model, const uint32_t* num_matches, 62026fa459cSmrg const BackwardMatch* matches, ZopfliNode* nodes) { 62126fa459cSmrg const size_t stream_offset = params->stream_offset; 62226fa459cSmrg const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin); 62326fa459cSmrg const size_t max_zopfli_len = MaxZopfliLen(params); 62426fa459cSmrg StartPosQueue queue; 62526fa459cSmrg size_t cur_match_pos = 0; 62626fa459cSmrg size_t i; 62726fa459cSmrg nodes[0].length = 0; 62826fa459cSmrg nodes[0].u.cost = 0; 62926fa459cSmrg InitStartPosQueue(&queue); 63026fa459cSmrg for (i = 0; i + 3 < num_bytes; i++) { 63126fa459cSmrg size_t skip = UpdateNodes(num_bytes, position, i, ringbuffer, 63226fa459cSmrg ringbuffer_mask, params, max_backward_limit, dist_cache, 63326fa459cSmrg num_matches[i], &matches[cur_match_pos], model, &queue, nodes); 63426fa459cSmrg if (skip < BROTLI_LONG_COPY_QUICK_STEP) skip = 0; 63526fa459cSmrg cur_match_pos += num_matches[i]; 63626fa459cSmrg if (num_matches[i] == 1 && 63726fa459cSmrg BackwardMatchLength(&matches[cur_match_pos - 1]) > max_zopfli_len) { 63826fa459cSmrg skip = BROTLI_MAX(size_t, 63926fa459cSmrg BackwardMatchLength(&matches[cur_match_pos - 1]), skip); 64026fa459cSmrg } 64126fa459cSmrg if (skip > 1) { 64226fa459cSmrg skip--; 64326fa459cSmrg while (skip) { 64426fa459cSmrg i++; 64526fa459cSmrg if (i + 3 >= num_bytes) break; 64626fa459cSmrg EvaluateNode(position + stream_offset, i, max_backward_limit, gap, 64726fa459cSmrg dist_cache, model, &queue, nodes); 64826fa459cSmrg cur_match_pos += num_matches[i]; 64926fa459cSmrg skip--; 65026fa459cSmrg } 65126fa459cSmrg } 65226fa459cSmrg } 65326fa459cSmrg return ComputeShortestPathFromNodes(num_bytes, nodes); 65426fa459cSmrg} 65526fa459cSmrg 65626fa459cSmrg/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */ 65726fa459cSmrgsize_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes, 65826fa459cSmrg size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask, 65926fa459cSmrg ContextLut literal_context_lut, const BrotliEncoderParams* params, 66026fa459cSmrg const int* dist_cache, Hasher* hasher, ZopfliNode* nodes) { 66126fa459cSmrg const size_t stream_offset = params->stream_offset; 66226fa459cSmrg const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin); 66326fa459cSmrg const size_t max_zopfli_len = MaxZopfliLen(params); 66426fa459cSmrg ZopfliCostModel model; 66526fa459cSmrg StartPosQueue queue; 66626fa459cSmrg BackwardMatch matches[2 * (MAX_NUM_MATCHES_H10 + 64)]; 66726fa459cSmrg const size_t store_end = num_bytes >= StoreLookaheadH10() ? 66826fa459cSmrg position + num_bytes - StoreLookaheadH10() + 1 : position; 66926fa459cSmrg size_t i; 67026fa459cSmrg size_t gap = 0; 67126fa459cSmrg size_t lz_matches_offset = 0; 67226fa459cSmrg BROTLI_UNUSED(literal_context_lut); 67326fa459cSmrg nodes[0].length = 0; 67426fa459cSmrg nodes[0].u.cost = 0; 67526fa459cSmrg InitZopfliCostModel(m, &model, ¶ms->dist, num_bytes); 67626fa459cSmrg if (BROTLI_IS_OOM(m)) return 0; 67726fa459cSmrg ZopfliCostModelSetFromLiteralCosts( 67826fa459cSmrg &model, position, ringbuffer, ringbuffer_mask); 67926fa459cSmrg InitStartPosQueue(&queue); 68026fa459cSmrg for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; i++) { 68126fa459cSmrg const size_t pos = position + i; 68226fa459cSmrg const size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit); 68326fa459cSmrg const size_t dictionary_start = BROTLI_MIN(size_t, 68426fa459cSmrg pos + stream_offset, max_backward_limit); 68526fa459cSmrg size_t skip; 68626fa459cSmrg size_t num_matches; 68726fa459cSmrg num_matches = FindAllMatchesH10(&hasher->privat._H10, 68826fa459cSmrg ¶ms->dictionary, 68926fa459cSmrg ringbuffer, ringbuffer_mask, pos, num_bytes - i, max_distance, 69026fa459cSmrg dictionary_start + gap, params, &matches[lz_matches_offset]); 69126fa459cSmrg if (num_matches > 0 && 69226fa459cSmrg BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) { 69326fa459cSmrg matches[0] = matches[num_matches - 1]; 69426fa459cSmrg num_matches = 1; 69526fa459cSmrg } 69626fa459cSmrg skip = UpdateNodes(num_bytes, position, i, ringbuffer, ringbuffer_mask, 69726fa459cSmrg params, max_backward_limit, dist_cache, num_matches, matches, &model, 69826fa459cSmrg &queue, nodes); 69926fa459cSmrg if (skip < BROTLI_LONG_COPY_QUICK_STEP) skip = 0; 70026fa459cSmrg if (num_matches == 1 && BackwardMatchLength(&matches[0]) > max_zopfli_len) { 70126fa459cSmrg skip = BROTLI_MAX(size_t, BackwardMatchLength(&matches[0]), skip); 70226fa459cSmrg } 70326fa459cSmrg if (skip > 1) { 70426fa459cSmrg /* Add the tail of the copy to the hasher. */ 70526fa459cSmrg StoreRangeH10(&hasher->privat._H10, 70626fa459cSmrg ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN( 70726fa459cSmrg size_t, pos + skip, store_end)); 70826fa459cSmrg skip--; 70926fa459cSmrg while (skip) { 71026fa459cSmrg i++; 71126fa459cSmrg if (i + HashTypeLengthH10() - 1 >= num_bytes) break; 71226fa459cSmrg EvaluateNode(position + stream_offset, i, max_backward_limit, gap, 71326fa459cSmrg dist_cache, &model, &queue, nodes); 71426fa459cSmrg skip--; 71526fa459cSmrg } 71626fa459cSmrg } 71726fa459cSmrg } 71826fa459cSmrg CleanupZopfliCostModel(m, &model); 71926fa459cSmrg return ComputeShortestPathFromNodes(num_bytes, nodes); 72026fa459cSmrg} 72126fa459cSmrg 72226fa459cSmrgvoid BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes, 72326fa459cSmrg size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask, 72426fa459cSmrg ContextLut literal_context_lut, const BrotliEncoderParams* params, 72526fa459cSmrg Hasher* hasher, int* dist_cache, size_t* last_insert_len, 72626fa459cSmrg Command* commands, size_t* num_commands, size_t* num_literals) { 72726fa459cSmrg ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1); 72826fa459cSmrg if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return; 72926fa459cSmrg BrotliInitZopfliNodes(nodes, num_bytes + 1); 73026fa459cSmrg *num_commands += BrotliZopfliComputeShortestPath(m, num_bytes, 73126fa459cSmrg position, ringbuffer, ringbuffer_mask, literal_context_lut, params, 73226fa459cSmrg dist_cache, hasher, nodes); 73326fa459cSmrg if (BROTLI_IS_OOM(m)) return; 73426fa459cSmrg BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache, 73526fa459cSmrg last_insert_len, params, commands, num_literals); 73626fa459cSmrg BROTLI_FREE(m, nodes); 73726fa459cSmrg} 73826fa459cSmrg 73926fa459cSmrgvoid BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes, 74026fa459cSmrg size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask, 74126fa459cSmrg ContextLut literal_context_lut, const BrotliEncoderParams* params, 74226fa459cSmrg Hasher* hasher, int* dist_cache, size_t* last_insert_len, 74326fa459cSmrg Command* commands, size_t* num_commands, size_t* num_literals) { 74426fa459cSmrg const size_t stream_offset = params->stream_offset; 74526fa459cSmrg const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin); 74626fa459cSmrg uint32_t* num_matches = BROTLI_ALLOC(m, uint32_t, num_bytes); 74726fa459cSmrg size_t matches_size = 4 * num_bytes; 74826fa459cSmrg const size_t store_end = num_bytes >= StoreLookaheadH10() ? 74926fa459cSmrg position + num_bytes - StoreLookaheadH10() + 1 : position; 75026fa459cSmrg size_t cur_match_pos = 0; 75126fa459cSmrg size_t i; 75226fa459cSmrg size_t orig_num_literals; 75326fa459cSmrg size_t orig_last_insert_len; 75426fa459cSmrg int orig_dist_cache[4]; 75526fa459cSmrg size_t orig_num_commands; 75626fa459cSmrg ZopfliCostModel model; 75726fa459cSmrg ZopfliNode* nodes; 75826fa459cSmrg BackwardMatch* matches = BROTLI_ALLOC(m, BackwardMatch, matches_size); 75926fa459cSmrg size_t gap = 0; 76026fa459cSmrg size_t shadow_matches = 0; 76126fa459cSmrg BROTLI_UNUSED(literal_context_lut); 76226fa459cSmrg if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(num_matches) || 76326fa459cSmrg BROTLI_IS_NULL(matches)) { 76426fa459cSmrg return; 76526fa459cSmrg } 76626fa459cSmrg for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; ++i) { 76726fa459cSmrg const size_t pos = position + i; 76826fa459cSmrg size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit); 76926fa459cSmrg size_t dictionary_start = BROTLI_MIN(size_t, 77026fa459cSmrg pos + stream_offset, max_backward_limit); 77126fa459cSmrg size_t max_length = num_bytes - i; 77226fa459cSmrg size_t num_found_matches; 77326fa459cSmrg size_t cur_match_end; 77426fa459cSmrg size_t j; 77526fa459cSmrg /* Ensure that we have enough free slots. */ 77626fa459cSmrg BROTLI_ENSURE_CAPACITY(m, BackwardMatch, matches, matches_size, 77726fa459cSmrg cur_match_pos + MAX_NUM_MATCHES_H10 + shadow_matches); 77826fa459cSmrg if (BROTLI_IS_OOM(m)) return; 77926fa459cSmrg num_found_matches = FindAllMatchesH10(&hasher->privat._H10, 78026fa459cSmrg ¶ms->dictionary, 78126fa459cSmrg ringbuffer, ringbuffer_mask, pos, max_length, 78226fa459cSmrg max_distance, dictionary_start + gap, params, 78326fa459cSmrg &matches[cur_match_pos + shadow_matches]); 78426fa459cSmrg cur_match_end = cur_match_pos + num_found_matches; 78526fa459cSmrg for (j = cur_match_pos; j + 1 < cur_match_end; ++j) { 78626fa459cSmrg BROTLI_DCHECK(BackwardMatchLength(&matches[j]) <= 78726fa459cSmrg BackwardMatchLength(&matches[j + 1])); 78826fa459cSmrg } 78926fa459cSmrg num_matches[i] = (uint32_t)num_found_matches; 79026fa459cSmrg if (num_found_matches > 0) { 79126fa459cSmrg const size_t match_len = BackwardMatchLength(&matches[cur_match_end - 1]); 79226fa459cSmrg if (match_len > MAX_ZOPFLI_LEN_QUALITY_11) { 79326fa459cSmrg const size_t skip = match_len - 1; 79426fa459cSmrg matches[cur_match_pos++] = matches[cur_match_end - 1]; 79526fa459cSmrg num_matches[i] = 1; 79626fa459cSmrg /* Add the tail of the copy to the hasher. */ 79726fa459cSmrg StoreRangeH10(&hasher->privat._H10, 79826fa459cSmrg ringbuffer, ringbuffer_mask, pos + 1, 79926fa459cSmrg BROTLI_MIN(size_t, pos + match_len, store_end)); 80026fa459cSmrg memset(&num_matches[i + 1], 0, skip * sizeof(num_matches[0])); 80126fa459cSmrg i += skip; 80226fa459cSmrg } else { 80326fa459cSmrg cur_match_pos = cur_match_end; 80426fa459cSmrg } 80526fa459cSmrg } 80626fa459cSmrg } 80726fa459cSmrg orig_num_literals = *num_literals; 80826fa459cSmrg orig_last_insert_len = *last_insert_len; 80926fa459cSmrg memcpy(orig_dist_cache, dist_cache, 4 * sizeof(dist_cache[0])); 81026fa459cSmrg orig_num_commands = *num_commands; 81126fa459cSmrg nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1); 81226fa459cSmrg if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return; 81326fa459cSmrg InitZopfliCostModel(m, &model, ¶ms->dist, num_bytes); 81426fa459cSmrg if (BROTLI_IS_OOM(m)) return; 81526fa459cSmrg for (i = 0; i < 2; i++) { 81626fa459cSmrg BrotliInitZopfliNodes(nodes, num_bytes + 1); 81726fa459cSmrg if (i == 0) { 81826fa459cSmrg ZopfliCostModelSetFromLiteralCosts( 81926fa459cSmrg &model, position, ringbuffer, ringbuffer_mask); 82026fa459cSmrg } else { 82126fa459cSmrg ZopfliCostModelSetFromCommands(&model, position, ringbuffer, 82226fa459cSmrg ringbuffer_mask, commands, *num_commands - orig_num_commands, 82326fa459cSmrg orig_last_insert_len); 82426fa459cSmrg } 82526fa459cSmrg *num_commands = orig_num_commands; 82626fa459cSmrg *num_literals = orig_num_literals; 82726fa459cSmrg *last_insert_len = orig_last_insert_len; 82826fa459cSmrg memcpy(dist_cache, orig_dist_cache, 4 * sizeof(dist_cache[0])); 82926fa459cSmrg *num_commands += ZopfliIterate(num_bytes, position, ringbuffer, 83026fa459cSmrg ringbuffer_mask, params, gap, dist_cache, &model, num_matches, matches, 83126fa459cSmrg nodes); 83226fa459cSmrg BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache, 83326fa459cSmrg last_insert_len, params, commands, num_literals); 83426fa459cSmrg } 83526fa459cSmrg CleanupZopfliCostModel(m, &model); 83626fa459cSmrg BROTLI_FREE(m, nodes); 83726fa459cSmrg BROTLI_FREE(m, matches); 83826fa459cSmrg BROTLI_FREE(m, num_matches); 83926fa459cSmrg} 84026fa459cSmrg 84126fa459cSmrg#if defined(__cplusplus) || defined(c_plusplus) 84226fa459cSmrg} /* extern "C" */ 84326fa459cSmrg#endif 844