brotli 0.1.3 → 0.1.4

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