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 +4 -4
- data/README.md +87 -85
- data/ext/brs_ext/buffer.c +21 -7
- data/ext/brs_ext/buffer.h +7 -7
- data/ext/brs_ext/common.h +3 -0
- data/ext/brs_ext/error.c +0 -1
- data/ext/brs_ext/error.h +2 -1
- data/ext/brs_ext/gvl.h +24 -0
- data/ext/brs_ext/io.c +273 -157
- data/ext/brs_ext/main.c +0 -1
- data/ext/brs_ext/option.c +37 -30
- data/ext/brs_ext/option.h +39 -32
- data/ext/brs_ext/stream/compressor.c +124 -61
- data/ext/brs_ext/stream/compressor.h +7 -4
- data/ext/brs_ext/stream/decompressor.c +60 -31
- data/ext/brs_ext/stream/decompressor.h +7 -4
- data/ext/brs_ext/string.c +118 -66
- data/ext/extconf.rb +9 -0
- data/lib/brs/file.rb +4 -0
- data/lib/brs/option.rb +6 -0
- data/lib/brs/stream/abstract.rb +9 -12
- data/lib/brs/stream/raw/abstract.rb +6 -2
- data/lib/brs/stream/raw/compressor.rb +3 -7
- data/lib/brs/stream/raw/decompressor.rb +1 -5
- data/lib/brs/stream/reader.rb +71 -52
- data/lib/brs/stream/writer.rb +10 -5
- data/lib/brs/stream/writer_helpers.rb +6 -5
- data/lib/brs/validation.rb +15 -2
- data/lib/brs/version.rb +1 -1
- metadata +20 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 239de67878a08e54f6b89af1381711ad94c70c1f29d99c8dca22ced06ebd850a
|
4
|
+
data.tar.gz: 2601159e2ede572b8bcdc8ce0ee7ca738f06f42cb0d6e59a159eb525e2f70420
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 |
|
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) | [![
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
92
|
+
get "/" do
|
93
|
+
headers["Content-Encoding"] = "br"
|
94
|
+
BRS::String.compress "sample string"
|
95
|
+
end
|
105
96
|
```
|
106
97
|
|
107
|
-
|
98
|
+
## Options
|
108
99
|
|
109
|
-
|
110
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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
|
-
|
347
|
-
|
348
|
-
|
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).
|
data/ext/brs_ext/buffer.c
CHANGED
@@ -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
|
13
|
+
VALUE brs_ext_resize_string_buffer(VALUE buffer_args)
|
14
14
|
{
|
15
|
-
VALUE buffer = rb_ary_entry(
|
16
|
-
VALUE length = rb_ary_entry(
|
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(
|
25
|
-
|
26
|
-
|
27
|
-
rb_define_const(
|
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
|
}
|
data/ext/brs_ext/buffer.h
CHANGED
@@ -6,10 +6,10 @@
|
|
6
6
|
|
7
7
|
#include "ruby.h"
|
8
8
|
|
9
|
-
#define BRS_DEFAULT_SOURCE_BUFFER_LENGTH_FOR_COMPRESSOR
|
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
|
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
|
20
|
+
VALUE brs_ext_resize_string_buffer(VALUE buffer_args);
|
21
21
|
|
22
|
-
#define BRS_EXT_RESIZE_STRING_BUFFER(buffer, length, exception)
|
23
|
-
VALUE
|
24
|
-
buffer
|
25
|
-
RB_GC_GUARD(
|
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
|
|
data/ext/brs_ext/common.h
CHANGED
data/ext/brs_ext/error.c
CHANGED
data/ext/brs_ext/error.h
CHANGED
data/ext/brs_ext/gvl.h
ADDED
@@ -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
|
data/ext/brs_ext/io.c
CHANGED
@@ -1,32 +1,33 @@
|
|
1
1
|
// Ruby bindings for brotli library.
|
2
2
|
// Copyright (c) 2019 AUTHORS, MIT License.
|
3
3
|
|
4
|
-
#include "
|
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/
|
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
|
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
|
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
|
-
|
59
|
-
|
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
|
-
|
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
|
-
|
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*
|
86
|
-
const
|
87
|
-
|
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
|
90
|
-
size_t
|
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
|
-
|
108
|
-
size_t
|
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
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
return ext_result;
|
139
|
-
}
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
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*
|
164
|
-
|
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
|
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*
|
207
|
-
const
|
208
|
-
|
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
|
-
|
215
|
-
size_t
|
216
|
-
size_t
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
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*
|
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
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
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
|
-
|
261
|
-
size_t
|
262
|
-
size_t
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
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*
|
298
|
-
|
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
|
301
|
-
|
302
|
-
|
303
|
-
size_t
|
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,
|
310
|
-
|
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
|
-
|
351
|
-
|
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,
|
365
|
-
|
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*
|
385
|
-
const
|
386
|
-
|
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
|
-
|
389
|
-
|
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
|
-
|
393
|
-
size_t
|
394
|
-
size_t
|
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
|
-
|
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 !=
|
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*
|
433
|
-
|
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
|
436
|
-
|
437
|
-
|
438
|
-
size_t
|
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,
|
445
|
-
|
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
|
-
|
478
|
-
|
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,
|
492
|
-
|
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);
|