brotli 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +4 -0
  6. data/Gemfile +4 -0
  7. data/README.md +36 -0
  8. data/Rakefile +13 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +7 -0
  11. data/brotli.gemspec +28 -0
  12. data/ext/brotli/brotli.cc +67 -0
  13. data/ext/brotli/brotli.h +9 -0
  14. data/ext/brotli/extconf.rb +34 -0
  15. data/lib/brotli.rb +2 -0
  16. data/lib/brotli/version.rb +3 -0
  17. data/vendor/brotli/LICENSE +202 -0
  18. data/vendor/brotli/dec/Makefile +12 -0
  19. data/vendor/brotli/dec/bit_reader.c +55 -0
  20. data/vendor/brotli/dec/bit_reader.h +256 -0
  21. data/vendor/brotli/dec/context.h +260 -0
  22. data/vendor/brotli/dec/decode.c +1573 -0
  23. data/vendor/brotli/dec/decode.h +160 -0
  24. data/vendor/brotli/dec/dictionary.h +9494 -0
  25. data/vendor/brotli/dec/huffman.c +325 -0
  26. data/vendor/brotli/dec/huffman.h +77 -0
  27. data/vendor/brotli/dec/port.h +148 -0
  28. data/vendor/brotli/dec/prefix.h +756 -0
  29. data/vendor/brotli/dec/state.c +149 -0
  30. data/vendor/brotli/dec/state.h +185 -0
  31. data/vendor/brotli/dec/streams.c +99 -0
  32. data/vendor/brotli/dec/streams.h +100 -0
  33. data/vendor/brotli/dec/transform.h +315 -0
  34. data/vendor/brotli/dec/types.h +36 -0
  35. data/vendor/brotli/enc/Makefile +11 -0
  36. data/vendor/brotli/enc/backward_references.cc +769 -0
  37. data/vendor/brotli/enc/backward_references.h +50 -0
  38. data/vendor/brotli/enc/bit_cost.h +147 -0
  39. data/vendor/brotli/enc/block_splitter.cc +418 -0
  40. data/vendor/brotli/enc/block_splitter.h +78 -0
  41. data/vendor/brotli/enc/brotli_bit_stream.cc +884 -0
  42. data/vendor/brotli/enc/brotli_bit_stream.h +149 -0
  43. data/vendor/brotli/enc/cluster.h +290 -0
  44. data/vendor/brotli/enc/command.h +140 -0
  45. data/vendor/brotli/enc/context.h +185 -0
  46. data/vendor/brotli/enc/dictionary.h +9485 -0
  47. data/vendor/brotli/enc/dictionary_hash.h +4125 -0
  48. data/vendor/brotli/enc/encode.cc +715 -0
  49. data/vendor/brotli/enc/encode.h +196 -0
  50. data/vendor/brotli/enc/encode_parallel.cc +354 -0
  51. data/vendor/brotli/enc/encode_parallel.h +37 -0
  52. data/vendor/brotli/enc/entropy_encode.cc +492 -0
  53. data/vendor/brotli/enc/entropy_encode.h +88 -0
  54. data/vendor/brotli/enc/fast_log.h +179 -0
  55. data/vendor/brotli/enc/find_match_length.h +87 -0
  56. data/vendor/brotli/enc/hash.h +686 -0
  57. data/vendor/brotli/enc/histogram.cc +76 -0
  58. data/vendor/brotli/enc/histogram.h +100 -0
  59. data/vendor/brotli/enc/literal_cost.cc +172 -0
  60. data/vendor/brotli/enc/literal_cost.h +38 -0
  61. data/vendor/brotli/enc/metablock.cc +544 -0
  62. data/vendor/brotli/enc/metablock.h +88 -0
  63. data/vendor/brotli/enc/port.h +151 -0
  64. data/vendor/brotli/enc/prefix.h +85 -0
  65. data/vendor/brotli/enc/ringbuffer.h +108 -0
  66. data/vendor/brotli/enc/static_dict.cc +441 -0
  67. data/vendor/brotli/enc/static_dict.h +40 -0
  68. data/vendor/brotli/enc/static_dict_lut.h +12063 -0
  69. data/vendor/brotli/enc/streams.cc +127 -0
  70. data/vendor/brotli/enc/streams.h +129 -0
  71. data/vendor/brotli/enc/transform.h +250 -0
  72. data/vendor/brotli/enc/write_bits.h +91 -0
  73. metadata +171 -0
