brotli 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/main.yml +34 -0
  3. data/.github/workflows/publish.yml +34 -0
  4. data/Gemfile +6 -2
  5. data/Rakefile +18 -6
  6. data/bin/before_install.sh +9 -0
  7. data/brotli.gemspec +7 -13
  8. data/ext/brotli/brotli.c +209 -11
  9. data/ext/brotli/buffer.c +1 -7
  10. data/ext/brotli/buffer.h +1 -1
  11. data/ext/brotli/extconf.rb +45 -26
  12. data/lib/brotli/version.rb +1 -1
  13. data/smoke.sh +1 -1
  14. data/test/brotli_test.rb +104 -0
  15. data/test/brotli_writer_test.rb +36 -0
  16. data/test/test_helper.rb +8 -0
  17. data/vendor/brotli/c/common/constants.c +15 -0
  18. data/vendor/brotli/c/common/constants.h +149 -6
  19. data/vendor/brotli/c/{dec/context.h → common/context.c} +91 -186
  20. data/vendor/brotli/c/common/context.h +113 -0
  21. data/vendor/brotli/c/common/dictionary.bin +0 -0
  22. data/vendor/brotli/c/common/dictionary.bin.br +0 -0
  23. data/vendor/brotli/c/common/dictionary.c +11 -2
  24. data/vendor/brotli/c/common/dictionary.h +4 -4
  25. data/vendor/brotli/c/common/platform.c +22 -0
  26. data/vendor/brotli/c/common/platform.h +594 -0
  27. data/vendor/brotli/c/common/transform.c +291 -0
  28. data/vendor/brotli/c/common/transform.h +85 -0
  29. data/vendor/brotli/c/common/version.h +8 -1
  30. data/vendor/brotli/c/dec/bit_reader.c +29 -1
  31. data/vendor/brotli/c/dec/bit_reader.h +91 -100
  32. data/vendor/brotli/c/dec/decode.c +665 -437
  33. data/vendor/brotli/c/dec/huffman.c +65 -84
  34. data/vendor/brotli/c/dec/huffman.h +67 -14
  35. data/vendor/brotli/c/dec/prefix.h +1 -20
  36. data/vendor/brotli/c/dec/state.c +32 -45
  37. data/vendor/brotli/c/dec/state.h +173 -55
  38. data/vendor/brotli/c/enc/backward_references.c +27 -16
  39. data/vendor/brotli/c/enc/backward_references.h +7 -7
  40. data/vendor/brotli/c/enc/backward_references_hq.c +155 -116
  41. data/vendor/brotli/c/enc/backward_references_hq.h +22 -23
  42. data/vendor/brotli/c/enc/backward_references_inc.h +32 -22
  43. data/vendor/brotli/c/enc/bit_cost.c +1 -1
  44. data/vendor/brotli/c/enc/bit_cost.h +5 -5
  45. data/vendor/brotli/c/enc/block_encoder_inc.h +7 -6
  46. data/vendor/brotli/c/enc/block_splitter.c +5 -6
  47. data/vendor/brotli/c/enc/block_splitter.h +1 -1
  48. data/vendor/brotli/c/enc/block_splitter_inc.h +26 -17
  49. data/vendor/brotli/c/enc/brotli_bit_stream.c +107 -123
  50. data/vendor/brotli/c/enc/brotli_bit_stream.h +19 -38
  51. data/vendor/brotli/c/enc/cluster.c +1 -1
  52. data/vendor/brotli/c/enc/cluster.h +1 -1
  53. data/vendor/brotli/c/enc/cluster_inc.h +6 -3
  54. data/vendor/brotli/c/enc/command.c +28 -0
  55. data/vendor/brotli/c/enc/command.h +52 -42
  56. data/vendor/brotli/c/enc/compress_fragment.c +21 -22
  57. data/vendor/brotli/c/enc/compress_fragment.h +1 -1
  58. data/vendor/brotli/c/enc/compress_fragment_two_pass.c +102 -69
  59. data/vendor/brotli/c/enc/compress_fragment_two_pass.h +1 -1
  60. data/vendor/brotli/c/enc/dictionary_hash.c +1827 -1101
  61. data/vendor/brotli/c/enc/dictionary_hash.h +2 -1
  62. data/vendor/brotli/c/enc/encode.c +358 -195
  63. data/vendor/brotli/c/enc/encoder_dict.c +33 -0
  64. data/vendor/brotli/c/enc/encoder_dict.h +43 -0
  65. data/vendor/brotli/c/enc/entropy_encode.c +16 -14
  66. data/vendor/brotli/c/enc/entropy_encode.h +7 -7
  67. data/vendor/brotli/c/enc/entropy_encode_static.h +3 -3
  68. data/vendor/brotli/c/enc/fast_log.c +105 -0
  69. data/vendor/brotli/c/enc/fast_log.h +20 -99
  70. data/vendor/brotli/c/enc/find_match_length.h +5 -6
  71. data/vendor/brotli/c/enc/hash.h +145 -103
  72. data/vendor/brotli/c/enc/hash_composite_inc.h +125 -0
  73. data/vendor/brotli/c/enc/hash_forgetful_chain_inc.h +93 -53
  74. data/vendor/brotli/c/enc/hash_longest_match64_inc.h +54 -53
  75. data/vendor/brotli/c/enc/hash_longest_match_inc.h +58 -54
  76. data/vendor/brotli/c/enc/hash_longest_match_quickly_inc.h +95 -63
  77. data/vendor/brotli/c/enc/hash_rolling_inc.h +212 -0
  78. data/vendor/brotli/c/enc/hash_to_binary_tree_inc.h +46 -43
  79. data/vendor/brotli/c/enc/histogram.c +9 -6
  80. data/vendor/brotli/c/enc/histogram.h +6 -3
  81. data/vendor/brotli/c/enc/histogram_inc.h +1 -1
  82. data/vendor/brotli/c/enc/literal_cost.c +5 -5
  83. data/vendor/brotli/c/enc/literal_cost.h +2 -2
  84. data/vendor/brotli/c/enc/memory.c +5 -16
  85. data/vendor/brotli/c/enc/memory.h +52 -1
  86. data/vendor/brotli/c/enc/metablock.c +171 -36
  87. data/vendor/brotli/c/enc/metablock.h +13 -8
  88. data/vendor/brotli/c/enc/metablock_inc.h +2 -2
  89. data/vendor/brotli/c/enc/params.h +46 -0
  90. data/vendor/brotli/c/enc/prefix.h +3 -4
  91. data/vendor/brotli/c/enc/quality.h +29 -24
  92. data/vendor/brotli/c/enc/ringbuffer.h +19 -12
  93. data/vendor/brotli/c/enc/static_dict.c +49 -45
  94. data/vendor/brotli/c/enc/static_dict.h +4 -3
  95. data/vendor/brotli/c/enc/static_dict_lut.h +1 -1
  96. data/vendor/brotli/c/enc/utf8_util.c +21 -21
  97. data/vendor/brotli/c/enc/utf8_util.h +1 -1
  98. data/vendor/brotli/c/enc/write_bits.h +35 -38
  99. data/vendor/brotli/c/include/brotli/decode.h +13 -8
  100. data/vendor/brotli/c/include/brotli/encode.h +54 -8
  101. data/vendor/brotli/c/include/brotli/port.h +225 -83
  102. data/vendor/brotli/c/include/brotli/types.h +0 -7
  103. metadata +28 -87
  104. data/.travis.yml +0 -30
  105. data/spec/brotli_spec.rb +0 -88
  106. data/spec/inflate_spec.rb +0 -75
  107. data/spec/spec_helper.rb +0 -4
  108. data/vendor/brotli/c/dec/port.h +0 -168
  109. data/vendor/brotli/c/dec/transform.h +0 -300
  110. data/vendor/brotli/c/enc/context.h +0 -184
  111. data/vendor/brotli/c/enc/port.h +0 -184
