ruby-brs 1.1.1 → 1.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 774954dc3bd3496501331c3799402c19bb6cd683fb0852420228677c8cc9bee5
4
- data.tar.gz: 162bbb4c99689035c3c2a245ba0c242886c1f75eab278ce1082984110896366e
3
+ metadata.gz: 239de67878a08e54f6b89af1381711ad94c70c1f29d99c8dca22ced06ebd850a
4
+ data.tar.gz: 2601159e2ede572b8bcdc8ce0ee7ca738f06f42cb0d6e59a159eb525e2f70420
5
5
  SHA512:
6
- metadata.gz: 2560264e86f2ff77dd810261d94576d9999682c5f9f70334d2e85d28dfc7e576bd1e996872020b65e3588d3334e019d3a6c056960ddcd0cbe98c406fc2794c6c
7
- data.tar.gz: fef04f25c06b4cdac5b187feced270ca021361c4c112db269d7509dea636fdf53d492d10566b137889dea543433ed332ec1e8d643163233f0db8657c03342dc5
6
+ metadata.gz: d12cfbf9280a63ad850ce4198e1bdaa044afc4502bccdeadeef8af746f1806182fb560bd580dd0bafafeaff93fd8e2e40435d7ac12079bad89a79b9cb22ef088
7
+ data.tar.gz: 13cb28b02d174fe3c448f291b85a80625cabb3f07ab32f5a5233a244425299ed04f248737be934d9f3171c6bc93c31062cbb1e7daf9f146e46a617163298a678
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Ruby bindings for brotli library
2
2
 
