brotli 0.2.3 → 0.5.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.
Files changed (124) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +37 -0
  3. data/.github/workflows/publish.yml +24 -0
  4. data/.gitmodules +1 -1
  5. data/Gemfile +6 -3
  6. data/README.md +2 -2
  7. data/Rakefile +16 -9
  8. data/brotli.gemspec +7 -13
  9. data/ext/brotli/brotli.c +210 -31
  10. data/ext/brotli/buffer.c +1 -7
  11. data/ext/brotli/buffer.h +1 -1
  12. data/ext/brotli/extconf.rb +25 -17
  13. data/lib/brotli/version.rb +1 -1
  14. data/test/brotli_test.rb +107 -0
  15. data/test/brotli_writer_test.rb +36 -0
  16. data/test/test_helper.rb +8 -0
  17. data/vendor/brotli/c/common/constants.c +15 -0
  18. data/vendor/brotli/c/common/constants.h +137 -0
  19. data/vendor/brotli/c/common/context.c +156 -0
  20. data/vendor/brotli/c/common/context.h +4 -152
  21. data/vendor/brotli/c/common/dictionary.bin.br +0 -0
  22. data/vendor/brotli/c/common/dictionary.c +14 -3
  23. data/vendor/brotli/c/common/platform.c +23 -0
  24. data/vendor/brotli/c/common/platform.h +95 -122
  25. data/vendor/brotli/c/common/shared_dictionary.c +521 -0
  26. data/vendor/brotli/c/common/shared_dictionary_internal.h +75 -0
  27. data/vendor/brotli/c/common/transform.c +60 -4
  28. data/vendor/brotli/c/common/transform.h +5 -0
  29. data/vendor/brotli/c/common/version.h +31 -6
  30. data/vendor/brotli/c/dec/bit_reader.c +34 -4
  31. data/vendor/brotli/c/dec/bit_reader.h +221 -107
  32. data/vendor/brotli/c/dec/decode.c +772 -403
  33. data/vendor/brotli/c/dec/huffman.c +7 -4
  34. data/vendor/brotli/c/dec/huffman.h +8 -13
  35. data/vendor/brotli/c/dec/prefix.h +1 -18
  36. data/vendor/brotli/c/dec/state.c +40 -21
  37. data/vendor/brotli/c/dec/state.h +201 -59
  38. data/vendor/brotli/c/enc/backward_references.c +88 -25
  39. data/vendor/brotli/c/enc/backward_references.h +10 -8
  40. data/vendor/brotli/c/enc/backward_references_hq.c +194 -80
  41. data/vendor/brotli/c/enc/backward_references_hq.h +17 -13
  42. data/vendor/brotli/c/enc/backward_references_inc.h +52 -16
  43. data/vendor/brotli/c/enc/bit_cost.c +8 -7
  44. data/vendor/brotli/c/enc/bit_cost.h +5 -4
  45. data/vendor/brotli/c/enc/block_splitter.c +40 -17
  46. data/vendor/brotli/c/enc/block_splitter.h +5 -4
  47. data/vendor/brotli/c/enc/block_splitter_inc.h +99 -49
  48. data/vendor/brotli/c/enc/brotli_bit_stream.c +142 -137
  49. data/vendor/brotli/c/enc/brotli_bit_stream.h +11 -6
  50. data/vendor/brotli/c/enc/cluster.c +10 -9
  51. data/vendor/brotli/c/enc/cluster.h +7 -6
  52. data/vendor/brotli/c/enc/cluster_inc.h +30 -22
  53. data/vendor/brotli/c/enc/command.c +28 -0
  54. data/vendor/brotli/c/enc/command.h +17 -16
  55. data/vendor/brotli/c/enc/compound_dictionary.c +207 -0
  56. data/vendor/brotli/c/enc/compound_dictionary.h +74 -0
  57. data/vendor/brotli/c/enc/compress_fragment.c +93 -83
  58. data/vendor/brotli/c/enc/compress_fragment.h +32 -7
  59. data/vendor/brotli/c/enc/compress_fragment_two_pass.c +100 -88
  60. data/vendor/brotli/c/enc/compress_fragment_two_pass.h +21 -3
  61. data/vendor/brotli/c/enc/dictionary_hash.c +1829 -1101
  62. data/vendor/brotli/c/enc/dictionary_hash.h +2 -1
  63. data/vendor/brotli/c/enc/encode.c +550 -416
  64. data/vendor/brotli/c/enc/encoder_dict.c +613 -5
  65. data/vendor/brotli/c/enc/encoder_dict.h +120 -4
  66. data/vendor/brotli/c/enc/entropy_encode.c +5 -2
  67. data/vendor/brotli/c/enc/entropy_encode.h +4 -3
  68. data/vendor/brotli/c/enc/entropy_encode_static.h +5 -2
  69. data/vendor/brotli/c/enc/fast_log.c +105 -0
  70. data/vendor/brotli/c/enc/fast_log.h +21 -101
  71. data/vendor/brotli/c/enc/find_match_length.h +17 -25
  72. data/vendor/brotli/c/enc/hash.h +350 -120
  73. data/vendor/brotli/c/enc/hash_composite_inc.h +71 -67
  74. data/vendor/brotli/c/enc/hash_forgetful_chain_inc.h +92 -51
  75. data/vendor/brotli/c/enc/hash_longest_match64_inc.h +79 -84
  76. data/vendor/brotli/c/enc/hash_longest_match_inc.h +53 -54
  77. data/vendor/brotli/c/enc/hash_longest_match_quickly_inc.h +93 -62
  78. data/vendor/brotli/c/enc/hash_rolling_inc.h +25 -29
  79. data/vendor/brotli/c/enc/hash_to_binary_tree_inc.h +42 -40
  80. data/vendor/brotli/c/enc/histogram.c +4 -4
  81. data/vendor/brotli/c/enc/histogram.h +7 -6
  82. data/vendor/brotli/c/enc/literal_cost.c +20 -15
  83. data/vendor/brotli/c/enc/literal_cost.h +4 -2
  84. data/vendor/brotli/c/enc/memory.c +29 -5
  85. data/vendor/brotli/c/enc/memory.h +43 -14
  86. data/vendor/brotli/c/enc/metablock.c +95 -85
  87. data/vendor/brotli/c/enc/metablock.h +9 -8
  88. data/vendor/brotli/c/enc/metablock_inc.h +9 -7
  89. data/vendor/brotli/c/enc/params.h +7 -4
  90. data/vendor/brotli/c/enc/prefix.h +3 -2
  91. data/vendor/brotli/c/enc/quality.h +40 -3
  92. data/vendor/brotli/c/enc/ringbuffer.h +8 -4
  93. data/vendor/brotli/c/enc/state.h +104 -0
  94. data/vendor/brotli/c/enc/static_dict.c +60 -4
  95. data/vendor/brotli/c/enc/static_dict.h +3 -2
  96. data/vendor/brotli/c/enc/static_dict_lut.h +2 -0
  97. data/vendor/brotli/c/enc/utf8_util.c +2 -2
  98. data/vendor/brotli/c/enc/utf8_util.h +2 -1
  99. data/vendor/brotli/c/enc/write_bits.h +29 -26
  100. data/vendor/brotli/c/include/brotli/decode.h +67 -2
  101. data/vendor/brotli/c/include/brotli/encode.h +77 -3
  102. data/vendor/brotli/c/include/brotli/port.h +34 -3
  103. data/vendor/brotli/c/include/brotli/shared_dictionary.h +100 -0
  104. metadata +23 -97
  105. data/.travis.yml +0 -31
  106. data/docs/Brotli/Error.html +0 -124
  107. data/docs/Brotli.html +0 -485
  108. data/docs/_index.html +0 -122
  109. data/docs/class_list.html +0 -51
  110. data/docs/css/common.css +0 -1
  111. data/docs/css/full_list.css +0 -58
  112. data/docs/css/style.css +0 -496
  113. data/docs/file.README.html +0 -127
  114. data/docs/file_list.html +0 -56
  115. data/docs/frames.html +0 -17
  116. data/docs/index.html +0 -127
  117. data/docs/js/app.js +0 -292
  118. data/docs/js/full_list.js +0 -216
  119. data/docs/js/jquery.js +0 -4
  120. data/docs/method_list.html +0 -67
  121. data/docs/top-level-namespace.html +0 -110
  122. data/spec/brotli_spec.rb +0 -88
  123. data/spec/inflate_spec.rb +0 -75
  124. data/spec/spec_helper.rb +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab7474a5a27fb0167098bc9838f8e57bc78082d596c5e38a7c86764fdf62bf13