@@ -9,12 +9,13 @@
9
9
  #include "./backward_references.h"
10
10
 
11
11
  #include "../common/constants.h"
12
+ #include "../common/context.h"
12
13
  #include "../common/dictionary.h"
14
+ #include "../common/platform.h"
13
15
  #include <brotli/types.h>
14
16
  #include "./command.h"
15
17
  #include "./dictionary_hash.h"
16
18
  #include "./memory.h"
17
- #include "./port.h"
18
19
  #include "./quality.h"
19
20
 
20
21
  #if defined(__cplusplus) || defined(c_plusplus)
@@ -49,6 +50,7 @@ static BROTLI_INLINE size_t ComputeDistanceCode(size_t distance,
49
50
  #define CAT(a, b) a ## b
50
51
  #define FN(X) EXPAND_CAT(X, HASHER())
51
52
  #define EXPORT_FN(X) EXPAND_CAT(X, EXPAND_CAT(PREFIX(), HASHER()))
53
+
52
54
  #define PREFIX() N
53
55
 
54
56
  #define HASHER() H2
@@ -96,30 +98,39 @@ static BROTLI_INLINE size_t ComputeDistanceCode(size_t distance,
96
98
  #include "./backward_references_inc.h"
97
99
  #undef HASHER
98
100
 
101
+ #define HASHER() H35
102
+ /* NOLINTNEXTLINE(build/include) */
103
+ #include "./backward_references_inc.h"
104
+ #undef HASHER
105
+
106
+ #define HASHER() H55
107
+ /* NOLINTNEXTLINE(build/include) */
108
+ #include "./backward_references_inc.h"
109
+ #undef HASHER
110
+
111
+ #define HASHER() H65
112
+ /* NOLINTNEXTLINE(build/include) */
113
+ #include "./backward_references_inc.h"
114
+ #undef HASHER
115
+
99
116
  #undef PREFIX
117
+
100
118
  #undef EXPORT_FN
101
119
  #undef FN
102
120
  #undef CAT
103
121
  #undef EXPAND_CAT
104
122
 
105
- void BrotliCreateBackwardReferences(const BrotliDictionary* dictionary,
106
- size_t num_bytes,
107
- size_t position,
108
- const uint8_t* ringbuffer,
109
- size_t ringbuffer_mask,
110
- const BrotliEncoderParams* params,
111
- HasherHandle hasher,
112
- int* dist_cache,
113
- size_t* last_insert_len,
114
- Command* commands,
115
- size_t* num_commands,
116
- size_t* num_literals) {
123
+ void BrotliCreateBackwardReferences(size_t num_bytes,
124
+ size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
125
+ ContextLut literal_context_lut, const BrotliEncoderParams* params,
126
+ Hasher* hasher, int* dist_cache, size_t* last_insert_len,
127
+ Command* commands, size_t* num_commands, size_t* num_literals) {
117
128
  switch (params->hasher.type) {
118
129
  #define CASE_(N) \
119
130
  case N: \
120
- CreateBackwardReferencesNH ## N(dictionary, \
121
- kStaticDictionaryHash, num_bytes, position, ringbuffer, \
122
- ringbuffer_mask, params, hasher, dist_cache, \
131
+ CreateBackwardReferencesNH ## N(num_bytes, \
132
+ position, ringbuffer, ringbuffer_mask, \
133
+ literal_context_lut, params, hasher, dist_cache, \
123
134
  last_insert_len, commands, num_commands, num_literals); \
124
135
  return;
125
136
  FOR_GENERIC_HASHERS(CASE_)
@@ -10,11 +10,12 @@
10
10
  #define BROTLI_ENC_BACKWARD_REFERENCES_H_
11
11
 
12
12
  #include "../common/constants.h"
13
+ #include "../common/context.h"
13
14
  #include "../common/dictionary.h"
15
+ #include "../common/platform.h"
14
16
  #include <brotli/types.h>
15
17
  #include "./command.h"
16
18
  #include "./hash.h"
17
- #include "./port.h"
18
19
  #include "./quality.h"
19
20
 
20
21
  #if defined(__cplusplus) || defined(c_plusplus)
@@ -25,12 +26,11 @@ extern "C" {
25
26
  initially the total amount of commands output by previous
26
27
  CreateBackwardReferences calls, and must be incremented by the amount written
27
28
  by this call. */
28
- BROTLI_INTERNAL void BrotliCreateBackwardReferences(
29
- const BrotliDictionary* dictionary, size_t num_bytes, size_t position,
30
- const uint8_t* ringbuffer, size_t ringbuffer_mask,
31
- const BrotliEncoderParams* params, HasherHandle hasher, int* dist_cache,
32
- size_t* last_insert_len, Command* commands, size_t* num_commands,
33
- size_t* num_literals);
29
+ BROTLI_INTERNAL void BrotliCreateBackwardReferences(size_t num_bytes,
30
+ size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
31
+ ContextLut literal_context_lut, const BrotliEncoderParams* params,
32
+ Hasher* hasher, int* dist_cache, size_t* last_insert_len,
33
+ Command* commands, size_t* num_commands, size_t* num_literals);
34
34
 
35
35
  #if defined(__cplusplus) || defined(c_plusplus)
36
36
  } /* extern "C" */
@@ -11,13 +11,15 @@
11
11
  #include <string.h> /* memcpy, memset */
12
12
 
13
13
  #include "../common/constants.h"
14
+ #include "../common/context.h"
15
+ #include "../common/platform.h"
14
16
  #include <brotli/types.h>
15
17
  #include "./command.h"
16
18
  #include "./fast_log.h"
17
19
  #include "./find_match_length.h"
18
20
  #include "./literal_cost.h"
19
21
  #include "./memory.h"
20
- #include "./port.h"
22
+ #include "./params.h"
21
23
  #include "./prefix.h"
22
24
  #include "./quality.h"
23
25
 
@@ -25,6 +27,9 @@
25
27
  extern "C" {
26
28
  #endif
27
29
 
30
+ /* BrotliCalculateDistanceCodeLimit(BROTLI_MAX_ALLOWED_DISTANCE, 3, 120). */
31
+ #define BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE 544
32
+
28
33
  static const float kInfinity = 1.7e38f; /* ~= 2 ^ 127 */
29
34
 
30
35
  static const uint32_t kDistanceCacheIndex[] = {
@@ -39,40 +44,41 @@ void BrotliInitZopfliNodes(ZopfliNode* array, size_t length) {
39
44
  size_t i;
40
45
  stub.length = 1;
41
46
  stub.distance = 0;
42
- stub.insert_length = 0;
47
+ stub.dcode_insert_length = 0;
43
48
  stub.u.cost = kInfinity;
44
49
  for (i = 0; i < length; ++i) array[i] = stub;
45
50
  }
46
51
 
47
52
  static BROTLI_INLINE uint32_t ZopfliNodeCopyLength(const ZopfliNode* self) {
48
- return self->length & 0xffffff;
53
+ return self->length & 0x1FFFFFF;
49
54
  }
50
55
 
51
56
  static BROTLI_INLINE uint32_t ZopfliNodeLengthCode(const ZopfliNode* self) {
52
- const uint32_t modifier = self->length >> 24;
57
+ const uint32_t modifier = self->length >> 25;
53
58
  return ZopfliNodeCopyLength(self) + 9u - modifier;
54
59
  }
55
60
 
56
61
  static BROTLI_INLINE uint32_t ZopfliNodeCopyDistance(const ZopfliNode* self) {
57
- return self->distance & 0x1ffffff;
62
+ return self->distance;
58
63
  }
59
64
 
60
65
  static BROTLI_INLINE uint32_t ZopfliNodeDistanceCode(const ZopfliNode* self) {
61
- const uint32_t short_code = self->distance >> 25;
66
+ const uint32_t short_code = self->dcode_insert_length >> 27;
62
67
  return short_code == 0 ?
63
68
  ZopfliNodeCopyDistance(self) + BROTLI_NUM_DISTANCE_SHORT_CODES - 1 :
64
69
  short_code - 1;
65
70
  }
66
71
 
67
72
  static BROTLI_INLINE uint32_t ZopfliNodeCommandLength(const ZopfliNode* self) {
68
- return ZopfliNodeCopyLength(self) + self->insert_length;
73
+ return ZopfliNodeCopyLength(self) + (self->dcode_insert_length & 0x7FFFFFF);
69
74
  }
70
75
 
71
76
  /* Histogram based cost model for zopflification. */
72
77
  typedef struct ZopfliCostModel {
73
78
  /* The insert and copy length symbols. */
74
79
  float cost_cmd_[BROTLI_NUM_COMMAND_SYMBOLS];
75
- float cost_dist_[BROTLI_NUM_DISTANCE_SYMBOLS];
80
+ float* cost_dist_;
81
+ uint32_t distance_histogram_size;
76
82
  /* Cumulative costs of literals per position in the stream. */
77
83
  float* literal_costs_;
78
84
  float min_cost_cmd_;
@@ -80,28 +86,41 @@ typedef struct ZopfliCostModel {
80
86
  } ZopfliCostModel;
81
87
 
82
88
  static void InitZopfliCostModel(
83
- MemoryManager* m, ZopfliCostModel* self, size_t num_bytes) {
89
+ MemoryManager* m, ZopfliCostModel* self, const BrotliDistanceParams* dist,
90
+ size_t num_bytes) {
84
91
  self->num_bytes_ = num_bytes;
85
92
  self->literal_costs_ = BROTLI_ALLOC(m, float, num_bytes + 2);
93
+ self->cost_dist_ = BROTLI_ALLOC(m, float, dist->alphabet_size_limit);
94
+ self->distance_histogram_size = dist->alphabet_size_limit;
86
95
  if (BROTLI_IS_OOM(m)) return;
87
96
  }
88
97
 
89
98
  static void CleanupZopfliCostModel(MemoryManager* m, ZopfliCostModel* self) {
90
99
  BROTLI_FREE(m, self->literal_costs_);
100
+ BROTLI_FREE(m, self->cost_dist_);
91
101
  }
92
102
 
93
103
  static void SetCost(const uint32_t* histogram, size_t histogram_size,
94
- float* cost) {
104
+ BROTLI_BOOL literal_histogram, float* cost) {
95
105
  size_t sum = 0;
106
+ size_t missing_symbol_sum;
96
107
  float log2sum;
108
+ float missing_symbol_cost;
97
109
  size_t i;
98
110
  for (i = 0; i < histogram_size; i++) {
99
111
  sum += histogram[i];
100
112
  }
101
113
  log2sum = (float)FastLog2(sum);
114
+ missing_symbol_sum = sum;
115
+ if (!literal_histogram) {
116
+ for (i = 0; i < histogram_size; i++) {
117
+ if (histogram[i] == 0) missing_symbol_sum++;
118
+ }
119
+ }
120
+ missing_symbol_cost = (float)FastLog2(missing_symbol_sum) + 2;
102
121
  for (i = 0; i < histogram_size; i++) {
103
122
  if (histogram[i] == 0) {
104
- cost[i] = log2sum + 2;
123
+ cost[i] = missing_symbol_cost;
105
124
  continue;
106
125
  }
107
126
 
@@ -122,7 +141,7 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
122
141
  size_t last_insert_len) {
123
142
  uint32_t histogram_literal[BROTLI_NUM_LITERAL_SYMBOLS];
124
143
  uint32_t histogram_cmd[BROTLI_NUM_COMMAND_SYMBOLS];
125
- uint32_t histogram_dist[BROTLI_NUM_DISTANCE_SYMBOLS];
144
+ uint32_t histogram_dist[BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE];
126
145
  float cost_literal[BROTLI_NUM_LITERAL_SYMBOLS];
127
146
  size_t pos = position - last_insert_len;
128
147
  float min_cost_cmd = kInfinity;
@@ -136,7 +155,7 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
136
155
  for (i = 0; i < num_commands; i++) {
137
156
  size_t inslength = commands[i].insert_len_;
138
157
  size_t copylength = CommandCopyLen(&commands[i]);
139
- size_t distcode = commands[i].dist_prefix_;
158
+ size_t distcode = commands[i].dist_prefix_ & 0x3FF;
140
159
  size_t cmdcode = commands[i].cmd_prefix_;
141
160
  size_t j;
142
161
 
@@ -150,9 +169,12 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
150
169
  pos += inslength + copylength;
151
170
  }
152
171
 
153
- SetCost(histogram_literal, BROTLI_NUM_LITERAL_SYMBOLS, cost_literal);
154
- SetCost(histogram_cmd, BROTLI_NUM_COMMAND_SYMBOLS, cost_cmd);
155
- SetCost(histogram_dist, BROTLI_NUM_DISTANCE_SYMBOLS, self->cost_dist_);
172
+ SetCost(histogram_literal, BROTLI_NUM_LITERAL_SYMBOLS, BROTLI_TRUE,
173
+ cost_literal);
174
+ SetCost(histogram_cmd, BROTLI_NUM_COMMAND_SYMBOLS, BROTLI_FALSE,
175
+ cost_cmd);
176
+ SetCost(histogram_dist, self->distance_histogram_size, BROTLI_FALSE,
177
+ self->cost_dist_);
156
178
 
157
179
  for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
158
180
  min_cost_cmd = BROTLI_MIN(float, min_cost_cmd, cost_cmd[i]);
@@ -161,11 +183,14 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
161
183
 
162
184
  {
163
185
  float* literal_costs = self->literal_costs_;
186
+ float literal_carry = 0.0;
164
187
  size_t num_bytes = self->num_bytes_;
165
188
  literal_costs[0] = 0.0;
166
189
  for (i = 0; i < num_bytes; ++i) {
167
- literal_costs[i + 1] = literal_costs[i] +
190
+ literal_carry +=
168
191
  cost_literal[ringbuffer[(position + i) & ringbuffer_mask]];
192
+ literal_costs[i + 1] = literal_costs[i] + literal_carry;
193
+ literal_carry -= literal_costs[i + 1] - literal_costs[i];
169
194
  }
170
195
  }
171
196
  }
@@ -175,6 +200,7 @@ static void ZopfliCostModelSetFromLiteralCosts(ZopfliCostModel* self,
175
200
  const uint8_t* ringbuffer,
176
201
  size_t ringbuffer_mask) {
177
202
  float* literal_costs = self->literal_costs_;
203
+ float literal_carry = 0.0;
178
204
  float* cost_dist = self->cost_dist_;
179
205
  float* cost_cmd = self->cost_cmd_;
180
206
  size_t num_bytes = self->num_bytes_;
@@ -183,12 +209,14 @@ static void ZopfliCostModelSetFromLiteralCosts(ZopfliCostModel* self,
183
209
  ringbuffer, &literal_costs[1]);
184
210
  literal_costs[0] = 0.0;
185
211
  for (i = 0; i < num_bytes; ++i) {
186
- literal_costs[i + 1] += literal_costs[i];
212
+ literal_carry += literal_costs[i + 1];
213
+ literal_costs[i + 1] = literal_costs[i] + literal_carry;
214
+ literal_carry -= literal_costs[i + 1] - literal_costs[i];
187
215
  }
188
216
  for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
189
217
  cost_cmd[i] = (float)FastLog2(11 + (uint32_t)i);
190
218
  }
191
- for (i = 0; i < BROTLI_NUM_DISTANCE_SYMBOLS; ++i) {
219
+ for (i = 0; i < self->distance_histogram_size; ++i) {
192
220
  cost_dist[i] = (float)FastLog2(20 + (uint32_t)i);
193
221
  }
194
222
  self->min_cost_cmd_ = (float)FastLog2(11);
@@ -221,9 +249,10 @@ static BROTLI_INLINE void UpdateZopfliNode(ZopfliNode* nodes, size_t pos,
221
249
  size_t start_pos, size_t len, size_t len_code, size_t dist,
222
250
  size_t short_code, float cost) {
223
251
  ZopfliNode* next = &nodes[pos + len];
224
- next->length = (uint32_t)(len | ((len + 9u - len_code) << 24));
225
- next->distance = (uint32_t)(dist | (short_code << 25));
226
- next->insert_length = (uint32_t)(pos - start_pos);
252
+ next->length = (uint32_t)(len | ((len + 9u - len_code) << 25));
253
+ next->distance = (uint32_t)dist;
254
+ next->dcode_insert_length = (uint32_t)(
255
+ (short_code << 27) | (pos - start_pos));
227
256
  next->u.cost = cost;
228
257
  }
229
258
 
@@ -299,21 +328,21 @@ static size_t ComputeMinimumCopyLength(const float start_cost,
299
328
  REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
300
329
  static uint32_t ComputeDistanceShortcut(const size_t block_start,
301
330
  const size_t pos,
302
- const size_t max_backward,
331
+ const size_t max_backward_limit,
303
332
  const size_t gap,
304
333
  const ZopfliNode* nodes) {
305
334
  const size_t clen = ZopfliNodeCopyLength(&nodes[pos]);
306
- const size_t ilen = nodes[pos].insert_length;
335
+ const size_t ilen = nodes[pos].dcode_insert_length & 0x7FFFFFF;
307
336
  const size_t dist = ZopfliNodeCopyDistance(&nodes[pos]);
308
337
  /* Since |block_start + pos| is the end position of the command, the copy part
309
338
  starts from |block_start + pos - clen|. Distances that are greater than
310
- this or greater than |max_backward| are static dictionary references, and
311
- do not update the last distances. Also distance code 0 (last distance)
312
- does not update the last distances. */
339
+ this or greater than |max_backward_limit| + |gap| are static dictionary
340
+ references, and do not update the last distances.
341
+ Also distance code 0 (last distance) does not update the last distances. */
313
342
  if (pos == 0) {
314
343
  return 0;
315
344
  } else if (dist + clen <= block_start + pos + gap &&
316
- dist <= max_backward + gap &&
345
+ dist <= max_backward_limit + gap &&
317
346
  ZopfliNodeDistanceCode(&nodes[pos]) > 0) {
318
347
  return (uint32_t)pos;
319
348
  } else {
@@ -335,7 +364,7 @@ static void ComputeDistanceCache(const size_t pos,
335
364
  int idx = 0;
336
365
  size_t p = nodes[pos].u.shortcut;
337
366
  while (idx < 4 && p > 0) {
338
- const size_t ilen = nodes[p].insert_length;
367
+ const size_t ilen = nodes[p].dcode_insert_length & 0x7FFFFFF;
339
368
  const size_t clen = ZopfliNodeCopyLength(&nodes[p]);
340
369
  const size_t dist = ZopfliNodeCopyDistance(&nodes[p]);
341
370
  dist_cache[idx++] = (int)dist;
@@ -377,9 +406,12 @@ static size_t UpdateNodes(
377
406
  const int* starting_dist_cache, const size_t num_matches,
378
407
  const BackwardMatch* matches, const ZopfliCostModel* model,
379
408
  StartPosQueue* queue, ZopfliNode* nodes) {
409
+ const size_t stream_offset = params->stream_offset;
380
410
  const size_t cur_ix = block_start + pos;
381
411
  const size_t cur_ix_masked = cur_ix & ringbuffer_mask;
382
412
  const size_t max_distance = BROTLI_MIN(size_t, cur_ix, max_backward_limit);
413
+ const size_t dictionary_start = BROTLI_MIN(size_t,
414
+ cur_ix + stream_offset, max_backward_limit);
383
415
  const size_t max_len = num_bytes - pos;
384
416
  const size_t max_zopfli_len = MaxZopfliLen(params);
385
417
  const size_t max_iters = MaxZopfliCandidates(params);
@@ -388,8 +420,8 @@ static size_t UpdateNodes(
388
420
  size_t k;
389
421
  size_t gap = 0;
390
422
 
391
- EvaluateNode(block_start, pos, max_backward_limit, gap, starting_dist_cache,
392
- model, queue, nodes);
423
+ EvaluateNode(block_start + stream_offset, pos, max_backward_limit, gap,
424
+ starting_dist_cache, model, queue, nodes);
393
425
 
394
426
  {
395
427
  const PosData* posdata = StartPosQueueAt(queue, 0);
@@ -422,10 +454,12 @@ static size_t UpdateNodes(
422
454
  if (cur_ix_masked + best_len > ringbuffer_mask) {
423
455
  break;
424
456
  }
425
- if (BROTLI_PREDICT_FALSE(backward > max_distance + gap)) {
457
+ if (BROTLI_PREDICT_FALSE(backward > dictionary_start + gap)) {
458
+ /* Word dictionary -> ignore. */
426
459
  continue;
427
460
  }
428
461
  if (backward <= max_distance) {
462
+ /* Regular backward reference. */
429
463
  if (prev_ix >= cur_ix) {
430
464
  continue;
431
465
  }
@@ -439,6 +473,8 @@ static size_t UpdateNodes(
439
473
  &ringbuffer[cur_ix_masked],
440
474
  max_len);
441
475
  } else {
476
+ /* "Gray" area. It is addressable by decoder, but this encoder
477
+ instance does not have that data -> should not touch it. */
442
478
  continue;
443
479
  }
444
480
  {
@@ -473,7 +509,7 @@ static size_t UpdateNodes(
473
509
  BackwardMatch match = matches[j];
474
510
  size_t dist = match.distance;
475
511
  BROTLI_BOOL is_dictionary_match =
476
- TO_BROTLI_BOOL(dist > max_distance + gap);
512
+ TO_BROTLI_BOOL(dist > dictionary_start + gap);
477
513
  /* We already tried all possible last distance matches, so we can use
478
514
  normal distance code here. */
479
515
  size_t dist_code = dist + BROTLI_NUM_DISTANCE_SHORT_CODES - 1;
@@ -482,10 +518,12 @@ static size_t UpdateNodes(
482
518
  uint32_t distnumextra;
483
519
  float dist_cost;
484
520
  size_t max_match_len;
485
- PrefixEncodeCopyDistance(dist_code, 0, 0, &dist_symbol, &distextra);
486
- distnumextra = distextra >> 24;
521
+ PrefixEncodeCopyDistance(
522
+ dist_code, params->dist.num_direct_distance_codes,
523
+ params->dist.distance_postfix_bits, &dist_symbol, &distextra);
524
+ distnumextra = dist_symbol >> 10;
487
525
  dist_cost = base_cost + (float)distnumextra +
488
- ZopfliCostModelGetDistanceCost(model, dist_symbol);
526
+ ZopfliCostModelGetDistanceCost(model, dist_symbol & 0x3FF);
489
527
 
490
528
  /* Try all copy lengths up until the maximum copy length corresponding
491
529
  to this distance. If the distance refers to the static dictionary, or
@@ -517,7 +555,8 @@ static size_t ComputeShortestPathFromNodes(size_t num_bytes,
517
555
  ZopfliNode* nodes) {
518
556
  size_t index = num_bytes;
519
557
  size_t num_commands = 0;
520
- while (nodes[index].insert_length == 0 && nodes[index].length == 1) --index;
558
+ while ((nodes[index].dcode_insert_length & 0x7FFFFFF) == 0 &&
559
+ nodes[index].length == 1) --index;
521
560
  nodes[index].u.next = BROTLI_UINT32_MAX;
522
561
  while (index != 0) {
523
562
  size_t len = ZopfliNodeCommandLength(&nodes[index]);
@@ -530,23 +569,19 @@ static size_t ComputeShortestPathFromNodes(size_t num_bytes,
530
569
 
531
570
  /* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
532
571
  void BrotliZopfliCreateCommands(const size_t num_bytes,
533
- const size_t block_start,
534
- const size_t max_backward_limit,
535
- const ZopfliNode* nodes,
536
- int* dist_cache,
537
- size_t* last_insert_len,
538
- const BrotliEncoderParams* params,
539
- Command* commands,
540
- size_t* num_literals) {
572
+ const size_t block_start, const ZopfliNode* nodes, int* dist_cache,
573
+ size_t* last_insert_len, const BrotliEncoderParams* params,
574
+ Command* commands, size_t* num_literals) {
575
+ const size_t stream_offset = params->stream_offset;
576
+ const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
541
577
  size_t pos = 0;
542
578
  uint32_t offset = nodes[0].u.next;
543
579
  size_t i;
544
580
  size_t gap = 0;
545
- BROTLI_UNUSED(params);
546
581
  for (i = 0; offset != BROTLI_UINT32_MAX; i++) {
547
582
  const ZopfliNode* next = &nodes[pos + offset];
548
583
  size_t copy_length = ZopfliNodeCopyLength(next);
549
- size_t insert_length = next->insert_length;
584
+ size_t insert_length = next->dcode_insert_length & 0x7FFFFFF;
550
585
  pos += insert_length;
551
586
  offset = next->u.next;
552
587
  if (i == 0) {
@@ -556,12 +591,12 @@ void BrotliZopfliCreateCommands(const size_t num_bytes,
556
591
  {
557
592
  size_t distance = ZopfliNodeCopyDistance(next);
558
593
  size_t len_code = ZopfliNodeLengthCode(next);
559
- size_t max_distance =
560
- BROTLI_MIN(size_t, block_start + pos, max_backward_limit);
561
- BROTLI_BOOL is_dictionary = TO_BROTLI_BOOL(distance > max_distance + gap);
594
+ size_t dictionary_start = BROTLI_MIN(size_t,
595
+ block_start + pos + stream_offset, max_backward_limit);
596
+ BROTLI_BOOL is_dictionary =
597
+ TO_BROTLI_BOOL(distance > dictionary_start + gap);
562
598
  size_t dist_code = ZopfliNodeDistanceCode(next);
563
-
564
- InitCommand(&commands[i], insert_length,
599
+ InitCommand(&commands[i], &params->dist, insert_length,
565
600
  copy_length, (int)len_code - (int)copy_length, dist_code);
566
601
 
567
602
  if (!is_dictionary && dist_code > 0) {
@@ -578,18 +613,13 @@ void BrotliZopfliCreateCommands(const size_t num_bytes,
578
613
  *last_insert_len += num_bytes - pos;
579
614
  }
580
615
 
581
- static size_t ZopfliIterate(size_t num_bytes,
582
- size_t position,
583
- const uint8_t* ringbuffer,
584
- size_t ringbuffer_mask,
585
- const BrotliEncoderParams* params,
586
- const size_t max_backward_limit,
587
- const size_t gap,
588
- const int* dist_cache,
589
- const ZopfliCostModel* model,
590
- const uint32_t* num_matches,
591
- const BackwardMatch* matches,
592
- ZopfliNode* nodes) {
616
+ static size_t ZopfliIterate(size_t num_bytes, size_t position,
617
+ const uint8_t* ringbuffer, size_t ringbuffer_mask,
618
+ const BrotliEncoderParams* params, const size_t gap, const int* dist_cache,
619
+ const ZopfliCostModel* model, const uint32_t* num_matches,
620
+ const BackwardMatch* matches, ZopfliNode* nodes) {
621
+ const size_t stream_offset = params->stream_offset;
622
+ const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
593
623
  const size_t max_zopfli_len = MaxZopfliLen(params);
594
624
  StartPosQueue queue;
595
625
  size_t cur_match_pos = 0;
@@ -613,8 +643,8 @@ static size_t ZopfliIterate(size_t num_bytes,
613
643
  while (skip) {
614
644
  i++;
615
645
  if (i + 3 >= num_bytes) break;
616
- EvaluateNode(position, i, max_backward_limit, gap, dist_cache, model,
617
- &queue, nodes);
646
+ EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
647
+ dist_cache, model, &queue, nodes);
618
648
  cur_match_pos += num_matches[i];
619
649
  skip--;
620
650
  }
@@ -624,28 +654,25 @@ static size_t ZopfliIterate(size_t num_bytes,
624
654
  }
625
655
 
626
656
  /* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
627
- size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
628
- const BrotliDictionary* dictionary,
629
- size_t num_bytes,
630
- size_t position,
631
- const uint8_t* ringbuffer,
632
- size_t ringbuffer_mask,
633
- const BrotliEncoderParams* params,
634
- const size_t max_backward_limit,
635
- const int* dist_cache,
636
- HasherHandle hasher,
637
- ZopfliNode* nodes) {
657
+ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
658
+ size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
659
+ ContextLut literal_context_lut, const BrotliEncoderParams* params,
660
+ const int* dist_cache, Hasher* hasher, ZopfliNode* nodes) {
661
+ const size_t stream_offset = params->stream_offset;
662
+ const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
638
663
  const size_t max_zopfli_len = MaxZopfliLen(params);
639
664
  ZopfliCostModel model;
640
665
  StartPosQueue queue;
641
- BackwardMatch matches[MAX_NUM_MATCHES_H10];
666
+ BackwardMatch matches[2 * (MAX_NUM_MATCHES_H10 + 64)];
642
667
  const size_t store_end = num_bytes >= StoreLookaheadH10() ?
643
668
  position + num_bytes - StoreLookaheadH10() + 1 : position;
644
669
  size_t i;
645
670
  size_t gap = 0;
671
+ size_t lz_matches_offset = 0;
672
+ BROTLI_UNUSED(literal_context_lut);
646
673
  nodes[0].length = 0;
647
674
  nodes[0].u.cost = 0;
648
- InitZopfliCostModel(m, &model, num_bytes);
675
+ InitZopfliCostModel(m, &model, &params->dist, num_bytes);
649
676
  if (BROTLI_IS_OOM(m)) return 0;
650
677
  ZopfliCostModelSetFromLiteralCosts(
651
678
  &model, position, ringbuffer, ringbuffer_mask);
@@ -653,10 +680,14 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
653
680
  for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; i++) {
654
681
  const size_t pos = position + i;
655
682
  const size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
656
- size_t num_matches = FindAllMatchesH10(hasher, dictionary, ringbuffer,
657
- ringbuffer_mask, pos, num_bytes - i, max_distance, gap, params,
658
- matches);
683
+ const size_t dictionary_start = BROTLI_MIN(size_t,
684
+ pos + stream_offset, max_backward_limit);
659
685
  size_t skip;
686
+ size_t num_matches;
687
+ num_matches = FindAllMatchesH10(&hasher->privat._H10,
688
+ &params->dictionary,
689
+ ringbuffer, ringbuffer_mask, pos, num_bytes - i, max_distance,
690
+ dictionary_start + gap, params, &matches[lz_matches_offset]);
660
691
  if (num_matches > 0 &&
661
692
  BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) {
662
693
  matches[0] = matches[num_matches - 1];
@@ -671,14 +702,15 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
671
702
  }
672
703
  if (skip > 1) {
673
704
  /* Add the tail of the copy to the hasher. */
674
- StoreRangeH10(hasher, ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(
705
+ StoreRangeH10(&hasher->privat._H10,
706
+ ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(
675
707
  size_t, pos + skip, store_end));
676
708
  skip--;
677
709
  while (skip) {
678
710
  i++;
679
711
  if (i + HashTypeLengthH10() - 1 >= num_bytes) break;
680
- EvaluateNode(position, i, max_backward_limit, gap, dist_cache, &model,
681
- &queue, nodes);
712
+ EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
713
+ dist_cache, &model, &queue, nodes);
682
714
  skip--;
683
715
  }
684
716
  }
@@ -687,32 +719,29 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
687
719
  return ComputeShortestPathFromNodes(num_bytes, nodes);
688
720
  }
689
721
 
690
- void BrotliCreateZopfliBackwardReferences(
691
- MemoryManager* m, const BrotliDictionary* dictionary, size_t num_bytes,
722
+ void BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
692
723
  size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
693
- const BrotliEncoderParams* params, HasherHandle hasher, int* dist_cache,
694
- size_t* last_insert_len, Command* commands, size_t* num_commands,
695
- size_t* num_literals) {
696
- const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
697
- ZopfliNode* nodes;
698
- nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
699
- if (BROTLI_IS_OOM(m)) return;
724
+ ContextLut literal_context_lut, const BrotliEncoderParams* params,
725
+ Hasher* hasher, int* dist_cache, size_t* last_insert_len,
726
+ Command* commands, size_t* num_commands, size_t* num_literals) {
727
+ ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
728
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
700
729
  BrotliInitZopfliNodes(nodes, num_bytes + 1);
701
- *num_commands += BrotliZopfliComputeShortestPath(m, dictionary, num_bytes,
702
- position, ringbuffer, ringbuffer_mask, params, max_backward_limit,
730
+ *num_commands += BrotliZopfliComputeShortestPath(m, num_bytes,
731
+ position, ringbuffer, ringbuffer_mask, literal_context_lut, params,
703
732
  dist_cache, hasher, nodes);
704
733
  if (BROTLI_IS_OOM(m)) return;
705
- BrotliZopfliCreateCommands(num_bytes, position, max_backward_limit, nodes,
706
- dist_cache, last_insert_len, params, commands, num_literals);
734
+ BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
735
+ last_insert_len, params, commands, num_literals);
707
736
  BROTLI_FREE(m, nodes);
708
737
  }
709
738
 
710
- void BrotliCreateHqZopfliBackwardReferences(
711
- MemoryManager* m, const BrotliDictionary* dictionary, size_t num_bytes,
739
+ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
712
740
  size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
713
- const BrotliEncoderParams* params, HasherHandle hasher, int* dist_cache,
714
- size_t* last_insert_len, Command* commands, size_t* num_commands,
715
- size_t* num_literals) {
741
+ ContextLut literal_context_lut, const BrotliEncoderParams* params,
742
+ Hasher* hasher, int* dist_cache, size_t* last_insert_len,
743
+ Command* commands, size_t* num_commands, size_t* num_literals) {
744
+ const size_t stream_offset = params->stream_offset;
716
745
  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
717
746
  uint32_t* num_matches = BROTLI_ALLOC(m, uint32_t, num_bytes);
718
747
  size_t matches_size = 4 * num_bytes;
@@ -728,24 +757,33 @@ void BrotliCreateHqZopfliBackwardReferences(
728
757
  ZopfliNode* nodes;
729
758
  BackwardMatch* matches = BROTLI_ALLOC(m, BackwardMatch, matches_size);
730
759
  size_t gap = 0;
731
- if (BROTLI_IS_OOM(m)) return;
760
+ size_t shadow_matches = 0;
761
+ BROTLI_UNUSED(literal_context_lut);
762
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(num_matches) ||
763
+ BROTLI_IS_NULL(matches)) {
764
+ return;
765
+ }
732
766
  for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; ++i) {
733
767
  const size_t pos = position + i;
734
768
  size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
769
+ size_t dictionary_start = BROTLI_MIN(size_t,
770
+ pos + stream_offset, max_backward_limit);
735
771
  size_t max_length = num_bytes - i;
736
772
  size_t num_found_matches;
737
773
  size_t cur_match_end;
738
774
  size_t j;
739
775
  /* Ensure that we have enough free slots. */
740
776
  BROTLI_ENSURE_CAPACITY(m, BackwardMatch, matches, matches_size,
741
- cur_match_pos + MAX_NUM_MATCHES_H10);
777
+ cur_match_pos + MAX_NUM_MATCHES_H10 + shadow_matches);
742
778
  if (BROTLI_IS_OOM(m)) return;
743
- num_found_matches = FindAllMatchesH10(hasher, dictionary, ringbuffer,
744
- ringbuffer_mask, pos, max_length, max_distance, gap, params,
745
- &matches[cur_match_pos]);
779
+ num_found_matches = FindAllMatchesH10(&hasher->privat._H10,
780
+ &params->dictionary,
781
+ ringbuffer, ringbuffer_mask, pos, max_length,
782
+ max_distance, dictionary_start + gap, params,
783
+ &matches[cur_match_pos + shadow_matches]);
746
784
  cur_match_end = cur_match_pos + num_found_matches;
747
785
  for (j = cur_match_pos; j + 1 < cur_match_end; ++j) {
748
- assert(BackwardMatchLength(&matches[j]) <=
786
+ BROTLI_DCHECK(BackwardMatchLength(&matches[j]) <=
749
787
  BackwardMatchLength(&matches[j + 1]));
750
788
  }
751
789
  num_matches[i] = (uint32_t)num_found_matches;
@@ -756,7 +794,8 @@ void BrotliCreateHqZopfliBackwardReferences(
756
794
  matches[cur_match_pos++] = matches[cur_match_end - 1];
757
795
  num_matches[i] = 1;
758
796
  /* Add the tail of the copy to the hasher. */
759
- StoreRangeH10(hasher, ringbuffer, ringbuffer_mask, pos + 1,
797
+ StoreRangeH10(&hasher->privat._H10,
798
+ ringbuffer, ringbuffer_mask, pos + 1,
760
799
  BROTLI_MIN(size_t, pos + match_len, store_end));
761
800
  memset(&num_matches[i + 1], 0, skip * sizeof(num_matches[0]));
762
801
  i += skip;
@@ -770,8 +809,8 @@ void BrotliCreateHqZopfliBackwardReferences(
770
809
  memcpy(orig_dist_cache, dist_cache, 4 * sizeof(dist_cache[0]));
771
810
  orig_num_commands = *num_commands;
772
811
  nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
773
- if (BROTLI_IS_OOM(m)) return;
774
- InitZopfliCostModel(m, &model, num_bytes);
812
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
813
+ InitZopfliCostModel(m, &model, &params->dist, num_bytes);
775
814
  if (BROTLI_IS_OOM(m)) return;
776
815
  for (i = 0; i < 2; i++) {
777
816
  BrotliInitZopfliNodes(nodes, num_bytes + 1);
@@ -788,10 +827,10 @@ void BrotliCreateHqZopfliBackwardReferences(
788
827
  *last_insert_len = orig_last_insert_len;
789
828
  memcpy(dist_cache, orig_dist_cache, 4 * sizeof(dist_cache[0]));
790
829
  *num_commands += ZopfliIterate(num_bytes, position, ringbuffer,
791
- ringbuffer_mask, params, max_backward_limit, gap, dist_cache,
792
- &model, num_matches, matches, nodes);
793
- BrotliZopfliCreateCommands(num_bytes, position, max_backward_limit,
794
- nodes, dist_cache, last_insert_len, params, commands, num_literals);
830
+ ringbuffer_mask, params, gap, dist_cache, &model, num_matches, matches,
831
+ nodes);
832
+ BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
833
+ last_insert_len, params, commands, num_literals);
795
834
  }
796
835
  CleanupZopfliCostModel(m, &model);
797
836
  BROTLI_FREE(m, nodes);