3
- | Travis | AppVeyor | Cirrus | Circle | Codecov |
4
- | :---: | :---: | :---: | :---: | :---: |
5
- | [![Travis test status](https://travis-ci.com/andrew-aladev/ruby-brs.svg?branch=master)](https://travis-ci.com/andrew-aladev/ruby-brs) | [![AppVeyor test status](https://ci.appveyor.com/api/projects/status/github/andrew-aladev/ruby-brs?branch=master&svg=true)](https://ci.appveyor.com/project/andrew-aladev/ruby-brs/branch/master) | [![Cirrus test status](https://api.cirrus-ci.com/github/andrew-aladev/ruby-brs.svg?branch=master)](https://cirrus-ci.com/github/andrew-aladev/ruby-brs) | [![Circle test status](https://circleci.com/gh/andrew-aladev/ruby-brs/tree/master.svg?style=shield)](https://circleci.com/gh/andrew-aladev/ruby-brs/tree/master) | [![Codecov](https://codecov.io/gh/andrew-aladev/ruby-brs/branch/master/graph/badge.svg)](https://codecov.io/gh/andrew-aladev/ruby-brs) |
3
+ | Travis | AppVeyor | Circle | Codecov | Gem |
4
+ | :---: | :---: | :---: | :---: | :---: |
5
+ | [![Travis test status](https://travis-ci.com/andrew-aladev/ruby-brs.svg?branch=master)](https://travis-ci.com/andrew-aladev/ruby-brs) | [![AppVeyor test status](https://ci.appveyor.com/api/projects/status/github/andrew-aladev/ruby-brs?branch=master&svg=true)](https://ci.appveyor.com/project/andrew-aladev/ruby-brs/branch/master) | [![Circle test status](https://circleci.com/gh/andrew-aladev/ruby-brs/tree/master.svg?style=shield)](https://circleci.com/gh/andrew-aladev/ruby-brs/tree/master) | [![Codecov](https://codecov.io/gh/andrew-aladev/ruby-brs/branch/master/graph/badge.svg)](https://codecov.io/gh/andrew-aladev/ruby-brs) | [![Gem](https://img.shields.io/gem/v/ruby-brs.svg)](https://rubygems.org/gems/ruby-brs) |
6
6
 
7
7
  See [brotli library](https://github.com/google/brotli).
8
8
 
@@ -21,6 +21,8 @@ rake gem
21
21
  gem install pkg/ruby-brs-*.gem
22
22
  ```
23
23
 
24
+ You can also use [overlay](https://github.com/andrew-aladev/overlay) for gentoo.
25
+
24
26
  ## Usage
25
27
 
26
28
  There are simple APIs: `String` and `File`. Also you can use generic streaming API: `Stream::Writer` and `Stream::Reader`.
@@ -36,9 +38,30 @@ BRS::File.decompress "file.txt.br", "file.txt"
36
38
 
37
39
  BRS::Stream::Writer.open("file.txt.br") { |writer| writer << "sample string" }
38
40
  puts BRS::Stream::Reader.open("file.txt.br") { |reader| reader.read }
41
+
42
+ writer = BRS::Stream::Writer.new output_socket
43
+ begin
44
+ bytes_written = writer.write_nonblock "sample string"
45
+ # handle "bytes_written"
46
+ rescue IO::WaitWritable
47
+ # handle wait
48
+ ensure
49
+ writer.close
50
+ end
51
+
52
+ reader = BRS::Stream::Reader.new input_socket
53
+ begin
54
+ puts reader.read_nonblock(512)
55
+ rescue IO::WaitReadable
56
+ # handle wait
57
+ rescue ::EOFError
58
+ # handle eof
59
+ ensure
60
+ reader.close
61
+ end
39
62
  ```
40
63
 
41
- You can create and read `tar.br` archives with `minitar` for example.
64
+ You can create and read `tar.br` archives with [minitar](https://github.com/halostatue/minitar) for example.
42
65
 
43
66
  ```ruby
44
67
  require "brs"
@@ -60,76 +83,58 @@ BRS::Stream::Reader.open "file.tar.br" do |reader|
60
83
  end
61
84
  ```
62
85
 
63
- ## Options
64
-
65
- Each API supports several options:
66
-
67
- ```
68
- :source_buffer_length
69
- :destination_buffer_length
70
- ```
71
-
72
- There are internal buffers for compressed and decompressed data.
73
- For example you want to use 1 KB as source buffer length for compressor - please use 256 B as destination buffer length.
74
- You want to use 256 B as source buffer length for decompressor - please use 1 KB as destination buffer length.
75
-
76
- Values: 0 - infinity, default value: 0.
77
- 0 means automatic buffer length selection.
78
-
79
- ```
80
- :mode
81
- ```
82
-
83
- Values: `BRS::Option::MODES`, default value: `:generic`.
84
-
85
- ```
86
- :quality
87
- ```
88
-
89
- Values: `BRS::Option::MIN_QUALITY` - `BRS::Option::MAX_QUALITY`, default value: `BRS::Option::MAX_QUALITY`.
90
-
91
- ```
92
- :lgwin
93
- ```
94
-
95
- Values: `BRS::Option::MIN_LGWIN` - `BRS::Option::MAX_LGWIN`, default value: `22`.
86
+ You can also use `Content-Encoding: br` with [sinatra](http://sinatrarb.com):
96
87
 
97
- ```
98
- :lgblock
99
- ```
100
-
101
- Values: `BRS::Option::MIN_LGBLOCK` - `BRS::Option::MAX_LGBLOCK`, default value: none.
88
+ ```ruby
89
+ require "brs"
90
+ require "sinatra"
102
91
 
103
- ```
104
- :disable_literal_context_modeling
92
+ get "/" do
93
+ headers["Content-Encoding"] = "br"
94
+ BRS::String.compress "sample string"
95
+ end
105
96
  ```
106
97
 
107
- Values: true/false, default value: false.
98
+ ## Options
108
99
 
109
- ```
110
- :disable_ring_buffer_reallocation
111
- ```
100
+ | Option | Values | Default | Description |
101
+ |------------------------------------|------------|------------|-------------|
102
+ | `source_buffer_length` | 0 - inf | 0 (auto) | internal buffer length for source data |
103
+ | `destination_buffer_length` | 0 - inf | 0 (auto) | internal buffer length for description data |
104
+ | `gvl` | true/false | false | enables global VM lock where possible |
105
+ | `mode` | `MODES` | `:generic` | compressor mode |
106
+ | `quality` | 0 - 11 | 11 | compression level |
107
+ | `lgwin` | 10 - 24 | 22 | compressor window size |
108
+ | `lgblock` | 16 - 24 | nil (auto) | compressor input block size |
109
+ | `disable_literal_context_modeling` | true/false | false | disables literal context modeling format |
110
+ | `disable_ring_buffer_reallocation` | true/false | false | disables ring buffer reallocation |
111
+ | `size_hint` | 0 - inf | 0 (auto) | size of input (if known) |
112
+ | `large_window` | true/false | false | enables large window |
112
113
 
113
- Values: true/false, default value: false.
114
+ There are internal buffers for compressed and decompressed data.
115
+ For example you want to use 1 KB as `source_buffer_length` for compressor - please use 256 B as `destination_buffer_length`.
116
+ You want to use 256 B as `source_buffer_length` for decompressor - please use 1 KB as `destination_buffer_length`.
114
117
 
115
- ```
116
- :size_hint
117
- ```
118
+ `gvl` is disabled by default, this mode allows running multiple compressors/decompressors in different threads simultaneously.
119
+ Please consider enabling `gvl` if you don't want to launch processors in separate threads.
120
+ If `gvl` is enabled ruby won't waste time on acquiring/releasing VM lock.
118
121
 
119
- Values: 0 - infinity, default value: 0.
120
- It is reasonable to provide size of input (if known) for streaming api.
121
122
  `String` and `File` will set `:size_hint` automaticaly.
122
123
 
123
- ```
124
- :large_window
125
- ```
126
-
127
- Values: true/false, default value: false.
124
+ You can also read brotli docs for more info about options.
128
125
 
129
- Please read brotli docs for more info about options.
126
+ | Option | Related constants |
127
+ |-----------|-------------------|
128
+ | `mode` | `BRS::Option::MODES` = `%i[text font generic]` |
129
+ | `quality` | `BRS::Option::MIN_QUALITY` = 0, `BRS::Option::MAX_QUALITY` = 11 |
130
+ | `lgwin` | `BRS::Option::MIN_LGWIN` = 10, `BRS::Option::MAX_LGWIN` = 24 |
131
+ | `lgblock` | `BRS::Option::MIN_LGBLOCK` = 16, `BRS::Option::MAX_LGBLOCK` = 24 |
130
132
 
131
133
  Possible compressor options:
132
134
  ```
135
+ :source_buffer_length
136
+ :destination_buffer_length
137
+ :gvl
133
138
  :mode
134
139
  :quality
135
140
  :lgwin
@@ -141,6 +146,9 @@ Possible compressor options:
141
146
 
142
147
  Possible decompressor options:
143
148
  ```
149
+ :source_buffer_length
150
+ :destination_buffer_length
151
+ :gvl
144
152
  :disable_ring_buffer_reallocation
145
153
  :large_window
146
154
  ```
@@ -154,18 +162,6 @@ data = BRS::String.compress "sample string", :quality => 5
154
162
  puts BRS::String.decompress(data, :disable_ring_buffer_reallocation => true)
155
163
  ```
156
164
 
157
- HTTP encoding (`Content-Encoding: br`) using default options:
158
-
159
- ```ruby
160
- require "brs"
161
- require "sinatra"
162
-
163
- get "/" do
164
- headers["Content-Encoding"] = "br"
165
- BRS::String.compress "sample string"
166
- end
167
- ```
168
-
169
165
  ## String
170
166
 
171
167
  String maintains destination buffer only, so it accepts `destination_buffer_length` option only.
@@ -190,7 +186,7 @@ File maintains both source and destination buffers, it accepts both `source_buff
190
186
 
191
187
  ## Stream::Writer
192
188
 
193
- Its behaviour is similar to builtin [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib-2.6.1/libdoc/zlib/rdoc/Zlib/GzipWriter.html).
189
+ Its behaviour is similar to builtin [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib-2.7.0/libdoc/zlib/rdoc/Zlib/GzipWriter.html).
194
190
 
195
191
  Writer maintains destination buffer only, so it accepts `destination_buffer_length` option only.
196
192
 
@@ -228,7 +224,7 @@ Set another encodings, `nil` is just for compatibility with `IO`.
228
224
  #tell
229
225
  ```
230
226
 
231
- See [`IO`](https://ruby-doc.org/core-2.6.1/IO.html) docs.
227
+ See [`IO`](https://ruby-doc.org/core-2.7.0/IO.html) docs.
232
228
 
233
229
  ```
234
230
  #write(*objects)
@@ -238,7 +234,7 @@ See [`IO`](https://ruby-doc.org/core-2.6.1/IO.html) docs.
238
234
  #closed?
239
235
  ```
240
236
 
241
- See [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib-2.6.1/libdoc/zlib/rdoc/Zlib/GzipWriter.html) docs.
237
+ See [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib-2.7.0/libdoc/zlib/rdoc/Zlib/GzipWriter.html) docs.
242
238
 
243
239
  ```
244
240
  #write_nonblock(object, *options)
@@ -260,11 +256,11 @@ Behaviour is the same as `IO#write_nonblock` method.
260
256
  #puts(*objects)
261
257
  ```
262
258
 
263
- Typical helpers, see [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib-2.6.1/libdoc/zlib/rdoc/Zlib/GzipWriter.html) docs.
259
+ Typical helpers, see [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib-2.7.0/libdoc/zlib/rdoc/Zlib/GzipWriter.html) docs.
264
260
 
265
261
  ## Stream::Reader
266
262
 
267
- Its behaviour is similar to builtin [`Zlib::GzipReader`](https://ruby-doc.org/stdlib-2.6.1/libdoc/zlib/rdoc/Zlib/GzipReader.html).
263
+ Its behaviour is similar to builtin [`Zlib::GzipReader`](https://ruby-doc.org/stdlib-2.7.0/libdoc/zlib/rdoc/Zlib/GzipReader.html).
268
264
 
269
265
  Reader maintains both source and destination buffers, it accepts both `source_buffer_length` and `destination_buffer_length` options.
270
266
 
@@ -299,7 +295,7 @@ Set another encodings.
299
295
  #tell
300
296
  ```
301
297
 
302
- See [`IO`](https://ruby-doc.org/core-2.6.1/IO.html) docs.
298
+ See [`IO`](https://ruby-doc.org/core-2.7.0/IO.html) docs.
303
299
 
304
300
  ```
305
301
  #read(bytes_to_read = nil, out_buffer = nil)
@@ -309,14 +305,14 @@ See [`IO`](https://ruby-doc.org/core-2.6.1/IO.html) docs.
309
305
  #closed?
310
306
  ```
311
307
 
312
- See [`Zlib::GzipReader`](https://ruby-doc.org/stdlib-2.6.1/libdoc/zlib/rdoc/Zlib/GzipReader.html) docs.
308
+ See [`Zlib::GzipReader`](https://ruby-doc.org/stdlib-2.7.0/libdoc/zlib/rdoc/Zlib/GzipReader.html) docs.
313
309
 
314
310
  ```
315
311
  #readpartial(bytes_to_read = nil, out_buffer = nil)
316
312
  #read_nonblock(bytes_to_read, out_buffer = nil, *options)
317
313
  ```
318
314
 
319
- See [`IO`](https://ruby-doc.org/core-2.6.1/IO.html) docs.
315
+ See [`IO`](https://ruby-doc.org/core-2.7.0/IO.html) docs.
320
316
 
321
317
  ```
322
318
  #getbyte
@@ -339,14 +335,20 @@ See [`IO`](https://ruby-doc.org/core-2.6.1/IO.html) docs.
339
335
  #ungetline(line)
340
336
  ```
341
337
 
342
- Typical helpers, see [`Zlib::GzipReader`](https://ruby-doc.org/stdlib-2.6.1/libdoc/zlib/rdoc/Zlib/GzipReader.html) docs.
338
+ Typical helpers, see [`Zlib::GzipReader`](https://ruby-doc.org/stdlib-2.7.0/libdoc/zlib/rdoc/Zlib/GzipReader.html) docs.
339
+
340
+ ## Thread safety
341
+
342
+ `:gvl` option is disabled by default, you can use bindings effectively in multiple threads.
343
+ Please be careful: bindings are not thread safe.
344
+ You should lock all shared data between threads.
343
345
 
344
346
  ## CI
345
347
 
346
- Travis and Appveyor CI uses [scripts/ci_test.sh](scripts/ci_test.sh) directly.
347
- Cirrus and Circle CI uses prebuilt [scripts/test-images](scripts/test-images).
348
- Cirrus CI uses amd64 image, Circle CI - i686.
348
+ Please visit [scripts/test-images](scripts/test-images).
349
+ See universal test script [scripts/ci_test.sh](scripts/ci_test.sh) for CI.
350
+ You can run this script using many native and cross images.
349
351
 
350
352
  ## License
351
353
 
352
- MIT license, see LICENSE and AUTHORS.
354
+ MIT license, see [LICENSE](LICENSE) and [AUTHORS](AUTHORS).
@@ -10,10 +10,11 @@ VALUE brs_ext_create_string_buffer(VALUE length)
10
10
  return rb_str_new(NULL, NUM2SIZET(length));
11
11
  }
12
12
 
13
- VALUE brs_ext_resize_string_buffer(VALUE args)
13
+ VALUE brs_ext_resize_string_buffer(VALUE buffer_args)
14
14
  {
15
- VALUE buffer = rb_ary_entry(args, 0);
16
- VALUE length = rb_ary_entry(args, 1);
15
+ VALUE buffer = rb_ary_entry(buffer_args, 0);
16
+ VALUE length = rb_ary_entry(buffer_args, 1);
17
+
17
18
  return rb_str_resize(buffer, NUM2SIZET(length));
18
19
  }
19
20
 
@@ -21,8 +22,21 @@ void brs_ext_buffer_exports(VALUE root_module)
21
22
  {
22
23
  VALUE module = rb_define_module_under(root_module, "Buffer");
23
24
 
24
- rb_define_const(module, "DEFAULT_SOURCE_BUFFER_LENGTH_FOR_COMPRESSOR", SIZET2NUM(BRS_DEFAULT_SOURCE_BUFFER_LENGTH_FOR_COMPRESSOR));
25
- rb_define_const(module, "DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_COMPRESSOR", SIZET2NUM(BRS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_COMPRESSOR));
26
- rb_define_const(module, "DEFAULT_SOURCE_BUFFER_LENGTH_FOR_DECOMPRESSOR", SIZET2NUM(BRS_DEFAULT_SOURCE_BUFFER_LENGTH_FOR_DECOMPRESSOR));
27
- rb_define_const(module, "DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_DECOMPRESSOR", SIZET2NUM(BRS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_DECOMPRESSOR));
25
+ rb_define_const(
26
+ module, "DEFAULT_SOURCE_BUFFER_LENGTH_FOR_COMPRESSOR", SIZET2NUM(BRS_DEFAULT_SOURCE_BUFFER_LENGTH_FOR_COMPRESSOR));
27
+
28
+ rb_define_const(
29
+ module,
30
+ "DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_COMPRESSOR",
31
+ SIZET2NUM(BRS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_COMPRESSOR));
32
+
33
+ rb_define_const(
34
+ module,
35
+ "DEFAULT_SOURCE_BUFFER_LENGTH_FOR_DECOMPRESSOR",
36
+ SIZET2NUM(BRS_DEFAULT_SOURCE_BUFFER_LENGTH_FOR_DECOMPRESSOR));
37
+
38
+ rb_define_const(
39
+ module,
40
+ "DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_DECOMPRESSOR",
41
+ SIZET2NUM(BRS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_DECOMPRESSOR));
28
42
  }
@@ -6,10 +6,10 @@
6
6
 
7
7
  #include "ruby.h"
8
8
 
9
- #define BRS_DEFAULT_SOURCE_BUFFER_LENGTH_FOR_COMPRESSOR (1 << 18) // 256 KB
9
+ #define BRS_DEFAULT_SOURCE_BUFFER_LENGTH_FOR_COMPRESSOR (1 << 18) // 256 KB
10
10
  #define BRS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_COMPRESSOR (1 << 16) // 64 KB
11
11
 
12
- #define BRS_DEFAULT_SOURCE_BUFFER_LENGTH_FOR_DECOMPRESSOR (1 << 16) // 64 KB
12
+ #define BRS_DEFAULT_SOURCE_BUFFER_LENGTH_FOR_DECOMPRESSOR (1 << 16) // 64 KB
13
13
  #define BRS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_DECOMPRESSOR (1 << 18) // 256 KB
14
14
 
15
15
  VALUE brs_ext_create_string_buffer(VALUE length);
@@ -17,12 +17,12 @@ VALUE brs_ext_create_string_buffer(VALUE length);
17
17
  #define BRS_EXT_CREATE_STRING_BUFFER(buffer, length, exception) \
18
18
  VALUE buffer = rb_protect(brs_ext_create_string_buffer, SIZET2NUM(length), &exception);
19
19
 
20
- VALUE brs_ext_resize_string_buffer(VALUE args);
20
+ VALUE brs_ext_resize_string_buffer(VALUE buffer_args);
21
21
 
22
- #define BRS_EXT_RESIZE_STRING_BUFFER(buffer, length, exception) \
23
- VALUE args = rb_ary_new_from_args(2, buffer, SIZET2NUM(length)); \
24
- buffer = rb_protect(brs_ext_resize_string_buffer, args, &exception); \
25
- RB_GC_GUARD(args);
22
+ #define BRS_EXT_RESIZE_STRING_BUFFER(buffer, length, exception) \
23
+ VALUE buffer_args = rb_ary_new_from_args(2, buffer, SIZET2NUM(length)); \
24
+ buffer = rb_protect(brs_ext_resize_string_buffer, buffer_args, &exception); \
25
+ RB_GC_GUARD(buffer_args);
26
26
 
27
27
  void brs_ext_buffer_exports(VALUE root_module);
28
28
 
@@ -10,4 +10,7 @@
10
10
 
11
11
  typedef uint_fast8_t brs_ext_result_t;
12
12
 
13
+ typedef uint8_t brs_ext_byte_t;
14
+ typedef uint_fast8_t brs_ext_byte_fast_t;
15
+
13
16
  #endif // BRS_EXT_COMMON_H
@@ -5,7 +5,6 @@
5
5
 
6
6
  #include <brotli/decode.h>
7
7
 
8
- #include "brs_ext/common.h"
9
8
  #include "ruby.h"
10
9
 
11
10
  brs_ext_result_t brs_ext_get_decompressor_error(BrotliDecoderErrorCode error_code)
@@ -11,7 +11,8 @@
11
11
 
12
12
  // Results for errors listed in "lib/brs/error" used in c extension.
13
13
 
14
- enum {
14
+ enum
15
+ {
15
16
  BRS_EXT_ERROR_ALLOCATE_FAILED = 1,
16
17
  BRS_EXT_ERROR_VALIDATE_FAILED,
17
18
 
@@ -0,0 +1,24 @@
1
+ // Ruby bindings for brotli library.
2
+ // Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ #if !defined(BRS_EXT_GVL_H)
5
+ #define BRS_EXT_GVL_H
6
+
7
+ #ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
8
+
9
+ #include "ruby/thread.h"
10
+
11
+ #define BRS_EXT_GVL_WRAP(gvl, function, data) \
12
+ if (gvl) { \
13
+ function((void*) data); \
14
+ } else { \
15
+ rb_thread_call_without_gvl(function, (void*) data, RUBY_UBF_IO, NULL); \
16
+ }
17
+
18
+ #else
19
+
20
+ #define BRS_EXT_GVL_WRAP(_gvl, function, data) function((void*) data);
21
+
22
+ #endif
23
+
24
+ #endif // BRS_EXT_GVL_H
@@ -1,32 +1,33 @@
1
1
  // Ruby bindings for brotli library.
2
2
  // Copyright (c) 2019 AUTHORS, MIT License.
3
3
 
4
- #include "ruby/io.h"
4
+ #include "brs_ext/io.h"
5
5
 
6
6
  #include <brotli/decode.h>
7
7
  #include <brotli/encode.h>
8
8
  #include <brotli/types.h>
9
- #include <stdint.h>
10
9
  #include <stdio.h>
11
10
  #include <stdlib.h>
12
11
  #include <string.h>
13
12
 
14
13
  #include "brs_ext/buffer.h"
15
- #include "brs_ext/common.h"
16
14
  #include "brs_ext/error.h"
17
- #include "brs_ext/io.h"
15
+ #include "brs_ext/gvl.h"
18
16
  #include "brs_ext/macro.h"
19
17
  #include "brs_ext/option.h"
20
18
  #include "ruby.h"
19
+ #include "ruby/io.h"
21
20
 
22
21
  // Additional possible results:
23
- enum {
22
+ enum
23
+ {
24
24
  BRS_EXT_FILE_READ_FINISHED = 128
25
25
  };
26
26
 
27
27
  // -- file --
28
28
 
29
- static inline brs_ext_result_t read_file(FILE* source_file, uint8_t* source_buffer, size_t* source_length_ptr, size_t source_buffer_length)
29
+ static inline brs_ext_result_t
30
+ read_file(FILE* source_file, brs_ext_byte_t* source_buffer, size_t* source_length_ptr, size_t source_buffer_length)
30
31
  {
31
32
  size_t read_length = fread(source_buffer, 1, source_buffer_length, source_file);
32
33
  if (read_length == 0 && feof(source_file)) {
@@ -42,7 +43,8 @@ static inline brs_ext_result_t read_file(FILE* source_file, uint8_t* source_buff
42
43
  return 0;
43
44
  }
44
45
 
45
- static inline brs_ext_result_t write_file(FILE* destination_file, uint8_t* destination_buffer, size_t destination_length)
46
+ static inline brs_ext_result_t
47
+ write_file(FILE* destination_file, brs_ext_byte_t* destination_buffer, size_t destination_length)
46
48
  {
47
49
  size_t written_length = fwrite(destination_buffer, 1, destination_length, destination_file);
48
50
  if (written_length != destination_length) {
@@ -55,15 +57,17 @@ static inline brs_ext_result_t write_file(FILE* destination_file, uint8_t* desti
55
57
  // -- buffer --
56
58
 
57
59
  static inline brs_ext_result_t create_buffers(
58
- uint8_t** source_buffer_ptr, size_t source_buffer_length,
59
- uint8_t** destination_buffer_ptr, size_t destination_buffer_length)
60
+ brs_ext_byte_t** source_buffer_ptr,
61
+ size_t source_buffer_length,
62
+ brs_ext_byte_t** destination_buffer_ptr,
63
+ size_t destination_buffer_length)
60
64
  {
61
- uint8_t* source_buffer = malloc(source_buffer_length);
65
+ brs_ext_byte_t* source_buffer = malloc(source_buffer_length);
62
66
  if (source_buffer == NULL) {
63
67
  return BRS_EXT_ERROR_ALLOCATE_FAILED;
64
68
  }
65
69
 
66
- uint8_t* destination_buffer = malloc(destination_buffer_length);
70
+ brs_ext_byte_t* destination_buffer = malloc(destination_buffer_length);
67
71
  if (destination_buffer == NULL) {
68
72
  free(source_buffer);
69
73
  return BRS_EXT_ERROR_ALLOCATE_FAILED;
@@ -82,12 +86,14 @@ static inline brs_ext_result_t create_buffers(
82
86
  // Algorithm can use same buffer again.
83
87
 
84
88
  static inline brs_ext_result_t read_more_source(
85
- FILE* source_file,
86
- const uint8_t** source_ptr, size_t* source_length_ptr,
87
- uint8_t* source_buffer, size_t source_buffer_length)
89
+ FILE* source_file,
90
+ const brs_ext_byte_t** source_ptr,
91
+ size_t* source_length_ptr,
92
+ brs_ext_byte_t* source_buffer,
93
+ size_t source_buffer_length)
88
94
  {
89
- const uint8_t* source = *source_ptr;
90
- size_t source_length = *source_length_ptr;
95
+ const brs_ext_byte_t* source = *source_ptr;
96
+ size_t source_length = *source_length_ptr;
91
97
 
92
98
  if (source != source_buffer) {
93
99
  if (source_length != 0) {
@@ -104,10 +110,12 @@ static inline brs_ext_result_t read_more_source(
104
110
  return BRS_EXT_ERROR_NOT_ENOUGH_SOURCE_BUFFER;
105
111
  }
106
112
 
107
- uint8_t* remaining_source_buffer = source_buffer + source_length;
108
- size_t new_source_length;
113
+ brs_ext_byte_t* remaining_source_buffer = source_buffer + source_length;
114
+ size_t new_source_length;
115
+
116
+ brs_ext_result_t ext_result =
117
+ read_file(source_file, remaining_source_buffer, &new_source_length, remaining_source_buffer_length);
109
118
 
110
- brs_ext_result_t ext_result = read_file(source_file, remaining_source_buffer, &new_source_length, remaining_source_buffer_length);
111
119
  if (ext_result != 0) {
112
120
  return ext_result;
113
121
  }
@@ -117,42 +125,37 @@ static inline brs_ext_result_t read_more_source(
117
125
  return 0;
118
126
  }
119
127
 
120
- #define BUFFERED_READ_SOURCE(function, ...) \
121
- do { \
122
- bool is_function_called = false; \
123
- \
124
- while (true) { \
125
- ext_result = read_more_source( \
126
- source_file, \
127
- &source, &source_length, \
128
- source_buffer, source_buffer_length); \
129
- \
130
- if (ext_result == BRS_EXT_FILE_READ_FINISHED) { \
131
- if (source_length != 0) { \
132
- /* Brotli won't provide any remainder by design. */ \
133
- return BRS_EXT_ERROR_READ_IO; \
134
- } \
135
- break; \
136
- } \
137
- else if (ext_result != 0) { \
138
- return ext_result; \
139
- } \
140
- \
141
- ext_result = function(__VA_ARGS__); \
142
- if (ext_result != 0) { \
143
- return ext_result; \
144
- } \
145
- \
146
- is_function_called = true; \
147
- } \
148
- \
149
- if (!is_function_called) { \
150
- /* Function should be called at least once. */ \
151
- ext_result = function(__VA_ARGS__); \
152
- if (ext_result != 0) { \
153
- return ext_result; \
154
- } \
155
- } \
128
+ #define BUFFERED_READ_SOURCE(function, ...) \
129
+ do { \
130
+ bool is_function_called = false; \
131
+ \
132
+ while (true) { \
133
+ ext_result = read_more_source(source_file, &source, &source_length, source_buffer, source_buffer_length); \
134
+ if (ext_result == BRS_EXT_FILE_READ_FINISHED) { \
135
+ if (source_length != 0) { \
136
+ /* Brotli won't provide any remainder by design. */ \
137
+ return BRS_EXT_ERROR_READ_IO; \
138
+ } \
139
+ break; \
140
+ } else if (ext_result != 0) { \
141
+ return ext_result; \
142
+ } \
143
+ \
144
+ ext_result = function(__VA_ARGS__); \
145
+ if (ext_result != 0) { \
146
+ return ext_result; \
147
+ } \
148
+ \
149
+ is_function_called = true; \
150
+ } \
151
+ \
152
+ if (!is_function_called) { \
153
+ /* Function should be called at least once. */ \
154
+ ext_result = function(__VA_ARGS__); \
155
+ if (ext_result != 0) { \
156
+ return ext_result; \
157
+ } \
158
+ } \
156
159
  } while (false);
157
160
 
158
161
  // Algorithm has written data into destination buffer.
@@ -160,8 +163,10 @@ static inline brs_ext_result_t read_more_source(
160
163
  // Than algorithm can use same buffer again.
161
164
 
162
165
  static inline brs_ext_result_t flush_destination_buffer(
163
- FILE* destination_file,
164
- uint8_t* destination_buffer, size_t* destination_length_ptr, size_t destination_buffer_length)
166
+ FILE* destination_file,
167
+ brs_ext_byte_t* destination_buffer,
168
+ size_t* destination_length_ptr,
169
+ size_t destination_buffer_length)
165
170
  {
166
171
  if (*destination_length_ptr == 0) {
167
172
  // We want to write more data at once, than buffer has.
@@ -178,7 +183,8 @@ static inline brs_ext_result_t flush_destination_buffer(
178
183
  return 0;
179
184
  }
180
185
 
181
- static inline brs_ext_result_t write_remaining_destination(FILE* destination_file, uint8_t* destination_buffer, size_t destination_length)
186
+ static inline brs_ext_result_t
187
+ write_remaining_destination(FILE* destination_file, brs_ext_byte_t* destination_buffer, size_t destination_length)
182
188
  {
183
189
  if (destination_length == 0) {
184
190
  return 0;
@@ -200,29 +206,57 @@ static inline brs_ext_result_t write_remaining_destination(FILE* destination_fil
200
206
  brs_ext_raise_error(BRS_EXT_ERROR_ACCESS_IO); \
201
207
  }
202
208
 
203
- // -- compress --
209
+ // -- buffered compress --
210
+
211
+ typedef struct
212
+ {
213
+ BrotliEncoderState* state_ptr;
214
+ const brs_ext_byte_t** source_ptr;
215
+ size_t* source_length_ptr;
216
+ brs_ext_byte_t* remaining_destination_buffer;
217
+ size_t* remaining_destination_buffer_length_ptr;
218
+ BROTLI_BOOL result;
219
+ } compress_args_t;
220
+
221
+ static inline void* compress_wrapper(void* data)
222
+ {
223
+ compress_args_t* args = data;
224
+
225
+ args->result = BrotliEncoderCompressStream(
226
+ args->state_ptr,
227
+ BROTLI_OPERATION_PROCESS,
228
+ args->source_length_ptr,
229
+ args->source_ptr,
230
+ args->remaining_destination_buffer_length_ptr,
231
+ &args->remaining_destination_buffer,
232
+ NULL);
233
+
234
+ return NULL;
235
+ }
204
236
 
205
237
  static inline brs_ext_result_t buffered_compress(
206
- BrotliEncoderState* state_ptr,
207
- const uint8_t** source_ptr, size_t* source_length_ptr,
208
- FILE* destination_file, uint8_t* destination_buffer, size_t* destination_length_ptr, size_t destination_buffer_length)
238
+ BrotliEncoderState* state_ptr,
239
+ const brs_ext_byte_t** source_ptr,
240
+ size_t* source_length_ptr,
241
+ FILE* destination_file,
242
+ brs_ext_byte_t* destination_buffer,
243
+ size_t* destination_length_ptr,
244
+ size_t destination_buffer_length,
245
+ bool gvl)
209
246
  {
210
- BROTLI_BOOL result;
211
247
  brs_ext_result_t ext_result;
248
+ compress_args_t args = {.state_ptr = state_ptr, .source_ptr = source_ptr, .source_length_ptr = source_length_ptr};
212
249
 
213
250
  while (true) {
214
- uint8_t* remaining_destination_buffer = destination_buffer + *destination_length_ptr;
215
- size_t remaining_destination_buffer_length = destination_buffer_length - *destination_length_ptr;
216
- size_t prev_remaining_destination_buffer_length = remaining_destination_buffer_length;
217
-
218
- result = BrotliEncoderCompressStream(
219
- state_ptr,
220
- BROTLI_OPERATION_PROCESS,
221
- source_length_ptr, source_ptr,
222
- &remaining_destination_buffer_length, &remaining_destination_buffer,
223
- NULL);
224
-
225
- if (!result) {
251
+ brs_ext_byte_t* remaining_destination_buffer = destination_buffer + *destination_length_ptr;
252
+ size_t remaining_destination_buffer_length = destination_buffer_length - *destination_length_ptr;
253
+ size_t prev_remaining_destination_buffer_length = remaining_destination_buffer_length;
254
+
255
+ args.remaining_destination_buffer = remaining_destination_buffer;
256
+ args.remaining_destination_buffer_length_ptr = &remaining_destination_buffer_length;
257
+
258
+ BRS_EXT_GVL_WRAP(gvl, compress_wrapper, &args);
259
+ if (!args.result) {
226
260
  return BRS_EXT_ERROR_UNEXPECTED;
227
261
  }
228
262
 
@@ -230,8 +264,7 @@ static inline brs_ext_result_t buffered_compress(
230
264
 
231
265
  if (BrotliEncoderHasMoreOutput(state_ptr)) {
232
266
  ext_result = flush_destination_buffer(
233
- destination_file,
234
- destination_buffer, destination_length_ptr, destination_buffer_length);
267
+ destination_file, destination_buffer, destination_length_ptr, destination_buffer_length);
235
268
 
236
269
  if (ext_result != 0) {
237
270
  return ext_result;
@@ -246,29 +279,57 @@ static inline brs_ext_result_t buffered_compress(
246
279
  return 0;
247
280
  }
248
281
 
282
+ // -- buffered compressor finish --
283
+
284
+ typedef struct
285
+ {
286
+ BrotliEncoderState* state_ptr;
287
+ const brs_ext_byte_t** source_ptr;
288
+ size_t* source_length_ptr;
289
+ brs_ext_byte_t* remaining_destination_buffer;
290
+ size_t* remaining_destination_buffer_length_ptr;
291
+ BROTLI_BOOL result;
292
+ } compressor_finish_args_t;
293
+
294
+ static inline void* compressor_finish_wrapper(void* data)
295
+ {
296
+ compressor_finish_args_t* args = data;
297
+
298
+ args->result = BrotliEncoderCompressStream(
299
+ args->state_ptr,
300
+ BROTLI_OPERATION_FINISH,
301
+ args->source_length_ptr,
302
+ args->source_ptr,
303
+ args->remaining_destination_buffer_length_ptr,
304
+ &args->remaining_destination_buffer,
305
+ NULL);
306
+
307
+ return NULL;
308
+ }
309
+
249
310
  static inline brs_ext_result_t buffered_compressor_finish(
250
311
  BrotliEncoderState* state_ptr,
251
- FILE* destination_file, uint8_t* destination_buffer, size_t* destination_length_ptr, size_t destination_buffer_length)
312
+ FILE* destination_file,
313
+ brs_ext_byte_t* destination_buffer,
314
+ size_t* destination_length_ptr,
315
+ size_t destination_buffer_length,
316
+ bool gvl)
252
317
  {
253
- BROTLI_BOOL result;
254
- brs_ext_result_t ext_result;
255
-
256
- const uint8_t* source = NULL;
257
- size_t source_length = 0;
318
+ brs_ext_result_t ext_result;
319
+ const brs_ext_byte_t* source = NULL;
320
+ size_t source_length = 0;
321
+ compressor_finish_args_t args = {.state_ptr = state_ptr, .source_ptr = &source, .source_length_ptr = &source_length};
258
322
 
259
323
  while (true) {
260
- uint8_t* remaining_destination_buffer = destination_buffer + *destination_length_ptr;
261
- size_t remaining_destination_buffer_length = destination_buffer_length - *destination_length_ptr;
262
- size_t prev_remaining_destination_buffer_length = remaining_destination_buffer_length;
263
-
264
- result = BrotliEncoderCompressStream(
265
- state_ptr,
266
- BROTLI_OPERATION_FINISH,
267
- &source_length, &source,
268
- &remaining_destination_buffer_length, &remaining_destination_buffer,
269
- NULL);
270
-
271
- if (!result) {
324
+ brs_ext_byte_t* remaining_destination_buffer = destination_buffer + *destination_length_ptr;
325
+ size_t remaining_destination_buffer_length = destination_buffer_length - *destination_length_ptr;
326
+ size_t prev_remaining_destination_buffer_length = remaining_destination_buffer_length;
327
+
328
+ args.remaining_destination_buffer = remaining_destination_buffer;
329
+ args.remaining_destination_buffer_length_ptr = &remaining_destination_buffer_length;
330
+
331
+ BRS_EXT_GVL_WRAP(gvl, compressor_finish_wrapper, &args);
332
+ if (!args.result) {
272
333
  return BRS_EXT_ERROR_UNEXPECTED;
273
334
  }
274
335
 
@@ -276,8 +337,7 @@ static inline brs_ext_result_t buffered_compressor_finish(
276
337
 
277
338
  if (BrotliEncoderHasMoreOutput(state_ptr) || !BrotliEncoderIsFinished(state_ptr)) {
278
339
  ext_result = flush_destination_buffer(
279
- destination_file,
280
- destination_buffer, destination_length_ptr, destination_buffer_length);
340
+ destination_file, destination_buffer, destination_length_ptr, destination_buffer_length);
281
341
 
282
342
  if (ext_result != 0) {
283
343
  return ext_result;
@@ -292,26 +352,36 @@ static inline brs_ext_result_t buffered_compressor_finish(
292
352
  return 0;
293
353
  }
294
354
 
355
+ // -- compress --
356
+
295
357
  static inline brs_ext_result_t compress(
296
358
  BrotliEncoderState* state_ptr,
297
- FILE* source_file, uint8_t* source_buffer, size_t source_buffer_length,
298
- FILE* destination_file, uint8_t* destination_buffer, size_t destination_buffer_length)
359
+ FILE* source_file,
360
+ brs_ext_byte_t* source_buffer,
361
+ size_t source_buffer_length,
362
+ FILE* destination_file,
363
+ brs_ext_byte_t* destination_buffer,
364
+ size_t destination_buffer_length,
365
+ bool gvl)
299
366
  {
300
- brs_ext_result_t ext_result;
301
-
302
- const uint8_t* source = source_buffer;
303
- size_t source_length = 0;
304
- size_t destination_length = 0;
367
+ brs_ext_result_t ext_result;
368
+ const brs_ext_byte_t* source = source_buffer;
369
+ size_t source_length = 0;
370
+ size_t destination_length = 0;
305
371
 
306
372
  BUFFERED_READ_SOURCE(
307
373
  buffered_compress,
308
374
  state_ptr,
309
- &source, &source_length,
310
- destination_file, destination_buffer, &destination_length, destination_buffer_length);
375
+ &source,
376
+ &source_length,
377
+ destination_file,
378
+ destination_buffer,
379
+ &destination_length,
380
+ destination_buffer_length,
381
+ gvl);
311
382
 
312
383
  ext_result = buffered_compressor_finish(
313
- state_ptr,
314
- destination_file, destination_buffer, &destination_length, destination_buffer_length);
384
+ state_ptr, destination_file, destination_buffer, &destination_length, destination_buffer_length, gvl);
315
385
 
316
386
  if (ext_result != 0) {
317
387
  return ext_result;
@@ -325,9 +395,10 @@ VALUE brs_ext_compress_io(VALUE BRS_EXT_UNUSED(self), VALUE source, VALUE destin
325
395
  GET_FILE(source);
326
396
  GET_FILE(destination);
327
397
  Check_Type(options, T_HASH);
398
+ BRS_EXT_GET_SIZE_OPTION(options, source_buffer_length);
399
+ BRS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
400
+ BRS_EXT_GET_BOOL_OPTION(options, gvl);
328
401
  BRS_EXT_GET_COMPRESSOR_OPTIONS(options);
329
- BRS_EXT_GET_BUFFER_LENGTH_OPTION(options, source_buffer_length);
330
- BRS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
331
402
 
332
403
  BrotliEncoderState* state_ptr = BrotliEncoderCreateInstance(NULL, NULL, NULL);
333
404
  if (state_ptr == NULL) {
@@ -347,13 +418,10 @@ VALUE brs_ext_compress_io(VALUE BRS_EXT_UNUSED(self), VALUE source, VALUE destin
347
418
  destination_buffer_length = BRS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_COMPRESSOR;
348
419
  }
349
420
 
350
- uint8_t* source_buffer;
351
- uint8_t* destination_buffer;
352
-
353
- ext_result = create_buffers(
354
- &source_buffer, source_buffer_length,
355
- &destination_buffer, destination_buffer_length);
421
+ brs_ext_byte_t* source_buffer;
422
+ brs_ext_byte_t* destination_buffer;
356
423
 
424
+ ext_result = create_buffers(&source_buffer, source_buffer_length, &destination_buffer, destination_buffer_length);
357
425
  if (ext_result != 0) {
358
426
  BrotliEncoderDestroyInstance(state_ptr);
359
427
  brs_ext_raise_error(ext_result);
@@ -361,8 +429,13 @@ VALUE brs_ext_compress_io(VALUE BRS_EXT_UNUSED(self), VALUE source, VALUE destin
361
429
 
362
430
  ext_result = compress(
363
431
  state_ptr,
364
- source_file, source_buffer, source_buffer_length,
365
- destination_file, destination_buffer, destination_buffer_length);
432
+ source_file,
433
+ source_buffer,
434
+ source_buffer_length,
435
+ destination_file,
436
+ destination_buffer,
437
+ destination_buffer_length,
438
+ gvl);
366
439
 
367
440
  free(source_buffer);
368
441
  free(destination_buffer);
@@ -378,41 +451,68 @@ VALUE brs_ext_compress_io(VALUE BRS_EXT_UNUSED(self), VALUE source, VALUE destin
378
451
  return Qnil;
379
452
  }
380
453
 
381
- // -- decompress --
454
+ // -- buffered decompress --
455
+
456
+ typedef struct
457
+ {
458
+ BrotliDecoderState* state_ptr;
459
+ const brs_ext_byte_t** source_ptr;
460
+ size_t* source_length_ptr;
461
+ brs_ext_byte_t* remaining_destination_buffer;
462
+ size_t* remaining_destination_buffer_length_ptr;
463
+ BrotliDecoderResult result;
464
+ } decompress_args_t;
465
+
466
+ static inline void* decompress_wrapper(void* data)
467
+ {
468
+ decompress_args_t* args = data;
469
+
470
+ args->result = BrotliDecoderDecompressStream(
471
+ args->state_ptr,
472
+ args->source_length_ptr,
473
+ args->source_ptr,
474
+ args->remaining_destination_buffer_length_ptr,
475
+ &args->remaining_destination_buffer,
476
+ NULL);
477
+
478
+ return NULL;
479
+ }
382
480
 
383
481
  static inline brs_ext_result_t buffered_decompress(
384
- BrotliDecoderState* state_ptr,
385
- const uint8_t** source_ptr, size_t* source_length_ptr,
386
- FILE* destination_file, uint8_t* destination_buffer, size_t* destination_length_ptr, size_t destination_buffer_length)
482
+ BrotliDecoderState* state_ptr,
483
+ const brs_ext_byte_t** source_ptr,
484
+ size_t* source_length_ptr,
485
+ FILE* destination_file,
486
+ brs_ext_byte_t* destination_buffer,
487
+ size_t* destination_length_ptr,
488
+ size_t destination_buffer_length,
489
+ bool gvl)
387
490
  {
388
- BrotliDecoderResult result;
389
- brs_ext_result_t ext_result;
491
+ brs_ext_result_t ext_result;
492
+ decompress_args_t args = {.state_ptr = state_ptr, .source_ptr = source_ptr, .source_length_ptr = source_length_ptr};
390
493
 
391
494
  while (true) {
392
- uint8_t* remaining_destination_buffer = destination_buffer + *destination_length_ptr;
393
- size_t remaining_destination_buffer_length = destination_buffer_length - *destination_length_ptr;
394
- size_t prev_remaining_destination_buffer_length = remaining_destination_buffer_length;
495
+ brs_ext_byte_t* remaining_destination_buffer = destination_buffer + *destination_length_ptr;
496
+ size_t remaining_destination_buffer_length = destination_buffer_length - *destination_length_ptr;
497
+ size_t prev_remaining_destination_buffer_length = remaining_destination_buffer_length;
498
+
499
+ args.remaining_destination_buffer = remaining_destination_buffer;
500
+ args.remaining_destination_buffer_length_ptr = &remaining_destination_buffer_length;
395
501
 
396
- result = BrotliDecoderDecompressStream(
397
- state_ptr,
398
- source_length_ptr, source_ptr,
399
- &remaining_destination_buffer_length, &remaining_destination_buffer,
400
- NULL);
502
+ BRS_EXT_GVL_WRAP(gvl, decompress_wrapper, &args);
401
503
 
402
504
  if (
403
- result != BROTLI_DECODER_RESULT_SUCCESS &&
404
- result != BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT &&
405
- result != BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
505
+ args.result != BROTLI_DECODER_RESULT_SUCCESS && args.result != BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT &&
506
+ args.result != BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
406
507
  BrotliDecoderErrorCode error_code = BrotliDecoderGetErrorCode(state_ptr);
407
508
  return brs_ext_get_decompressor_error(error_code);
408
509
  }
409
510
 
410
511
  *destination_length_ptr += prev_remaining_destination_buffer_length - remaining_destination_buffer_length;
411
512
 
412
- if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
513
+ if (args.result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
413
514
  ext_result = flush_destination_buffer(
414
- destination_file,
415
- destination_buffer, destination_length_ptr, destination_buffer_length);
515
+ destination_file, destination_buffer, destination_length_ptr, destination_buffer_length);
416
516
 
417
517
  if (ext_result != 0) {
418
518
  return ext_result;
@@ -427,22 +527,33 @@ static inline brs_ext_result_t buffered_decompress(
427
527
  return 0;
428
528
  }
429
529
 
530
+ // -- decompress --
531
+
430
532
  static inline brs_ext_result_t decompress(
431
533
  BrotliDecoderState* state_ptr,
432
- FILE* source_file, uint8_t* source_buffer, size_t source_buffer_length,
433
- FILE* destination_file, uint8_t* destination_buffer, size_t destination_buffer_length)
534
+ FILE* source_file,
535
+ brs_ext_byte_t* source_buffer,
536
+ size_t source_buffer_length,
537
+ FILE* destination_file,
538
+ brs_ext_byte_t* destination_buffer,
539
+ size_t destination_buffer_length,
540
+ bool gvl)
434
541
  {
435
- brs_ext_result_t ext_result;
436
-
437
- const uint8_t* source = source_buffer;
438
- size_t source_length = 0;
439
- size_t destination_length = 0;
542
+ brs_ext_result_t ext_result;
543
+ const brs_ext_byte_t* source = source_buffer;
544
+ size_t source_length = 0;
545
+ size_t destination_length = 0;
440
546
 
441
547
  BUFFERED_READ_SOURCE(
442
548
  buffered_decompress,
443
549
  state_ptr,
444
- &source, &source_length,
445
- destination_file, destination_buffer, &destination_length, destination_buffer_length);
550
+ &source,
551
+ &source_length,
552
+ destination_file,
553
+ destination_buffer,
554
+ &destination_length,
555
+ destination_buffer_length,
556
+ gvl);
446
557
 
447
558
  return write_remaining_destination(destination_file, destination_buffer, destination_length);
448
559
  }
@@ -452,9 +563,10 @@ VALUE brs_ext_decompress_io(VALUE BRS_EXT_UNUSED(self), VALUE source, VALUE dest
452
563
  GET_FILE(source);
453
564
  GET_FILE(destination);
454
565
  Check_Type(options, T_HASH);
566
+ BRS_EXT_GET_SIZE_OPTION(options, source_buffer_length);
567
+ BRS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
568
+ BRS_EXT_GET_BOOL_OPTION(options, gvl);
455
569
  BRS_EXT_GET_DECOMPRESSOR_OPTIONS(options);
456
- BRS_EXT_GET_BUFFER_LENGTH_OPTION(options, source_buffer_length);
457
- BRS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
458
570
 
459
571
  BrotliDecoderState* state_ptr = BrotliDecoderCreateInstance(NULL, NULL, NULL);
460
572
  if (state_ptr == NULL) {
@@ -474,13 +586,10 @@ VALUE brs_ext_decompress_io(VALUE BRS_EXT_UNUSED(self), VALUE source, VALUE dest
474
586
  destination_buffer_length = BRS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_DECOMPRESSOR;
475
587
  }
476
588
 
477
- uint8_t* source_buffer;
478
- uint8_t* destination_buffer;
479
-
480
- ext_result = create_buffers(
481
- &source_buffer, source_buffer_length,
482
- &destination_buffer, destination_buffer_length);
589
+ brs_ext_byte_t* source_buffer;
590
+ brs_ext_byte_t* destination_buffer;
483
591
 
592
+ ext_result = create_buffers(&source_buffer, source_buffer_length, &destination_buffer, destination_buffer_length);
484
593
  if (ext_result != 0) {
485
594
  BrotliDecoderDestroyInstance(state_ptr);
486
595
  brs_ext_raise_error(ext_result);
@@ -488,8 +597,13 @@ VALUE brs_ext_decompress_io(VALUE BRS_EXT_UNUSED(self), VALUE source, VALUE dest
488
597
 
489
598
  ext_result = decompress(
490
599
  state_ptr,
491
- source_file, source_buffer, source_buffer_length,
492
- destination_file, destination_buffer, destination_buffer_length);
600
+ source_file,
601
+ source_buffer,
602
+ source_buffer_length,
603
+ destination_file,
604
+ destination_buffer,
605
+ destination_buffer_length,
606
+ gvl);
493
607
 
494
608
  free(source_buffer);
495
609
  free(destination_buffer);
@@ -505,6 +619,8 @@ VALUE brs_ext_decompress_io(VALUE BRS_EXT_UNUSED(self), VALUE source, VALUE dest
505
619
  return Qnil;
506
620
  }
507
621
 
622
+ // -- exports --
623
+
508
624
  void brs_ext_io_exports(VALUE root_module)
509
625
  {
510
626
  rb_define_module_function(root_module, "_native_compress_io", RUBY_METHOD_FUNC(brs_ext_compress_io), 3);