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.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +28 -0
  3. data/README.md +67 -0
  4. data/Rakefile +158 -0
  5. data/contrib/brotli/LICENSE +202 -0
  6. data/contrib/brotli/README.md +18 -0
  7. data/contrib/brotli/dec/bit_reader.c +55 -0
  8. data/contrib/brotli/dec/bit_reader.h +256 -0
  9. data/contrib/brotli/dec/context.h +260 -0
  10. data/contrib/brotli/dec/decode.c +1573 -0
  11. data/contrib/brotli/dec/decode.h +160 -0
  12. data/contrib/brotli/dec/dictionary.h +9494 -0
  13. data/contrib/brotli/dec/huffman.c +325 -0
  14. data/contrib/brotli/dec/huffman.h +77 -0
  15. data/contrib/brotli/dec/port.h +148 -0
  16. data/contrib/brotli/dec/prefix.h +756 -0
  17. data/contrib/brotli/dec/state.c +149 -0
  18. data/contrib/brotli/dec/state.h +185 -0
  19. data/contrib/brotli/dec/streams.c +99 -0
  20. data/contrib/brotli/dec/streams.h +100 -0
  21. data/contrib/brotli/dec/transform.h +315 -0
  22. data/contrib/brotli/dec/types.h +36 -0
  23. data/contrib/brotli/enc/backward_references.cc +769 -0
  24. data/contrib/brotli/enc/backward_references.h +50 -0
  25. data/contrib/brotli/enc/bit_cost.h +147 -0
  26. data/contrib/brotli/enc/block_splitter.cc +418 -0
  27. data/contrib/brotli/enc/block_splitter.h +78 -0
  28. data/contrib/brotli/enc/brotli_bit_stream.cc +884 -0
  29. data/contrib/brotli/enc/brotli_bit_stream.h +149 -0
  30. data/contrib/brotli/enc/cluster.h +290 -0
  31. data/contrib/brotli/enc/command.h +140 -0
  32. data/contrib/brotli/enc/context.h +185 -0
  33. data/contrib/brotli/enc/dictionary.h +9485 -0
  34. data/contrib/brotli/enc/dictionary_hash.h +4125 -0
  35. data/contrib/brotli/enc/encode.cc +715 -0
  36. data/contrib/brotli/enc/encode.h +196 -0
  37. data/contrib/brotli/enc/encode_parallel.cc +354 -0
  38. data/contrib/brotli/enc/encode_parallel.h +37 -0
  39. data/contrib/brotli/enc/entropy_encode.cc +492 -0
  40. data/contrib/brotli/enc/entropy_encode.h +88 -0
  41. data/contrib/brotli/enc/fast_log.h +179 -0
  42. data/contrib/brotli/enc/find_match_length.h +87 -0
  43. data/contrib/brotli/enc/hash.h +686 -0
  44. data/contrib/brotli/enc/histogram.cc +76 -0
  45. data/contrib/brotli/enc/histogram.h +100 -0
  46. data/contrib/brotli/enc/literal_cost.cc +172 -0
  47. data/contrib/brotli/enc/literal_cost.h +38 -0
  48. data/contrib/brotli/enc/metablock.cc +544 -0
  49. data/contrib/brotli/enc/metablock.h +88 -0
  50. data/contrib/brotli/enc/port.h +151 -0
  51. data/contrib/brotli/enc/prefix.h +85 -0
  52. data/contrib/brotli/enc/ringbuffer.h +108 -0
  53. data/contrib/brotli/enc/static_dict.cc +441 -0
  54. data/contrib/brotli/enc/static_dict.h +40 -0
  55. data/contrib/brotli/enc/static_dict_lut.h +12063 -0
  56. data/contrib/brotli/enc/streams.cc +127 -0
  57. data/contrib/brotli/enc/streams.h +129 -0
  58. data/contrib/brotli/enc/transform.h +250 -0
  59. data/contrib/brotli/enc/write_bits.h +91 -0
  60. data/ext/extbrotli.cc +24 -0
  61. data/ext/extbrotli.h +73 -0
  62. data/ext/extconf.rb +35 -0
  63. data/ext/lldecoder.c +220 -0
  64. data/ext/llencoder.cc +433 -0
  65. data/gemstub.rb +21 -0
  66. data/lib/extbrotli.rb +243 -0
  67. data/lib/extbrotli/version.rb +3 -0
  68. metadata +140 -0
