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 +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
|
-
| [](https://travis-ci.com/andrew-aladev/ruby-brs) | [](https://ci.appveyor.com/project/andrew-aladev/ruby-brs/branch/master) | [](https://travis-ci.com/andrew-aladev/ruby-brs) | [](https://ci.appveyor.com/project/andrew-aladev/ruby-brs/branch/master) | [](https://circleci.com/gh/andrew-aladev/ruby-brs/tree/master) | [](https://codecov.io/gh/andrew-aladev/ruby-brs) | [](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);
|