ruby-lzws 1.2.0 → 1.4.1
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 +63 -29
- data/ext/extconf.rb +90 -20
- data/ext/lzws_ext/buffer.c +3 -5
- data/ext/lzws_ext/buffer.h +5 -5
- data/ext/lzws_ext/error.c +11 -13
- data/ext/lzws_ext/gvl.h +24 -0
- data/ext/lzws_ext/io.c +81 -13
- data/ext/lzws_ext/main.c +5 -1
- data/ext/lzws_ext/option.c +36 -19
- data/ext/lzws_ext/option.h +22 -20
- data/ext/lzws_ext/stream/compressor.c +77 -27
- data/ext/lzws_ext/stream/compressor.h +2 -0
- data/ext/lzws_ext/stream/decompressor.c +50 -20
- data/ext/lzws_ext/stream/decompressor.h +2 -0
- data/ext/lzws_ext/string.c +113 -33
- data/lib/lzws/file.rb +2 -2
- data/lib/lzws/option.rb +34 -4
- data/lib/lzws/stream/abstract.rb +5 -3
- data/lib/lzws/stream/reader.rb +3 -2
- data/lib/lzws/stream/reader_helpers.rb +1 -1
- data/lib/lzws/validation.rb +3 -1
- data/lib/lzws/version.rb +1 -1
- metadata +75 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0cd332331b0c0eac3a21a008ec7796ffbee88d7b79039108f9e4857f5ed2a793
|
4
|
+
data.tar.gz: 42f29271be355fe9e48a877a640391d21e8820fd34ca96975b07d063dc3e1abb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9545c057aee9de7e1528905d215c45fe15aa798d1f81dc03e418e1a9ae0b0669d17282d82997f33844563612f731b1ee87b744639b3d04b173d37b28bf492344
|
7
|
+
data.tar.gz: a8eec9b071600eb5ff98efb53aefbf0c48779aa3e468b3c538916bf3335171eefe0e1a73b3d6de8385823e439bd939c6c033cafd5a7c281111f1b4a51b012645
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# Ruby bindings for lzws library
|
2
2
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
| [](https://ci.appveyor.com/project/andrew-aladev/ruby-lzws/branch/master) | [](https://circleci.com/gh/andrew-aladev/ruby-lzws/tree/master) | [](https://github.com/andrew-aladev/ruby-lzws/actions) | [](https://codecov.io/gh/andrew-aladev/ruby-lzws) | [](https://rubygems.org/gems/ruby-lzws) |
|
6
6
|
|
7
7
|
See [lzws library](https://github.com/andrew-aladev/lzws).
|
8
8
|
|
@@ -61,8 +61,8 @@ ensure
|
|
61
61
|
end
|
62
62
|
```
|
63
63
|
|
64
|
-
You can create and read `tar.Z` archives with
|
65
|
-
LZWS is compatible with UNIX compress (with default options).
|
64
|
+
You can create and read `tar.Z` archives with [minitar](https://github.com/halostatue/minitar).
|
65
|
+
LZWS is compatible with [UNIX compress](https://en.wikipedia.org/wiki/Compress) (with default options).
|
66
66
|
|
67
67
|
```ruby
|
68
68
|
require "lzws"
|
@@ -84,12 +84,37 @@ LZWS::Stream::Reader.open "file.tar.Z" do |reader|
|
|
84
84
|
end
|
85
85
|
```
|
86
86
|
|
87
|
+
You can also use `Content-Encoding: compress` with [sinatra](http://sinatrarb.com):
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
require "lzws"
|
91
|
+
require "sinatra"
|
92
|
+
|
93
|
+
get "/" do
|
94
|
+
headers["Content-Encoding"] = "compress"
|
95
|
+
LZWS::String.compress "TOBEORNOTTOBEORTOBEORNOT"
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
All functionality (including streaming) can be used inside multiple threads with [parallel](https://github.com/grosser/parallel).
|
100
|
+
This code will provide heavy load for your CPU.
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
require "lzws"
|
104
|
+
require "parallel"
|
105
|
+
|
106
|
+
Parallel.each large_datas do |large_data|
|
107
|
+
LZWS::String.compress large_data
|
108
|
+
end
|
109
|
+
```
|
110
|
+
|
87
111
|
## Options
|
88
112
|
|
89
113
|
| Option | Values | Default | Description |
|
90
114
|
|-----------------------------|------------|----------|-------------|
|
91
115
|
| `source_buffer_length` | 0, 2 - inf | 0 (auto) | internal buffer length for source data |
|
92
116
|
| `destination_buffer_length` | 0, 2 - inf | 0 (auto) | internal buffer length for description data |
|
117
|
+
| `gvl` | true/false | false | enables global VM lock where possible |
|
93
118
|
| `max_code_bit_length` | 9 - 16 | 16 | max code bit length |
|
94
119
|
| `block_mode` | true/false | true | enables block mode |
|
95
120
|
| `without_magic_header` | true/false | false | disables magic header |
|
@@ -101,6 +126,10 @@ There are internal buffers for compressed and decompressed data.
|
|
101
126
|
For example you want to use 1 KB as `source_buffer_length` for compressor - please use 256 B as `destination_buffer_length`.
|
102
127
|
You want to use 256 B as `source_buffer_length` for decompressor - please use 1 KB as `destination_buffer_length`.
|
103
128
|
|
129
|
+
`gvl` is disabled by default, this mode allows running multiple compressors/decompressors in different threads simultaneously.
|
130
|
+
Please consider enabling `gvl` if you don't want to launch processors in separate threads.
|
131
|
+
If `gvl` is enabled ruby won't waste time on acquiring/releasing VM lock.
|
132
|
+
|
104
133
|
You can also read lzws docs for more info about options.
|
105
134
|
|
106
135
|
| Option | Related constants |
|
@@ -111,6 +140,7 @@ Possible compressor options:
|
|
111
140
|
```
|
112
141
|
:source_buffer_length
|
113
142
|
:destination_buffer_length
|
143
|
+
:gvl
|
114
144
|
:max_code_bit_length
|
115
145
|
:block_mode
|
116
146
|
:without_magic_header
|
@@ -123,6 +153,7 @@ Possible decompressor options:
|
|
123
153
|
```
|
124
154
|
:source_buffer_length
|
125
155
|
:destination_buffer_length
|
156
|
+
:gvl
|
126
157
|
:without_magic_header
|
127
158
|
:msb
|
128
159
|
:unaligned_bit_groups
|
@@ -138,18 +169,6 @@ data = LZWS::String.compress "TOBEORNOTTOBEORTOBEORNOT", :msb => true
|
|
138
169
|
puts LZWS::String.decompress(data, :msb => true)
|
139
170
|
```
|
140
171
|
|
141
|
-
Default options are compatible with UNIX compress (`Content-Encoding: compress`):
|
142
|
-
|
143
|
-
```ruby
|
144
|
-
require "lzws"
|
145
|
-
require "sinatra"
|
146
|
-
|
147
|
-
get "/" do
|
148
|
-
headers["Content-Encoding"] = "compress"
|
149
|
-
LZWS::String.compress "TOBEORNOTTOBEORTOBEORNOT"
|
150
|
-
end
|
151
|
-
```
|
152
|
-
|
153
172
|
Please read more about compatibility in lzws docs.
|
154
173
|
|
155
174
|
## String
|
@@ -176,7 +195,7 @@ File maintains both source and destination buffers, it accepts both `source_buff
|
|
176
195
|
|
177
196
|
## Stream::Writer
|
178
197
|
|
179
|
-
Its behaviour is similar to builtin [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib
|
198
|
+
Its behaviour is similar to builtin [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib/libdoc/zlib/rdoc/Zlib/GzipWriter.html).
|
180
199
|
|
181
200
|
Writer maintains destination buffer only, so it accepts `destination_buffer_length` option only.
|
182
201
|
|
@@ -210,7 +229,7 @@ Set another encodings, `nil` is just for compatibility with `IO`.
|
|
210
229
|
#tell
|
211
230
|
```
|
212
231
|
|
213
|
-
See [`IO`](https://ruby-doc.org/core
|
232
|
+
See [`IO`](https://ruby-doc.org/core/IO.html) docs.
|
214
233
|
|
215
234
|
```
|
216
235
|
#write(*objects)
|
@@ -220,7 +239,7 @@ See [`IO`](https://ruby-doc.org/core-2.7.0/IO.html) docs.
|
|
220
239
|
#closed?
|
221
240
|
```
|
222
241
|
|
223
|
-
See [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib
|
242
|
+
See [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib/libdoc/zlib/rdoc/Zlib/GzipWriter.html) docs.
|
224
243
|
|
225
244
|
```
|
226
245
|
#write_nonblock(object, *options)
|
@@ -234,6 +253,9 @@ Special asynchronous methods missing in `Zlib::GzipWriter`.
|
|
234
253
|
So it is possible to have asynchronous variants for these synchronous methods.
|
235
254
|
Behaviour is the same as `IO#write_nonblock` method.
|
236
255
|
|
256
|
+
All nonblock operations for file will raise `EBADF` error on Windows.
|
257
|
+
Setting file into nonblocking mode is [not available on Windows](https://github.com/ruby/ruby/blob/master/win32/win32.c#L4388).
|
258
|
+
|
237
259
|
```
|
238
260
|
#<<(object)
|
239
261
|
#print(*objects)
|
@@ -242,11 +264,11 @@ Behaviour is the same as `IO#write_nonblock` method.
|
|
242
264
|
#puts(*objects)
|
243
265
|
```
|
244
266
|
|
245
|
-
Typical helpers, see [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib
|
267
|
+
Typical helpers, see [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib/libdoc/zlib/rdoc/Zlib/GzipWriter.html) docs.
|
246
268
|
|
247
269
|
## Stream::Reader
|
248
270
|
|
249
|
-
Its behaviour is similar to builtin [`Zlib::GzipReader`](https://ruby-doc.org/stdlib
|
271
|
+
Its behaviour is similar to builtin [`Zlib::GzipReader`](https://ruby-doc.org/stdlib/libdoc/zlib/rdoc/Zlib/GzipReader.html).
|
250
272
|
|
251
273
|
Reader maintains both source and destination buffers, it accepts both `source_buffer_length` and `destination_buffer_length` options.
|
252
274
|
|
@@ -281,7 +303,7 @@ Set another encodings.
|
|
281
303
|
#tell
|
282
304
|
```
|
283
305
|
|
284
|
-
See [`IO`](https://ruby-doc.org/core
|
306
|
+
See [`IO`](https://ruby-doc.org/core/IO.html) docs.
|
285
307
|
|
286
308
|
```
|
287
309
|
#read(bytes_to_read = nil, out_buffer = nil)
|
@@ -291,14 +313,14 @@ See [`IO`](https://ruby-doc.org/core-2.7.0/IO.html) docs.
|
|
291
313
|
#closed?
|
292
314
|
```
|
293
315
|
|
294
|
-
See [`Zlib::GzipReader`](https://ruby-doc.org/stdlib
|
316
|
+
See [`Zlib::GzipReader`](https://ruby-doc.org/stdlib/libdoc/zlib/rdoc/Zlib/GzipReader.html) docs.
|
295
317
|
|
296
318
|
```
|
297
319
|
#readpartial(bytes_to_read = nil, out_buffer = nil)
|
298
320
|
#read_nonblock(bytes_to_read, out_buffer = nil, *options)
|
299
321
|
```
|
300
322
|
|
301
|
-
See [`IO`](https://ruby-doc.org/core
|
323
|
+
See [`IO`](https://ruby-doc.org/core/IO.html) docs.
|
302
324
|
|
303
325
|
```
|
304
326
|
#getbyte
|
@@ -321,14 +343,26 @@ See [`IO`](https://ruby-doc.org/core-2.7.0/IO.html) docs.
|
|
321
343
|
#ungetline(line)
|
322
344
|
```
|
323
345
|
|
324
|
-
Typical helpers, see [`Zlib::GzipReader`](https://ruby-doc.org/stdlib
|
346
|
+
Typical helpers, see [`Zlib::GzipReader`](https://ruby-doc.org/stdlib/libdoc/zlib/rdoc/Zlib/GzipReader.html) docs.
|
347
|
+
|
348
|
+
## Thread safety
|
349
|
+
|
350
|
+
`:gvl` option is disabled by default, you can use bindings effectively in multiple threads.
|
351
|
+
Please be careful: bindings are not thread safe.
|
352
|
+
You should lock all shared data between threads.
|
353
|
+
|
354
|
+
For example: you should not use same compressor/decompressor inside multiple threads.
|
355
|
+
Please verify that you are using each processor inside single thread at the same time.
|
356
|
+
|
357
|
+
## Operating systems
|
358
|
+
|
359
|
+
GNU/Linux, FreeBSD, OSX, Windows (MinGW).
|
325
360
|
|
326
361
|
## CI
|
327
362
|
|
328
|
-
See universal test script [scripts/ci_test.sh](scripts/ci_test.sh) for CI.
|
329
363
|
Please visit [scripts/test-images](scripts/test-images).
|
330
|
-
|
364
|
+
See universal test script [scripts/ci_test.sh](scripts/ci_test.sh) for CI.
|
331
365
|
|
332
366
|
## License
|
333
367
|
|
334
|
-
MIT license, see LICENSE and AUTHORS.
|
368
|
+
MIT license, see [LICENSE](LICENSE) and [AUTHORS](AUTHORS).
|
data/ext/extconf.rb
CHANGED
@@ -3,23 +3,96 @@
|
|
3
3
|
|
4
4
|
require "mkmf"
|
5
5
|
|
6
|
-
|
6
|
+
have_func "rb_thread_call_without_gvl", "ruby/thread.h"
|
7
|
+
|
8
|
+
def require_header(name, constants: [], macroses: [], types: [], variables: [])
|
7
9
|
abort "Can't find #{name} header" unless find_header name
|
8
10
|
|
11
|
+
constants.each do |constant|
|
12
|
+
abort "Can't find #{constant} constant in #{name} header" unless have_const constant, name
|
13
|
+
end
|
14
|
+
|
15
|
+
macroses.each do |macro|
|
16
|
+
abort "Can't find #{macro} macro in #{name} header" unless have_macro macro, name
|
17
|
+
end
|
18
|
+
|
9
19
|
types.each do |type|
|
10
20
|
abort "Can't find #{type} type in #{name} header" unless find_type type, nil, name
|
11
21
|
end
|
22
|
+
|
23
|
+
variables.each do |variable|
|
24
|
+
abort "Can't find #{variable} variable in #{name} header" unless have_var variable, name
|
25
|
+
end
|
12
26
|
end
|
13
27
|
|
14
|
-
require_header
|
15
|
-
|
16
|
-
|
28
|
+
require_header(
|
29
|
+
"lzws/buffer.h",
|
30
|
+
:macroses => %w[
|
31
|
+
LZWS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_COMPRESSOR
|
32
|
+
LZWS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_DECOMPRESSOR
|
33
|
+
LZWS_DEFAULT_SOURCE_BUFFER_LENGTH_FOR_COMPRESSOR
|
34
|
+
LZWS_DEFAULT_SOURCE_BUFFER_LENGTH_FOR_DECOMPRESSOR
|
35
|
+
]
|
36
|
+
)
|
37
|
+
require_header(
|
38
|
+
"lzws/common.h",
|
39
|
+
:constants => %w[
|
40
|
+
LZWS_BIGGEST_MAX_CODE_BIT_LENGTH
|
41
|
+
LZWS_LOWEST_MAX_CODE_BIT_LENGTH
|
42
|
+
],
|
43
|
+
:types => %w[
|
44
|
+
lzws_byte_fast_t
|
45
|
+
lzws_result_t
|
46
|
+
]
|
47
|
+
)
|
48
|
+
require_header(
|
49
|
+
"lzws/compressor/common.h",
|
50
|
+
:constants => %w[
|
51
|
+
LZWS_COMPRESSOR_ALLOCATE_FAILED
|
52
|
+
LZWS_COMPRESSOR_INVALID_MAX_CODE_BIT_LENGTH
|
53
|
+
LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION
|
54
|
+
],
|
55
|
+
:types => %w[lzws_compressor_options_t],
|
56
|
+
:variables => %w[LZWS_COMPRESSOR_DEFAULT_OPTIONS]
|
57
|
+
)
|
17
58
|
require_header "lzws/compressor/main.h"
|
18
|
-
require_header
|
19
|
-
|
59
|
+
require_header(
|
60
|
+
"lzws/compressor/state.h",
|
61
|
+
:types => %w[lzws_compressor_state_t]
|
62
|
+
)
|
63
|
+
require_header(
|
64
|
+
"lzws/config.h",
|
65
|
+
:macroses => %w[LZWS_VERSION]
|
66
|
+
)
|
67
|
+
require_header(
|
68
|
+
"lzws/decompressor/common.h",
|
69
|
+
:constants => %w[
|
70
|
+
LZWS_DECOMPRESSOR_ALLOCATE_FAILED
|
71
|
+
LZWS_DECOMPRESSOR_CORRUPTED_SOURCE
|
72
|
+
LZWS_DECOMPRESSOR_INVALID_MAGIC_HEADER
|
73
|
+
LZWS_DECOMPRESSOR_INVALID_MAX_CODE_BIT_LENGTH
|
74
|
+
LZWS_DECOMPRESSOR_NEEDS_MORE_DESTINATION
|
75
|
+
],
|
76
|
+
:types => %w[lzws_decompressor_options_t],
|
77
|
+
:variables => %w[LZWS_DECOMPRESSOR_DEFAULT_OPTIONS]
|
78
|
+
)
|
20
79
|
require_header "lzws/decompressor/main.h"
|
21
|
-
require_header
|
22
|
-
|
80
|
+
require_header(
|
81
|
+
"lzws/decompressor/state.h",
|
82
|
+
:types => %w[lzws_decompressor_state_t]
|
83
|
+
)
|
84
|
+
require_header(
|
85
|
+
"lzws/file.h",
|
86
|
+
:constants => %w[
|
87
|
+
LZWS_FILE_ALLOCATE_FAILED
|
88
|
+
LZWS_FILE_DECOMPRESSOR_CORRUPTED_SOURCE
|
89
|
+
LZWS_FILE_NOT_ENOUGH_DESTINATION_BUFFER
|
90
|
+
LZWS_FILE_NOT_ENOUGH_SOURCE_BUFFER
|
91
|
+
LZWS_FILE_READ_FAILED
|
92
|
+
LZWS_FILE_VALIDATE_FAILED
|
93
|
+
LZWS_FILE_WRITE_FAILED
|
94
|
+
]
|
95
|
+
)
|
23
96
|
|
24
97
|
def require_library(name, functions)
|
25
98
|
functions.each do |function|
|
@@ -30,22 +103,19 @@ end
|
|
30
103
|
require_library(
|
31
104
|
"lzws",
|
32
105
|
%w[
|
106
|
+
lzws_compress
|
107
|
+
lzws_compress_file
|
108
|
+
lzws_compressor_finish
|
109
|
+
lzws_compressor_free_state
|
110
|
+
lzws_compressor_get_initial_state
|
33
111
|
lzws_create_source_buffer_for_compressor
|
34
|
-
lzws_create_destination_buffer_for_compressor
|
35
112
|
lzws_create_source_buffer_for_decompressor
|
113
|
+
lzws_create_destination_buffer_for_compressor
|
36
114
|
lzws_create_destination_buffer_for_decompressor
|
37
|
-
|
38
|
-
lzws_compressor_get_initial_state
|
39
|
-
lzws_compressor_free_state
|
40
|
-
lzws_compress
|
41
|
-
lzws_compressor_finish
|
42
|
-
|
43
|
-
lzws_decompressor_get_initial_state
|
44
|
-
lzws_decompressor_free_state
|
45
115
|
lzws_decompress
|
46
|
-
|
47
|
-
lzws_compress_file
|
48
116
|
lzws_decompress_file
|
117
|
+
lzws_decompressor_free_state
|
118
|
+
lzws_decompressor_get_initial_state
|
49
119
|
]
|
50
120
|
)
|
51
121
|
|
@@ -73,7 +143,7 @@ $libs = $libs.split(%r{\s})
|
|
73
143
|
.uniq
|
74
144
|
.join " "
|
75
145
|
|
76
|
-
if ENV["CI"]
|
146
|
+
if ENV["CI"]
|
77
147
|
$CFLAGS << " --coverage"
|
78
148
|
$LDFLAGS << " --coverage"
|
79
149
|
end
|
data/ext/lzws_ext/buffer.c
CHANGED
@@ -5,17 +5,15 @@
|
|
5
5
|
|
6
6
|
#include <lzws/buffer.h>
|
7
7
|
|
8
|
-
#include "ruby.h"
|
9
|
-
|
10
8
|
VALUE lzws_ext_create_string_buffer(VALUE length)
|
11
9
|
{
|
12
10
|
return rb_str_new(NULL, NUM2SIZET(length));
|
13
11
|
}
|
14
12
|
|
15
|
-
VALUE lzws_ext_resize_string_buffer(VALUE
|
13
|
+
VALUE lzws_ext_resize_string_buffer(VALUE buffer_args)
|
16
14
|
{
|
17
|
-
VALUE buffer = rb_ary_entry(
|
18
|
-
VALUE length = rb_ary_entry(
|
15
|
+
VALUE buffer = rb_ary_entry(buffer_args, 0);
|
16
|
+
VALUE length = rb_ary_entry(buffer_args, 1);
|
19
17
|
|
20
18
|
return rb_str_resize(buffer, NUM2SIZET(length));
|
21
19
|
}
|
data/ext/lzws_ext/buffer.h
CHANGED
@@ -11,12 +11,12 @@ VALUE lzws_ext_create_string_buffer(VALUE length);
|
|
11
11
|
#define LZWS_EXT_CREATE_STRING_BUFFER(buffer, length, exception) \
|
12
12
|
VALUE buffer = rb_protect(lzws_ext_create_string_buffer, SIZET2NUM(length), &exception);
|
13
13
|
|
14
|
-
VALUE lzws_ext_resize_string_buffer(VALUE
|
14
|
+
VALUE lzws_ext_resize_string_buffer(VALUE buffer_args);
|
15
15
|
|
16
|
-
#define LZWS_EXT_RESIZE_STRING_BUFFER(buffer, length, exception)
|
17
|
-
VALUE
|
18
|
-
buffer
|
19
|
-
RB_GC_GUARD(
|
16
|
+
#define LZWS_EXT_RESIZE_STRING_BUFFER(buffer, length, exception) \
|
17
|
+
VALUE buffer_args = rb_ary_new_from_args(2, buffer, SIZET2NUM(length)); \
|
18
|
+
buffer = rb_protect(lzws_ext_resize_string_buffer, buffer_args, &exception); \
|
19
|
+
RB_GC_GUARD(buffer_args);
|
20
20
|
|
21
21
|
void lzws_ext_buffer_exports(VALUE root_module);
|
22
22
|
|
data/ext/lzws_ext/error.c
CHANGED
@@ -3,9 +3,7 @@
|
|
3
3
|
|
4
4
|
#include "lzws_ext/error.h"
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
static inline NORETURN(void raise(const char* name, const char* description))
|
6
|
+
static inline NORETURN(void raise_error(const char* name, const char* description))
|
9
7
|
{
|
10
8
|
VALUE module = rb_define_module(LZWS_EXT_MODULE_NAME);
|
11
9
|
VALUE error = rb_const_get(module, rb_intern(name));
|
@@ -16,28 +14,28 @@ void lzws_ext_raise_error(lzws_ext_result_t ext_result)
|
|
16
14
|
{
|
17
15
|
switch (ext_result) {
|
18
16
|
case LZWS_EXT_ERROR_ALLOCATE_FAILED:
|
19
|
-
|
17
|
+
raise_error("AllocateError", "allocate error");
|
20
18
|
case LZWS_EXT_ERROR_VALIDATE_FAILED:
|
21
|
-
|
19
|
+
raise_error("ValidateError", "validate error");
|
22
20
|
|
23
21
|
case LZWS_EXT_ERROR_USED_AFTER_CLOSE:
|
24
|
-
|
22
|
+
raise_error("UsedAfterCloseError", "used after closed");
|
25
23
|
case LZWS_EXT_ERROR_NOT_ENOUGH_SOURCE_BUFFER:
|
26
|
-
|
24
|
+
raise_error("NotEnoughSourceBufferError", "not enough source buffer");
|
27
25
|
case LZWS_EXT_ERROR_NOT_ENOUGH_DESTINATION_BUFFER:
|
28
|
-
|
26
|
+
raise_error("NotEnoughDestinationBufferError", "not enough destination buffer");
|
29
27
|
case LZWS_EXT_ERROR_DECOMPRESSOR_CORRUPTED_SOURCE:
|
30
|
-
|
28
|
+
raise_error("DecompressorCorruptedSourceError", "decompressor received corrupted source");
|
31
29
|
|
32
30
|
case LZWS_EXT_ERROR_ACCESS_IO:
|
33
|
-
|
31
|
+
raise_error("AccessIOError", "failed to access IO");
|
34
32
|
case LZWS_EXT_ERROR_READ_IO:
|
35
|
-
|
33
|
+
raise_error("ReadIOError", "failed to read IO");
|
36
34
|
case LZWS_EXT_ERROR_WRITE_IO:
|
37
|
-
|
35
|
+
raise_error("WriteIOError", "failed to write IO");
|
38
36
|
|
39
37
|
default:
|
40
38
|
// LZWS_EXT_ERROR_UNEXPECTED
|
41
|
-
|
39
|
+
raise_error("UnexpectedError", "unexpected error");
|
42
40
|
}
|
43
41
|
}
|
data/ext/lzws_ext/gvl.h
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
// Ruby bindings for lzws library.
|
2
|
+
// Copyright (c) 2019 AUTHORS, MIT License.
|
3
|
+
|
4
|
+
#if !defined(LZWS_EXT_GVL_H)
|
5
|
+
#define LZWS_EXT_GVL_H
|
6
|
+
|
7
|
+
#ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
|
8
|
+
|
9
|
+
#include "ruby/thread.h"
|
10
|
+
|
11
|
+
#define LZWS_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 LZWS_EXT_GVL_WRAP(_gvl, function, data) function((void*) data);
|
21
|
+
|
22
|
+
#endif
|
23
|
+
|
24
|
+
#endif // LZWS_EXT_GVL_H
|
data/ext/lzws_ext/io.c
CHANGED
@@ -6,11 +6,13 @@
|
|
6
6
|
#include <lzws/file.h>
|
7
7
|
|
8
8
|
#include "lzws_ext/error.h"
|
9
|
+
#include "lzws_ext/gvl.h"
|
9
10
|
#include "lzws_ext/macro.h"
|
10
11
|
#include "lzws_ext/option.h"
|
11
|
-
#include "ruby.h"
|
12
12
|
#include "ruby/io.h"
|
13
13
|
|
14
|
+
// -- utils --
|
15
|
+
|
14
16
|
#define GET_FILE(target) \
|
15
17
|
Check_Type(target, T_FILE); \
|
16
18
|
\
|
@@ -47,20 +49,52 @@ static inline lzws_ext_result_t get_file_error(lzws_result_t result)
|
|
47
49
|
}
|
48
50
|
}
|
49
51
|
|
52
|
+
// -- compress --
|
53
|
+
|
54
|
+
typedef struct
|
55
|
+
{
|
56
|
+
FILE* source_file;
|
57
|
+
size_t source_buffer_length;
|
58
|
+
FILE* destination_file;
|
59
|
+
size_t destination_buffer_length;
|
60
|
+
lzws_compressor_options_t* compressor_options_ptr;
|
61
|
+
lzws_result_t result;
|
62
|
+
} compress_args_t;
|
63
|
+
|
64
|
+
static inline void* compress_wrapper(void* data)
|
65
|
+
{
|
66
|
+
compress_args_t* args = data;
|
67
|
+
|
68
|
+
args->result = lzws_compress_file(
|
69
|
+
args->source_file,
|
70
|
+
args->source_buffer_length,
|
71
|
+
args->destination_file,
|
72
|
+
args->destination_buffer_length,
|
73
|
+
args->compressor_options_ptr);
|
74
|
+
|
75
|
+
return NULL;
|
76
|
+
}
|
77
|
+
|
50
78
|
VALUE lzws_ext_compress_io(VALUE LZWS_EXT_UNUSED(self), VALUE source, VALUE destination, VALUE options)
|
51
79
|
{
|
52
80
|
GET_FILE(source);
|
53
81
|
GET_FILE(destination);
|
54
82
|
Check_Type(options, T_HASH);
|
83
|
+
LZWS_EXT_GET_SIZE_OPTION(options, source_buffer_length);
|
84
|
+
LZWS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
|
85
|
+
LZWS_EXT_GET_BOOL_OPTION(options, gvl);
|
55
86
|
LZWS_EXT_GET_COMPRESSOR_OPTIONS(options);
|
56
|
-
LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, source_buffer_length);
|
57
|
-
LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
|
58
87
|
|
59
|
-
|
60
|
-
source_file
|
88
|
+
compress_args_t args = {
|
89
|
+
.source_file = source_file,
|
90
|
+
.source_buffer_length = source_buffer_length,
|
91
|
+
.destination_file = destination_file,
|
92
|
+
.destination_buffer_length = destination_buffer_length,
|
93
|
+
.compressor_options_ptr = &compressor_options};
|
61
94
|
|
62
|
-
|
63
|
-
|
95
|
+
LZWS_EXT_GVL_WRAP(gvl, compress_wrapper, &args);
|
96
|
+
if (args.result != 0) {
|
97
|
+
lzws_ext_raise_error(get_file_error(args.result));
|
64
98
|
}
|
65
99
|
|
66
100
|
// Ruby itself won't flush stdio file before closing fd, flush is required.
|
@@ -69,20 +103,52 @@ VALUE lzws_ext_compress_io(VALUE LZWS_EXT_UNUSED(self), VALUE source, VALUE dest
|
|
69
103
|
return Qnil;
|
70
104
|
}
|
71
105
|
|
106
|
+
// -- decompress --
|
107
|
+
|
108
|
+
typedef struct
|
109
|
+
{
|
110
|
+
FILE* source_file;
|
111
|
+
size_t source_buffer_length;
|
112
|
+
FILE* destination_file;
|
113
|
+
size_t destination_buffer_length;
|
114
|
+
lzws_decompressor_options_t* decompressor_options_ptr;
|
115
|
+
lzws_result_t result;
|
116
|
+
} decompress_args_t;
|
117
|
+
|
118
|
+
static inline void* decompress_wrapper(void* data)
|
119
|
+
{
|
120
|
+
decompress_args_t* args = data;
|
121
|
+
|
122
|
+
args->result = lzws_decompress_file(
|
123
|
+
args->source_file,
|
124
|
+
args->source_buffer_length,
|
125
|
+
args->destination_file,
|
126
|
+
args->destination_buffer_length,
|
127
|
+
args->decompressor_options_ptr);
|
128
|
+
|
129
|
+
return NULL;
|
130
|
+
}
|
131
|
+
|
72
132
|
VALUE lzws_ext_decompress_io(VALUE LZWS_EXT_UNUSED(self), VALUE source, VALUE destination, VALUE options)
|
73
133
|
{
|
74
134
|
GET_FILE(source);
|
75
135
|
GET_FILE(destination);
|
76
136
|
Check_Type(options, T_HASH);
|
137
|
+
LZWS_EXT_GET_SIZE_OPTION(options, source_buffer_length);
|
138
|
+
LZWS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
|
139
|
+
LZWS_EXT_GET_BOOL_OPTION(options, gvl);
|
77
140
|
LZWS_EXT_GET_DECOMPRESSOR_OPTIONS(options);
|
78
|
-
LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, source_buffer_length);
|
79
|
-
LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
|
80
141
|
|
81
|
-
|
82
|
-
source_file
|
142
|
+
decompress_args_t args = {
|
143
|
+
.source_file = source_file,
|
144
|
+
.source_buffer_length = source_buffer_length,
|
145
|
+
.destination_file = destination_file,
|
146
|
+
.destination_buffer_length = destination_buffer_length,
|
147
|
+
.decompressor_options_ptr = &decompressor_options};
|
83
148
|
|
84
|
-
|
85
|
-
|
149
|
+
LZWS_EXT_GVL_WRAP(gvl, decompress_wrapper, &args);
|
150
|
+
if (args.result != 0) {
|
151
|
+
lzws_ext_raise_error(get_file_error(args.result));
|
86
152
|
}
|
87
153
|
|
88
154
|
// Ruby itself won't flush stdio file before closing fd, flush is required.
|
@@ -91,6 +157,8 @@ VALUE lzws_ext_decompress_io(VALUE LZWS_EXT_UNUSED(self), VALUE source, VALUE de
|
|
91
157
|
return Qnil;
|
92
158
|
}
|
93
159
|
|
160
|
+
// -- exports --
|
161
|
+
|
94
162
|
void lzws_ext_io_exports(VALUE root_module)
|
95
163
|
{
|
96
164
|
rb_define_module_function(root_module, "_native_compress_io", RUBY_METHOD_FUNC(lzws_ext_compress_io), 3);
|
data/ext/lzws_ext/main.c
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
// Ruby bindings for lzws library.
|
2
2
|
// Copyright (c) 2019 AUTHORS, MIT License.
|
3
3
|
|
4
|
+
#include <lzws/config.h>
|
5
|
+
|
4
6
|
#include "lzws_ext/buffer.h"
|
5
7
|
#include "lzws_ext/io.h"
|
6
8
|
#include "lzws_ext/option.h"
|
7
9
|
#include "lzws_ext/stream/compressor.h"
|
8
10
|
#include "lzws_ext/stream/decompressor.h"
|
9
11
|
#include "lzws_ext/string.h"
|
10
|
-
#include "ruby.h"
|
11
12
|
|
12
13
|
void Init_lzws_ext()
|
13
14
|
{
|
@@ -19,4 +20,7 @@ void Init_lzws_ext()
|
|
19
20
|
lzws_ext_compressor_exports(root_module);
|
20
21
|
lzws_ext_decompressor_exports(root_module);
|
21
22
|
lzws_ext_string_exports(root_module);
|
23
|
+
|
24
|
+
VALUE version = rb_str_new2(LZWS_VERSION);
|
25
|
+
rb_define_const(root_module, "LIBRARY_VERSION", rb_obj_freeze(version));
|
22
26
|
}
|