@@ -0,0 +1,196 @@
1
+ // Copyright 2013 Google Inc. All Rights Reserved.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ //
15
+ // API for Brotli compression
16
+
17
+ #ifndef BROTLI_ENC_ENCODE_H_
18
+ #define BROTLI_ENC_ENCODE_H_
19
+
20
+ #include <stddef.h>
21
+ #include <stdint.h>
22
+ #include <string>
23
+ #include <vector>
24
+ #include "./command.h"
25
+ #include "./hash.h"
26
+ #include "./ringbuffer.h"
27
+ #include "./static_dict.h"
28
+ #include "./streams.h"
29
+
30
+ namespace brotli {
31
+
32
+ static const int kMaxWindowBits = 24;
33
+ static const int kMinWindowBits = 10;
34
+ static const int kMinInputBlockBits = 16;
35
+ static const int kMaxInputBlockBits = 24;
36
+
37
+ struct BrotliParams {
38
+ BrotliParams()
39
+ : mode(MODE_GENERIC),
40
+ quality(11),
41
+ lgwin(22),
42
+ lgblock(0),
43
+ enable_dictionary(true),
44
+ enable_transforms(false),
45
+ greedy_block_split(false),
46
+ enable_context_modeling(true) {}
47
+
48
+ enum Mode {
49
+ // Default compression mode. The compressor does not know anything in
50
+ // advance about the properties of the input.
51
+ MODE_GENERIC = 0,
52
+ // Compression mode for UTF-8 format text input.
53
+ MODE_TEXT = 1,
54
+ // Compression mode used in WOFF 2.0.
55
+ MODE_FONT = 2,
56
+ };
57
+ Mode mode;
58
+
59
+ // Controls the compression-speed vs compression-density tradeoffs. The higher
60
+ // the quality, the slower the compression. Range is 0 to 11.
61
+ int quality;
62
+ // Base 2 logarithm of the sliding window size. Range is 10 to 24.
63
+ int lgwin;
64
+ // Base 2 logarithm of the maximum input block size. Range is 16 to 24.
65
+ // If set to 0, the value will be set based on the quality.
66
+ int lgblock;
67
+
68
+ // These settings are deprecated and will be ignored.
69
+ // All speed vs. size compromises are controlled by the quality param.
70
+ bool enable_dictionary;
71
+ bool enable_transforms;
72
+ bool greedy_block_split;
73
+ bool enable_context_modeling;
74
+ };
75
+
76
+ // An instance can not be reused for multiple brotli streams.
77
+ class BrotliCompressor {
78
+ public:
79
+ explicit BrotliCompressor(BrotliParams params);
80
+ ~BrotliCompressor();
81
+
82
+ // The maximum input size that can be processed at once.
83
+ size_t input_block_size() const { return 1 << params_.lgblock; }
84
+
85
+ // Encodes the data in input_buffer as a meta-block and writes it to
86
+ // encoded_buffer (*encoded_size should be set to the size of
87
+ // encoded_buffer) and sets *encoded_size to the number of bytes that
88
+ // was written. Returns 0 if there was an error and 1 otherwise.
89
+ bool WriteMetaBlock(const size_t input_size,
90
+ const uint8_t* input_buffer,
91
+ const bool is_last,
92
+ size_t* encoded_size,
93
+ uint8_t* encoded_buffer);
94
+
95
+ // Writes a metadata meta-block containing the given input to encoded_buffer.
96
+ // *encoded_size should be set to the size of the encoded_buffer.
97
+ // Sets *encoded_size to the number of bytes that was written.
98
+ // Note that the given input data will not be part of the sliding window and
99
+ // thus no backward references can be made to this data from subsequent
100
+ // metablocks.
101
+ bool WriteMetadata(const size_t input_size,
102
+ const uint8_t* input_buffer,
103
+ const bool is_last,
104
+ size_t* encoded_size,
105
+ uint8_t* encoded_buffer);
106
+
107
+ // Writes a zero-length meta-block with end-of-input bit set to the
108
+ // internal output buffer and copies the output buffer to encoded_buffer
109
+ // (*encoded_size should be set to the size of encoded_buffer) and sets
110
+ // *encoded_size to the number of bytes written. Returns false if there was
111
+ // an error and true otherwise.
112
+ bool FinishStream(size_t* encoded_size, uint8_t* encoded_buffer);
113
+
114
+ // Copies the given input data to the internal ring buffer of the compressor.
115
+ // No processing of the data occurs at this time and this function can be
116
+ // called multiple times before calling WriteBrotliData() to process the
117
+ // accumulated input. At most input_block_size() bytes of input data can be
118
+ // copied to the ring buffer, otherwise the next WriteBrotliData() will fail.
119
+ void CopyInputToRingBuffer(const size_t input_size,
120
+ const uint8_t* input_buffer);
121
+
122
+ // Processes the accumulated input data and sets *out_size to the length of
123
+ // the new output meta-block, or to zero if no new output meta-block was
124
+ // created (in this case the processed input data is buffered internally).
125
+ // If *out_size is positive, *output points to the start of the output data.
126
+ // Returns false if the size of the input data is larger than
127
+ // input_block_size() or if there was an error during writing the output.
128
+ // If is_last or force_flush is true, an output meta-block is always created.
129
+ bool WriteBrotliData(const bool is_last, const bool force_flush,
130
+ size_t* out_size, uint8_t** output);
131
+
132
+ // Fills the new state with a dictionary for LZ77, warming up the ringbuffer,
133
+ // e.g. for custom static dictionaries for data formats.
134
+ // Not to be confused with the built-in transformable dictionary of Brotli.
135
+ // To decode, use BrotliSetCustomDictionary of the decoder with the same
136
+ // dictionary.
137
+ void BrotliSetCustomDictionary(size_t size, const uint8_t* dict);
138
+
139
+ // No-op, but we keep it here for API backward-compatibility.
140
+ void WriteStreamHeader() {}
141
+
142
+ private:
143
+ uint8_t* GetBrotliStorage(size_t size);
144
+
145
+ bool WriteMetaBlockInternal(const bool is_last,
146
+ const bool utf8_mode,
147
+ size_t* out_size,
148
+ uint8_t** output);
149
+
150
+ BrotliParams params_;
151
+ int max_backward_distance_;
152
+ std::unique_ptr<Hashers> hashers_;
153
+ int hash_type_;
154
+ size_t input_pos_;
155
+ std::unique_ptr<RingBuffer> ringbuffer_;
156
+ std::unique_ptr<float[]> literal_cost_;
157
+ size_t literal_cost_mask_;
158
+ size_t cmd_buffer_size_;
159
+ std::unique_ptr<Command[]> commands_;
160
+ int num_commands_;
161
+ int num_literals_;
162
+ int last_insert_len_;
163
+ size_t last_flush_pos_;
164
+ size_t last_processed_pos_;
165
+ int dist_cache_[4];
166
+ int saved_dist_cache_[4];
167
+ uint8_t last_byte_;
168
+ uint8_t last_byte_bits_;
169
+ uint8_t prev_byte_;
170
+ uint8_t prev_byte2_;
171
+ int storage_size_;
172
+ std::unique_ptr<uint8_t[]> storage_;
173
+ };
174
+
175
+ // Compresses the data in input_buffer into encoded_buffer, and sets
176
+ // *encoded_size to the compressed length.
177
+ // Returns 0 if there was an error and 1 otherwise.
178
+ int BrotliCompressBuffer(BrotliParams params,
179
+ size_t input_size,
180
+ const uint8_t* input_buffer,
181
+ size_t* encoded_size,
182
+ uint8_t* encoded_buffer);
183
+
184
+ // Same as above, but uses the specified input and output classes instead
185
+ // of reading from and writing to pre-allocated memory buffers.
186
+ int BrotliCompress(BrotliParams params, BrotliIn* in, BrotliOut* out);
187
+
188
+ // Before compressing the data, sets a custom LZ77 dictionary with
189
+ // BrotliCompressor::BrotliSetCustomDictionary.
190
+ int BrotliCompressWithCustomDictionary(size_t dictsize, const uint8_t* dict,
191
+ BrotliParams params,
192
+ BrotliIn* in, BrotliOut* out);
193
+
194
+ } // namespace brotli
195
+
196
+ #endif // BROTLI_ENC_ENCODE_H_
@@ -0,0 +1,354 @@
1
+ // Copyright 2013 Google Inc. All Rights Reserved.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ //
15
+ // Implementation of parallel Brotli compressor.
16
+
17
+ #include "./encode_parallel.h"
18
+
19
+ #include <algorithm>
20
+ #include <limits>
21
+
22
+ #include "./backward_references.h"
23
+ #include "./bit_cost.h"
24
+ #include "./block_splitter.h"
25
+ #include "./brotli_bit_stream.h"
26
+ #include "./cluster.h"
27
+ #include "./context.h"
28
+ #include "./metablock.h"
29
+ #include "./transform.h"
30
+ #include "./entropy_encode.h"
31
+ #include "./fast_log.h"
32
+ #include "./hash.h"
33
+ #include "./histogram.h"
34
+ #include "./literal_cost.h"
35
+ #include "./prefix.h"
36
+ #include "./write_bits.h"
37
+
38
+ namespace brotli {
39
+
40
+ namespace {
41
+
42
+ int ParseAsUTF8(int* symbol, const uint8_t* input, int size) {
43
+ // ASCII
44
+ if ((input[0] & 0x80) == 0) {
45
+ *symbol = input[0];
46
+ if (*symbol > 0) {
47
+ return 1;
48
+ }
49
+ }
50
+ // 2-byte UTF8
51
+ if (size > 1 &&
52
+ (input[0] & 0xe0) == 0xc0 &&
53
+ (input[1] & 0xc0) == 0x80) {
54
+ *symbol = (((input[0] & 0x1f) << 6) |
55
+ (input[1] & 0x3f));
56
+ if (*symbol > 0x7f) {
57
+ return 2;
58
+ }
59
+ }
60
+ // 3-byte UFT8
61
+ if (size > 2 &&
62
+ (input[0] & 0xf0) == 0xe0 &&
63
+ (input[1] & 0xc0) == 0x80 &&
64
+ (input[2] & 0xc0) == 0x80) {
65
+ *symbol = (((input[0] & 0x0f) << 12) |
66
+ ((input[1] & 0x3f) << 6) |
67
+ (input[2] & 0x3f));
68
+ if (*symbol > 0x7ff) {
69
+ return 3;
70
+ }
71
+ }
72
+ // 4-byte UFT8
73
+ if (size > 3 &&
74
+ (input[0] & 0xf8) == 0xf0 &&
75
+ (input[1] & 0xc0) == 0x80 &&
76
+ (input[2] & 0xc0) == 0x80 &&
77
+ (input[3] & 0xc0) == 0x80) {
78
+ *symbol = (((input[0] & 0x07) << 18) |
79
+ ((input[1] & 0x3f) << 12) |
80
+ ((input[2] & 0x3f) << 6) |
81
+ (input[3] & 0x3f));
82
+ if (*symbol > 0xffff && *symbol <= 0x10ffff) {
83
+ return 4;
84
+ }
85
+ }
86
+ // Not UTF8, emit a special symbol above the UTF8-code space
87
+ *symbol = 0x110000 | input[0];
88
+ return 1;
89
+ }
90
+
91
+ // Returns true if at least min_fraction of the data is UTF8-encoded.
92
+ bool IsMostlyUTF8(const uint8_t* data, size_t length, double min_fraction) {
93
+ size_t size_utf8 = 0;
94
+ for (size_t pos = 0; pos < length; ) {
95
+ int symbol;
96
+ int bytes_read = ParseAsUTF8(&symbol, data + pos, length - pos);
97
+ pos += bytes_read;
98
+ if (symbol < 0x110000) size_utf8 += bytes_read;
99
+ }
100
+ return size_utf8 > min_fraction * length;
101
+ }
102
+
103
+ void RecomputeDistancePrefixes(std::vector<Command>* cmds,
104
+ int num_direct_distance_codes,
105
+ int distance_postfix_bits) {
106
+ if (num_direct_distance_codes == 0 &&
107
+ distance_postfix_bits == 0) {
108
+ return;
109
+ }
110
+ for (int i = 0; i < cmds->size(); ++i) {
111
+ Command* cmd = &(*cmds)[i];
112
+ if (cmd->copy_len_ > 0 && cmd->cmd_prefix_ >= 128) {
113
+ PrefixEncodeCopyDistance(cmd->DistanceCode(),
114
+ num_direct_distance_codes,
115
+ distance_postfix_bits,
116
+ &cmd->dist_prefix_,
117
+ &cmd->dist_extra_);
118
+ }
119
+ }
120
+ }
121
+
122
+ bool WriteMetaBlockParallel(const BrotliParams& params,
123
+ const size_t block_size,
124
+ const uint8_t* input_buffer,
125
+ const size_t prefix_size,
126
+ const uint8_t* prefix_buffer,
127
+ const bool is_first,
128
+ const bool is_last,
129
+ size_t* encoded_size,
130
+ uint8_t* encoded_buffer) {
131
+ if (block_size == 0) {
132
+ return false;
133
+ }
134
+ const size_t input_size = block_size;
135
+
136
+ // Copy prefix + next input block into a continuous area.
137
+ size_t input_pos = prefix_size;
138
+ // CreateBackwardReferences reads up to 3 bytes past the end of input if the
139
+ // mask points past the end of input.
140
+ // FindMatchLengthWithLimit could do another 8 bytes look-forward.
141
+ std::vector<uint8_t> input(prefix_size + input_size + 4 + 8);
142
+ memcpy(&input[0], prefix_buffer, prefix_size);
143
+ memcpy(&input[input_pos], input_buffer, input_size);
144
+ // Since we don't have a ringbuffer, masking is a no-op.
145
+ // We use one less bit than the full range because some of the code uses
146
+ // mask + 1 as the size of the ringbuffer.
147
+ const size_t mask = std::numeric_limits<size_t>::max() >> 1;
148
+
149
+ uint8_t prev_byte = input_pos > 0 ? input[(input_pos - 1) & mask] : 0;
150
+ uint8_t prev_byte2 = input_pos > 1 ? input[(input_pos - 2) & mask] : 0;
151
+
152
+ // Decide about UTF8 mode.
153
+ static const double kMinUTF8Ratio = 0.75;
154
+ bool utf8_mode = IsMostlyUTF8(&input[input_pos], input_size, kMinUTF8Ratio);
155
+
156
+ // Compute literal costs. The 4 bytes at the end are there to cover for an
157
+ // over-read past the end of input, but not past the mask, in
158
+ // CreateBackwardReferences.
159
+ std::vector<float> literal_cost(prefix_size + input_size + 4);
160
+ if (utf8_mode) {
161
+ EstimateBitCostsForLiteralsUTF8(input_pos, input_size, mask, mask,
162
+ &input[0], &literal_cost[0]);
163
+ } else {
164
+ EstimateBitCostsForLiterals(input_pos, input_size, mask, mask,
165
+ &input[0], &literal_cost[0]);
166
+ }
167
+
168
+ // Initialize hashers.
169
+ int hash_type = std::min(9, params.quality);
170
+ std::unique_ptr<Hashers> hashers(new Hashers());
171
+ hashers->Init(hash_type);
172
+
173
+ // Compute backward references.
174
+ int last_insert_len = 0;
175
+ int num_commands = 0;
176
+ int num_literals = 0;
177
+ int max_backward_distance = (1 << params.lgwin) - 16;
178
+ int dist_cache[4] = { -4, -4, -4, -4 };
179
+ std::vector<Command> commands((input_size + 1) >> 1);
180
+ CreateBackwardReferences(
181
+ input_size, input_pos,
182
+ &input[0], mask,
183
+ &literal_cost[0], mask,
184
+ max_backward_distance,
185
+ params.quality,
186
+ hashers.get(),
187
+ hash_type,
188
+ dist_cache,
189
+ &last_insert_len,
190
+ &commands[0],
191
+ &num_commands,
192
+ &num_literals);
193
+ commands.resize(num_commands);
194
+ if (last_insert_len > 0) {
195
+ commands.push_back(Command(last_insert_len));
196
+ num_literals += last_insert_len;
197
+ }
198
+
199
+ // Build the meta-block.
200
+ MetaBlockSplit mb;
201
+ int num_direct_distance_codes =
202
+ params.mode == BrotliParams::MODE_FONT ? 12 : 0;
203
+ int distance_postfix_bits = params.mode == BrotliParams::MODE_FONT ? 1 : 0;
204
+ int literal_context_mode = utf8_mode ? CONTEXT_UTF8 : CONTEXT_SIGNED;
205
+ RecomputeDistancePrefixes(&commands,
206
+ num_direct_distance_codes,
207
+ distance_postfix_bits);
208
+ if (params.quality <= 9) {
209
+ BuildMetaBlockGreedy(&input[0], input_pos, mask,
210
+ commands.data(), commands.size(),
211
+ &mb);
212
+ } else {
213
+ BuildMetaBlock(&input[0], input_pos, mask,
214
+ prev_byte, prev_byte2,
215
+ commands.data(), commands.size(),
216
+ literal_context_mode,
217
+ &mb);
218
+ }
219
+
220
+ // Set up the temporary output storage.
221
+ const size_t max_out_size = 2 * input_size + 500;
222
+ std::vector<uint8_t> storage(max_out_size);
223
+ int first_byte = 0;
224
+ int first_byte_bits = 0;
225
+ if (is_first) {
226
+ if (params.lgwin == 16) {
227
+ first_byte = 0;
228
+ first_byte_bits = 1;
229
+ } else if (params.lgwin == 17) {
230
+ first_byte = 1;
231
+ first_byte_bits = 7;
232
+ } else {
233
+ first_byte = ((params.lgwin - 17) << 1) | 1;
234
+ first_byte_bits = 4;
235
+ }
236
+ }
237
+ storage[0] = first_byte;
238
+ int storage_ix = first_byte_bits;
239
+
240
+ // Store the meta-block to the temporary output.
241
+ if (!StoreMetaBlock(&input[0], input_pos, input_size, mask,
242
+ prev_byte, prev_byte2,
243
+ is_last,
244
+ num_direct_distance_codes,
245
+ distance_postfix_bits,
246
+ literal_context_mode,
247
+ commands.data(), commands.size(),
248
+ mb,
249
+ &storage_ix, &storage[0])) {
250
+ return false;
251
+ }
252
+
253
+ // If this is not the last meta-block, store an empty metadata
254
+ // meta-block so that the meta-block will end at a byte boundary.
255
+ if (!is_last) {
256
+ StoreSyncMetaBlock(&storage_ix, &storage[0]);
257
+ }
258
+
259
+ // If the compressed data is too large, fall back to an uncompressed
260
+ // meta-block.
261
+ size_t output_size = storage_ix >> 3;
262
+ if (input_size + 4 < output_size) {
263
+ storage[0] = first_byte;
264
+ storage_ix = first_byte_bits;
265
+ if (!StoreUncompressedMetaBlock(is_last, &input[0], input_pos, mask,
266
+ input_size,
267
+ &storage_ix, &storage[0])) {
268
+ return false;
269
+ }
270
+ output_size = storage_ix >> 3;
271
+ }
272
+
273
+ // Copy the temporary output with size-check to the output.
274
+ if (output_size > *encoded_size) {
275
+ return false;
276
+ }
277
+ memcpy(encoded_buffer, &storage[0], output_size);
278
+ *encoded_size = output_size;
279
+ return true;
280
+ }
281
+
282
+ } // namespace
283
+
284
+ int BrotliCompressBufferParallel(BrotliParams params,
285
+ size_t input_size,
286
+ const uint8_t* input_buffer,
287
+ size_t* encoded_size,
288
+ uint8_t* encoded_buffer) {
289
+ if (*encoded_size == 0) {
290
+ // Output buffer needs at least one byte.
291
+ return 0;
292
+ } else if (input_size == 0) {
293
+ encoded_buffer[0] = 6;
294
+ *encoded_size = 1;
295
+ return 1;
296
+ }
297
+
298
+ // Sanitize params.
299
+ if (params.lgwin < kMinWindowBits) {
300
+ params.lgwin = kMinWindowBits;
301
+ } else if (params.lgwin > kMaxWindowBits) {
302
+ params.lgwin = kMaxWindowBits;
303
+ }
304
+ if (params.lgblock == 0) {
305
+ params.lgblock = 16;
306
+ if (params.quality >= 9 && params.lgwin > params.lgblock) {
307
+ params.lgblock = std::min(21, params.lgwin);
308
+ }
309
+ } else if (params.lgblock < kMinInputBlockBits) {
310
+ params.lgblock = kMinInputBlockBits;
311
+ } else if (params.lgblock > kMaxInputBlockBits) {
312
+ params.lgblock = kMaxInputBlockBits;
313
+ }
314
+ size_t max_input_block_size = 1 << params.lgblock;
315
+
316
+ std::vector<std::vector<uint8_t> > compressed_pieces;
317
+
318
+ // Compress block-by-block independently.
319
+ for (size_t pos = 0; pos < input_size; ) {
320
+ size_t input_block_size = std::min(max_input_block_size, input_size - pos);
321
+ size_t out_size = 1.2 * input_block_size + 1024;
322
+ std::vector<uint8_t> out(out_size);
323
+ if (!WriteMetaBlockParallel(params,
324
+ input_block_size,
325
+ &input_buffer[pos],
326
+ pos,
327
+ input_buffer,
328
+ pos == 0,
329
+ pos + input_block_size == input_size,
330
+ &out_size,
331
+ &out[0])) {
332
+ return false;
333
+ }
334
+ out.resize(out_size);
335
+ compressed_pieces.push_back(out);
336
+ pos += input_block_size;
337
+ }
338
+
339
+ // Piece together the output.
340
+ size_t out_pos = 0;
341
+ for (int i = 0; i < compressed_pieces.size(); ++i) {
342
+ const std::vector<uint8_t>& out = compressed_pieces[i];
343
+ if (out_pos + out.size() > *encoded_size) {
344
+ return false;
345
+ }
346
+ memcpy(&encoded_buffer[out_pos], &out[0], out.size());
347
+ out_pos += out.size();
348
+ }
349
+ *encoded_size = out_pos;
350
+
351
+ return true;
352
+ }
353
+
354
+ } // namespace brotli