brotli 0.7.0 → 0.9.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.
- checksums.yaml +4 -4
- data/README.md +113 -1
- data/ext/brotli/brotli.c +908 -288
- data/ext/brotli/brotli.h +0 -5
- data/ext/brotli/buffer.c +43 -65
- data/ext/brotli/buffer.h +6 -9
- data/ext/brotli/extconf.rb +115 -50
- data/lib/brotli/reader.rb +167 -0
- data/lib/brotli/version.rb +1 -1
- data/lib/brotli/writer.rb +81 -0
- data/lib/brotli.rb +2 -0
- data/vendor/brotli/c/common/constants.c +7 -7
- data/vendor/brotli/c/common/constants.h +2 -5
- data/vendor/brotli/c/common/context.c +2 -2
- data/vendor/brotli/c/common/context.h +1 -2
- data/vendor/brotli/c/common/dictionary.c +4 -5856
- data/vendor/brotli/c/common/dictionary.h +1 -2
- data/vendor/brotli/c/common/dictionary_inc.h +5847 -0
- data/vendor/brotli/c/common/platform.c +0 -4
- data/vendor/brotli/c/common/platform.h +182 -43
- data/vendor/brotli/c/common/shared_dictionary.c +3 -7
- data/vendor/brotli/c/common/shared_dictionary_internal.h +1 -1
- data/vendor/brotli/c/common/static_init.h +56 -0
- data/vendor/brotli/c/common/transform.c +6 -4
- data/vendor/brotli/c/common/transform.h +1 -2
- data/vendor/brotli/c/common/version.h +3 -3
- data/vendor/brotli/c/dec/bit_reader.c +2 -3
- data/vendor/brotli/c/dec/bit_reader.h +0 -4
- data/vendor/brotli/c/dec/decode.c +128 -39
- data/vendor/brotli/c/dec/huffman.c +2 -5
- data/vendor/brotli/c/dec/huffman.h +0 -2
- data/vendor/brotli/c/dec/prefix.c +67 -0
- data/vendor/brotli/c/dec/prefix.h +18 -708
- data/vendor/brotli/c/dec/prefix_inc.h +707 -0
- data/vendor/brotli/c/dec/state.c +18 -15
- data/vendor/brotli/c/dec/state.h +2 -6
- data/vendor/brotli/c/dec/static_init.c +53 -0
- data/vendor/brotli/c/dec/static_init.h +30 -0
- data/vendor/brotli/c/enc/backward_references.c +32 -8
- data/vendor/brotli/c/enc/backward_references.h +1 -5
- data/vendor/brotli/c/enc/backward_references_hq.c +15 -15
- data/vendor/brotli/c/enc/backward_references_hq.h +1 -5
- data/vendor/brotli/c/enc/bit_cost.c +28 -4
- data/vendor/brotli/c/enc/bit_cost.h +8 -40
- data/vendor/brotli/c/enc/bit_cost_inc.h +1 -1
- data/vendor/brotli/c/enc/block_splitter.c +9 -12
- data/vendor/brotli/c/enc/block_splitter.h +0 -3
- data/vendor/brotli/c/enc/block_splitter_inc.h +14 -8
- data/vendor/brotli/c/enc/brotli_bit_stream.c +10 -9
- data/vendor/brotli/c/enc/brotli_bit_stream.h +0 -6
- data/vendor/brotli/c/enc/cluster.c +0 -2
- data/vendor/brotli/c/enc/cluster.h +0 -2
- data/vendor/brotli/c/enc/command.c +1 -1
- data/vendor/brotli/c/enc/command.h +8 -10
- data/vendor/brotli/c/enc/compound_dictionary.c +3 -5
- data/vendor/brotli/c/enc/compound_dictionary.h +1 -4
- data/vendor/brotli/c/enc/compress_fragment.c +3 -13
- data/vendor/brotli/c/enc/compress_fragment.h +0 -2
- data/vendor/brotli/c/enc/compress_fragment_two_pass.c +5 -15
- data/vendor/brotli/c/enc/compress_fragment_two_pass.h +0 -2
- data/vendor/brotli/c/enc/dictionary_hash.c +127 -1830
- data/vendor/brotli/c/enc/dictionary_hash.h +23 -3
- data/vendor/brotli/c/enc/dictionary_hash_inc.h +1829 -0
- data/vendor/brotli/c/enc/encode.c +77 -52
- data/vendor/brotli/c/enc/encoder_dict.c +9 -7
- data/vendor/brotli/c/enc/encoder_dict.h +2 -4
- data/vendor/brotli/c/enc/entropy_encode.c +3 -6
- data/vendor/brotli/c/enc/entropy_encode.h +2 -4
- data/vendor/brotli/c/enc/entropy_encode_static.h +18 -12
- data/vendor/brotli/c/enc/fast_log.c +1 -1
- data/vendor/brotli/c/enc/fast_log.h +2 -3
- data/vendor/brotli/c/enc/find_match_length.h +0 -2
- data/vendor/brotli/c/enc/hash.h +38 -31
- data/vendor/brotli/c/enc/hash_base.h +38 -0
- data/vendor/brotli/c/enc/hash_forgetful_chain_inc.h +11 -1
- data/vendor/brotli/c/enc/hash_longest_match64_inc.h +24 -7
- data/vendor/brotli/c/enc/hash_longest_match64_simd_inc.h +304 -0
- data/vendor/brotli/c/enc/hash_longest_match_inc.h +30 -11
- data/vendor/brotli/c/enc/hash_longest_match_quickly_inc.h +4 -0
- data/vendor/brotli/c/enc/hash_longest_match_simd_inc.h +278 -0
- data/vendor/brotli/c/enc/histogram.c +1 -0
- data/vendor/brotli/c/enc/histogram.h +0 -4
- data/vendor/brotli/c/enc/literal_cost.c +4 -6
- data/vendor/brotli/c/enc/literal_cost.h +0 -2
- data/vendor/brotli/c/enc/matching_tag_mask.h +69 -0
- data/vendor/brotli/c/enc/memory.c +0 -5
- data/vendor/brotli/c/enc/memory.h +0 -4
- data/vendor/brotli/c/enc/metablock.c +7 -9
- data/vendor/brotli/c/enc/metablock.h +3 -3
- data/vendor/brotli/c/enc/metablock_inc.h +4 -4
- data/vendor/brotli/c/enc/params.h +0 -1
- data/vendor/brotli/c/enc/prefix.h +0 -2
- data/vendor/brotli/c/enc/quality.h +17 -10
- data/vendor/brotli/c/enc/ringbuffer.h +1 -4
- data/vendor/brotli/c/enc/state.h +2 -2
- data/vendor/brotli/c/enc/static_dict.c +5 -11
- data/vendor/brotli/c/enc/static_dict.h +1 -3
- data/vendor/brotli/c/enc/static_dict_lut.c +224 -0
- data/vendor/brotli/c/enc/static_dict_lut.h +20 -5837
- data/vendor/brotli/c/enc/static_dict_lut_inc.h +5830 -0
- data/vendor/brotli/c/enc/static_init.c +59 -0
- data/vendor/brotli/c/enc/static_init.h +30 -0
- data/vendor/brotli/c/enc/utf8_util.c +1 -1
- data/vendor/brotli/c/enc/utf8_util.h +0 -2
- data/vendor/brotli/c/enc/write_bits.h +0 -2
- data/vendor/brotli/c/include/brotli/decode.h +1 -1
- data/vendor/brotli/c/include/brotli/encode.h +5 -1
- data/vendor/brotli/c/include/brotli/port.h +4 -7
- data/vendor/brotli/c/include/brotli/types.h +2 -2
- metadata +24 -28
- data/.github/workflows/main.yml +0 -37
- data/.github/workflows/publish.yml +0 -24
- data/.gitignore +0 -18
- data/.gitmodules +0 -3
- data/.rspec +0 -2
- data/Dockerfile +0 -38
- data/Gemfile +0 -10
- data/Rakefile +0 -42
- data/bin/before_install.sh +0 -9
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/brotli.gemspec +0 -27
- data/smoke.sh +0 -8
- data/test/brotli_test.rb +0 -183
- data/test/brotli_writer_test.rb +0 -93
- data/test/test_helper.rb +0 -9
- data/vendor/brotli/c/common/dictionary.bin +0 -432
- data/vendor/brotli/c/common/dictionary.bin.br +0 -0
data/ext/brotli/brotli.c
CHANGED
|
@@ -1,21 +1,65 @@
|
|
|
1
1
|
#include "brotli.h"
|
|
2
2
|
|
|
3
|
-
#define CSTR2SYM(x) ID2SYM(rb_intern(x))
|
|
4
|
-
|
|
5
3
|
static VALUE rb_eBrotli;
|
|
4
|
+
static ID id_cmp;
|
|
5
|
+
static ID id_dictionary;
|
|
6
|
+
static ID id_font;
|
|
7
|
+
static ID id_generic;
|
|
8
|
+
static ID id_lgblock;
|
|
9
|
+
static ID id_lgwin;
|
|
10
|
+
static ID id_mode;
|
|
11
|
+
static ID id_output_buffer_limit;
|
|
12
|
+
static ID id_quality;
|
|
13
|
+
static ID id_read;
|
|
14
|
+
static ID id_text;
|
|
6
15
|
|
|
7
16
|
static inline void*
|
|
8
17
|
brotli_alloc(void* opaque, size_t size)
|
|
9
18
|
{
|
|
19
|
+
(void)opaque;
|
|
10
20
|
return ruby_xmalloc(size);
|
|
11
21
|
}
|
|
12
22
|
|
|
13
23
|
static inline void
|
|
14
24
|
brotli_free(void* opaque, void* address)
|
|
15
25
|
{
|
|
16
|
-
|
|
17
|
-
|
|
26
|
+
(void)opaque;
|
|
27
|
+
ruby_xfree(address);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static VALUE
|
|
31
|
+
brotli_hash_lookup(VALUE hash, ID key)
|
|
32
|
+
{
|
|
33
|
+
if (NIL_P(hash)) {
|
|
34
|
+
return Qnil;
|
|
18
35
|
}
|
|
36
|
+
|
|
37
|
+
Check_Type(hash, T_HASH);
|
|
38
|
+
return rb_hash_lookup(hash, ID2SYM(key));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static BrotliEncoderState*
|
|
42
|
+
brotli_encoder_state_create(void)
|
|
43
|
+
{
|
|
44
|
+
BrotliEncoderState* state = BrotliEncoderCreateInstance(brotli_alloc, brotli_free, NULL);
|
|
45
|
+
|
|
46
|
+
if (!state) {
|
|
47
|
+
rb_raise(rb_eNoMemError, "BrotliEncoderCreateInstance failed");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return state;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
static BrotliDecoderState*
|
|
54
|
+
brotli_decoder_state_create(void)
|
|
55
|
+
{
|
|
56
|
+
BrotliDecoderState* state = BrotliDecoderCreateInstance(brotli_alloc, brotli_free, NULL);
|
|
57
|
+
|
|
58
|
+
if (!state) {
|
|
59
|
+
rb_raise(rb_eNoMemError, "BrotliDecoderCreateInstance failed");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return state;
|
|
19
63
|
}
|
|
20
64
|
|
|
21
65
|
/*******************************************************************************
|
|
@@ -32,6 +76,17 @@ typedef struct {
|
|
|
32
76
|
size_t dict_len;
|
|
33
77
|
} brotli_inflate_args_t;
|
|
34
78
|
|
|
79
|
+
static void
|
|
80
|
+
brotli_inflate_cleanup(brotli_inflate_args_t* args)
|
|
81
|
+
{
|
|
82
|
+
delete_buffer(args->buffer);
|
|
83
|
+
args->buffer = NULL;
|
|
84
|
+
if (args->s) {
|
|
85
|
+
BrotliDecoderDestroyInstance(args->s);
|
|
86
|
+
args->s = NULL;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
35
90
|
static void*
|
|
36
91
|
brotli_inflate_no_gvl(void *arg)
|
|
37
92
|
{
|
|
@@ -46,13 +101,11 @@ brotli_inflate_no_gvl(void *arg)
|
|
|
46
101
|
buffer_t* buffer = args->buffer;
|
|
47
102
|
BrotliDecoderState* s = args->s;
|
|
48
103
|
|
|
49
|
-
#ifdef HAVE_BROTLIDECODERATTACHDICTIONARY
|
|
50
104
|
/* Attach dictionary if provided */
|
|
51
105
|
if (args->dict && args->dict_len > 0) {
|
|
52
106
|
BrotliDecoderAttachDictionary(s, BROTLI_SHARED_DICTIONARY_RAW,
|
|
53
107
|
args->dict_len, args->dict);
|
|
54
108
|
}
|
|
55
|
-
#endif
|
|
56
109
|
|
|
57
110
|
for (;;) {
|
|
58
111
|
r = BrotliDecoderDecompressStream(s,
|
|
@@ -78,73 +131,74 @@ brotli_inflate_no_gvl(void *arg)
|
|
|
78
131
|
return arg;
|
|
79
132
|
}
|
|
80
133
|
|
|
81
|
-
static
|
|
134
|
+
static VALUE
|
|
135
|
+
brotli_inflate_take_result(VALUE arg)
|
|
136
|
+
{
|
|
137
|
+
brotli_inflate_args_t *args = (brotli_inflate_args_t *)arg;
|
|
138
|
+
return rb_str_new(args->buffer->ptr, args->buffer->used);
|
|
139
|
+
}
|
|
82
140
|
|
|
83
141
|
static VALUE
|
|
84
142
|
brotli_inflate(int argc, VALUE *argv, VALUE self)
|
|
85
143
|
{
|
|
86
|
-
VALUE str = Qnil
|
|
87
|
-
|
|
144
|
+
VALUE str = Qnil;
|
|
145
|
+
VALUE opts = Qnil;
|
|
146
|
+
VALUE value = Qnil;
|
|
147
|
+
VALUE dict = Qnil;
|
|
148
|
+
const char *error = NULL;
|
|
149
|
+
brotli_inflate_args_t args = {0};
|
|
150
|
+
|
|
151
|
+
(void)self;
|
|
88
152
|
|
|
89
153
|
rb_scan_args(argc, argv, "11", &str, &opts);
|
|
90
154
|
|
|
91
155
|
if (rb_respond_to(str, id_read)) {
|
|
92
|
-
|
|
156
|
+
str = rb_funcall(str, id_read, 0);
|
|
93
157
|
}
|
|
94
158
|
|
|
95
159
|
StringValue(str);
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
Check_Type(opts, T_HASH);
|
|
100
|
-
dict = rb_hash_aref(opts, CSTR2SYM("dictionary"));
|
|
160
|
+
dict = brotli_hash_lookup(opts, id_dictionary);
|
|
161
|
+
if (!NIL_P(dict)) {
|
|
162
|
+
StringValue(dict);
|
|
101
163
|
}
|
|
102
164
|
|
|
103
165
|
args.str = (uint8_t*)RSTRING_PTR(str);
|
|
104
166
|
args.len = (size_t)RSTRING_LEN(str);
|
|
167
|
+
args.s = brotli_decoder_state_create();
|
|
105
168
|
args.buffer = create_buffer(BUFSIZ);
|
|
106
|
-
args.s = BrotliDecoderCreateInstance(brotli_alloc,
|
|
107
|
-
brotli_free,
|
|
108
|
-
NULL);
|
|
109
169
|
args.r = BROTLI_DECODER_RESULT_ERROR;
|
|
110
170
|
|
|
111
|
-
/* Set dictionary parameters */
|
|
112
171
|
if (!NIL_P(dict)) {
|
|
113
|
-
#ifdef HAVE_BROTLIDECODERATTACHDICTIONARY
|
|
114
|
-
StringValue(dict);
|
|
115
172
|
args.dict = (uint8_t*)RSTRING_PTR(dict);
|
|
116
173
|
args.dict_len = (size_t)RSTRING_LEN(dict);
|
|
117
|
-
#else
|
|
118
|
-
rb_raise(rb_eBrotli, "Dictionary support not available in this build");
|
|
119
|
-
#endif
|
|
120
174
|
} else {
|
|
121
175
|
args.dict = NULL;
|
|
122
176
|
args.dict_len = 0;
|
|
123
177
|
}
|
|
124
178
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
#endif
|
|
179
|
+
rb_thread_call_without_gvl(brotli_inflate_no_gvl, &args, NULL, NULL);
|
|
180
|
+
RB_GC_GUARD(str);
|
|
181
|
+
RB_GC_GUARD(dict);
|
|
182
|
+
|
|
130
183
|
if (args.r == BROTLI_DECODER_RESULT_SUCCESS) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
184
|
+
int state = 0;
|
|
185
|
+
value = rb_protect(brotli_inflate_take_result, (VALUE)&args, &state);
|
|
186
|
+
if (state) {
|
|
187
|
+
brotli_inflate_cleanup(&args);
|
|
188
|
+
rb_jump_tag(state);
|
|
189
|
+
}
|
|
134
190
|
} else if (args.r == BROTLI_DECODER_RESULT_ERROR) {
|
|
135
|
-
|
|
136
|
-
delete_buffer(args.buffer);
|
|
137
|
-
BrotliDecoderDestroyInstance(args.s);
|
|
138
|
-
rb_raise(rb_eBrotli, "%s", error);
|
|
191
|
+
error = BrotliDecoderErrorString(BrotliDecoderGetErrorCode(args.s));
|
|
139
192
|
} else if (args.r == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
193
|
+
error = "Needs more input";
|
|
194
|
+
} else {
|
|
195
|
+
error = "Needs more output";
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
brotli_inflate_cleanup(&args);
|
|
199
|
+
|
|
200
|
+
if (error) {
|
|
201
|
+
rb_raise(rb_eBrotli, "%s", error);
|
|
148
202
|
}
|
|
149
203
|
|
|
150
204
|
return value;
|
|
@@ -154,81 +208,113 @@ brotli_inflate(int argc, VALUE *argv, VALUE self)
|
|
|
154
208
|
* deflate
|
|
155
209
|
******************************************************************************/
|
|
156
210
|
|
|
157
|
-
static
|
|
211
|
+
static const char *
|
|
158
212
|
brotli_deflate_set_mode(BrotliEncoderState* s, VALUE value)
|
|
159
213
|
{
|
|
160
214
|
if (NIL_P(value)) {
|
|
161
|
-
return;
|
|
215
|
+
return NULL;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (value == ID2SYM(id_generic)) {
|
|
219
|
+
BrotliEncoderSetParameter(s, BROTLI_PARAM_MODE, BROTLI_MODE_GENERIC);
|
|
220
|
+
} else if (value == ID2SYM(id_text)) {
|
|
221
|
+
BrotliEncoderSetParameter(s, BROTLI_PARAM_MODE, BROTLI_MODE_TEXT);
|
|
222
|
+
} else if (value == ID2SYM(id_font)) {
|
|
223
|
+
BrotliEncoderSetParameter(s, BROTLI_PARAM_MODE, BROTLI_MODE_FONT);
|
|
162
224
|
} else {
|
|
163
|
-
|
|
164
|
-
BrotliEncoderSetParameter(s, BROTLI_PARAM_MODE, BROTLI_MODE_GENERIC);
|
|
165
|
-
} else if (value == CSTR2SYM("text")) {
|
|
166
|
-
BrotliEncoderSetParameter(s, BROTLI_PARAM_MODE, BROTLI_MODE_TEXT);
|
|
167
|
-
} else if (value == CSTR2SYM("font")) {
|
|
168
|
-
BrotliEncoderSetParameter(s, BROTLI_PARAM_MODE, BROTLI_MODE_FONT);
|
|
169
|
-
} else {
|
|
170
|
-
rb_raise(rb_eArgError, "invalid mode");
|
|
171
|
-
}
|
|
225
|
+
return "invalid mode";
|
|
172
226
|
}
|
|
227
|
+
|
|
228
|
+
return NULL;
|
|
173
229
|
}
|
|
174
230
|
|
|
175
|
-
static
|
|
231
|
+
static const char *
|
|
176
232
|
brotli_deflate_set_quality(BrotliEncoderState* s, VALUE value)
|
|
177
233
|
{
|
|
234
|
+
long param;
|
|
235
|
+
|
|
178
236
|
if (NIL_P(value)) {
|
|
179
|
-
return;
|
|
237
|
+
return NULL;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (!FIXNUM_P(value)) {
|
|
241
|
+
return "invalid quality value. Should be 0 to 11.";
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
param = FIX2LONG(value);
|
|
245
|
+
if (0 <= param && param <= 11) {
|
|
246
|
+
BrotliEncoderSetParameter(s, BROTLI_PARAM_QUALITY, (uint32_t)param);
|
|
180
247
|
} else {
|
|
181
|
-
|
|
182
|
-
if (0 <= param && param <= 11) {
|
|
183
|
-
BrotliEncoderSetParameter(s, BROTLI_PARAM_QUALITY, param);
|
|
184
|
-
} else {
|
|
185
|
-
rb_raise(rb_eArgError, "invalid quality value. Should be 0 to 11.");
|
|
186
|
-
}
|
|
248
|
+
return "invalid quality value. Should be 0 to 11.";
|
|
187
249
|
}
|
|
250
|
+
|
|
251
|
+
return NULL;
|
|
188
252
|
}
|
|
189
253
|
|
|
190
|
-
static
|
|
254
|
+
static const char *
|
|
191
255
|
brotli_deflate_set_lgwin(BrotliEncoderState* s, VALUE value)
|
|
192
256
|
{
|
|
257
|
+
long param;
|
|
258
|
+
|
|
193
259
|
if (NIL_P(value)) {
|
|
194
|
-
return;
|
|
260
|
+
return NULL;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (!FIXNUM_P(value)) {
|
|
264
|
+
return "invalid lgwin value. Should be 10 to 24.";
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
param = FIX2LONG(value);
|
|
268
|
+
if (10 <= param && param <= 24) {
|
|
269
|
+
BrotliEncoderSetParameter(s, BROTLI_PARAM_LGWIN, (uint32_t)param);
|
|
195
270
|
} else {
|
|
196
|
-
|
|
197
|
-
if (10 <= param && param <= 24) {
|
|
198
|
-
BrotliEncoderSetParameter(s, BROTLI_PARAM_LGWIN, param);
|
|
199
|
-
} else {
|
|
200
|
-
rb_raise(rb_eArgError, "invalid lgwin value. Should be 10 to 24.");
|
|
201
|
-
}
|
|
271
|
+
return "invalid lgwin value. Should be 10 to 24.";
|
|
202
272
|
}
|
|
273
|
+
|
|
274
|
+
return NULL;
|
|
203
275
|
}
|
|
204
276
|
|
|
205
|
-
static
|
|
277
|
+
static const char *
|
|
206
278
|
brotli_deflate_set_lgblock(BrotliEncoderState* s, VALUE value)
|
|
207
279
|
{
|
|
280
|
+
long param;
|
|
281
|
+
|
|
208
282
|
if (NIL_P(value)) {
|
|
209
|
-
return;
|
|
283
|
+
return NULL;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (!FIXNUM_P(value)) {
|
|
287
|
+
return "invalid lgblock value. Should be 0 or 16 to 24.";
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
param = FIX2LONG(value);
|
|
291
|
+
if (param == 0 || (16 <= param && param <= 24)) {
|
|
292
|
+
BrotliEncoderSetParameter(s, BROTLI_PARAM_LGBLOCK, (uint32_t)param);
|
|
210
293
|
} else {
|
|
211
|
-
|
|
212
|
-
if ((param == 0) || (16 <= param && param <= 24)) {
|
|
213
|
-
BrotliEncoderSetParameter(s, BROTLI_PARAM_LGBLOCK, param);
|
|
214
|
-
} else {
|
|
215
|
-
rb_raise(rb_eArgError, "invalid lgblock value. Should be 0 or 16 to 24.");
|
|
216
|
-
}
|
|
294
|
+
return "invalid lgblock value. Should be 0 or 16 to 24.";
|
|
217
295
|
}
|
|
296
|
+
|
|
297
|
+
return NULL;
|
|
218
298
|
}
|
|
219
299
|
|
|
220
|
-
static
|
|
300
|
+
static const char *
|
|
221
301
|
brotli_deflate_parse_options(BrotliEncoderState* s, VALUE opts)
|
|
222
302
|
{
|
|
223
|
-
|
|
224
|
-
Check_Type(opts, T_HASH);
|
|
225
|
-
brotli_deflate_set_mode(s, rb_hash_aref(opts, CSTR2SYM("mode")));
|
|
226
|
-
brotli_deflate_set_quality(s, rb_hash_aref(opts, CSTR2SYM("quality")));
|
|
227
|
-
brotli_deflate_set_lgwin(s, rb_hash_aref(opts, CSTR2SYM("lgwin")));
|
|
228
|
-
brotli_deflate_set_lgblock(s, rb_hash_aref(opts, CSTR2SYM("lgblock")));
|
|
229
|
-
}
|
|
303
|
+
const char *err;
|
|
230
304
|
|
|
231
|
-
|
|
305
|
+
err = brotli_deflate_set_mode(s, brotli_hash_lookup(opts, id_mode));
|
|
306
|
+
if (err) {
|
|
307
|
+
return err;
|
|
308
|
+
}
|
|
309
|
+
err = brotli_deflate_set_quality(s, brotli_hash_lookup(opts, id_quality));
|
|
310
|
+
if (err) {
|
|
311
|
+
return err;
|
|
312
|
+
}
|
|
313
|
+
err = brotli_deflate_set_lgwin(s, brotli_hash_lookup(opts, id_lgwin));
|
|
314
|
+
if (err) {
|
|
315
|
+
return err;
|
|
316
|
+
}
|
|
317
|
+
return brotli_deflate_set_lgblock(s, brotli_hash_lookup(opts, id_lgblock));
|
|
232
318
|
}
|
|
233
319
|
|
|
234
320
|
typedef struct {
|
|
@@ -237,10 +323,24 @@ typedef struct {
|
|
|
237
323
|
BrotliEncoderState* s;
|
|
238
324
|
buffer_t* buffer;
|
|
239
325
|
BROTLI_BOOL finished;
|
|
240
|
-
|
|
241
|
-
size_t dict_len;
|
|
326
|
+
BrotliEncoderPreparedDictionary* prepared_dict;
|
|
242
327
|
} brotli_deflate_args_t;
|
|
243
328
|
|
|
329
|
+
static void
|
|
330
|
+
brotli_deflate_cleanup(brotli_deflate_args_t* args)
|
|
331
|
+
{
|
|
332
|
+
delete_buffer(args->buffer);
|
|
333
|
+
args->buffer = NULL;
|
|
334
|
+
if (args->s) {
|
|
335
|
+
BrotliEncoderDestroyInstance(args->s);
|
|
336
|
+
args->s = NULL;
|
|
337
|
+
}
|
|
338
|
+
if (args->prepared_dict) {
|
|
339
|
+
BrotliEncoderDestroyPreparedDictionary(args->prepared_dict);
|
|
340
|
+
args->prepared_dict = NULL;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
244
344
|
static void*
|
|
245
345
|
brotli_deflate_no_gvl(void *arg)
|
|
246
346
|
{
|
|
@@ -255,19 +355,6 @@ brotli_deflate_no_gvl(void *arg)
|
|
|
255
355
|
buffer_t* buffer = args->buffer;
|
|
256
356
|
BrotliEncoderState* s = args->s;
|
|
257
357
|
|
|
258
|
-
#if defined(HAVE_BROTLIENCODERPREPAREDICTIONARY) && defined(HAVE_BROTLIENCODERATTACHPREPAREDDICTIONARY)
|
|
259
|
-
/* Attach dictionary if provided */
|
|
260
|
-
if (args->dict && args->dict_len > 0) {
|
|
261
|
-
BrotliEncoderPreparedDictionary* dict = BrotliEncoderPrepareDictionary(
|
|
262
|
-
BROTLI_SHARED_DICTIONARY_RAW, args->dict_len, args->dict,
|
|
263
|
-
BROTLI_MAX_QUALITY, brotli_alloc, brotli_free, NULL);
|
|
264
|
-
if (dict) {
|
|
265
|
-
BrotliEncoderAttachPreparedDictionary(s, dict);
|
|
266
|
-
/* Note: dict is owned by encoder after attach, no need to free */
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
#endif
|
|
270
|
-
|
|
271
358
|
for (;;) {
|
|
272
359
|
r = BrotliEncoderCompressStream(s,
|
|
273
360
|
BROTLI_OPERATION_FINISH,
|
|
@@ -291,59 +378,85 @@ brotli_deflate_no_gvl(void *arg)
|
|
|
291
378
|
return arg;
|
|
292
379
|
}
|
|
293
380
|
|
|
381
|
+
static VALUE
|
|
382
|
+
brotli_deflate_take_result(VALUE arg)
|
|
383
|
+
{
|
|
384
|
+
brotli_deflate_args_t *args = (brotli_deflate_args_t *)arg;
|
|
385
|
+
return rb_str_new(args->buffer->ptr, args->buffer->used);
|
|
386
|
+
}
|
|
387
|
+
|
|
294
388
|
static VALUE
|
|
295
389
|
brotli_deflate(int argc, VALUE *argv, VALUE self)
|
|
296
390
|
{
|
|
297
|
-
VALUE str = Qnil
|
|
298
|
-
|
|
391
|
+
VALUE str = Qnil;
|
|
392
|
+
VALUE opts = Qnil;
|
|
393
|
+
VALUE value = Qnil;
|
|
394
|
+
VALUE dict = Qnil;
|
|
395
|
+
brotli_deflate_args_t args = {0};
|
|
396
|
+
size_t max_compressed_size;
|
|
397
|
+
const char *err;
|
|
398
|
+
|
|
399
|
+
(void)self;
|
|
299
400
|
|
|
300
401
|
rb_scan_args(argc, argv, "11", &str, &opts);
|
|
301
402
|
if (NIL_P(str)) {
|
|
302
403
|
rb_raise(rb_eArgError, "input should not be nil");
|
|
303
|
-
return Qnil;
|
|
304
404
|
}
|
|
305
405
|
StringValue(str);
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
Check_Type(opts, T_HASH);
|
|
310
|
-
dict = rb_hash_aref(opts, CSTR2SYM("dictionary"));
|
|
406
|
+
dict = brotli_hash_lookup(opts, id_dictionary);
|
|
407
|
+
if (!NIL_P(dict)) {
|
|
408
|
+
StringValue(dict);
|
|
311
409
|
}
|
|
312
410
|
|
|
313
411
|
args.str = (uint8_t*)RSTRING_PTR(str);
|
|
314
412
|
args.len = (size_t)RSTRING_LEN(str);
|
|
315
|
-
args.s =
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
413
|
+
args.s = brotli_encoder_state_create();
|
|
414
|
+
err = brotli_deflate_parse_options(args.s, opts);
|
|
415
|
+
if (err) {
|
|
416
|
+
brotli_deflate_cleanup(&args);
|
|
417
|
+
rb_raise(rb_eArgError, "%s", err);
|
|
418
|
+
}
|
|
419
|
+
max_compressed_size = BrotliEncoderMaxCompressedSize(args.len);
|
|
319
420
|
args.buffer = create_buffer(max_compressed_size);
|
|
320
421
|
args.finished = BROTLI_FALSE;
|
|
321
422
|
|
|
322
|
-
|
|
423
|
+
args.prepared_dict = NULL;
|
|
323
424
|
if (!NIL_P(dict)) {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
args.
|
|
333
|
-
|
|
425
|
+
args.prepared_dict = BrotliEncoderPrepareDictionary(
|
|
426
|
+
BROTLI_SHARED_DICTIONARY_RAW,
|
|
427
|
+
(size_t)RSTRING_LEN(dict),
|
|
428
|
+
(const uint8_t*)RSTRING_PTR(dict),
|
|
429
|
+
BROTLI_MAX_QUALITY,
|
|
430
|
+
brotli_alloc,
|
|
431
|
+
brotli_free,
|
|
432
|
+
NULL);
|
|
433
|
+
if (!args.prepared_dict) {
|
|
434
|
+
brotli_deflate_cleanup(&args);
|
|
435
|
+
rb_raise(rb_eBrotli, "Failed to prepare dictionary for compression");
|
|
436
|
+
}
|
|
437
|
+
if (!BrotliEncoderAttachPreparedDictionary(args.s, args.prepared_dict)) {
|
|
438
|
+
brotli_deflate_cleanup(&args);
|
|
439
|
+
rb_raise(rb_eBrotli, "Failed to attach dictionary for compression");
|
|
440
|
+
}
|
|
334
441
|
}
|
|
335
442
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
brotli_deflate_no_gvl((void *)&args);
|
|
340
|
-
#endif
|
|
443
|
+
rb_thread_call_without_gvl(brotli_deflate_no_gvl, &args, NULL, NULL);
|
|
444
|
+
RB_GC_GUARD(str);
|
|
445
|
+
RB_GC_GUARD(dict);
|
|
341
446
|
if (args.finished == BROTLI_TRUE) {
|
|
342
|
-
|
|
447
|
+
int state = 0;
|
|
448
|
+
value = rb_protect(brotli_deflate_take_result, (VALUE)&args, &state);
|
|
449
|
+
if (state) {
|
|
450
|
+
brotli_deflate_cleanup(&args);
|
|
451
|
+
rb_jump_tag(state);
|
|
452
|
+
}
|
|
343
453
|
}
|
|
344
454
|
|
|
345
|
-
|
|
346
|
-
|
|
455
|
+
brotli_deflate_cleanup(&args);
|
|
456
|
+
|
|
457
|
+
if (args.finished != BROTLI_TRUE) {
|
|
458
|
+
rb_raise(rb_eBrotli, "Failed to compress");
|
|
459
|
+
}
|
|
347
460
|
|
|
348
461
|
return value;
|
|
349
462
|
}
|
|
@@ -355,212 +468,706 @@ brotli_deflate(int argc, VALUE *argv, VALUE self)
|
|
|
355
468
|
static VALUE brotli_version(VALUE klass) {
|
|
356
469
|
uint32_t ver = BrotliEncoderVersion();
|
|
357
470
|
char version[255];
|
|
471
|
+
|
|
472
|
+
(void)klass;
|
|
358
473
|
snprintf(version, sizeof(version), "%u.%u.%u", ver >> 24, (ver >> 12) & 0xFFF, ver & 0xFFF);
|
|
359
|
-
return
|
|
474
|
+
return rb_str_new_cstr(version);
|
|
360
475
|
}
|
|
361
476
|
|
|
362
477
|
/*******************************************************************************
|
|
363
|
-
*
|
|
478
|
+
* Streaming APIs
|
|
364
479
|
******************************************************************************/
|
|
365
480
|
|
|
366
|
-
static
|
|
367
|
-
|
|
368
|
-
struct brotli {
|
|
369
|
-
VALUE io;
|
|
370
|
-
BrotliEncoderState* state;
|
|
371
|
-
};
|
|
481
|
+
static VALUE rb_cBrotliCompressor;
|
|
482
|
+
static VALUE rb_cBrotliDecompressor;
|
|
372
483
|
|
|
373
|
-
static
|
|
484
|
+
static uint8_t*
|
|
485
|
+
brotli_copy_string_data(VALUE string, size_t* len)
|
|
374
486
|
{
|
|
375
|
-
|
|
376
|
-
|
|
487
|
+
size_t copy_len;
|
|
488
|
+
size_t alloc_len;
|
|
489
|
+
uint8_t* copy;
|
|
490
|
+
|
|
491
|
+
StringValue(string);
|
|
492
|
+
copy_len = (size_t)RSTRING_LEN(string);
|
|
493
|
+
alloc_len = copy_len > 0 ? copy_len : 1;
|
|
494
|
+
copy = brotli_alloc(NULL, alloc_len);
|
|
495
|
+
if (copy_len > 0) {
|
|
496
|
+
memcpy(copy, RSTRING_PTR(string), copy_len);
|
|
497
|
+
}
|
|
498
|
+
*len = copy_len;
|
|
499
|
+
return copy;
|
|
377
500
|
}
|
|
378
501
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
}
|
|
502
|
+
typedef struct {
|
|
503
|
+
BrotliEncoderState* state;
|
|
504
|
+
BrotliEncoderPreparedDictionary* prepared_dict;
|
|
505
|
+
uint8_t* dict_data;
|
|
506
|
+
size_t dict_len;
|
|
507
|
+
BROTLI_BOOL finished;
|
|
508
|
+
} brotli_encoder_t;
|
|
387
509
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
}
|
|
510
|
+
typedef struct {
|
|
511
|
+
brotli_encoder_t encoder;
|
|
512
|
+
} brotli_compressor_t;
|
|
392
513
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
514
|
+
typedef struct {
|
|
515
|
+
BrotliDecoderState* state;
|
|
516
|
+
uint8_t* dict_data;
|
|
517
|
+
size_t dict_len;
|
|
518
|
+
VALUE pending_input;
|
|
519
|
+
BROTLI_BOOL needs_more_output;
|
|
520
|
+
BROTLI_BOOL finished;
|
|
521
|
+
} brotli_decompressor_t;
|
|
398
522
|
|
|
399
523
|
typedef struct {
|
|
400
524
|
BrotliEncoderState* state;
|
|
401
525
|
BrotliEncoderOperation op;
|
|
402
526
|
size_t available_in;
|
|
403
527
|
const uint8_t* next_in;
|
|
528
|
+
BROTLI_BOOL ok;
|
|
404
529
|
} brotli_encoder_args_t;
|
|
405
530
|
|
|
531
|
+
typedef struct {
|
|
532
|
+
BrotliDecoderState* state;
|
|
533
|
+
size_t available_in;
|
|
534
|
+
const uint8_t* next_in;
|
|
535
|
+
size_t available_out;
|
|
536
|
+
uint8_t* next_out;
|
|
537
|
+
BrotliDecoderResult result;
|
|
538
|
+
} brotli_decoder_args_t;
|
|
539
|
+
|
|
406
540
|
static void* compress_no_gvl(void *ptr) {
|
|
407
541
|
brotli_encoder_args_t *args = ptr;
|
|
408
542
|
size_t zero = 0;
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
rb_raise(rb_eBrotli, "BrotliEncoderCompressStream failed");
|
|
413
|
-
}
|
|
543
|
+
args->ok = BrotliEncoderCompressStream(args->state, args->op,
|
|
544
|
+
&args->available_in, &args->next_in,
|
|
545
|
+
&zero, NULL, NULL);
|
|
414
546
|
return NULL;
|
|
415
547
|
}
|
|
416
548
|
|
|
417
|
-
static
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
549
|
+
static void* decompress_no_gvl(void *ptr) {
|
|
550
|
+
brotli_decoder_args_t *args = ptr;
|
|
551
|
+
args->result = BrotliDecoderDecompressStream(args->state,
|
|
552
|
+
&args->available_in,
|
|
553
|
+
&args->next_in,
|
|
554
|
+
&args->available_out,
|
|
555
|
+
&args->next_out,
|
|
556
|
+
NULL);
|
|
557
|
+
return NULL;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
static void
|
|
561
|
+
brotli_encoder_step(brotli_encoder_args_t *args)
|
|
562
|
+
{
|
|
563
|
+
rb_thread_call_without_gvl(compress_no_gvl, (void*)args, NULL, NULL);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
static void
|
|
567
|
+
brotli_decompressor_step(brotli_decoder_args_t *args)
|
|
568
|
+
{
|
|
569
|
+
rb_thread_call_without_gvl(decompress_no_gvl, (void*)args, NULL, NULL);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
static void
|
|
573
|
+
brotli_encoder_destroy(brotli_encoder_t* encoder)
|
|
574
|
+
{
|
|
575
|
+
if (encoder->state) {
|
|
576
|
+
BrotliEncoderDestroyInstance(encoder->state);
|
|
577
|
+
encoder->state = NULL;
|
|
578
|
+
}
|
|
579
|
+
if (encoder->prepared_dict) {
|
|
580
|
+
BrotliEncoderDestroyPreparedDictionary(encoder->prepared_dict);
|
|
581
|
+
encoder->prepared_dict = NULL;
|
|
582
|
+
}
|
|
583
|
+
brotli_free(NULL, encoder->dict_data);
|
|
584
|
+
encoder->dict_data = NULL;
|
|
585
|
+
encoder->dict_len = 0;
|
|
586
|
+
encoder->finished = BROTLI_FALSE;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
static void
|
|
590
|
+
brotli_encoder_reset(brotli_encoder_t* encoder)
|
|
591
|
+
{
|
|
592
|
+
brotli_encoder_destroy(encoder);
|
|
593
|
+
encoder->state = brotli_encoder_state_create();
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
static void
|
|
597
|
+
brotli_encoder_take_output_to_string(BrotliEncoderState* state, VALUE output)
|
|
598
|
+
{
|
|
599
|
+
while (BrotliEncoderHasMoreOutput(state)) {
|
|
600
|
+
size_t len = 0;
|
|
601
|
+
const uint8_t* out = BrotliEncoderTakeOutput(state, &len);
|
|
421
602
|
if (len > 0) {
|
|
422
|
-
|
|
603
|
+
rb_str_cat(output, (const char*)out, len);
|
|
423
604
|
}
|
|
424
605
|
}
|
|
425
|
-
return len;
|
|
426
606
|
}
|
|
427
607
|
|
|
428
|
-
static
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
if (
|
|
434
|
-
|
|
435
|
-
|
|
608
|
+
static void
|
|
609
|
+
brotli_encoder_attach_dictionary(brotli_encoder_t* encoder, VALUE opts)
|
|
610
|
+
{
|
|
611
|
+
VALUE dict = brotli_hash_lookup(opts, id_dictionary);
|
|
612
|
+
|
|
613
|
+
if (NIL_P(dict)) {
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
encoder->dict_data = brotli_copy_string_data(dict, &encoder->dict_len);
|
|
618
|
+
encoder->prepared_dict = BrotliEncoderPrepareDictionary(
|
|
619
|
+
BROTLI_SHARED_DICTIONARY_RAW,
|
|
620
|
+
encoder->dict_len,
|
|
621
|
+
encoder->dict_data,
|
|
622
|
+
BROTLI_MAX_QUALITY,
|
|
623
|
+
brotli_alloc,
|
|
624
|
+
brotli_free,
|
|
625
|
+
NULL);
|
|
626
|
+
|
|
627
|
+
if (!encoder->prepared_dict) {
|
|
628
|
+
brotli_free(NULL, encoder->dict_data);
|
|
629
|
+
encoder->dict_data = NULL;
|
|
630
|
+
encoder->dict_len = 0;
|
|
631
|
+
rb_raise(rb_eBrotli, "Failed to prepare dictionary for compression");
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
if (!BrotliEncoderAttachPreparedDictionary(encoder->state, encoder->prepared_dict)) {
|
|
635
|
+
BrotliEncoderDestroyPreparedDictionary(encoder->prepared_dict);
|
|
636
|
+
encoder->prepared_dict = NULL;
|
|
637
|
+
brotli_free(NULL, encoder->dict_data);
|
|
638
|
+
encoder->dict_data = NULL;
|
|
639
|
+
encoder->dict_len = 0;
|
|
640
|
+
rb_raise(rb_eBrotli, "Failed to attach dictionary for compression");
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
static VALUE
|
|
645
|
+
brotli_encoder_stream_to_string(brotli_encoder_t* encoder,
|
|
646
|
+
BrotliEncoderOperation op,
|
|
647
|
+
const uint8_t* input,
|
|
648
|
+
size_t input_len)
|
|
649
|
+
{
|
|
650
|
+
VALUE output = rb_str_buf_new(BUFSIZ);
|
|
651
|
+
brotli_encoder_args_t args = {
|
|
652
|
+
.state = encoder->state,
|
|
653
|
+
.op = op,
|
|
654
|
+
.available_in = input_len,
|
|
655
|
+
.next_in = input,
|
|
656
|
+
.ok = BROTLI_FALSE
|
|
657
|
+
};
|
|
658
|
+
|
|
659
|
+
if (op == BROTLI_OPERATION_PROCESS && input_len == 0) {
|
|
660
|
+
return output;
|
|
436
661
|
}
|
|
662
|
+
|
|
663
|
+
for (;;) {
|
|
664
|
+
long output_len_before;
|
|
665
|
+
size_t produced;
|
|
666
|
+
|
|
667
|
+
brotli_encoder_step(&args);
|
|
668
|
+
if (args.ok == BROTLI_FALSE) {
|
|
669
|
+
rb_raise(rb_eBrotli, "BrotliEncoderCompressStream failed");
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
output_len_before = RSTRING_LEN(output);
|
|
673
|
+
brotli_encoder_take_output_to_string(encoder->state, output);
|
|
674
|
+
produced = (size_t)(RSTRING_LEN(output) - output_len_before);
|
|
675
|
+
|
|
676
|
+
if (args.available_in > 0 || BrotliEncoderHasMoreOutput(encoder->state)) {
|
|
677
|
+
continue;
|
|
678
|
+
}
|
|
679
|
+
if (op != BROTLI_OPERATION_PROCESS && produced > 0) {
|
|
680
|
+
continue;
|
|
681
|
+
}
|
|
682
|
+
break;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
return output;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/*******************************************************************************
|
|
689
|
+
* Compressor
|
|
690
|
+
******************************************************************************/
|
|
691
|
+
|
|
692
|
+
static void
|
|
693
|
+
brotli_compressor_free(void *p)
|
|
694
|
+
{
|
|
695
|
+
brotli_compressor_t* br = p;
|
|
696
|
+
brotli_encoder_destroy(&br->encoder);
|
|
697
|
+
ruby_xfree(br);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
static size_t
|
|
701
|
+
brotli_compressor_memsize(const void *p)
|
|
702
|
+
{
|
|
703
|
+
const brotli_compressor_t *br = p;
|
|
704
|
+
return sizeof(*br) + br->encoder.dict_len;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
static const rb_data_type_t brotli_compressor_data_type = {
|
|
708
|
+
"brotli_compressor",
|
|
709
|
+
{ 0, brotli_compressor_free, brotli_compressor_memsize },
|
|
710
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
|
|
711
|
+
};
|
|
712
|
+
|
|
713
|
+
static VALUE
|
|
714
|
+
rb_compressor_alloc(VALUE klass)
|
|
715
|
+
{
|
|
716
|
+
brotli_compressor_t *br;
|
|
717
|
+
VALUE obj = TypedData_Make_Struct(klass, brotli_compressor_t, &brotli_compressor_data_type, br);
|
|
718
|
+
br->encoder.state = NULL;
|
|
719
|
+
br->encoder.prepared_dict = NULL;
|
|
720
|
+
br->encoder.dict_data = NULL;
|
|
721
|
+
br->encoder.dict_len = 0;
|
|
722
|
+
br->encoder.finished = BROTLI_FALSE;
|
|
437
723
|
return obj;
|
|
438
724
|
}
|
|
439
725
|
|
|
440
|
-
static
|
|
441
|
-
|
|
726
|
+
static void
|
|
727
|
+
brotli_compressor_ensure_open(brotli_compressor_t* br)
|
|
728
|
+
{
|
|
729
|
+
if (!br->encoder.state) {
|
|
730
|
+
rb_raise(rb_eBrotli, "Compressor is closed");
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
static VALUE
|
|
735
|
+
rb_compressor_initialize(int argc, VALUE* argv, VALUE self)
|
|
736
|
+
{
|
|
442
737
|
VALUE opts = Qnil;
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
738
|
+
brotli_compressor_t *br;
|
|
739
|
+
const char *err;
|
|
740
|
+
|
|
741
|
+
rb_scan_args(argc, argv, "01", &opts);
|
|
742
|
+
|
|
743
|
+
TypedData_Get_Struct(self, brotli_compressor_t, &brotli_compressor_data_type, br);
|
|
744
|
+
brotli_encoder_reset(&br->encoder);
|
|
745
|
+
err = brotli_deflate_parse_options(br->encoder.state, opts);
|
|
746
|
+
if (err) {
|
|
747
|
+
rb_raise(rb_eArgError, "%s", err);
|
|
448
748
|
}
|
|
749
|
+
brotli_encoder_attach_dictionary(&br->encoder, opts);
|
|
449
750
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
BrotliEncoderPreparedDictionary* prepared_dict = BrotliEncoderPrepareDictionary(
|
|
463
|
-
BROTLI_SHARED_DICTIONARY_RAW,
|
|
464
|
-
(size_t)RSTRING_LEN(dict),
|
|
465
|
-
(uint8_t*)RSTRING_PTR(dict),
|
|
466
|
-
BROTLI_MAX_QUALITY,
|
|
467
|
-
brotli_alloc,
|
|
468
|
-
brotli_free,
|
|
469
|
-
NULL);
|
|
470
|
-
if (prepared_dict) {
|
|
471
|
-
BrotliEncoderAttachPreparedDictionary(br->state, prepared_dict);
|
|
472
|
-
/* Note: dict is owned by encoder after attach, no need to free */
|
|
473
|
-
} else {
|
|
474
|
-
rb_raise(rb_eBrotli, "Failed to prepare dictionary for compression");
|
|
475
|
-
}
|
|
476
|
-
}
|
|
751
|
+
return self;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
static VALUE
|
|
755
|
+
rb_compressor_process(VALUE self, VALUE input)
|
|
756
|
+
{
|
|
757
|
+
brotli_compressor_t *br;
|
|
758
|
+
VALUE output;
|
|
759
|
+
TypedData_Get_Struct(self, brotli_compressor_t, &brotli_compressor_data_type, br);
|
|
760
|
+
brotli_compressor_ensure_open(br);
|
|
761
|
+
if (br->encoder.finished) {
|
|
762
|
+
rb_raise(rb_eBrotli, "Compressor is finished");
|
|
477
763
|
}
|
|
764
|
+
|
|
765
|
+
StringValue(input);
|
|
766
|
+
output = brotli_encoder_stream_to_string(&br->encoder,
|
|
767
|
+
BROTLI_OPERATION_PROCESS,
|
|
768
|
+
(const uint8_t*)RSTRING_PTR(input),
|
|
769
|
+
(size_t)RSTRING_LEN(input));
|
|
770
|
+
RB_GC_GUARD(input);
|
|
771
|
+
return output;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
static VALUE
|
|
775
|
+
rb_compressor_flush(VALUE self)
|
|
776
|
+
{
|
|
777
|
+
brotli_compressor_t *br;
|
|
778
|
+
TypedData_Get_Struct(self, brotli_compressor_t, &brotli_compressor_data_type, br);
|
|
779
|
+
brotli_compressor_ensure_open(br);
|
|
780
|
+
if (br->encoder.finished) {
|
|
781
|
+
rb_raise(rb_eBrotli, "Compressor is finished");
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
return brotli_encoder_stream_to_string(&br->encoder, BROTLI_OPERATION_FLUSH, NULL, 0);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
static VALUE
|
|
788
|
+
rb_compressor_finish(VALUE self)
|
|
789
|
+
{
|
|
790
|
+
brotli_compressor_t *br;
|
|
791
|
+
VALUE output;
|
|
792
|
+
|
|
793
|
+
TypedData_Get_Struct(self, brotli_compressor_t, &brotli_compressor_data_type, br);
|
|
794
|
+
brotli_compressor_ensure_open(br);
|
|
795
|
+
|
|
796
|
+
if (br->encoder.finished) {
|
|
797
|
+
return rb_str_new("", 0);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
output = brotli_encoder_stream_to_string(&br->encoder, BROTLI_OPERATION_FINISH, NULL, 0);
|
|
801
|
+
br->encoder.finished = BROTLI_TRUE;
|
|
802
|
+
return output;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
static VALUE
|
|
806
|
+
rb_compressor_is_finished(VALUE self)
|
|
807
|
+
{
|
|
808
|
+
brotli_compressor_t *br;
|
|
809
|
+
|
|
810
|
+
TypedData_Get_Struct(self, brotli_compressor_t, &brotli_compressor_data_type, br);
|
|
811
|
+
brotli_compressor_ensure_open(br);
|
|
812
|
+
return br->encoder.finished ? Qtrue : Qfalse;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
/*******************************************************************************
|
|
816
|
+
* Decompressor
|
|
817
|
+
******************************************************************************/
|
|
818
|
+
|
|
819
|
+
static void
|
|
820
|
+
brotli_decompressor_mark(void *p)
|
|
821
|
+
{
|
|
822
|
+
brotli_decompressor_t *br = p;
|
|
823
|
+
#ifdef HAVE_RB_GC_MARK_MOVABLE
|
|
824
|
+
rb_gc_mark_movable(br->pending_input);
|
|
478
825
|
#else
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
826
|
+
rb_gc_mark(br->pending_input);
|
|
827
|
+
#endif
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
static void
|
|
831
|
+
brotli_decompressor_free(void *p)
|
|
832
|
+
{
|
|
833
|
+
brotli_decompressor_t *br = p;
|
|
834
|
+
if (br->state) {
|
|
835
|
+
BrotliDecoderDestroyInstance(br->state);
|
|
836
|
+
br->state = NULL;
|
|
837
|
+
}
|
|
838
|
+
brotli_free(NULL, br->dict_data);
|
|
839
|
+
br->dict_data = NULL;
|
|
840
|
+
br->dict_len = 0;
|
|
841
|
+
br->pending_input = Qnil;
|
|
842
|
+
br->needs_more_output = BROTLI_FALSE;
|
|
843
|
+
br->finished = BROTLI_FALSE;
|
|
844
|
+
ruby_xfree(br);
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
static void
|
|
848
|
+
brotli_decompressor_set_pending_input(VALUE self, brotli_decompressor_t* br, VALUE pending_input)
|
|
849
|
+
{
|
|
850
|
+
RB_OBJ_WRITE(self, &br->pending_input, pending_input);
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
static void
|
|
854
|
+
brotli_decompressor_reset(VALUE self, brotli_decompressor_t* br)
|
|
855
|
+
{
|
|
856
|
+
if (br->state) {
|
|
857
|
+
BrotliDecoderDestroyInstance(br->state);
|
|
858
|
+
br->state = NULL;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
brotli_free(NULL, br->dict_data);
|
|
862
|
+
br->dict_data = NULL;
|
|
863
|
+
br->dict_len = 0;
|
|
864
|
+
brotli_decompressor_set_pending_input(self, br, Qnil);
|
|
865
|
+
br->needs_more_output = BROTLI_FALSE;
|
|
866
|
+
br->finished = BROTLI_FALSE;
|
|
867
|
+
br->state = brotli_decoder_state_create();
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
static size_t
|
|
871
|
+
brotli_decompressor_memsize(const void *p)
|
|
872
|
+
{
|
|
873
|
+
const brotli_decompressor_t *br = p;
|
|
874
|
+
return sizeof(*br) + br->dict_len;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
#ifdef HAVE_RB_GC_MARK_MOVABLE
|
|
878
|
+
static void
|
|
879
|
+
brotli_decompressor_compact(void *p)
|
|
880
|
+
{
|
|
881
|
+
brotli_decompressor_t *br = p;
|
|
882
|
+
|
|
883
|
+
if (!NIL_P(br->pending_input)) {
|
|
884
|
+
br->pending_input = rb_gc_location(br->pending_input);
|
|
486
885
|
}
|
|
886
|
+
}
|
|
487
887
|
#endif
|
|
488
888
|
|
|
889
|
+
static const rb_data_type_t brotli_decompressor_data_type = {
|
|
890
|
+
"brotli_decompressor",
|
|
891
|
+
{
|
|
892
|
+
brotli_decompressor_mark,
|
|
893
|
+
brotli_decompressor_free,
|
|
894
|
+
brotli_decompressor_memsize,
|
|
895
|
+
#ifdef HAVE_RB_GC_MARK_MOVABLE
|
|
896
|
+
brotli_decompressor_compact,
|
|
897
|
+
#endif
|
|
898
|
+
},
|
|
899
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
|
|
900
|
+
};
|
|
901
|
+
|
|
902
|
+
static VALUE
|
|
903
|
+
rb_decompressor_alloc(VALUE klass)
|
|
904
|
+
{
|
|
905
|
+
brotli_decompressor_t *br;
|
|
906
|
+
VALUE obj = TypedData_Make_Struct(klass, brotli_decompressor_t, &brotli_decompressor_data_type, br);
|
|
907
|
+
br->state = NULL;
|
|
908
|
+
br->dict_data = NULL;
|
|
909
|
+
br->dict_len = 0;
|
|
910
|
+
RB_OBJ_WRITE(obj, &br->pending_input, Qnil);
|
|
911
|
+
br->needs_more_output = BROTLI_FALSE;
|
|
912
|
+
br->finished = BROTLI_FALSE;
|
|
913
|
+
return obj;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
static void
|
|
917
|
+
brotli_decompressor_attach_dictionary(brotli_decompressor_t* br, VALUE opts)
|
|
918
|
+
{
|
|
919
|
+
VALUE dict = brotli_hash_lookup(opts, id_dictionary);
|
|
920
|
+
if (NIL_P(dict)) {
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
br->dict_data = brotli_copy_string_data(dict, &br->dict_len);
|
|
925
|
+
if (!BrotliDecoderAttachDictionary(br->state,
|
|
926
|
+
BROTLI_SHARED_DICTIONARY_RAW,
|
|
927
|
+
br->dict_len,
|
|
928
|
+
br->dict_data)) {
|
|
929
|
+
brotli_free(NULL, br->dict_data);
|
|
930
|
+
br->dict_data = NULL;
|
|
931
|
+
br->dict_len = 0;
|
|
932
|
+
rb_raise(rb_eBrotli, "Failed to attach dictionary for decompression");
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
static VALUE
|
|
937
|
+
rb_decompressor_initialize(int argc, VALUE* argv, VALUE self)
|
|
938
|
+
{
|
|
939
|
+
VALUE opts = Qnil;
|
|
940
|
+
brotli_decompressor_t *br;
|
|
941
|
+
|
|
942
|
+
rb_scan_args(argc, argv, "01", &opts);
|
|
943
|
+
TypedData_Get_Struct(self, brotli_decompressor_t, &brotli_decompressor_data_type, br);
|
|
944
|
+
brotli_decompressor_reset(self, br);
|
|
945
|
+
brotli_decompressor_attach_dictionary(br, opts);
|
|
946
|
+
|
|
489
947
|
return self;
|
|
490
948
|
}
|
|
491
949
|
|
|
492
|
-
static
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
950
|
+
static BROTLI_BOOL
|
|
951
|
+
brotli_decompressor_has_pending_input(const brotli_decompressor_t *br)
|
|
952
|
+
{
|
|
953
|
+
return !NIL_P(br->pending_input) && RSTRING_LEN(br->pending_input) > 0;
|
|
954
|
+
}
|
|
496
955
|
|
|
497
|
-
|
|
956
|
+
static size_t
|
|
957
|
+
brotli_decompressor_pending_input_length(const brotli_decompressor_t *br)
|
|
958
|
+
{
|
|
959
|
+
if (!brotli_decompressor_has_pending_input(br)) {
|
|
960
|
+
return 0;
|
|
961
|
+
}
|
|
962
|
+
return (size_t)RSTRING_LEN(br->pending_input);
|
|
963
|
+
}
|
|
498
964
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
};
|
|
965
|
+
static void
|
|
966
|
+
brotli_decompressor_clear_pending_input(VALUE self, brotli_decompressor_t* br)
|
|
967
|
+
{
|
|
968
|
+
brotli_decompressor_set_pending_input(self, br, Qnil);
|
|
969
|
+
}
|
|
505
970
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
971
|
+
static void
|
|
972
|
+
brotli_decompressor_ensure_open(const brotli_decompressor_t* br)
|
|
973
|
+
{
|
|
974
|
+
if (!br->state) {
|
|
975
|
+
rb_raise(rb_eBrotli, "Decompressor is closed");
|
|
509
976
|
}
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
static BROTLI_BOOL
|
|
980
|
+
brotli_decompressor_needs_output_drain(const brotli_decompressor_t *br)
|
|
981
|
+
{
|
|
982
|
+
return br->needs_more_output || brotli_decompressor_has_pending_input(br) ||
|
|
983
|
+
BrotliDecoderHasMoreOutput(br->state);
|
|
984
|
+
}
|
|
510
985
|
|
|
511
|
-
|
|
986
|
+
static void
|
|
987
|
+
brotli_decompressor_store_pending_input(VALUE self,
|
|
988
|
+
brotli_decompressor_t* br,
|
|
989
|
+
const uint8_t* next_in,
|
|
990
|
+
size_t available_in)
|
|
991
|
+
{
|
|
992
|
+
if (available_in == 0) {
|
|
993
|
+
brotli_decompressor_clear_pending_input(self, br);
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
996
|
+
brotli_decompressor_set_pending_input(self, br, rb_str_new((const char*)next_in, (long)available_in));
|
|
512
997
|
}
|
|
513
998
|
|
|
514
|
-
static
|
|
515
|
-
|
|
516
|
-
|
|
999
|
+
static size_t
|
|
1000
|
+
brotli_output_buffer_limit(VALUE opts)
|
|
1001
|
+
{
|
|
1002
|
+
VALUE limit_value = brotli_hash_lookup(opts, id_output_buffer_limit);
|
|
517
1003
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
.available_in = 0,
|
|
522
|
-
.next_in = NULL
|
|
523
|
-
};
|
|
1004
|
+
if (NIL_P(limit_value)) {
|
|
1005
|
+
return 0;
|
|
1006
|
+
}
|
|
524
1007
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
push_output(br);
|
|
1008
|
+
if (rb_cmpint(rb_funcall(limit_value, id_cmp, 1, INT2FIX(0)), limit_value, INT2FIX(0)) <= 0) {
|
|
1009
|
+
rb_raise(rb_eArgError, "output_buffer_limit must be positive");
|
|
528
1010
|
}
|
|
529
|
-
|
|
1011
|
+
|
|
1012
|
+
return NUM2SIZET(limit_value);
|
|
530
1013
|
}
|
|
531
1014
|
|
|
532
|
-
static VALUE
|
|
533
|
-
|
|
534
|
-
|
|
1015
|
+
static VALUE
|
|
1016
|
+
rb_decompressor_process(int argc, VALUE* argv, VALUE self)
|
|
1017
|
+
{
|
|
1018
|
+
brotli_decompressor_t *br;
|
|
1019
|
+
VALUE input = Qnil;
|
|
1020
|
+
VALUE opts = Qnil;
|
|
1021
|
+
VALUE input_source = Qnil;
|
|
1022
|
+
VALUE output;
|
|
1023
|
+
size_t available_in;
|
|
1024
|
+
const uint8_t* next_in;
|
|
1025
|
+
size_t output_buffer_limit;
|
|
1026
|
+
BROTLI_BOOL limit_output;
|
|
1027
|
+
BrotliDecoderResult result = BROTLI_DECODER_RESULT_ERROR;
|
|
1028
|
+
uint8_t outbuf[BUFSIZ];
|
|
1029
|
+
|
|
1030
|
+
rb_scan_args(argc, argv, "11", &input, &opts);
|
|
1031
|
+
TypedData_Get_Struct(self, brotli_decompressor_t, &brotli_decompressor_data_type, br);
|
|
1032
|
+
brotli_decompressor_ensure_open(br);
|
|
1033
|
+
output_buffer_limit = brotli_output_buffer_limit(opts);
|
|
1034
|
+
limit_output = output_buffer_limit > 0 ? BROTLI_TRUE : BROTLI_FALSE;
|
|
1035
|
+
|
|
1036
|
+
if (br->finished) {
|
|
1037
|
+
StringValue(input);
|
|
1038
|
+
available_in = (size_t)RSTRING_LEN(input);
|
|
1039
|
+
if (available_in == 0) {
|
|
1040
|
+
return rb_str_buf_new(0);
|
|
1041
|
+
}
|
|
1042
|
+
rb_raise(rb_eBrotli, "Decompressor is finished");
|
|
1043
|
+
}
|
|
535
1044
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
1045
|
+
StringValue(input);
|
|
1046
|
+
if (brotli_decompressor_needs_output_drain(br)) {
|
|
1047
|
+
if (RSTRING_LEN(input) > 0) {
|
|
1048
|
+
rb_raise(rb_eBrotli,
|
|
1049
|
+
"Decompressor cannot accept more data until pending output is drained");
|
|
1050
|
+
}
|
|
1051
|
+
if (brotli_decompressor_has_pending_input(br)) {
|
|
1052
|
+
input_source = br->pending_input;
|
|
1053
|
+
} else {
|
|
1054
|
+
input_source = input;
|
|
1055
|
+
}
|
|
1056
|
+
} else {
|
|
1057
|
+
input_source = input;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
if (input_source == br->pending_input) {
|
|
1061
|
+
available_in = brotli_decompressor_pending_input_length(br);
|
|
1062
|
+
next_in = (const uint8_t*)RSTRING_PTR(input_source);
|
|
1063
|
+
} else {
|
|
1064
|
+
available_in = (size_t)RSTRING_LEN(input_source);
|
|
1065
|
+
next_in = (const uint8_t*)RSTRING_PTR(input_source);
|
|
1066
|
+
brotli_decompressor_clear_pending_input(self, br);
|
|
1067
|
+
}
|
|
1068
|
+
br->needs_more_output = BROTLI_FALSE;
|
|
1069
|
+
output = rb_str_buf_new(BUFSIZ);
|
|
1070
|
+
|
|
1071
|
+
for (;;) {
|
|
1072
|
+
size_t chunk_size = BUFSIZ;
|
|
1073
|
+
brotli_decoder_args_t args;
|
|
1074
|
+
size_t produced;
|
|
1075
|
+
|
|
1076
|
+
if (limit_output) {
|
|
1077
|
+
size_t used = (size_t)RSTRING_LEN(output);
|
|
1078
|
+
if (used >= output_buffer_limit) {
|
|
1079
|
+
brotli_decompressor_store_pending_input(self, br, next_in, available_in);
|
|
1080
|
+
br->needs_more_output = BROTLI_TRUE;
|
|
1081
|
+
break;
|
|
1082
|
+
}
|
|
1083
|
+
if (output_buffer_limit - used < chunk_size) {
|
|
1084
|
+
chunk_size = output_buffer_limit - used;
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
542
1087
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
1088
|
+
args.state = br->state;
|
|
1089
|
+
args.available_in = available_in;
|
|
1090
|
+
args.next_in = next_in;
|
|
1091
|
+
args.available_out = chunk_size;
|
|
1092
|
+
args.next_out = outbuf;
|
|
1093
|
+
args.result = BROTLI_DECODER_RESULT_ERROR;
|
|
1094
|
+
brotli_decompressor_step(&args);
|
|
1095
|
+
available_in = args.available_in;
|
|
1096
|
+
next_in = args.next_in;
|
|
1097
|
+
result = args.result;
|
|
1098
|
+
|
|
1099
|
+
produced = chunk_size - args.available_out;
|
|
1100
|
+
if (produced > 0) {
|
|
1101
|
+
rb_str_cat(output, (const char*)outbuf, produced);
|
|
1102
|
+
}
|
|
547
1103
|
|
|
548
|
-
|
|
549
|
-
|
|
1104
|
+
if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
|
|
1105
|
+
if (limit_output && (size_t)RSTRING_LEN(output) >= output_buffer_limit) {
|
|
1106
|
+
brotli_decompressor_store_pending_input(self, br, next_in, available_in);
|
|
1107
|
+
br->needs_more_output = BROTLI_TRUE;
|
|
1108
|
+
break;
|
|
1109
|
+
}
|
|
1110
|
+
continue;
|
|
1111
|
+
}
|
|
1112
|
+
if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
|
|
1113
|
+
if (BrotliDecoderHasMoreOutput(br->state)) {
|
|
1114
|
+
continue;
|
|
1115
|
+
}
|
|
1116
|
+
brotli_decompressor_clear_pending_input(self, br);
|
|
1117
|
+
br->needs_more_output = BROTLI_FALSE;
|
|
1118
|
+
break;
|
|
1119
|
+
}
|
|
1120
|
+
if (result == BROTLI_DECODER_RESULT_SUCCESS) {
|
|
1121
|
+
br->finished = BROTLI_TRUE;
|
|
1122
|
+
brotli_decompressor_store_pending_input(self, br, next_in, available_in);
|
|
1123
|
+
br->needs_more_output = BROTLI_FALSE;
|
|
1124
|
+
break;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
rb_raise(rb_eBrotli, "%s",
|
|
1128
|
+
BrotliDecoderErrorString(BrotliDecoderGetErrorCode(br->state)));
|
|
550
1129
|
}
|
|
551
|
-
|
|
1130
|
+
|
|
1131
|
+
RB_GC_GUARD(input_source);
|
|
1132
|
+
return output;
|
|
552
1133
|
}
|
|
553
1134
|
|
|
554
|
-
static VALUE
|
|
555
|
-
|
|
556
|
-
|
|
1135
|
+
static VALUE
|
|
1136
|
+
rb_decompressor_is_finished(VALUE self)
|
|
1137
|
+
{
|
|
1138
|
+
brotli_decompressor_t *br;
|
|
1139
|
+
|
|
1140
|
+
TypedData_Get_Struct(self, brotli_decompressor_t, &brotli_decompressor_data_type, br);
|
|
1141
|
+
brotli_decompressor_ensure_open(br);
|
|
1142
|
+
|
|
1143
|
+
if (br->finished || BrotliDecoderIsFinished(br->state)) {
|
|
1144
|
+
br->finished = BROTLI_TRUE;
|
|
1145
|
+
return Qtrue;
|
|
1146
|
+
}
|
|
1147
|
+
return Qfalse;
|
|
1148
|
+
}
|
|
557
1149
|
|
|
558
|
-
|
|
1150
|
+
static VALUE
|
|
1151
|
+
rb_decompressor_can_accept_more_data(VALUE self)
|
|
1152
|
+
{
|
|
1153
|
+
brotli_decompressor_t *br;
|
|
1154
|
+
TypedData_Get_Struct(self, brotli_decompressor_t, &brotli_decompressor_data_type, br);
|
|
1155
|
+
brotli_decompressor_ensure_open(br);
|
|
1156
|
+
return (br->finished || brotli_decompressor_needs_output_drain(br)) ? Qfalse : Qtrue;
|
|
1157
|
+
}
|
|
559
1158
|
|
|
560
|
-
|
|
561
|
-
|
|
1159
|
+
static VALUE
|
|
1160
|
+
rb_decompressor_unused_data(VALUE self)
|
|
1161
|
+
{
|
|
1162
|
+
brotli_decompressor_t *br;
|
|
1163
|
+
size_t available_in;
|
|
1164
|
+
TypedData_Get_Struct(self, brotli_decompressor_t, &brotli_decompressor_data_type, br);
|
|
1165
|
+
brotli_decompressor_ensure_open(br);
|
|
1166
|
+
available_in = brotli_decompressor_pending_input_length(br);
|
|
1167
|
+
if (!br->finished || available_in == 0) {
|
|
1168
|
+
return rb_str_buf_new(0);
|
|
562
1169
|
}
|
|
563
|
-
return br->
|
|
1170
|
+
return rb_str_dup(br->pending_input);
|
|
564
1171
|
}
|
|
565
1172
|
|
|
566
1173
|
/*******************************************************************************
|
|
@@ -570,28 +1177,41 @@ static VALUE rb_writer_close(VALUE self) {
|
|
|
570
1177
|
void
|
|
571
1178
|
Init_brotli(void)
|
|
572
1179
|
{
|
|
573
|
-
#if HAVE_RB_EXT_RACTOR_SAFE
|
|
574
1180
|
rb_ext_ractor_safe(true);
|
|
575
|
-
#endif
|
|
576
1181
|
|
|
577
1182
|
VALUE rb_mBrotli;
|
|
578
|
-
VALUE rb_Writer;
|
|
579
1183
|
rb_mBrotli = rb_define_module("Brotli");
|
|
580
1184
|
rb_eBrotli = rb_define_class_under(rb_mBrotli, "Error", rb_eStandardError);
|
|
581
|
-
rb_global_variable(&rb_eBrotli);
|
|
582
1185
|
rb_define_singleton_method(rb_mBrotli, "deflate", brotli_deflate, -1);
|
|
583
1186
|
rb_define_singleton_method(rb_mBrotli, "inflate", brotli_inflate, -1);
|
|
584
1187
|
rb_define_singleton_method(rb_mBrotli, "version", brotli_version, 0);
|
|
1188
|
+
id_cmp = rb_intern("<=>");
|
|
1189
|
+
id_dictionary = rb_intern("dictionary");
|
|
1190
|
+
id_font = rb_intern("font");
|
|
1191
|
+
id_generic = rb_intern("generic");
|
|
1192
|
+
id_lgblock = rb_intern("lgblock");
|
|
1193
|
+
id_lgwin = rb_intern("lgwin");
|
|
1194
|
+
id_mode = rb_intern("mode");
|
|
1195
|
+
id_output_buffer_limit = rb_intern("output_buffer_limit");
|
|
1196
|
+
id_quality = rb_intern("quality");
|
|
585
1197
|
id_read = rb_intern("read");
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
rb_define_method(
|
|
593
|
-
rb_define_method(
|
|
594
|
-
rb_define_method(
|
|
595
|
-
|
|
596
|
-
|
|
1198
|
+
id_text = rb_intern("text");
|
|
1199
|
+
|
|
1200
|
+
rb_cBrotliCompressor = rb_define_class_under(rb_mBrotli, "Compressor", rb_cObject);
|
|
1201
|
+
rb_define_alloc_func(rb_cBrotliCompressor, rb_compressor_alloc);
|
|
1202
|
+
rb_define_method(rb_cBrotliCompressor, "initialize", rb_compressor_initialize, -1);
|
|
1203
|
+
rb_define_method(rb_cBrotliCompressor, "process", rb_compressor_process, 1);
|
|
1204
|
+
rb_define_method(rb_cBrotliCompressor, "flush", rb_compressor_flush, 0);
|
|
1205
|
+
rb_define_method(rb_cBrotliCompressor, "finish", rb_compressor_finish, 0);
|
|
1206
|
+
rb_define_method(rb_cBrotliCompressor, "finished?", rb_compressor_is_finished, 0);
|
|
1207
|
+
|
|
1208
|
+
rb_cBrotliDecompressor = rb_define_class_under(rb_mBrotli, "Decompressor", rb_cObject);
|
|
1209
|
+
rb_define_alloc_func(rb_cBrotliDecompressor, rb_decompressor_alloc);
|
|
1210
|
+
rb_define_method(rb_cBrotliDecompressor, "initialize", rb_decompressor_initialize, -1);
|
|
1211
|
+
rb_define_method(rb_cBrotliDecompressor, "process", rb_decompressor_process, -1);
|
|
1212
|
+
rb_define_method(rb_cBrotliDecompressor, "is_finished", rb_decompressor_is_finished, 0);
|
|
1213
|
+
rb_define_method(rb_cBrotliDecompressor, "finished?", rb_decompressor_is_finished, 0);
|
|
1214
|
+
rb_define_method(rb_cBrotliDecompressor, "can_accept_more_data", rb_decompressor_can_accept_more_data, 0);
|
|
1215
|
+
rb_define_method(rb_cBrotliDecompressor, "can_accept_more_data?", rb_decompressor_can_accept_more_data, 0);
|
|
1216
|
+
rb_define_method(rb_cBrotliDecompressor, "unused_data", rb_decompressor_unused_data, 0);
|
|
597
1217
|
}
|