extbrotli 0.0.1.PROTOTYPE
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.
- checksums.yaml +7 -0
- data/LICENSE +28 -0
- data/README.md +67 -0
- data/Rakefile +158 -0
- data/contrib/brotli/LICENSE +202 -0
- data/contrib/brotli/README.md +18 -0
- data/contrib/brotli/dec/bit_reader.c +55 -0
- data/contrib/brotli/dec/bit_reader.h +256 -0
- data/contrib/brotli/dec/context.h +260 -0
- data/contrib/brotli/dec/decode.c +1573 -0
- data/contrib/brotli/dec/decode.h +160 -0
- data/contrib/brotli/dec/dictionary.h +9494 -0
- data/contrib/brotli/dec/huffman.c +325 -0
- data/contrib/brotli/dec/huffman.h +77 -0
- data/contrib/brotli/dec/port.h +148 -0
- data/contrib/brotli/dec/prefix.h +756 -0
- data/contrib/brotli/dec/state.c +149 -0
- data/contrib/brotli/dec/state.h +185 -0
- data/contrib/brotli/dec/streams.c +99 -0
- data/contrib/brotli/dec/streams.h +100 -0
- data/contrib/brotli/dec/transform.h +315 -0
- data/contrib/brotli/dec/types.h +36 -0
- data/contrib/brotli/enc/backward_references.cc +769 -0
- data/contrib/brotli/enc/backward_references.h +50 -0
- data/contrib/brotli/enc/bit_cost.h +147 -0
- data/contrib/brotli/enc/block_splitter.cc +418 -0
- data/contrib/brotli/enc/block_splitter.h +78 -0
- data/contrib/brotli/enc/brotli_bit_stream.cc +884 -0
- data/contrib/brotli/enc/brotli_bit_stream.h +149 -0
- data/contrib/brotli/enc/cluster.h +290 -0
- data/contrib/brotli/enc/command.h +140 -0
- data/contrib/brotli/enc/context.h +185 -0
- data/contrib/brotli/enc/dictionary.h +9485 -0
- data/contrib/brotli/enc/dictionary_hash.h +4125 -0
- data/contrib/brotli/enc/encode.cc +715 -0
- data/contrib/brotli/enc/encode.h +196 -0
- data/contrib/brotli/enc/encode_parallel.cc +354 -0
- data/contrib/brotli/enc/encode_parallel.h +37 -0
- data/contrib/brotli/enc/entropy_encode.cc +492 -0
- data/contrib/brotli/enc/entropy_encode.h +88 -0
- data/contrib/brotli/enc/fast_log.h +179 -0
- data/contrib/brotli/enc/find_match_length.h +87 -0
- data/contrib/brotli/enc/hash.h +686 -0
- data/contrib/brotli/enc/histogram.cc +76 -0
- data/contrib/brotli/enc/histogram.h +100 -0
- data/contrib/brotli/enc/literal_cost.cc +172 -0
- data/contrib/brotli/enc/literal_cost.h +38 -0
- data/contrib/brotli/enc/metablock.cc +544 -0
- data/contrib/brotli/enc/metablock.h +88 -0
- data/contrib/brotli/enc/port.h +151 -0
- data/contrib/brotli/enc/prefix.h +85 -0
- data/contrib/brotli/enc/ringbuffer.h +108 -0
- data/contrib/brotli/enc/static_dict.cc +441 -0
- data/contrib/brotli/enc/static_dict.h +40 -0
- data/contrib/brotli/enc/static_dict_lut.h +12063 -0
- data/contrib/brotli/enc/streams.cc +127 -0
- data/contrib/brotli/enc/streams.h +129 -0
- data/contrib/brotli/enc/transform.h +250 -0
- data/contrib/brotli/enc/write_bits.h +91 -0
- data/ext/extbrotli.cc +24 -0
- data/ext/extbrotli.h +73 -0
- data/ext/extconf.rb +35 -0
- data/ext/lldecoder.c +220 -0
- data/ext/llencoder.cc +433 -0
- data/gemstub.rb +21 -0
- data/lib/extbrotli.rb +243 -0
- data/lib/extbrotli/version.rb +3 -0
- metadata +140 -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
|