data/ext/llencoder.cc ADDED
@@ -0,0 +1,433 @@
1
+ #include "extbrotli.h"
2
+ #include <functional>
3
+ #include <brotli/enc/encode.h>
4
+
5
+ static inline size_t
6
+ aux_brotli_compress_bound(size_t srcsize)
7
+ {
8
+ return srcsize * 1.2 + 10240;
9
+ }
10
+
11
+ static inline size_t
12
+ rb_num2sizet(VALUE n)
13
+ {
14
+ #if SIZEOF_SIZE_T > SIZEOF_LONG && defined(SIZEOF_LONG_LONG)
15
+ return (size_t)NUM2ULL(n);
16
+ #else
17
+ return (size_t)NUM2ULONG(n);
18
+ #endif
19
+ }
20
+
21
+ static inline size_t
22
+ rb_num2ssizet(VALUE n)
23
+ {
24
+ #if SIZEOF_SIZE_T > SIZEOF_LONG && defined(SIZEOF_LONG_LONG)
25
+ return (ssize_t)NUM2LL(n);
26
+ #else
27
+ return (ssize_t)NUM2LONG(n);
28
+ #endif
29
+ }
30
+
31
+ struct aux_ruby_jump_tag
32
+ {
33
+ int tag;
34
+
35
+ aux_ruby_jump_tag(int tag) : tag(tag) { }
36
+
37
+ static void check_and_throw(int tag)
38
+ {
39
+ if (tag) {
40
+ throw aux_ruby_jump_tag(tag);
41
+ }
42
+ }
43
+ };
44
+
45
+ #if 0 && __cplusplus >= 201103L
46
+ static VALUE
47
+ aux_throw_ruby_exception_protected(VALUE pp)
48
+ {
49
+ const std::function<void ()> &func = *reinterpret_cast<const std::function<void (void)> *>(pp);
50
+ func();
51
+ return 0;
52
+ }
53
+
54
+ template <typename T>
55
+ static inline T
56
+ aux_throw_ruby_exception(const std::function<T (void)> &func)
57
+ {
58
+ int tag;
59
+ VALUE s;
60
+ const std::function<void (void)> lambda = [&] { s = func(); };
61
+ rb_protect(aux_throw_ruby_exception_protected, (VALUE)&lambda, &tag);
62
+ aux_ruby_jump_tag::check_and_throw(tag);
63
+ return s;
64
+ }
65
+
66
+ static inline void
67
+ aux_throw_ruby_exception(const std::function<void (void)> &func)
68
+ {
69
+ int tag;
70
+ const std::function<void (void)> lambda = [&] { func(); };
71
+ rb_protect(aux_throw_ruby_exception_protected, (VALUE)&lambda, &tag);
72
+ aux_ruby_jump_tag::check_and_throw(tag);
73
+ }
74
+
75
+ static inline void
76
+ aux_raise_stub(VALUE exc, const char *fmt, ...)
77
+ {
78
+ va_list args;
79
+ VALUE mesg;
80
+
81
+ va_start(args, fmt);
82
+ mesg = rb_vsprintf(fmt, args);
83
+ va_end(args);
84
+ throw rb_exc_new3(exc, mesg);
85
+ }
86
+
87
+ #define rb_check_type(...) \
88
+ aux_throw_ruby_exception([&] { rb_check_type(__VA_ARGS__); }) \
89
+
90
+ #define rb_str_buf_new(...) \
91
+ aux_throw_ruby_exception<VALUE>([&] { return rb_str_buf_new(__VA_ARGS__); }) \
92
+
93
+ #define rb_num2sizet(...) \
94
+ aux_throw_ruby_exception<size_t>([&] { return rb_num2sizet(__VA_ARGS__); }) \
95
+
96
+ #endif
97
+
98
+ static VALUE cLLEncoder;
99
+
100
+ using namespace std;
101
+ using namespace brotli;
102
+
103
+ static int
104
+ getoption_int(VALUE opts, ID key, int min, int max, int default_value)
105
+ {
106
+ VALUE v = rb_hash_lookup(opts, ID2SYM(key));
107
+ if (NIL_P(v)) { return default_value; }
108
+ int n = NUM2INT(v);
109
+ if (n >= min && (n <= max || max <= min)) { return n; }
110
+ if (max > min) {
111
+ rb_raise(rb_eArgError,
112
+ "option ``%s'' is out of range (%d for %d .. %d)",
113
+ rb_id2name(key), n, min, max);
114
+ } else {
115
+ rb_raise(rb_eArgError,
116
+ "option ``%s'' is out of range (%d for %d+)",
117
+ rb_id2name(key), n, min);
118
+ }
119
+ }
120
+
121
+ static void
122
+ setup_encode_params(VALUE opts, BrotliParams &params, VALUE &predict)
123
+ {
124
+ static const ID id_predict = rb_intern("predict");
125
+ static const ID id_mode = rb_intern("mode");
126
+ static const ID id_quality = rb_intern("quality");
127
+ static const ID id_lgwin = rb_intern("lgwin");
128
+ static const ID id_lgblock = rb_intern("lgblock");
129
+
130
+ if (NIL_P(opts)) {
131
+ predict = Qnil;
132
+ params.quality = 9; // FIXME: changed from 11 as constructor.
133
+ return;
134
+ }
135
+ rb_check_type(opts, RUBY_T_HASH);
136
+
137
+ predict = rb_hash_lookup(opts, ID2SYM(id_predict));
138
+ if (!NIL_P(predict)) { rb_check_type(predict, RUBY_T_STRING); }
139
+
140
+ params.mode = (BrotliParams::Mode)getoption_int(opts, id_mode, BrotliParams::MODE_GENERIC, BrotliParams::MODE_FONT, BrotliParams::MODE_GENERIC);
141
+ params.quality = getoption_int(opts, id_quality, 0, 11, 9);
142
+ params.lgwin = getoption_int(opts, id_lgwin, kMinWindowBits, kMaxWindowBits, 22);
143
+ params.lgblock = getoption_int(opts, id_lgblock, kMinInputBlockBits, kMaxInputBlockBits, 0);
144
+ }
145
+
146
+ static void
147
+ llenc_free(void *pp)
148
+ {
149
+ if (pp) {
150
+ BrotliCompressor *p = (BrotliCompressor *)pp;
151
+ delete p;
152
+ }
153
+ }
154
+
155
+ static const rb_data_type_t llencoder_type = {
156
+ /* .wrap_struct_name = */ "extbrotli.lowlevelencoder",
157
+ /* .function.dmark = */ NULL,
158
+ /* .function.dfree = */ llenc_free,
159
+ /* .function.dsize = */ NULL,
160
+ };
161
+
162
+ static inline BrotliCompressor *
163
+ getencoderp(VALUE obj)
164
+ {
165
+ return (BrotliCompressor *)getrefp(obj, &llencoder_type);
166
+ }
167
+
168
+ static inline BrotliCompressor *
169
+ getencoder(VALUE obj)
170
+ {
171
+ return (BrotliCompressor *)getref(obj, &llencoder_type);
172
+ }
173
+
174
+ static VALUE
175
+ llenc_alloc(VALUE mod)
176
+ {
177
+ return TypedData_Wrap_Struct(mod, &llencoder_type, NULL);
178
+ }
179
+
180
+ static void
181
+ llenc_init_args(int argc, VALUE argv[], BrotliParams &params, VALUE &predict)
182
+ {
183
+ VALUE opts;
184
+ rb_scan_args(argc, argv, "0:", &opts);
185
+ setup_encode_params(opts, params, predict);
186
+ }
187
+
188
+ /*
189
+ * call-seq:
190
+ * initialize(opts = {})
191
+ *
192
+ * [opts predict: nil] preset dictionary. string or nil
193
+ * [opts mode: 0] Brotli::MODE_GENERIC, Brotli::MODE_TEXT or Brotli::MODE_FONT
194
+ * [opts quality: 9] given 0 .. 11. lower is high speed, higher is high compression.
195
+ * [opts lgwin: 22] log window size. given 10 .. 24.
196
+ * [opts lgblock: nil] log block size. given 16 .. 24.
197
+ *
198
+ */
199
+ static VALUE
200
+ llenc_init(int argc, VALUE argv[], VALUE enc)
201
+ {
202
+ BrotliCompressor *p = getencoderp(enc);
203
+ if (p) { reiniterror(enc); }
204
+ try {
205
+ VALUE predict;
206
+ BrotliParams params;
207
+ llenc_init_args(argc, argv, params, predict);
208
+ rb_obj_infect(enc, predict);
209
+ DATA_PTR(enc) = p = new BrotliCompressor(params);
210
+ if (!NIL_P(predict)) {
211
+ p->BrotliSetCustomDictionary(RSTRING_LEN(predict), (const uint8_t *)RSTRING_PTR(predict));
212
+ }
213
+ } catch(...) {
214
+ rb_raise(eError, "C++ runtime error - #<%s:%p>", rb_obj_classname(enc), (void *)enc);
215
+ }
216
+ return enc;
217
+ }
218
+
219
+ /*
220
+ * call-seq:
221
+ * encode_metablock(src, dest, destsize, islast) -> dest
222
+ */
223
+ static VALUE
224
+ llenc_encode_metablock(VALUE enc, VALUE src, VALUE dest, VALUE destsize, VALUE islast)
225
+ {
226
+ BrotliCompressor *p = getencoder(enc);
227
+ rb_obj_infect(enc, src);
228
+ rb_check_type(src, RUBY_T_STRING);
229
+ rb_check_type(dest, RUBY_T_STRING);
230
+ rb_str_modify(dest);
231
+ rb_str_set_len(dest, 0);
232
+ size_t destsize1 = NUM2SIZET(destsize);
233
+ rb_str_modify_expand(dest, destsize1);
234
+ bool islast1 = RTEST(islast) ? true : false;
235
+ bool s = p->WriteMetaBlock(RSTRING_LEN(src), (const uint8_t *)RSTRING_PTR(src),
236
+ islast1, &destsize1, (uint8_t *)RSTRING_PTR(dest));
237
+ if (!s) {
238
+ rb_raise(eError,
239
+ "failed BrotliCompressor::WriteMetaBlock() - #<%s:%p>",
240
+ rb_obj_classname(enc), (void *)enc);
241
+ }
242
+ rb_obj_infect(dest, enc);
243
+ rb_str_set_len(dest, destsize1);
244
+ return dest;
245
+ }
246
+
247
+ /*
248
+ * call-seq:
249
+ * encode_metadata(src, dest, destsize, islast) -> dest
250
+ */
251
+ static VALUE
252
+ llenc_encode_metadata(VALUE enc, VALUE src, VALUE dest, VALUE destsize, VALUE islast)
253
+ {
254
+ BrotliCompressor *p = getencoder(enc);
255
+ rb_obj_infect(enc, src);
256
+ rb_check_type(src, RUBY_T_STRING);
257
+ rb_check_type(dest, RUBY_T_STRING);
258
+ rb_str_modify(dest);
259
+ rb_str_set_len(dest, 0);
260
+ size_t destsize1 = NUM2SIZET(destsize);
261
+ rb_str_modify_expand(dest, destsize1);
262
+ bool islast1 = RTEST(islast) ? true : false;
263
+ bool s = p->WriteMetadata(RSTRING_LEN(src), (const uint8_t *)RSTRING_PTR(src),
264
+ islast1, &destsize1, (uint8_t *)RSTRING_PTR(dest));
265
+ if (!s) {
266
+ rb_raise(eError,
267
+ "failed BrotliCompressor::WriteMetadata - #<%s:%p>",
268
+ rb_obj_classname(enc), (void *)enc);
269
+ }
270
+ rb_obj_infect(dest, enc);
271
+ rb_str_set_len(dest, destsize1);
272
+ return dest;
273
+ }
274
+
275
+ /*
276
+ * call-seq:
277
+ * finish(dest, destsize) -> dest
278
+ */
279
+ static VALUE
280
+ llenc_finish(VALUE enc, VALUE dest, VALUE destsize)
281
+ {
282
+ BrotliCompressor *p = getencoder(enc);
283
+ rb_check_type(dest, RUBY_T_STRING);
284
+ rb_str_modify(dest);
285
+ rb_str_set_len(dest, 0);
286
+ size_t destsize1 = NUM2SIZET(destsize);
287
+ rb_str_modify_expand(dest, destsize1);
288
+ bool s = p->FinishStream(&destsize1, (uint8_t *)RSTRING_PTR(dest));
289
+ if (!s) { rb_raise(eError, "failed BrotliCompressor::FinishStream - #<%s:%p>", rb_obj_classname(enc), (void *)enc); }
290
+ rb_obj_infect(dest, enc);
291
+ rb_str_set_len(dest, destsize1);
292
+ return dest;
293
+ }
294
+
295
+ /*
296
+ * call-seq:
297
+ * copy_to_ringbuffer(src) -> self
298
+ */
299
+ static VALUE
300
+ llenc_copy_to_ringbuffer(VALUE enc, VALUE src)
301
+ {
302
+ BrotliCompressor *p = getencoder(enc);
303
+ rb_obj_infect(enc, src);
304
+ rb_check_type(src, RUBY_T_STRING);
305
+ p->CopyInputToRingBuffer(RSTRING_LEN(src), (uint8_t *)RSTRING_PTR(src));
306
+ return enc;
307
+ }
308
+
309
+ /*
310
+ * call-seq:
311
+ * encode_brotlidata(dest, islast, forceflush) -> dest
312
+ */
313
+ static VALUE
314
+ llenc_encode_brotlidata(VALUE enc, VALUE dest, VALUE islast, VALUE forceflush)
315
+ {
316
+ BrotliCompressor *p = getencoder(enc);
317
+ rb_check_type(dest, RUBY_T_STRING);
318
+ rb_str_modify(dest);
319
+ rb_str_set_len(dest, 0);
320
+ size_t destsize = 0;
321
+ char *destp = NULL;
322
+ bool s = p->WriteBrotliData(RTEST(islast), RTEST(forceflush), &destsize, (uint8_t **)&destp);
323
+ if (!s) { rb_raise(eError, "failed BrotliCompressor::WriteBrotliData - #<%s:%p>", rb_obj_classname(enc), (void *)enc); }
324
+ rb_str_modify_expand(dest, destsize);
325
+ memcpy(RSTRING_PTR(dest), destp, destsize);
326
+ rb_obj_infect(dest, enc);
327
+ rb_str_set_len(dest, destsize);
328
+ return dest;
329
+ }
330
+
331
+ static VALUE
332
+ llenc_blocksize(VALUE enc)
333
+ {
334
+ return SIZET2NUM(getencoder(enc)->input_block_size());
335
+ }
336
+
337
+ static inline void
338
+ llenc_s_encode_args(int argc, VALUE argv[], VALUE &src, size_t &srcsize, VALUE &dest, size_t &destsize, VALUE &predict, BrotliParams &params)
339
+ {
340
+ VALUE opts, u, v;
341
+ switch (rb_scan_args(argc, argv, "12:", &src, &u, &v, &opts)) {
342
+ case 1:
343
+ rb_check_type(src, RUBY_T_STRING);
344
+ srcsize = RSTRING_LEN(src);
345
+ destsize = aux_brotli_compress_bound(srcsize);
346
+ dest = rb_str_buf_new(destsize);
347
+ break;
348
+ case 2:
349
+ rb_check_type(src, RUBY_T_STRING);
350
+ srcsize = RSTRING_LEN(src);
351
+ if (rb_type_p(u, RUBY_T_STRING)) {
352
+ destsize = aux_brotli_compress_bound(srcsize);
353
+ rb_check_type(dest = u, RUBY_T_STRING);
354
+ rb_str_modify(dest);
355
+ rb_str_set_len(dest, 0);
356
+ rb_str_modify_expand(dest, destsize);
357
+ } else {
358
+ destsize = rb_num2sizet(u);
359
+ dest = rb_str_buf_new(destsize);
360
+ }
361
+ break;
362
+ case 3:
363
+ rb_check_type(src, RUBY_T_STRING);
364
+ srcsize = RSTRING_LEN(src);
365
+ destsize = rb_num2sizet(u);
366
+ rb_check_type(dest = v, RUBY_T_STRING);
367
+ rb_str_modify(dest);
368
+ rb_str_set_len(dest, 0);
369
+ rb_str_modify_expand(dest, destsize);
370
+ break;
371
+ default:
372
+ rb_error_arity(argc, 1, 3);
373
+ }
374
+
375
+ setup_encode_params(opts, params, predict);
376
+ }
377
+
378
+ /*
379
+ * call-seq:
380
+ * encode(src, dest = "", predict: nil, mode: 0, quality: 9, lgwin: 22, lgblock: nil) -> encoded binary string
381
+ * encode(src, destsize, dest = "", predict: nil, mode: 0, quality: 9, lgwin: 22, lgblock: nil) -> encoded binary string
382
+ */
383
+ static VALUE
384
+ llenc_s_encode(int argc, VALUE argv[], VALUE br)
385
+ {
386
+ try {
387
+ VALUE src, dest, predict;
388
+ size_t srcsize, destsize;
389
+ BrotliParams params;
390
+ llenc_s_encode_args(argc, argv, src, srcsize, dest, destsize, predict, params);
391
+
392
+ const uint8_t *srcp = reinterpret_cast<const uint8_t *>(RSTRING_PTR(src));
393
+ uint8_t *destp = reinterpret_cast<uint8_t *>(RSTRING_PTR(dest));
394
+ int st = BrotliCompressBuffer(params, srcsize, srcp, &destsize, destp);
395
+ if (!st) {
396
+ rb_raise(eError, "failed BrotliCompressBuffer() (status=%d)", st);
397
+ }
398
+ rb_obj_infect(dest, src);
399
+ rb_str_set_len(dest, destsize);
400
+ return dest;
401
+ } catch(VALUE e) {
402
+ rb_exc_raise(e);
403
+ } catch(aux_ruby_jump_tag e) {
404
+ rb_jump_tag(e.tag);
405
+ } catch(...) {
406
+ rb_raise(eError, "C++ runtime error");
407
+ }
408
+ }
409
+
410
+ static VALUE
411
+ llenc_s_compress_bound(VALUE mod, VALUE size)
412
+ {
413
+ return SIZET2NUM(aux_brotli_compress_bound(NUM2SIZET(size)));
414
+ }
415
+
416
+ void
417
+ extbrotli_init_lowlevelencoder(void)
418
+ {
419
+ cLLEncoder = rb_define_class_under(mBrotli, "LowLevelEncoder", rb_cObject);
420
+ rb_define_singleton_method(cLLEncoder, "encode", RUBY_METHOD_FUNC(llenc_s_encode), -1);
421
+ rb_define_singleton_method(cLLEncoder, "compress_bound", RUBY_METHOD_FUNC(llenc_s_compress_bound), 1);
422
+
423
+ rb_define_alloc_func(cLLEncoder, llenc_alloc);
424
+ rb_define_method(cLLEncoder, "initialize", RUBY_METHOD_FUNC(llenc_init), -1);
425
+ rb_define_method(cLLEncoder, "encode_metablock", RUBY_METHOD_FUNC(llenc_encode_metablock), 4);
426
+ rb_define_method(cLLEncoder, "encode_metadata", RUBY_METHOD_FUNC(llenc_encode_metadata), 4);
427
+ rb_define_method(cLLEncoder, "finish", RUBY_METHOD_FUNC(llenc_finish), 2);
428
+ rb_define_method(cLLEncoder, "copy_to_ringbuffer", RUBY_METHOD_FUNC(llenc_copy_to_ringbuffer), 1);
429
+ rb_define_method(cLLEncoder, "encode_brotlidata", RUBY_METHOD_FUNC(llenc_encode_brotlidata), 3);
430
+ rb_define_method(cLLEncoder, "blocksize", RUBY_METHOD_FUNC(llenc_blocksize), 0);
431
+
432
+ rb_include_module(cLLEncoder, mConst);
433
+ }
data/gemstub.rb ADDED
@@ -0,0 +1,21 @@
1
+ #vim: set fileencoding:utf-8
2
+
3
+ require_relative "lib/extbrotli/version"
4
+
5
+ GEMSTUB = Gem::Specification.new do |s|
6
+ s.name = "extbrotli"
7
+ s.version = Brotli::VERSION
8
+ s.summary = "ruby bindings for brotli"
9
+ s.description = <<EOS
10
+ unofficial ruby bindings for brotli <https://github.com/google/brotli> the compression library.
11
+ EOS
12
+ s.homepage = "https://osdn.jp/projects/rutsubo/"
13
+ s.license = "2-clause BSD License"
14
+ s.author = "dearblue"
15
+ s.email = "dearblue@users.osdn.me"
16
+
17
+ s.required_ruby_version = ">= 2.0"
18
+ s.add_development_dependency "rake", "~> 10.0"
19
+ end
20
+
21
+ EXTRA.concat(FileList["contrib/brotli/{LICENSE,README.md,{enc,dec}/**/*.{h,hh,hxx,hpp,c,cc,cxx,cpp,C}}"])