4
- data.tar.gz: 5a0b4d731bfd0fdbdd19a2cec36973cfc04460237acf58ac03dda51e8da82fe1
3
+ metadata.gz: 97953895465e26d5937e5959f86954aa58de2d2221301bc64ff639e682565605
4
+ data.tar.gz: 4f26bccb546a19c743eea5b0fd9207f8e623bfd73f05e08f3dae275b76c51482
5
5
  SHA512:
6
- metadata.gz: ae940a4cb85d44b0ad84a01fde9e8aaf285366dfcbccca4ba68619966005e1f003046de298b5d69098a4d3fcfd2a020ef49fa6eb5a3a0c790f59cd3060138bb6
7
- data.tar.gz: 92b9e926ad5b98f4afc7522c0b7a1a7490f32ed474d0881643f09ae8747ada70f25aa77360dc4707c369c6e58bfa747fc0eca7efb8cc05ee2f752e802202b017
6
+ metadata.gz: b5e79aee2804a948da509247c56b1f79e9248927ec6430319b1d2b6202973ed41bca1ceba215f8d4954ad98a52637a91e49bfa316af4ab3d35fcb779f0e94aa3
7
+ data.tar.gz: 46d42e9297f79aef7481b068e43da47c60d45b0f781a0ceb1fc7626cdb9c59bc306feaab0b05321cba17e23256e492814f340725db8fb21dc9e4c84198507bf5
@@ -0,0 +1,37 @@
1
+ name: Ruby
2
+
3
+ on: [pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ strategy:
8
+ fail-fast: false
9
+ matrix:
10
+ ruby: [2.7, 3.1, 3.2, 3.3]
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ with:
15
+ submodules: true
16
+ - name: Set up Ruby
17
+ uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: ${{ matrix.ruby }}
20
+ bundler-cache: true
21
+ - name: Run the default task
22
+ run: |
23
+ bundle exec rake clobber
24
+ bundle exec rake compile -- --enable-vendor
25
+ bundle exec rake test
26
+ bundle exec rake build
27
+ gem install --no-document "$(ls pkg/brotli-*.gem)"
28
+ cat <<EOF | ruby
29
+ require "brotli"
30
+ if Brotli.inflate(Brotli.deflate(File.read("README.md"))) == File.read("README.md")
31
+ puts "OK"
32
+ exit 0
33
+ else
34
+ puts "NG"
35
+ exit 0
36
+ end
37
+ EOF
@@ -0,0 +1,24 @@
1
+ name: Publish Gem
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ jobs:
9
+ build:
10
+ if: github.repository == 'miyucy/brotli'
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ contents: write
14
+ id-token: write
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ with:
18
+ submodules: true
19
+ - name: Set up Ruby
20
+ uses: ruby/setup-ruby@v1
21
+ with:
22
+ ruby-version: ruby
23
+ bundler-cache: true
24
+ - uses: rubygems/release-gem@v1
data/.gitmodules CHANGED
@@ -1,3 +1,3 @@
1
1
  [submodule "vendor/brotli"]
2
2
  path = vendor/brotli
3
- url = git://github.com/google/brotli.git
3
+ url = https://github.com/google/brotli.git
data/Gemfile CHANGED
@@ -1,7 +1,10 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in brotli.gemspec
4
4
  gemspec
5
5
 
6
- gem 'travis'
7
- gem 'yard'
6
+ gem "rake", "~> 13.0"
7
+ gem "rake-compiler"
8
+ gem "test-unit", "~> 3.0"
9
+ gem "test-unit-rr"
10
+ gem "rantly"
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Brotli [![](https://travis-ci.org/miyucy/brotli.svg)](https://travis-ci.org/miyucy/brotli)
1
+ # Brotli
2
2
 
3
3
  Brotli is a Ruby implementation of the Brotli generic-purpose lossless
4
4
  compression algorithm that compresses data using a combination of a modern
@@ -31,7 +31,7 @@ compressed = Brotli.deflate(string)
31
31
  decompressed = Brotli.inflate(compressed)
32
32
  ```
33
33
 
34
- See spec/brotli_spec.rb
34
+ See test/brotli_test.rb
35
35
 
36
36
  ## Development
37
37
 
data/Rakefile CHANGED
@@ -1,18 +1,25 @@
1
+ require "bundler/setup"
1
2
  require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
+ require "rake/clean"
4
+ require "rake/testtask"
3
5
  require "rake/extensiontask"
4
- require "yard"
5
6
 
6
- RSpec::Core::RakeTask.new(:spec)
7
+ CLEAN.include("ext/brotli/common")
8
+ CLEAN.include("ext/brotli/dec")
9
+ CLEAN.include("ext/brotli/enc")
10
+ CLEAN.include("ext/brotli/include")
7
11
 
8
- task :default => [:compile, :spec]
9
-
10
- task :build => :compile
12
+ Rake::TestTask.new(:test) do |t|
13
+ t.libs << "test"
14
+ t.test_files = FileList["test/**/*_test.rb"]
15
+ t.warning = true
16
+ t.verbose = true
17
+ end
11
18
 
12
19
  Rake::ExtensionTask.new("brotli") do |ext|
13
20
  ext.lib_dir = "lib/brotli"
14
21
  end
15
22
 
16
- YARD::Rake::YardocTask.new do |t|
17
- t.options = ["--no-progress", "--output-dir", "docs"]
18
- end
23
+ task :build => :compile
24
+ task :test => :compile
25
+ task :default => :test
data/brotli.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  # coding: utf-8
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'brotli/version'
4
+ require "brotli/version"
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "brotli"
@@ -9,25 +9,19 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["miyucy"]
10
10
  spec.email = ["fistfvck@gmail.com"]
11
11
 
12
- spec.summary = %q{Brotli compressor/decompressor}
13
- spec.description = %q{Brotli compressor/decompressor}
12
+ spec.summary = "Brotli compressor/decompressor"
13
+ spec.description = "Brotli compressor/decompressor"
14
14
  spec.homepage = "https://github.com/miyucy/brotli"
15
15
  spec.license = "MIT"
16
16
 
17
- spec.test_files = `git ls-files -z -- spec`.split("\x0")
17
+ spec.test_files = `git ls-files -z -- test`.split("\x0")
18
18
  spec.files = `git ls-files -z`.split("\x0")
19
19
  spec.files -= spec.test_files
20
- spec.files -= ['vendor/brotli']
21
- spec.files += Dir['vendor/brotli/c/{common,enc,dec,include}/**/*']
22
- spec.files += ['vendor/brotli/LICENSE']
20
+ spec.files -= ["vendor/brotli"]
21
+ spec.files += Dir["vendor/brotli/c/{common,enc,dec,include}/**/*"]
22
+ spec.files += ["vendor/brotli/LICENSE"]
23
23
  spec.bindir = "exe"
24
24
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
25
  spec.require_paths = ["lib"]
26
26
  spec.extensions = ["ext/brotli/extconf.rb"]
27
-
28
- spec.add_development_dependency "bundler"
29
- spec.add_development_dependency "rake"
30
- spec.add_development_dependency "rake-compiler"
31
- spec.add_development_dependency "rspec"
32
- spec.add_development_dependency "rantly"
33
27
  end
data/ext/brotli/brotli.c CHANGED
@@ -2,20 +2,19 @@
2
2
 
3
3
  #define CSTR2SYM(x) ID2SYM(rb_intern(x))
4
4
 
5
- static VALUE rb_mBrotli;
6
5
  static VALUE rb_eBrotli;
7
6
 
8
- static void*
7
+ static inline void*
9
8
  brotli_alloc(void* opaque, size_t size)
10
9
  {
11
- return malloc(size);
10
+ return ruby_xmalloc(size);
12
11
  }
13
12
 
14
- static void
13
+ static inline void
15
14
  brotli_free(void* opaque, void* address)
16
15
  {
17
16
  if (address) {
18
- free(address);
17
+ ruby_xfree(address);
19
18
  }
20
19
  }
21
20
 
@@ -138,11 +137,10 @@ brotli_deflate_set_mode(BrotliEncoderState* s, VALUE value)
138
137
  static void
139
138
  brotli_deflate_set_quality(BrotliEncoderState* s, VALUE value)
140
139
  {
141
- uint32_t param;
142
140
  if (NIL_P(value)) {
143
141
  return;
144
142
  } else {
145
- param = NUM2INT(value);
143
+ int32_t param = NUM2INT(value);
146
144
  if (0 <= param && param <= 11) {
147
145
  BrotliEncoderSetParameter(s, BROTLI_PARAM_QUALITY, param);
148
146
  } else {
@@ -154,11 +152,10 @@ brotli_deflate_set_quality(BrotliEncoderState* s, VALUE value)
154
152
  static void
155
153
  brotli_deflate_set_lgwin(BrotliEncoderState* s, VALUE value)
156
154
  {
157
- uint32_t param;
158
155
  if (NIL_P(value)) {
159
156
  return;
160
157
  } else {
161
- param = NUM2INT(value);
158
+ int32_t param = NUM2INT(value);
162
159
  if (10 <= param && param <= 24) {
163
160
  BrotliEncoderSetParameter(s, BROTLI_PARAM_LGWIN, param);
164
161
  } else {
@@ -170,11 +167,10 @@ brotli_deflate_set_lgwin(BrotliEncoderState* s, VALUE value)
170
167
  static void
171
168
  brotli_deflate_set_lgblock(BrotliEncoderState* s, VALUE value)
172
169
  {
173
- uint32_t param;
174
170
  if (NIL_P(value)) {
175
171
  return;
176
172
  } else {
177
- param = NUM2INT(value);
173
+ int32_t param = NUM2INT(value);
178
174
  if ((param == 0) || (16 <= param && param <= 24)) {
179
175
  BrotliEncoderSetParameter(s, BROTLI_PARAM_LGBLOCK, param);
180
176
  } else {
@@ -187,6 +183,7 @@ static BrotliEncoderState*
187
183
  brotli_deflate_parse_options(BrotliEncoderState* s, VALUE opts)
188
184
  {
189
185
  if (!NIL_P(opts)) {
186
+ Check_Type(opts, T_HASH);
190
187
  brotli_deflate_set_mode(s, rb_hash_aref(opts, CSTR2SYM("mode")));
191
188
  brotli_deflate_set_quality(s, rb_hash_aref(opts, CSTR2SYM("quality")));
192
189
  brotli_deflate_set_lgwin(s, rb_hash_aref(opts, CSTR2SYM("lgwin")));
@@ -241,26 +238,6 @@ brotli_deflate_no_gvl(void *arg)
241
238
  return arg;
242
239
  }
243
240
 
244
- /*
245
- * call-seq:
246
- * Brotli.deflate(str, opts=nil) -> String
247
- * @param [String] str
248
- * string
249
- * @param [Hash] opts
250
- * options
251
- * @option opts [Symbol] :mode
252
- * Deflate mode
253
- * * :generic
254
- * * :text
255
- * * :font
256
- * @option opts [Integer] :quality
257
- * quality 0-11
258
- * @option opts [Integer] :lgwin
259
- * lgwin 10-24
260
- * @option opts [Integer] :lgblock
261
- * lgblock 16-24 or 0
262
- * @return [String] Deflated string
263
- */
264
241
  static VALUE
265
242
  brotli_deflate(int argc, VALUE *argv, VALUE self)
266
243
  {
@@ -268,6 +245,10 @@ brotli_deflate(int argc, VALUE *argv, VALUE self)
268
245
  brotli_deflate_args_t args;
269
246
 
270
247
  rb_scan_args(argc, argv, "11", &str, &opts);
248
+ if (NIL_P(str)) {
249
+ rb_raise(rb_eArgError, "input should not be nil");
250
+ return Qnil;
251
+ }
271
252
  StringValue(str);
272
253
 
273
254
  args.str = (uint8_t*)RSTRING_PTR(str);
@@ -293,6 +274,185 @@ brotli_deflate(int argc, VALUE *argv, VALUE self)
293
274
  return value;
294
275
  }
295
276
 
277
+ /*******************************************************************************
278
+ * version
279
+ ******************************************************************************/
280
+
281
+ static VALUE brotli_version(VALUE klass) {
282
+ uint32_t ver = BrotliEncoderVersion();
283
+ char version[255];
284
+ snprintf(version, sizeof(version), "%u.%u.%u", ver >> 24, (ver >> 12) & 0xFFF, ver & 0xFFF);
285
+ return rb_str_new2(version);
286
+ }
287
+
288
+ /*******************************************************************************
289
+ * Writer
290
+ ******************************************************************************/
291
+
292
+ static ID id_write, id_flush, id_close;
293
+
294
+ struct brotli {
295
+ VALUE io;
296
+ BrotliEncoderState* state;
297
+ };
298
+
299
+ static void br_mark(void *p)
300
+ {
301
+ struct brotli *br = p;
302
+ rb_gc_mark(br->io);
303
+ }
304
+
305
+ static void br_free(void *p)
306
+ {
307
+ struct brotli* br = p;
308
+ BrotliEncoderDestroyInstance(br->state);
309
+ br->state = NULL;
310
+ br->io = Qnil;
311
+ ruby_xfree(br);
312
+ }
313
+
314
+ static size_t br_memsize(const void *p)
315
+ {
316
+ return sizeof(struct brotli);
317
+ }
318
+
319
+ static const rb_data_type_t brotli_data_type = {
320
+ "brotli",
321
+ { br_mark, br_free, br_memsize },
322
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
323
+ };
324
+
325
+ typedef struct {
326
+ BrotliEncoderState* state;
327
+ BrotliEncoderOperation op;
328
+ size_t available_in;
329
+ const uint8_t* next_in;
330
+ } brotli_encoder_args_t;
331
+
332
+ static void* compress_no_gvl(void *ptr) {
333
+ brotli_encoder_args_t *args = ptr;
334
+ size_t zero = 0;
335
+ if (!BrotliEncoderCompressStream(args->state, args->op,
336
+ &args->available_in, &args->next_in,
337
+ &zero, NULL, NULL)) {
338
+ rb_raise(rb_eBrotli, "BrotliEncoderCompressStream failed");
339
+ }
340
+ return NULL;
341
+ }
342
+
343
+ static size_t push_output(struct brotli *br) {
344
+ size_t len = 0;
345
+ if (BrotliEncoderHasMoreOutput(br->state)) {
346
+ const uint8_t* out = BrotliEncoderTakeOutput(br->state, &len);
347
+ if (len > 0) {
348
+ rb_funcall(br->io, id_write, 1, rb_str_new((const char*)out, len));
349
+ }
350
+ }
351
+ return len;
352
+ }
353
+
354
+ static VALUE rb_writer_alloc(VALUE klass) {
355
+ struct brotli *br;
356
+ VALUE obj = TypedData_Make_Struct(klass, struct brotli, &brotli_data_type, br);
357
+ br->io = Qnil;
358
+ br->state = BrotliEncoderCreateInstance(brotli_alloc, brotli_free, NULL);
359
+ if (!br->state) {
360
+ rb_raise(rb_eNoMemError, "BrotliEncoderCreateInstance failed");
361
+ return Qnil;
362
+ }
363
+ return obj;
364
+ }
365
+
366
+ static VALUE rb_writer_initialize(int argc, VALUE* argv, VALUE self) {
367
+ VALUE io = Qnil;
368
+ VALUE opts = Qnil;
369
+ rb_scan_args(argc, argv, "11", &io, &opts);
370
+ if (NIL_P(io)) {
371
+ rb_raise(rb_eArgError, "io should not be nil");
372
+ return Qnil;
373
+ }
374
+
375
+ struct brotli *br;
376
+ TypedData_Get_Struct(self, struct brotli, &brotli_data_type, br);
377
+ brotli_deflate_parse_options(br->state, opts);
378
+ br->io = io;
379
+ return self;
380
+ }
381
+
382
+ static VALUE rb_writer_write(VALUE self, VALUE buf) {
383
+ struct brotli* br;
384
+ TypedData_Get_Struct(self, struct brotli, &brotli_data_type, br);
385
+ StringValue(buf);
386
+
387
+ const size_t total = (size_t)RSTRING_LEN(buf);
388
+
389
+ brotli_encoder_args_t args = {
390
+ .state = br->state,
391
+ .op = BROTLI_OPERATION_PROCESS,
392
+ .available_in = total,
393
+ .next_in = (uint8_t*)RSTRING_PTR(buf)
394
+ };
395
+
396
+ while (args.available_in > 0) {
397
+ rb_thread_call_without_gvl(compress_no_gvl, (void*)&args, NULL, NULL);
398
+ push_output(br);
399
+ }
400
+
401
+ return SIZET2NUM(total);
402
+ }
403
+
404
+ static VALUE rb_writer_finish(VALUE self) {
405
+ struct brotli* br;
406
+ TypedData_Get_Struct(self, struct brotli, &brotli_data_type, br);
407
+
408
+ brotli_encoder_args_t args = {
409
+ .state = br->state,
410
+ .op = BROTLI_OPERATION_FINISH,
411
+ .available_in = 0,
412
+ .next_in = NULL
413
+ };
414
+
415
+ while (!BrotliEncoderIsFinished(br->state)) {
416
+ rb_thread_call_without_gvl(compress_no_gvl, (void*)&args, NULL, NULL);
417
+ push_output(br);
418
+ }
419
+ return br->io;
420
+ }
421
+
422
+ static VALUE rb_writer_flush(VALUE self) {
423
+ struct brotli *br;
424
+ TypedData_Get_Struct(self, struct brotli, &brotli_data_type, br);
425
+
426
+ brotli_encoder_args_t args = {
427
+ .state = br->state,
428
+ .op = BROTLI_OPERATION_FLUSH,
429
+ .available_in = 0,
430
+ .next_in = NULL
431
+ };
432
+
433
+ do {
434
+ rb_thread_call_without_gvl(compress_no_gvl, (void*)&args, NULL, NULL);
435
+ push_output(br);
436
+ } while (BrotliEncoderHasMoreOutput(br->state));
437
+
438
+ if (rb_respond_to(br->io, id_flush)) {
439
+ rb_funcall(br->io, id_flush, 0);
440
+ }
441
+ return self;
442
+ }
443
+
444
+ static VALUE rb_writer_close(VALUE self) {
445
+ struct brotli* br;
446
+ TypedData_Get_Struct(self, struct brotli, &brotli_data_type, br);
447
+
448
+ rb_writer_finish(self);
449
+
450
+ if (rb_respond_to(br->io, id_close)) {
451
+ rb_funcall(br->io, id_close, 0);
452
+ }
453
+ return br->io;
454
+ }
455
+
296
456
  /*******************************************************************************
297
457
  * entry
298
458
  ******************************************************************************/
@@ -300,8 +460,27 @@ brotli_deflate(int argc, VALUE *argv, VALUE self)
300
460
  void
301
461
  Init_brotli(void)
302
462
  {
463
+ #if HAVE_RB_EXT_RACTOR_SAFE
464
+ rb_ext_ractor_safe(true);
465
+ #endif
466
+
467
+ VALUE rb_mBrotli;
468
+ VALUE rb_Writer;
303
469
  rb_mBrotli = rb_define_module("Brotli");
304
470
  rb_eBrotli = rb_define_class_under(rb_mBrotli, "Error", rb_eStandardError);
471
+ rb_global_variable(&rb_eBrotli);
305
472
  rb_define_singleton_method(rb_mBrotli, "deflate", RUBY_METHOD_FUNC(brotli_deflate), -1);
306
473
  rb_define_singleton_method(rb_mBrotli, "inflate", RUBY_METHOD_FUNC(brotli_inflate), 1);
474
+ rb_define_singleton_method(rb_mBrotli, "version", RUBY_METHOD_FUNC(brotli_version), 0);
475
+ // Brotli::Writer
476
+ id_write = rb_intern("write");
477
+ id_flush = rb_intern("flush");
478
+ id_close = rb_intern("close");
479
+ rb_Writer = rb_define_class_under(rb_mBrotli, "Writer", rb_cObject);
480
+ rb_define_alloc_func(rb_Writer, rb_writer_alloc);
481
+ rb_define_method(rb_Writer, "initialize", RUBY_METHOD_FUNC(rb_writer_initialize), -1);
482
+ rb_define_method(rb_Writer, "write", RUBY_METHOD_FUNC(rb_writer_write), 1);
483
+ rb_define_method(rb_Writer, "finish", RUBY_METHOD_FUNC(rb_writer_finish), 0);
484
+ rb_define_method(rb_Writer, "flush", RUBY_METHOD_FUNC(rb_writer_flush), 0);
485
+ rb_define_method(rb_Writer, "close", RUBY_METHOD_FUNC(rb_writer_close), 0);
307
486
  }
data/ext/brotli/buffer.c CHANGED
@@ -34,13 +34,7 @@ static
34
34
  buffer_t*
35
35
  expand_buffer(buffer_t* const buffer, const size_t need) {
36
36
  size_t size = need * buffer->expand_ratio / 100;
37
- uint8_t* ptr = malloc(size);
38
- if (ptr == NULL) {
39
- return NULL;
40
- }
41
- memcpy(ptr, buffer->ptr, buffer->size);
42
- free(buffer->ptr);
43
- buffer->ptr = ptr;
37
+ buffer->ptr = realloc(buffer->ptr, size);
44
38
  buffer->size = size;
45
39
  buffer->expand_count += 1;
46
40
  return buffer;
data/ext/brotli/buffer.h CHANGED
@@ -5,7 +5,7 @@
5
5
  #include <string.h>
6
6
 
7
7
  typedef struct {
8
- uint8_t* ptr;
8
+ char* ptr;
9
9
  size_t size;
10
10
  size_t used;
11
11
  size_t expand_ratio;
@@ -1,6 +1,6 @@
1
- require 'mkmf'
2
- require 'fileutils'
3
- require 'rbconfig'
1
+ require "mkmf"
2
+ require "fileutils"
3
+ require "rbconfig"
4
4
 
5
5
  dir_config("brotli")
6
6
 
@@ -13,36 +13,44 @@ have_dev_pkg = [
13
13
  pkg_config("libbrotlienc")
14
14
  ].all? { |e| e }
15
15
 
16
- $CPPFLAGS << ' -DOS_MACOSX' if RbConfig::CONFIG['host_os'] =~ /darwin|mac os/
17
- unless have_dev_pkg
18
- $INCFLAGS << ' -I$(srcdir)/enc -I$(srcdir)/dec -I$(srcdir)/common -I$(srcdir)/include'
16
+ if enable_config("vendor")
17
+ have_dev_pkg = false
18
+ Logging::message "Use vendor brotli\n"
19
19
  end
20
20
 
21
- create_makefile('brotli/brotli')
21
+ $CPPFLAGS << " -DOS_MACOSX" if RbConfig::CONFIG["host_os"] =~ /darwin|mac os/
22
+ $INCFLAGS << " -I$(srcdir)/enc -I$(srcdir)/dec -I$(srcdir)/common -I$(srcdir)/include" unless have_dev_pkg
23
+
24
+ create_makefile("brotli/brotli")
22
25
 
23
26
  unless have_dev_pkg
24
- __DIR__ = File.expand_path(File.dirname __FILE__)
27
+ __DIR__ = File.expand_path(File.dirname(__FILE__))
25
28
 
26
29
  %w[enc dec common include].each do |dirname|
30
+ FileUtils.rm_rf dirname
27
31
  FileUtils.mkdir_p dirname
28
- FileUtils.cp_r File.expand_path(File.join(__DIR__, '..', '..', 'vendor', 'brotli', 'c', dirname), __DIR__), __DIR__, verbose: true
32
+ FileUtils.cp_r(
33
+ File.expand_path(File.join(__DIR__, "..", "..", "vendor", "brotli", "c", dirname), __DIR__),
34
+ __DIR__,
35
+ verbose: true
36
+ )
29
37
  end
30
38
 
31
39
  srcs = []
32
40
  objs = []
33
- Dir[File.expand_path(File.join('{enc,dec,common,include}', '**', '*.c'), __DIR__)].sort.each do |file|
34
- file[__DIR__ + File::SEPARATOR] = ''
41
+ Dir[File.expand_path(File.join("{enc,dec,common,include}", "**", "*.c"), __DIR__)].sort.each do |file|
42
+ file[__DIR__ + File::SEPARATOR] = ""
35
43
  srcs << file
36
- objs << file.sub(/\.c\z/, '.' + RbConfig::CONFIG['OBJEXT'])
44
+ objs << file.sub(/\.c\z/, "." + RbConfig::CONFIG["OBJEXT"])
37
45
  end
38
46
 
39
- File.open('Makefile', 'r+') do |f|
40
- obj_ext = RbConfig::CONFIG['OBJEXT']
41
- src = 'ORIG_SRCS = brotli.c buffer.c'
47
+ File.open("Makefile", "r+") do |f|
48
+ obj_ext = RbConfig::CONFIG["OBJEXT"]
49
+ src = "ORIG_SRCS = brotli.c buffer.c"
42
50
  obj = "OBJS = brotli.#{obj_ext} buffer.#{obj_ext}"
43
51
  txt = f.read
44
- .sub(/^ORIG_SRCS = .*$/, src + ' ' + srcs.join(' '))
45
- .sub(/^OBJS = .*$/, obj + ' ' + objs.join(' '))
52
+ .sub(/^ORIG_SRCS = .*$/, "#{src} #{srcs.join(" ")}")
53
+ .sub(/^OBJS = .*$/, "#{obj} #{objs.join(" ")}")
46
54
  f.rewind
47
55
  f.write txt
48
56
  end
@@ -1,3 +1,3 @@
1
1
  module Brotli
2
- VERSION = '0.2.3'
2
+ VERSION = '0.5.0'
3
3
  end