ruby-lzws 1.2.0 → 1.3.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 +33 -20
- data/ext/extconf.rb +2 -0
- data/ext/lzws_ext/buffer.c +3 -3
- data/ext/lzws_ext/buffer.h +5 -5
- data/ext/lzws_ext/gvl.h +24 -0
- data/ext/lzws_ext/io.c +81 -12
- data/ext/lzws_ext/option.c +36 -18
- data/ext/lzws_ext/option.h +22 -20
- data/ext/lzws_ext/stream/compressor.c +77 -25
- data/ext/lzws_ext/stream/compressor.h +2 -0
- data/ext/lzws_ext/stream/decompressor.c +50 -18
- data/ext/lzws_ext/stream/decompressor.h +2 -0
- data/ext/lzws_ext/string.c +113 -32
- data/lib/lzws/option.rb +26 -2
- data/lib/lzws/version.rb +1 -1
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46de1059ebc7e81a3c93869a70801e20571e99631a0a9a8acc0cad9b06e9c21f
|
4
|
+
data.tar.gz: c4d1d3859bd374404b496b9ae393f34b08b49bf94655e420862545fd8949cc12
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 88f2f3627fb6f98fffc6c1289301a9362c6ab22edc7de42732a90c85b1065bd2e3ee73547dbab0ee1c40d14c3490053f43d36d7b67abb25aa6ec2e938211e95e
|
7
|
+
data.tar.gz: e6b97fea5d39bd2ee8b4e9ad43d16453f0640536c86dd9e0d425443c3a48a5bb3bf99c5bb452e4065f3c21489572a4bf05a9809b1eccfd7ef39773a1eea0d05d
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# Ruby bindings for lzws library
|
2
2
|
|
3
|
-
| Travis | AppVeyor | Circle | Codecov |
|
4
|
-
| :---: | :---: | :---: | :---: |
|
5
|
-
| [](https://travis-ci.com/andrew-aladev/ruby-lzws) | [](https://ci.appveyor.com/project/andrew-aladev/ruby-lzws/branch/master) | [](https://circleci.com/gh/andrew-aladev/ruby-lzws/tree/master) | [](https://codecov.io/gh/andrew-aladev/ruby-lzws) |
|
3
|
+
| Travis | AppVeyor | Circle | Codecov | Gem |
|
4
|
+
| :---: | :---: | :---: | :---: | :---: |
|
5
|
+
| [](https://travis-ci.com/andrew-aladev/ruby-lzws) | [](https://ci.appveyor.com/project/andrew-aladev/ruby-lzws/branch/master) | [](https://circleci.com/gh/andrew-aladev/ruby-lzws/tree/master) | [](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) for example.
|
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,25 @@ 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
|
+
|
87
99
|
## Options
|
88
100
|
|
89
101
|
| Option | Values | Default | Description |
|
90
102
|
|-----------------------------|------------|----------|-------------|
|
91
103
|
| `source_buffer_length` | 0, 2 - inf | 0 (auto) | internal buffer length for source data |
|
92
104
|
| `destination_buffer_length` | 0, 2 - inf | 0 (auto) | internal buffer length for description data |
|
105
|
+
| `gvl` | true/false | false | enables global VM lock where possible |
|
93
106
|
| `max_code_bit_length` | 9 - 16 | 16 | max code bit length |
|
94
107
|
| `block_mode` | true/false | true | enables block mode |
|
95
108
|
| `without_magic_header` | true/false | false | disables magic header |
|
@@ -101,6 +114,10 @@ There are internal buffers for compressed and decompressed data.
|
|
101
114
|
For example you want to use 1 KB as `source_buffer_length` for compressor - please use 256 B as `destination_buffer_length`.
|
102
115
|
You want to use 256 B as `source_buffer_length` for decompressor - please use 1 KB as `destination_buffer_length`.
|
103
116
|
|
117
|
+
`gvl` is disabled by default, this mode allows running multiple compressors/decompressors in different threads simultaneously.
|
118
|
+
Please consider enabling `gvl` if you don't want to launch processors in separate threads.
|
119
|
+
If `gvl` is enabled ruby won't waste time on acquiring/releasing VM lock.
|
120
|
+
|
104
121
|
You can also read lzws docs for more info about options.
|
105
122
|
|
106
123
|
| Option | Related constants |
|
@@ -111,6 +128,7 @@ Possible compressor options:
|
|
111
128
|
```
|
112
129
|
:source_buffer_length
|
113
130
|
:destination_buffer_length
|
131
|
+
:gvl
|
114
132
|
:max_code_bit_length
|
115
133
|
:block_mode
|
116
134
|
:without_magic_header
|
@@ -123,6 +141,7 @@ Possible decompressor options:
|
|
123
141
|
```
|
124
142
|
:source_buffer_length
|
125
143
|
:destination_buffer_length
|
144
|
+
:gvl
|
126
145
|
:without_magic_header
|
127
146
|
:msb
|
128
147
|
:unaligned_bit_groups
|
@@ -138,18 +157,6 @@ data = LZWS::String.compress "TOBEORNOTTOBEORTOBEORNOT", :msb => true
|
|
138
157
|
puts LZWS::String.decompress(data, :msb => true)
|
139
158
|
```
|
140
159
|
|
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
160
|
Please read more about compatibility in lzws docs.
|
154
161
|
|
155
162
|
## String
|
@@ -323,12 +330,18 @@ See [`IO`](https://ruby-doc.org/core-2.7.0/IO.html) docs.
|
|
323
330
|
|
324
331
|
Typical helpers, see [`Zlib::GzipReader`](https://ruby-doc.org/stdlib-2.7.0/libdoc/zlib/rdoc/Zlib/GzipReader.html) docs.
|
325
332
|
|
333
|
+
## Thread safety
|
334
|
+
|
335
|
+
`:gvl` option is disabled by default, you can use bindings effectively in multiple threads.
|
336
|
+
Please be careful: bindings are not thread safe.
|
337
|
+
You should lock all shared data between threads.
|
338
|
+
|
326
339
|
## CI
|
327
340
|
|
328
|
-
See universal test script [scripts/ci_test.sh](scripts/ci_test.sh) for CI.
|
329
341
|
Please visit [scripts/test-images](scripts/test-images).
|
330
|
-
|
342
|
+
See universal test script [scripts/ci_test.sh](scripts/ci_test.sh) for CI.
|
343
|
+
You can run this script using many native and cross images.
|
331
344
|
|
332
345
|
## License
|
333
346
|
|
334
|
-
MIT license, see LICENSE and AUTHORS.
|
347
|
+
MIT license, see [LICENSE](LICENSE) and [AUTHORS](AUTHORS).
|
data/ext/extconf.rb
CHANGED
data/ext/lzws_ext/buffer.c
CHANGED
@@ -12,10 +12,10 @@ VALUE lzws_ext_create_string_buffer(VALUE length)
|
|
12
12
|
return rb_str_new(NULL, NUM2SIZET(length));
|
13
13
|
}
|
14
14
|
|
15
|
-
VALUE lzws_ext_resize_string_buffer(VALUE
|
15
|
+
VALUE lzws_ext_resize_string_buffer(VALUE buffer_args)
|
16
16
|
{
|
17
|
-
VALUE buffer = rb_ary_entry(
|
18
|
-
VALUE length = rb_ary_entry(
|
17
|
+
VALUE buffer = rb_ary_entry(buffer_args, 0);
|
18
|
+
VALUE length = rb_ary_entry(buffer_args, 1);
|
19
19
|
|
20
20
|
return rb_str_resize(buffer, NUM2SIZET(length));
|
21
21
|
}
|
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/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,14 @@
|
|
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
12
|
#include "ruby.h"
|
12
13
|
#include "ruby/io.h"
|
13
14
|
|
15
|
+
// -- utils --
|
16
|
+
|
14
17
|
#define GET_FILE(target) \
|
15
18
|
Check_Type(target, T_FILE); \
|
16
19
|
\
|
@@ -47,20 +50,52 @@ static inline lzws_ext_result_t get_file_error(lzws_result_t result)
|
|
47
50
|
}
|
48
51
|
}
|
49
52
|
|
53
|
+
// -- compress --
|
54
|
+
|
55
|
+
typedef struct
|
56
|
+
{
|
57
|
+
FILE* source_file;
|
58
|
+
size_t source_buffer_length;
|
59
|
+
FILE* destination_file;
|
60
|
+
size_t destination_buffer_length;
|
61
|
+
lzws_compressor_options_t* compressor_options_ptr;
|
62
|
+
lzws_result_t result;
|
63
|
+
} compress_args_t;
|
64
|
+
|
65
|
+
static inline void* compress_wrapper(void* data)
|
66
|
+
{
|
67
|
+
compress_args_t* args = data;
|
68
|
+
|
69
|
+
args->result = lzws_compress_file(
|
70
|
+
args->source_file,
|
71
|
+
args->source_buffer_length,
|
72
|
+
args->destination_file,
|
73
|
+
args->destination_buffer_length,
|
74
|
+
args->compressor_options_ptr);
|
75
|
+
|
76
|
+
return NULL;
|
77
|
+
}
|
78
|
+
|
50
79
|
VALUE lzws_ext_compress_io(VALUE LZWS_EXT_UNUSED(self), VALUE source, VALUE destination, VALUE options)
|
51
80
|
{
|
52
81
|
GET_FILE(source);
|
53
82
|
GET_FILE(destination);
|
54
83
|
Check_Type(options, T_HASH);
|
84
|
+
LZWS_EXT_GET_SIZE_OPTION(options, source_buffer_length);
|
85
|
+
LZWS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
|
86
|
+
LZWS_EXT_GET_BOOL_OPTION(options, gvl);
|
55
87
|
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
88
|
|
59
|
-
|
60
|
-
source_file
|
89
|
+
compress_args_t args = {
|
90
|
+
.source_file = source_file,
|
91
|
+
.source_buffer_length = source_buffer_length,
|
92
|
+
.destination_file = destination_file,
|
93
|
+
.destination_buffer_length = destination_buffer_length,
|
94
|
+
.compressor_options_ptr = &compressor_options};
|
61
95
|
|
62
|
-
|
63
|
-
|
96
|
+
LZWS_EXT_GVL_WRAP(gvl, compress_wrapper, &args);
|
97
|
+
if (args.result != 0) {
|
98
|
+
lzws_ext_raise_error(get_file_error(args.result));
|
64
99
|
}
|
65
100
|
|
66
101
|
// Ruby itself won't flush stdio file before closing fd, flush is required.
|
@@ -69,20 +104,52 @@ VALUE lzws_ext_compress_io(VALUE LZWS_EXT_UNUSED(self), VALUE source, VALUE dest
|
|
69
104
|
return Qnil;
|
70
105
|
}
|
71
106
|
|
107
|
+
// -- decompress --
|
108
|
+
|
109
|
+
typedef struct
|
110
|
+
{
|
111
|
+
FILE* source_file;
|
112
|
+
size_t source_buffer_length;
|
113
|
+
FILE* destination_file;
|
114
|
+
size_t destination_buffer_length;
|
115
|
+
lzws_decompressor_options_t* decompressor_options_ptr;
|
116
|
+
lzws_result_t result;
|
117
|
+
} decompress_args_t;
|
118
|
+
|
119
|
+
static inline void* decompress_wrapper(void* data)
|
120
|
+
{
|
121
|
+
decompress_args_t* args = data;
|
122
|
+
|
123
|
+
args->result = lzws_decompress_file(
|
124
|
+
args->source_file,
|
125
|
+
args->source_buffer_length,
|
126
|
+
args->destination_file,
|
127
|
+
args->destination_buffer_length,
|
128
|
+
args->decompressor_options_ptr);
|
129
|
+
|
130
|
+
return NULL;
|
131
|
+
}
|
132
|
+
|
72
133
|
VALUE lzws_ext_decompress_io(VALUE LZWS_EXT_UNUSED(self), VALUE source, VALUE destination, VALUE options)
|
73
134
|
{
|
74
135
|
GET_FILE(source);
|
75
136
|
GET_FILE(destination);
|
76
137
|
Check_Type(options, T_HASH);
|
138
|
+
LZWS_EXT_GET_SIZE_OPTION(options, source_buffer_length);
|
139
|
+
LZWS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
|
140
|
+
LZWS_EXT_GET_BOOL_OPTION(options, gvl);
|
77
141
|
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
142
|
|
81
|
-
|
82
|
-
source_file
|
143
|
+
decompress_args_t args = {
|
144
|
+
.source_file = source_file,
|
145
|
+
.source_buffer_length = source_buffer_length,
|
146
|
+
.destination_file = destination_file,
|
147
|
+
.destination_buffer_length = destination_buffer_length,
|
148
|
+
.decompressor_options_ptr = &decompressor_options};
|
83
149
|
|
84
|
-
|
85
|
-
|
150
|
+
LZWS_EXT_GVL_WRAP(gvl, decompress_wrapper, &args);
|
151
|
+
if (args.result != 0) {
|
152
|
+
lzws_ext_raise_error(get_file_error(args.result));
|
86
153
|
}
|
87
154
|
|
88
155
|
// Ruby itself won't flush stdio file before closing fd, flush is required.
|
@@ -91,6 +158,8 @@ VALUE lzws_ext_decompress_io(VALUE LZWS_EXT_UNUSED(self), VALUE source, VALUE de
|
|
91
158
|
return Qnil;
|
92
159
|
}
|
93
160
|
|
161
|
+
// -- exports --
|
162
|
+
|
94
163
|
void lzws_ext_io_exports(VALUE root_module)
|
95
164
|
{
|
96
165
|
rb_define_module_function(root_module, "_native_compress_io", RUBY_METHOD_FUNC(lzws_ext_compress_io), 3);
|
data/ext/lzws_ext/option.c
CHANGED
@@ -8,47 +8,65 @@
|
|
8
8
|
|
9
9
|
// -- values --
|
10
10
|
|
11
|
-
static inline VALUE
|
11
|
+
static inline VALUE get_raw_value(VALUE options, const char* name)
|
12
12
|
{
|
13
13
|
return rb_funcall(options, rb_intern("[]"), 1, ID2SYM(rb_intern(name)));
|
14
14
|
}
|
15
15
|
|
16
|
-
|
16
|
+
static inline bool get_bool_value(VALUE raw_value)
|
17
17
|
{
|
18
|
-
VALUE raw_value = get_raw_option_value(options, name);
|
19
|
-
if (raw_value == Qnil) {
|
20
|
-
return;
|
21
|
-
}
|
22
|
-
|
23
18
|
int raw_type = TYPE(raw_value);
|
24
19
|
if (raw_type != T_TRUE && raw_type != T_FALSE) {
|
25
20
|
lzws_ext_raise_error(LZWS_EXT_ERROR_VALIDATE_FAILED);
|
26
21
|
}
|
27
22
|
|
28
|
-
|
23
|
+
return raw_type == T_TRUE;
|
29
24
|
}
|
30
25
|
|
31
|
-
|
26
|
+
static inline unsigned int get_uint_value(VALUE raw_value)
|
32
27
|
{
|
33
|
-
VALUE raw_value = get_raw_option_value(options, name);
|
34
|
-
if (raw_value == Qnil) {
|
35
|
-
return;
|
36
|
-
}
|
37
|
-
|
38
28
|
Check_Type(raw_value, T_FIXNUM);
|
39
29
|
|
40
|
-
|
30
|
+
return NUM2UINT(raw_value);
|
41
31
|
}
|
42
32
|
|
43
|
-
size_t
|
33
|
+
static inline size_t get_size_value(VALUE raw_value)
|
44
34
|
{
|
45
|
-
VALUE raw_value = get_raw_option_value(options, name);
|
46
|
-
|
47
35
|
Check_Type(raw_value, T_FIXNUM);
|
48
36
|
|
49
37
|
return NUM2SIZET(raw_value);
|
50
38
|
}
|
51
39
|
|
40
|
+
void lzws_ext_resolve_bool_option(VALUE options, bool* option, const char* name)
|
41
|
+
{
|
42
|
+
VALUE raw_value = get_raw_value(options, name);
|
43
|
+
if (raw_value != Qnil) {
|
44
|
+
*option = get_bool_value(raw_value);
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
void lzws_ext_resolve_max_code_bit_length_option(VALUE options, lzws_byte_fast_t* option, const char* name)
|
49
|
+
{
|
50
|
+
VALUE raw_value = get_raw_value(options, name);
|
51
|
+
if (raw_value != Qnil) {
|
52
|
+
*option = get_uint_value(raw_value);
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
bool lzws_ext_get_bool_option_value(VALUE options, const char* name)
|
57
|
+
{
|
58
|
+
VALUE raw_value = get_raw_value(options, name);
|
59
|
+
|
60
|
+
return get_bool_value(raw_value);
|
61
|
+
}
|
62
|
+
|
63
|
+
size_t lzws_ext_get_size_option_value(VALUE options, const char* name)
|
64
|
+
{
|
65
|
+
VALUE raw_value = get_raw_value(options, name);
|
66
|
+
|
67
|
+
return get_size_value(raw_value);
|
68
|
+
}
|
69
|
+
|
52
70
|
// -- exports --
|
53
71
|
|
54
72
|
void lzws_ext_option_exports(VALUE root_module)
|
data/ext/lzws_ext/option.h
CHANGED
@@ -11,36 +11,38 @@
|
|
11
11
|
|
12
12
|
#include "ruby.h"
|
13
13
|
|
14
|
-
void
|
15
|
-
void
|
14
|
+
void lzws_ext_resolve_bool_option(VALUE options, bool* option, const char* name);
|
15
|
+
void lzws_ext_resolve_max_code_bit_length_option(VALUE options, lzws_byte_fast_t* option, const char* name);
|
16
16
|
|
17
|
-
#define
|
18
|
-
|
17
|
+
#define LZWS_EXT_RESOLVE_BOOL_OPTION(options, target_options, name) \
|
18
|
+
lzws_ext_resolve_bool_option(options, &target_options.name, #name);
|
19
19
|
|
20
|
-
#define
|
21
|
-
|
20
|
+
#define LZWS_EXT_RESOLVE_MAX_CODE_BIT_LENGTH_OPTION(options, target_options, name) \
|
21
|
+
lzws_ext_resolve_max_code_bit_length_option(options, &target_options.name, #name);
|
22
22
|
|
23
|
-
#define LZWS_EXT_GET_COMPRESSOR_OPTIONS(options)
|
24
|
-
lzws_compressor_options_t compressor_options = LZWS_COMPRESSOR_DEFAULT_OPTIONS;
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
23
|
+
#define LZWS_EXT_GET_COMPRESSOR_OPTIONS(options) \
|
24
|
+
lzws_compressor_options_t compressor_options = LZWS_COMPRESSOR_DEFAULT_OPTIONS; \
|
25
|
+
\
|
26
|
+
LZWS_EXT_RESOLVE_BOOL_OPTION(options, compressor_options, without_magic_header); \
|
27
|
+
LZWS_EXT_RESOLVE_MAX_CODE_BIT_LENGTH_OPTION(options, compressor_options, max_code_bit_length); \
|
28
|
+
LZWS_EXT_RESOLVE_BOOL_OPTION(options, compressor_options, block_mode); \
|
29
|
+
LZWS_EXT_RESOLVE_BOOL_OPTION(options, compressor_options, msb); \
|
30
|
+
LZWS_EXT_RESOLVE_BOOL_OPTION(options, compressor_options, unaligned_bit_groups); \
|
31
|
+
LZWS_EXT_RESOLVE_BOOL_OPTION(options, compressor_options, quiet);
|
32
32
|
|
33
33
|
#define LZWS_EXT_GET_DECOMPRESSOR_OPTIONS(options) \
|
34
34
|
lzws_decompressor_options_t decompressor_options = LZWS_DECOMPRESSOR_DEFAULT_OPTIONS; \
|
35
35
|
\
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
LZWS_EXT_RESOLVE_BOOL_OPTION(options, decompressor_options, without_magic_header); \
|
37
|
+
LZWS_EXT_RESOLVE_BOOL_OPTION(options, decompressor_options, msb); \
|
38
|
+
LZWS_EXT_RESOLVE_BOOL_OPTION(options, decompressor_options, unaligned_bit_groups); \
|
39
|
+
LZWS_EXT_RESOLVE_BOOL_OPTION(options, decompressor_options, quiet);
|
40
40
|
|
41
|
+
bool lzws_ext_get_bool_option_value(VALUE options, const char* name);
|
41
42
|
size_t lzws_ext_get_size_option_value(VALUE options, const char* name);
|
42
43
|
|
43
|
-
#define
|
44
|
+
#define LZWS_EXT_GET_BOOL_OPTION(options, name) bool name = lzws_ext_get_bool_option_value(options, #name);
|
45
|
+
#define LZWS_EXT_GET_SIZE_OPTION(options, name) size_t name = lzws_ext_get_size_option_value(options, #name);
|
44
46
|
|
45
47
|
void lzws_ext_option_exports(VALUE root_module);
|
46
48
|
|
@@ -8,9 +8,12 @@
|
|
8
8
|
#include <lzws/compressor/state.h>
|
9
9
|
|
10
10
|
#include "lzws_ext/error.h"
|
11
|
+
#include "lzws_ext/gvl.h"
|
11
12
|
#include "lzws_ext/option.h"
|
12
13
|
#include "ruby.h"
|
13
14
|
|
15
|
+
// -- initialization --
|
16
|
+
|
14
17
|
static void free_compressor(lzws_ext_compressor_t* compressor_ptr)
|
15
18
|
{
|
16
19
|
lzws_compressor_state_t* state_ptr = compressor_ptr->state_ptr;
|
@@ -36,6 +39,7 @@ VALUE lzws_ext_allocate_compressor(VALUE klass)
|
|
36
39
|
compressor_ptr->destination_buffer_length = 0;
|
37
40
|
compressor_ptr->remaining_destination_buffer = NULL;
|
38
41
|
compressor_ptr->remaining_destination_buffer_length = 0;
|
42
|
+
compressor_ptr->gvl = false;
|
39
43
|
|
40
44
|
return self;
|
41
45
|
}
|
@@ -48,8 +52,9 @@ VALUE lzws_ext_initialize_compressor(VALUE self, VALUE options)
|
|
48
52
|
{
|
49
53
|
GET_COMPRESSOR(self);
|
50
54
|
Check_Type(options, T_HASH);
|
55
|
+
LZWS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
|
56
|
+
LZWS_EXT_GET_BOOL_OPTION(options, gvl);
|
51
57
|
LZWS_EXT_GET_COMPRESSOR_OPTIONS(options);
|
52
|
-
LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
|
53
58
|
|
54
59
|
lzws_compressor_state_t* state_ptr;
|
55
60
|
|
@@ -80,63 +85,106 @@ VALUE lzws_ext_initialize_compressor(VALUE self, VALUE options)
|
|
80
85
|
compressor_ptr->destination_buffer_length = destination_buffer_length;
|
81
86
|
compressor_ptr->remaining_destination_buffer = destination_buffer;
|
82
87
|
compressor_ptr->remaining_destination_buffer_length = destination_buffer_length;
|
88
|
+
compressor_ptr->gvl = gvl;
|
83
89
|
|
84
90
|
return Qnil;
|
85
91
|
}
|
86
92
|
|
93
|
+
// -- compress --
|
94
|
+
|
87
95
|
#define DO_NOT_USE_AFTER_CLOSE(compressor_ptr) \
|
88
96
|
if (compressor_ptr->state_ptr == NULL || compressor_ptr->destination_buffer == NULL) { \
|
89
97
|
lzws_ext_raise_error(LZWS_EXT_ERROR_USED_AFTER_CLOSE); \
|
90
98
|
}
|
91
99
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
size_t
|
97
|
-
|
98
|
-
|
100
|
+
typedef struct
|
101
|
+
{
|
102
|
+
lzws_ext_compressor_t* compressor_ptr;
|
103
|
+
lzws_ext_byte_t* remaining_source;
|
104
|
+
size_t* remaining_source_length_ptr;
|
105
|
+
lzws_result_t result;
|
106
|
+
} compress_args_t;
|
99
107
|
|
100
|
-
|
108
|
+
static inline void* compress_wrapper(void* data)
|
101
109
|
{
|
102
|
-
|
103
|
-
|
104
|
-
GET_SOURCE_DATA(source_value);
|
110
|
+
compress_args_t* args = data;
|
111
|
+
lzws_ext_compressor_t* compressor_ptr = args->compressor_ptr;
|
105
112
|
|
106
|
-
|
113
|
+
args->result = lzws_compress(
|
107
114
|
compressor_ptr->state_ptr,
|
108
|
-
&remaining_source,
|
109
|
-
|
115
|
+
&args->remaining_source,
|
116
|
+
args->remaining_source_length_ptr,
|
110
117
|
&compressor_ptr->remaining_destination_buffer,
|
111
118
|
&compressor_ptr->remaining_destination_buffer_length);
|
112
119
|
|
113
|
-
|
120
|
+
return NULL;
|
121
|
+
}
|
122
|
+
|
123
|
+
VALUE lzws_ext_compress(VALUE self, VALUE source_value)
|
124
|
+
{
|
125
|
+
GET_COMPRESSOR(self);
|
126
|
+
DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
|
127
|
+
Check_Type(source_value, T_STRING);
|
128
|
+
|
129
|
+
const char* source = RSTRING_PTR(source_value);
|
130
|
+
size_t source_length = RSTRING_LEN(source_value);
|
131
|
+
lzws_ext_byte_t* remaining_source = (lzws_ext_byte_t*) source;
|
132
|
+
size_t remaining_source_length = source_length;
|
133
|
+
|
134
|
+
compress_args_t args = {
|
135
|
+
.compressor_ptr = compressor_ptr,
|
136
|
+
.remaining_source = remaining_source,
|
137
|
+
.remaining_source_length_ptr = &remaining_source_length};
|
138
|
+
|
139
|
+
LZWS_EXT_GVL_WRAP(compressor_ptr->gvl, compress_wrapper, &args);
|
140
|
+
if (args.result != 0 && args.result != LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION) {
|
114
141
|
lzws_ext_raise_error(LZWS_EXT_ERROR_UNEXPECTED);
|
115
142
|
}
|
116
143
|
|
117
144
|
VALUE bytes_written = SIZET2NUM(source_length - remaining_source_length);
|
118
|
-
VALUE needs_more_destination = result == LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION ? Qtrue : Qfalse;
|
145
|
+
VALUE needs_more_destination = args.result == LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION ? Qtrue : Qfalse;
|
119
146
|
|
120
147
|
return rb_ary_new_from_args(2, bytes_written, needs_more_destination);
|
121
148
|
}
|
122
149
|
|
123
|
-
|
150
|
+
// -- compressor finish --
|
151
|
+
|
152
|
+
typedef struct
|
124
153
|
{
|
125
|
-
|
126
|
-
|
154
|
+
lzws_ext_compressor_t* compressor_ptr;
|
155
|
+
lzws_result_t result;
|
156
|
+
} compressor_finish_args_t;
|
127
157
|
|
128
|
-
|
158
|
+
static inline void* compressor_finish_wrapper(void* data)
|
159
|
+
{
|
160
|
+
compressor_finish_args_t* args = data;
|
161
|
+
lzws_ext_compressor_t* compressor_ptr = args->compressor_ptr;
|
162
|
+
|
163
|
+
args->result = lzws_compressor_finish(
|
129
164
|
compressor_ptr->state_ptr,
|
130
165
|
&compressor_ptr->remaining_destination_buffer,
|
131
166
|
&compressor_ptr->remaining_destination_buffer_length);
|
132
167
|
|
133
|
-
|
168
|
+
return NULL;
|
169
|
+
}
|
170
|
+
|
171
|
+
VALUE lzws_ext_compressor_finish(VALUE self)
|
172
|
+
{
|
173
|
+
GET_COMPRESSOR(self);
|
174
|
+
DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
|
175
|
+
|
176
|
+
compressor_finish_args_t args = {.compressor_ptr = compressor_ptr};
|
177
|
+
|
178
|
+
LZWS_EXT_GVL_WRAP(compressor_ptr->gvl, compressor_finish_wrapper, &args);
|
179
|
+
if (args.result != 0 && args.result != LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION) {
|
134
180
|
lzws_ext_raise_error(LZWS_EXT_ERROR_UNEXPECTED);
|
135
181
|
}
|
136
182
|
|
137
|
-
return result == LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION ? Qtrue : Qfalse;
|
183
|
+
return args.result == LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION ? Qtrue : Qfalse;
|
138
184
|
}
|
139
185
|
|
186
|
+
// -- other --
|
187
|
+
|
140
188
|
VALUE lzws_ext_compressor_read_result(VALUE self)
|
141
189
|
{
|
142
190
|
GET_COMPRESSOR(self);
|
@@ -156,6 +204,8 @@ VALUE lzws_ext_compressor_read_result(VALUE self)
|
|
156
204
|
return result_value;
|
157
205
|
}
|
158
206
|
|
207
|
+
// -- cleanup --
|
208
|
+
|
159
209
|
VALUE lzws_ext_compressor_close(VALUE self)
|
160
210
|
{
|
161
211
|
GET_COMPRESSOR(self);
|
@@ -175,12 +225,14 @@ VALUE lzws_ext_compressor_close(VALUE self)
|
|
175
225
|
compressor_ptr->destination_buffer = NULL;
|
176
226
|
}
|
177
227
|
|
178
|
-
// It is possible to keep "destination_buffer_length", "remaining_destination_buffer"
|
179
|
-
// and "
|
228
|
+
// It is possible to keep "destination_buffer_length", "remaining_destination_buffer",
|
229
|
+
// "remaining_destination_buffer_length" and "gvl" as is.
|
180
230
|
|
181
231
|
return Qnil;
|
182
232
|
}
|
183
233
|
|
234
|
+
// -- exports --
|
235
|
+
|
184
236
|
void lzws_ext_compressor_exports(VALUE root_module)
|
185
237
|
{
|
186
238
|
VALUE module = rb_define_module_under(root_module, "Stream");
|
@@ -5,6 +5,7 @@
|
|
5
5
|
#define LZWS_EXT_STREAM_COMPRESSOR_H
|
6
6
|
|
7
7
|
#include <lzws/compressor/state.h>
|
8
|
+
#include <stdbool.h>
|
8
9
|
#include <stdlib.h>
|
9
10
|
|
10
11
|
#include "lzws_ext/common.h"
|
@@ -17,6 +18,7 @@ typedef struct
|
|
17
18
|
size_t destination_buffer_length;
|
18
19
|
lzws_ext_byte_t* remaining_destination_buffer;
|
19
20
|
size_t remaining_destination_buffer_length;
|
21
|
+
bool gvl;
|
20
22
|
} lzws_ext_compressor_t;
|
21
23
|
|
22
24
|
VALUE lzws_ext_allocate_compressor(VALUE klass);
|
@@ -8,9 +8,12 @@
|
|
8
8
|
#include <lzws/decompressor/state.h>
|
9
9
|
|
10
10
|
#include "lzws_ext/error.h"
|
11
|
+
#include "lzws_ext/gvl.h"
|
11
12
|
#include "lzws_ext/option.h"
|
12
13
|
#include "ruby.h"
|
13
14
|
|
15
|
+
// -- initialization --
|
16
|
+
|
14
17
|
static void free_decompressor(lzws_ext_decompressor_t* decompressor_ptr)
|
15
18
|
{
|
16
19
|
lzws_decompressor_state_t* state_ptr = decompressor_ptr->state_ptr;
|
@@ -48,8 +51,9 @@ VALUE lzws_ext_initialize_decompressor(VALUE self, VALUE options)
|
|
48
51
|
{
|
49
52
|
GET_DECOMPRESSOR(self);
|
50
53
|
Check_Type(options, T_HASH);
|
54
|
+
LZWS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
|
55
|
+
LZWS_EXT_GET_BOOL_OPTION(options, gvl);
|
51
56
|
LZWS_EXT_GET_DECOMPRESSOR_OPTIONS(options);
|
52
|
-
LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
|
53
57
|
|
54
58
|
lzws_decompressor_state_t* state_ptr;
|
55
59
|
|
@@ -78,38 +82,60 @@ VALUE lzws_ext_initialize_decompressor(VALUE self, VALUE options)
|
|
78
82
|
decompressor_ptr->destination_buffer_length = destination_buffer_length;
|
79
83
|
decompressor_ptr->remaining_destination_buffer = destination_buffer;
|
80
84
|
decompressor_ptr->remaining_destination_buffer_length = destination_buffer_length;
|
85
|
+
decompressor_ptr->gvl = gvl;
|
81
86
|
|
82
87
|
return Qnil;
|
83
88
|
}
|
84
89
|
|
90
|
+
// -- decompress --
|
91
|
+
|
85
92
|
#define DO_NOT_USE_AFTER_CLOSE(decompressor_ptr) \
|
86
93
|
if (decompressor_ptr->state_ptr == NULL || decompressor_ptr->destination_buffer == NULL) { \
|
87
94
|
lzws_ext_raise_error(LZWS_EXT_ERROR_USED_AFTER_CLOSE); \
|
88
95
|
}
|
89
96
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
size_t
|
95
|
-
|
96
|
-
|
97
|
+
typedef struct
|
98
|
+
{
|
99
|
+
lzws_ext_decompressor_t* decompressor_ptr;
|
100
|
+
lzws_ext_byte_t* remaining_source;
|
101
|
+
size_t* remaining_source_length_ptr;
|
102
|
+
lzws_result_t result;
|
103
|
+
} decompress_args_t;
|
97
104
|
|
98
|
-
|
105
|
+
static inline void* decompress_wrapper(void* data)
|
99
106
|
{
|
100
|
-
|
101
|
-
|
102
|
-
GET_SOURCE_DATA(source_value);
|
107
|
+
decompress_args_t* args = data;
|
108
|
+
lzws_ext_decompressor_t* decompressor_ptr = args->decompressor_ptr;
|
103
109
|
|
104
|
-
|
110
|
+
args->result = lzws_decompress(
|
105
111
|
decompressor_ptr->state_ptr,
|
106
|
-
&remaining_source,
|
107
|
-
|
112
|
+
&args->remaining_source,
|
113
|
+
args->remaining_source_length_ptr,
|
108
114
|
&decompressor_ptr->remaining_destination_buffer,
|
109
115
|
&decompressor_ptr->remaining_destination_buffer_length);
|
110
116
|
|
111
|
-
|
112
|
-
|
117
|
+
return NULL;
|
118
|
+
}
|
119
|
+
|
120
|
+
VALUE lzws_ext_decompress(VALUE self, VALUE source_value)
|
121
|
+
{
|
122
|
+
GET_DECOMPRESSOR(self);
|
123
|
+
DO_NOT_USE_AFTER_CLOSE(decompressor_ptr);
|
124
|
+
Check_Type(source_value, T_STRING);
|
125
|
+
|
126
|
+
const char* source = RSTRING_PTR(source_value);
|
127
|
+
size_t source_length = RSTRING_LEN(source_value);
|
128
|
+
lzws_ext_byte_t* remaining_source = (lzws_ext_byte_t*) source;
|
129
|
+
size_t remaining_source_length = source_length;
|
130
|
+
|
131
|
+
decompress_args_t args = {
|
132
|
+
.decompressor_ptr = decompressor_ptr,
|
133
|
+
.remaining_source = remaining_source,
|
134
|
+
.remaining_source_length_ptr = &remaining_source_length};
|
135
|
+
|
136
|
+
LZWS_EXT_GVL_WRAP(decompressor_ptr->gvl, decompress_wrapper, &args);
|
137
|
+
if (args.result != 0 && args.result != LZWS_DECOMPRESSOR_NEEDS_MORE_DESTINATION) {
|
138
|
+
switch (args.result) {
|
113
139
|
case LZWS_DECOMPRESSOR_INVALID_MAGIC_HEADER:
|
114
140
|
case LZWS_DECOMPRESSOR_INVALID_MAX_CODE_BIT_LENGTH:
|
115
141
|
lzws_ext_raise_error(LZWS_EXT_ERROR_VALIDATE_FAILED);
|
@@ -121,11 +147,13 @@ VALUE lzws_ext_decompress(VALUE self, VALUE source_value)
|
|
121
147
|
}
|
122
148
|
|
123
149
|
VALUE bytes_read = SIZET2NUM(source_length - remaining_source_length);
|
124
|
-
VALUE needs_more_destination = result == LZWS_DECOMPRESSOR_NEEDS_MORE_DESTINATION ? Qtrue : Qfalse;
|
150
|
+
VALUE needs_more_destination = args.result == LZWS_DECOMPRESSOR_NEEDS_MORE_DESTINATION ? Qtrue : Qfalse;
|
125
151
|
|
126
152
|
return rb_ary_new_from_args(2, bytes_read, needs_more_destination);
|
127
153
|
}
|
128
154
|
|
155
|
+
// -- other --
|
156
|
+
|
129
157
|
VALUE lzws_ext_decompressor_read_result(VALUE self)
|
130
158
|
{
|
131
159
|
GET_DECOMPRESSOR(self);
|
@@ -145,6 +173,8 @@ VALUE lzws_ext_decompressor_read_result(VALUE self)
|
|
145
173
|
return result_value;
|
146
174
|
}
|
147
175
|
|
176
|
+
// -- cleanup --
|
177
|
+
|
148
178
|
VALUE lzws_ext_decompressor_close(VALUE self)
|
149
179
|
{
|
150
180
|
GET_DECOMPRESSOR(self);
|
@@ -170,6 +200,8 @@ VALUE lzws_ext_decompressor_close(VALUE self)
|
|
170
200
|
return Qnil;
|
171
201
|
}
|
172
202
|
|
203
|
+
// -- exports --
|
204
|
+
|
173
205
|
void lzws_ext_decompressor_exports(VALUE root_module)
|
174
206
|
{
|
175
207
|
VALUE module = rb_define_module_under(root_module, "Stream");
|
@@ -5,6 +5,7 @@
|
|
5
5
|
#define LZWS_EXT_STREAM_DECOMPRESSOR_H
|
6
6
|
|
7
7
|
#include <lzws/decompressor/state.h>
|
8
|
+
#include <stdbool.h>
|
8
9
|
#include <stdlib.h>
|
9
10
|
|
10
11
|
#include "lzws_ext/common.h"
|
@@ -17,6 +18,7 @@ typedef struct
|
|
17
18
|
size_t destination_buffer_length;
|
18
19
|
lzws_ext_byte_t* remaining_destination_buffer;
|
19
20
|
size_t remaining_destination_buffer_length;
|
21
|
+
bool gvl;
|
20
22
|
} lzws_ext_decompressor_t;
|
21
23
|
|
22
24
|
VALUE lzws_ext_allocate_decompressor(VALUE klass);
|
data/ext/lzws_ext/string.c
CHANGED
@@ -12,6 +12,7 @@
|
|
12
12
|
|
13
13
|
#include "lzws_ext/buffer.h"
|
14
14
|
#include "lzws_ext/error.h"
|
15
|
+
#include "lzws_ext/gvl.h"
|
15
16
|
#include "lzws_ext/macro.h"
|
16
17
|
#include "lzws_ext/option.h"
|
17
18
|
#include "ruby.h"
|
@@ -41,30 +42,67 @@ static inline lzws_ext_result_t increase_destination_buffer(
|
|
41
42
|
return 0;
|
42
43
|
}
|
43
44
|
|
44
|
-
// --
|
45
|
+
// -- compress --
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
size_t
|
47
|
+
typedef struct
|
48
|
+
{
|
49
|
+
lzws_compressor_state_t* state_ptr;
|
50
|
+
lzws_ext_byte_t** remaining_source_ptr;
|
51
|
+
size_t* remaining_source_length_ptr;
|
52
|
+
lzws_ext_byte_t* remaining_destination_buffer;
|
53
|
+
size_t* remaining_destination_buffer_length_ptr;
|
54
|
+
lzws_result_t result;
|
55
|
+
} compress_args_t;
|
56
|
+
|
57
|
+
typedef struct
|
58
|
+
{
|
59
|
+
lzws_compressor_state_t* state_ptr;
|
60
|
+
lzws_ext_byte_t* remaining_destination_buffer;
|
61
|
+
size_t* remaining_destination_buffer_length_ptr;
|
62
|
+
lzws_result_t result;
|
63
|
+
} compressor_finish_args_t;
|
51
64
|
|
52
|
-
|
65
|
+
static inline void* compress_wrapper(void* data)
|
66
|
+
{
|
67
|
+
compress_args_t* args = data;
|
68
|
+
|
69
|
+
args->result = lzws_compress(
|
70
|
+
args->state_ptr,
|
71
|
+
args->remaining_source_ptr,
|
72
|
+
args->remaining_source_length_ptr,
|
73
|
+
&args->remaining_destination_buffer,
|
74
|
+
args->remaining_destination_buffer_length_ptr);
|
75
|
+
|
76
|
+
return NULL;
|
77
|
+
}
|
78
|
+
|
79
|
+
static inline void* compressor_finish_wrapper(void* data)
|
80
|
+
{
|
81
|
+
compressor_finish_args_t* args = data;
|
82
|
+
|
83
|
+
args->result = lzws_compressor_finish(
|
84
|
+
args->state_ptr, &args->remaining_destination_buffer, args->remaining_destination_buffer_length_ptr);
|
85
|
+
|
86
|
+
return NULL;
|
87
|
+
}
|
53
88
|
|
54
|
-
#define BUFFERED_COMPRESS(
|
89
|
+
#define BUFFERED_COMPRESS(gvl, wrapper, args) \
|
55
90
|
while (true) { \
|
56
91
|
lzws_ext_byte_t* remaining_destination_buffer = \
|
57
92
|
(lzws_ext_byte_t*) RSTRING_PTR(destination_value) + destination_length; \
|
58
93
|
size_t prev_remaining_destination_buffer_length = remaining_destination_buffer_length; \
|
59
94
|
\
|
60
|
-
|
61
|
-
|
95
|
+
args.remaining_destination_buffer = remaining_destination_buffer; \
|
96
|
+
args.remaining_destination_buffer_length_ptr = &remaining_destination_buffer_length; \
|
97
|
+
\
|
98
|
+
LZWS_EXT_GVL_WRAP(gvl, wrapper, &args); \
|
99
|
+
if (args.result != 0 && args.result != LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION) { \
|
62
100
|
return LZWS_EXT_ERROR_UNEXPECTED; \
|
63
101
|
} \
|
64
102
|
\
|
65
103
|
destination_length += prev_remaining_destination_buffer_length - remaining_destination_buffer_length; \
|
66
104
|
\
|
67
|
-
if (result == LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION) {
|
105
|
+
if (args.result == LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION) { \
|
68
106
|
ext_result = increase_destination_buffer( \
|
69
107
|
destination_value, destination_length, &remaining_destination_buffer_length, destination_buffer_length); \
|
70
108
|
\
|
@@ -83,17 +121,24 @@ static inline lzws_ext_result_t compress(
|
|
83
121
|
const char* source,
|
84
122
|
size_t source_length,
|
85
123
|
VALUE destination_value,
|
86
|
-
size_t destination_buffer_length
|
124
|
+
size_t destination_buffer_length,
|
125
|
+
bool gvl)
|
87
126
|
{
|
88
|
-
lzws_result_t result;
|
89
127
|
lzws_ext_result_t ext_result;
|
90
128
|
lzws_ext_byte_t* remaining_source = (lzws_ext_byte_t*) source;
|
91
129
|
size_t remaining_source_length = source_length;
|
92
130
|
size_t destination_length = 0;
|
93
131
|
size_t remaining_destination_buffer_length = destination_buffer_length;
|
94
132
|
|
95
|
-
|
96
|
-
|
133
|
+
compress_args_t args = {
|
134
|
+
.state_ptr = state_ptr,
|
135
|
+
.remaining_source_ptr = &remaining_source,
|
136
|
+
.remaining_source_length_ptr = &remaining_source_length};
|
137
|
+
|
138
|
+
BUFFERED_COMPRESS(gvl, compress_wrapper, args);
|
139
|
+
|
140
|
+
compressor_finish_args_t finish_args = {.state_ptr = state_ptr};
|
141
|
+
BUFFERED_COMPRESS(gvl, compressor_finish_wrapper, finish_args);
|
97
142
|
|
98
143
|
int exception;
|
99
144
|
|
@@ -107,10 +152,11 @@ static inline lzws_ext_result_t compress(
|
|
107
152
|
|
108
153
|
VALUE lzws_ext_compress_string(VALUE LZWS_EXT_UNUSED(self), VALUE source_value, VALUE options)
|
109
154
|
{
|
110
|
-
|
155
|
+
Check_Type(source_value, T_STRING);
|
111
156
|
Check_Type(options, T_HASH);
|
157
|
+
LZWS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
|
158
|
+
LZWS_EXT_GET_BOOL_OPTION(options, gvl);
|
112
159
|
LZWS_EXT_GET_COMPRESSOR_OPTIONS(options);
|
113
|
-
LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
|
114
160
|
|
115
161
|
lzws_compressor_state_t* state_ptr;
|
116
162
|
|
@@ -138,8 +184,11 @@ VALUE lzws_ext_compress_string(VALUE LZWS_EXT_UNUSED(self), VALUE source_value,
|
|
138
184
|
lzws_ext_raise_error(LZWS_EXT_ERROR_ALLOCATE_FAILED);
|
139
185
|
}
|
140
186
|
|
187
|
+
const char* source = RSTRING_PTR(source_value);
|
188
|
+
size_t source_length = RSTRING_LEN(source_value);
|
189
|
+
|
141
190
|
lzws_ext_result_t ext_result =
|
142
|
-
compress(state_ptr, source, source_length, destination_value, destination_buffer_length);
|
191
|
+
compress(state_ptr, source, source_length, destination_value, destination_buffer_length, gvl);
|
143
192
|
|
144
193
|
lzws_compressor_free_state(state_ptr);
|
145
194
|
|
@@ -152,34 +201,60 @@ VALUE lzws_ext_compress_string(VALUE LZWS_EXT_UNUSED(self), VALUE source_value,
|
|
152
201
|
|
153
202
|
// -- decompress --
|
154
203
|
|
204
|
+
typedef struct
|
205
|
+
{
|
206
|
+
lzws_decompressor_state_t* state_ptr;
|
207
|
+
lzws_ext_byte_t** remaining_source_ptr;
|
208
|
+
size_t* remaining_source_length_ptr;
|
209
|
+
lzws_ext_byte_t* remaining_destination_buffer;
|
210
|
+
size_t* remaining_destination_buffer_length_ptr;
|
211
|
+
lzws_result_t result;
|
212
|
+
} decompress_args_t;
|
213
|
+
|
214
|
+
static inline void* decompress_wrapper(void* data)
|
215
|
+
{
|
216
|
+
decompress_args_t* args = data;
|
217
|
+
|
218
|
+
args->result = lzws_decompress(
|
219
|
+
args->state_ptr,
|
220
|
+
args->remaining_source_ptr,
|
221
|
+
args->remaining_source_length_ptr,
|
222
|
+
&args->remaining_destination_buffer,
|
223
|
+
args->remaining_destination_buffer_length_ptr);
|
224
|
+
|
225
|
+
return NULL;
|
226
|
+
}
|
227
|
+
|
155
228
|
static inline lzws_ext_result_t decompress(
|
156
229
|
lzws_decompressor_state_t* state_ptr,
|
157
230
|
const char* source,
|
158
231
|
size_t source_length,
|
159
232
|
VALUE destination_value,
|
160
|
-
size_t destination_buffer_length
|
233
|
+
size_t destination_buffer_length,
|
234
|
+
bool gvl)
|
161
235
|
{
|
162
|
-
lzws_result_t result;
|
163
236
|
lzws_ext_result_t ext_result;
|
164
237
|
lzws_ext_byte_t* remaining_source = (lzws_ext_byte_t*) source;
|
165
238
|
size_t remaining_source_length = source_length;
|
166
239
|
size_t destination_length = 0;
|
167
240
|
size_t remaining_destination_buffer_length = destination_buffer_length;
|
168
241
|
|
242
|
+
decompress_args_t args = {
|
243
|
+
.state_ptr = state_ptr,
|
244
|
+
.remaining_source_ptr = &remaining_source,
|
245
|
+
.remaining_source_length_ptr = &remaining_source_length};
|
246
|
+
|
169
247
|
while (true) {
|
170
248
|
lzws_ext_byte_t* remaining_destination_buffer =
|
171
249
|
(lzws_ext_byte_t*) RSTRING_PTR(destination_value) + destination_length;
|
172
250
|
size_t prev_remaining_destination_buffer_length = remaining_destination_buffer_length;
|
173
251
|
|
174
|
-
|
175
|
-
|
176
|
-
&remaining_source,
|
177
|
-
&remaining_source_length,
|
178
|
-
&remaining_destination_buffer,
|
179
|
-
&remaining_destination_buffer_length);
|
252
|
+
args.remaining_destination_buffer = remaining_destination_buffer;
|
253
|
+
args.remaining_destination_buffer_length_ptr = &remaining_destination_buffer_length;
|
180
254
|
|
181
|
-
|
182
|
-
|
255
|
+
LZWS_EXT_GVL_WRAP(gvl, decompress_wrapper, &args);
|
256
|
+
if (args.result != 0 && args.result != LZWS_DECOMPRESSOR_NEEDS_MORE_DESTINATION) {
|
257
|
+
switch (args.result) {
|
183
258
|
case LZWS_DECOMPRESSOR_INVALID_MAGIC_HEADER:
|
184
259
|
case LZWS_DECOMPRESSOR_INVALID_MAX_CODE_BIT_LENGTH:
|
185
260
|
return LZWS_EXT_ERROR_VALIDATE_FAILED;
|
@@ -192,7 +267,7 @@ static inline lzws_ext_result_t decompress(
|
|
192
267
|
|
193
268
|
destination_length += prev_remaining_destination_buffer_length - remaining_destination_buffer_length;
|
194
269
|
|
195
|
-
if (result == LZWS_DECOMPRESSOR_NEEDS_MORE_DESTINATION) {
|
270
|
+
if (args.result == LZWS_DECOMPRESSOR_NEEDS_MORE_DESTINATION) {
|
196
271
|
ext_result = increase_destination_buffer(
|
197
272
|
destination_value, destination_length, &remaining_destination_buffer_length, destination_buffer_length);
|
198
273
|
|
@@ -218,10 +293,11 @@ static inline lzws_ext_result_t decompress(
|
|
218
293
|
|
219
294
|
VALUE lzws_ext_decompress_string(VALUE LZWS_EXT_UNUSED(self), VALUE source_value, VALUE options)
|
220
295
|
{
|
221
|
-
|
296
|
+
Check_Type(source_value, T_STRING);
|
222
297
|
Check_Type(options, T_HASH);
|
298
|
+
LZWS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
|
299
|
+
LZWS_EXT_GET_BOOL_OPTION(options, gvl);
|
223
300
|
LZWS_EXT_GET_DECOMPRESSOR_OPTIONS(options);
|
224
|
-
LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
|
225
301
|
|
226
302
|
lzws_decompressor_state_t* state_ptr;
|
227
303
|
|
@@ -247,8 +323,11 @@ VALUE lzws_ext_decompress_string(VALUE LZWS_EXT_UNUSED(self), VALUE source_value
|
|
247
323
|
lzws_ext_raise_error(LZWS_EXT_ERROR_ALLOCATE_FAILED);
|
248
324
|
}
|
249
325
|
|
326
|
+
const char* source = RSTRING_PTR(source_value);
|
327
|
+
size_t source_length = RSTRING_LEN(source_value);
|
328
|
+
|
250
329
|
lzws_ext_result_t ext_result =
|
251
|
-
decompress(state_ptr, source, source_length, destination_value, destination_buffer_length);
|
330
|
+
decompress(state_ptr, source, source_length, destination_value, destination_buffer_length, gvl);
|
252
331
|
|
253
332
|
lzws_decompressor_free_state(state_ptr);
|
254
333
|
|
@@ -259,6 +338,8 @@ VALUE lzws_ext_decompress_string(VALUE LZWS_EXT_UNUSED(self), VALUE source_value
|
|
259
338
|
return destination_value;
|
260
339
|
}
|
261
340
|
|
341
|
+
// -- exports --
|
342
|
+
|
262
343
|
void lzws_ext_string_exports(VALUE root_module)
|
263
344
|
{
|
264
345
|
rb_define_module_function(root_module, "_native_compress_string", RUBY_METHOD_FUNC(lzws_ext_compress_string), 2);
|
data/lib/lzws/option.rb
CHANGED
@@ -10,14 +10,36 @@ module LZWS
|
|
10
10
|
module Option
|
11
11
|
DEFAULT_BUFFER_LENGTH = 0
|
12
12
|
|
13
|
+
COMPRESSOR_DEFAULTS = {
|
14
|
+
:gvl => false,
|
15
|
+
:max_code_bit_length => nil,
|
16
|
+
:without_magic_header => nil,
|
17
|
+
:block_mode => nil,
|
18
|
+
:msb => nil,
|
19
|
+
:unaligned_bit_groups => nil,
|
20
|
+
:quiet => nil
|
21
|
+
}
|
22
|
+
.freeze
|
23
|
+
|
24
|
+
DECOMPRESSOR_DEFAULTS = {
|
25
|
+
:gvl => false,
|
26
|
+
:without_magic_header => nil,
|
27
|
+
:msb => nil,
|
28
|
+
:unaligned_bit_groups => nil,
|
29
|
+
:quiet => nil
|
30
|
+
}
|
31
|
+
.freeze
|
32
|
+
|
13
33
|
def self.get_compressor_options(options, buffer_length_names)
|
14
34
|
Validation.validate_hash options
|
15
35
|
|
16
36
|
buffer_length_defaults = buffer_length_names.each_with_object({}) { |name, defaults| defaults[name] = DEFAULT_BUFFER_LENGTH }
|
17
|
-
options = buffer_length_defaults.merge options
|
37
|
+
options = COMPRESSOR_DEFAULTS.merge(buffer_length_defaults).merge options
|
18
38
|
|
19
39
|
buffer_length_names.each { |name| Validation.validate_not_negative_integer options[name] }
|
20
40
|
|
41
|
+
Validation.validate_bool options[:gvl]
|
42
|
+
|
21
43
|
max_code_bit_length = options[:max_code_bit_length]
|
22
44
|
unless max_code_bit_length.nil?
|
23
45
|
Validation.validate_positive_integer max_code_bit_length
|
@@ -47,10 +69,12 @@ module LZWS
|
|
47
69
|
Validation.validate_hash options
|
48
70
|
|
49
71
|
buffer_length_defaults = buffer_length_names.each_with_object({}) { |name, defaults| defaults[name] = DEFAULT_BUFFER_LENGTH }
|
50
|
-
options = buffer_length_defaults.merge options
|
72
|
+
options = DECOMPRESSOR_DEFAULTS.merge(buffer_length_defaults).merge options
|
51
73
|
|
52
74
|
buffer_length_names.each { |name| Validation.validate_not_negative_integer options[name] }
|
53
75
|
|
76
|
+
Validation.validate_bool options[:gvl]
|
77
|
+
|
54
78
|
without_magic_header = options[:without_magic_header]
|
55
79
|
Validation.validate_bool without_magic_header unless without_magic_header.nil?
|
56
80
|
|
data/lib/lzws/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-lzws
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Aladjev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-10-
|
11
|
+
date: 2020-10-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: codecov
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '1.1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: parallel
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: rake
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -152,6 +166,7 @@ files:
|
|
152
166
|
- ext/lzws_ext/common.h
|
153
167
|
- ext/lzws_ext/error.c
|
154
168
|
- ext/lzws_ext/error.h
|
169
|
+
- ext/lzws_ext/gvl.h
|
155
170
|
- ext/lzws_ext/io.c
|
156
171
|
- ext/lzws_ext/io.h
|
157
172
|
- ext/lzws_ext/macro.h
|
@@ -203,5 +218,5 @@ requirements: []
|
|
203
218
|
rubygems_version: 3.1.4
|
204
219
|
signing_key:
|
205
220
|
specification_version: 4
|
206
|
-
summary: Ruby bindings for lzws library.
|
221
|
+
summary: Ruby bindings for lzws library (compatible with UNIX compress).
|
207
222
|
test_files: []
|