ruby-brs 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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);