ruby-lzws 1.0.0 → 1.1.4
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 +188 -30
- data/ext/extconf.rb +36 -34
- data/ext/lzws_ext/buffer.c +30 -0
- data/ext/lzws_ext/buffer.h +23 -0
- data/ext/lzws_ext/common.h +7 -0
- data/ext/lzws_ext/error.c +33 -4
- data/ext/lzws_ext/error.h +20 -1
- data/ext/lzws_ext/io.c +58 -47
- data/ext/lzws_ext/io.h +2 -0
- data/ext/lzws_ext/macro.h +0 -2
- data/ext/lzws_ext/main.c +8 -30
- data/ext/lzws_ext/option.c +30 -10
- data/ext/lzws_ext/option.h +33 -50
- data/ext/lzws_ext/stream/compressor.c +77 -90
- data/ext/lzws_ext/stream/compressor.h +7 -4
- data/ext/lzws_ext/stream/decompressor.c +73 -90
- data/ext/lzws_ext/stream/decompressor.h +6 -3
- data/ext/lzws_ext/string.c +246 -44
- data/ext/lzws_ext/string.h +2 -0
- data/lib/lzws.rb +5 -1
- data/lib/lzws/error.rb +8 -7
- data/lib/lzws/file.rb +6 -18
- data/lib/lzws/option.rb +13 -9
- data/lib/lzws/stream/abstract.rb +10 -8
- data/lib/lzws/stream/raw/abstract.rb +24 -9
- data/lib/lzws/stream/raw/compressor.rb +9 -31
- data/lib/lzws/stream/raw/decompressor.rb +6 -24
- data/lib/lzws/stream/reader.rb +22 -19
- data/lib/lzws/stream/reader_helpers.rb +5 -3
- data/lib/lzws/stream/writer.rb +1 -1
- data/lib/lzws/stream/writer_helpers.rb +7 -10
- data/lib/lzws/string.rb +4 -2
- data/lib/lzws/validation.rb +14 -1
- data/lib/lzws/version.rb +1 -1
- metadata +74 -16
@@ -5,22 +5,25 @@
|
|
5
5
|
#define LZWS_EXT_STREAM_DECOMPRESSOR_H
|
6
6
|
|
7
7
|
#include <lzws/decompressor/state.h>
|
8
|
+
#include <stdlib.h>
|
8
9
|
|
10
|
+
#include "lzws_ext/common.h"
|
9
11
|
#include "ruby.h"
|
10
12
|
|
11
13
|
typedef struct {
|
12
14
|
lzws_decompressor_state_t* state_ptr;
|
13
|
-
|
15
|
+
lzws_ext_byte_t* destination_buffer;
|
14
16
|
size_t destination_buffer_length;
|
15
|
-
|
17
|
+
lzws_ext_byte_t* remaining_destination_buffer;
|
16
18
|
size_t remaining_destination_buffer_length;
|
17
19
|
} lzws_ext_decompressor_t;
|
18
20
|
|
19
21
|
VALUE lzws_ext_allocate_decompressor(VALUE klass);
|
20
22
|
VALUE lzws_ext_initialize_decompressor(VALUE self, VALUE options);
|
21
|
-
VALUE lzws_ext_decompressor_read_magic_header(VALUE self, VALUE source);
|
22
23
|
VALUE lzws_ext_decompress(VALUE self, VALUE source);
|
23
24
|
VALUE lzws_ext_decompressor_read_result(VALUE self);
|
24
25
|
VALUE lzws_ext_decompressor_close(VALUE self);
|
25
26
|
|
27
|
+
void lzws_ext_decompressor_exports(VALUE root_module);
|
28
|
+
|
26
29
|
#endif // LZWS_EXT_STREAM_DECOMPRESSOR_H
|
data/ext/lzws_ext/string.c
CHANGED
@@ -1,78 +1,280 @@
|
|
1
1
|
// Ruby bindings for lzws library.
|
2
2
|
// Copyright (c) 2019 AUTHORS, MIT License.
|
3
3
|
|
4
|
-
#include
|
4
|
+
#include "lzws_ext/string.h"
|
5
5
|
|
6
|
-
#include
|
6
|
+
#include <lzws/buffer.h>
|
7
|
+
#include <lzws/common.h>
|
8
|
+
#include <lzws/compressor/common.h>
|
9
|
+
#include <lzws/compressor/main.h>
|
10
|
+
#include <lzws/compressor/state.h>
|
11
|
+
#include <lzws/decompressor/common.h>
|
12
|
+
#include <lzws/decompressor/main.h>
|
13
|
+
#include <lzws/decompressor/state.h>
|
14
|
+
#include <stdlib.h>
|
7
15
|
|
16
|
+
#include "lzws_ext/buffer.h"
|
8
17
|
#include "lzws_ext/error.h"
|
9
18
|
#include "lzws_ext/macro.h"
|
10
19
|
#include "lzws_ext/option.h"
|
11
|
-
#include "
|
20
|
+
#include "ruby.h"
|
21
|
+
|
22
|
+
// -- buffer --
|
23
|
+
|
24
|
+
static inline lzws_ext_result_t increase_destination_buffer(
|
25
|
+
VALUE destination_value, size_t destination_length,
|
26
|
+
size_t* remaining_destination_buffer_length_ptr, size_t destination_buffer_length)
|
27
|
+
{
|
28
|
+
if (*remaining_destination_buffer_length_ptr == destination_buffer_length) {
|
29
|
+
// We want to write more data at once, than buffer has.
|
30
|
+
return LZWS_EXT_ERROR_NOT_ENOUGH_DESTINATION_BUFFER;
|
31
|
+
}
|
32
|
+
|
33
|
+
int exception;
|
34
|
+
|
35
|
+
LZWS_EXT_RESIZE_STRING_BUFFER(destination_value, destination_length + destination_buffer_length, exception);
|
36
|
+
if (exception != 0) {
|
37
|
+
return LZWS_EXT_ERROR_ALLOCATE_FAILED;
|
38
|
+
}
|
39
|
+
|
40
|
+
*remaining_destination_buffer_length_ptr = destination_buffer_length;
|
41
|
+
|
42
|
+
return 0;
|
43
|
+
}
|
44
|
+
|
45
|
+
// -- utils --
|
46
|
+
|
47
|
+
#define GET_SOURCE_DATA(source_value) \
|
48
|
+
Check_Type(source_value, T_STRING); \
|
49
|
+
\
|
50
|
+
const char* source = RSTRING_PTR(source_value); \
|
51
|
+
size_t source_length = RSTRING_LEN(source_value);
|
12
52
|
|
13
|
-
|
14
|
-
Check_Type(source, T_STRING); \
|
15
|
-
\
|
16
|
-
const char* source_data = RSTRING_PTR(source); \
|
17
|
-
size_t source_length = RSTRING_LEN(source);
|
53
|
+
// -- compress --
|
18
54
|
|
19
|
-
|
55
|
+
#define BUFFERED_COMPRESS(function, ...) \
|
56
|
+
while (true) { \
|
57
|
+
lzws_ext_byte_t* remaining_destination_buffer = (lzws_ext_byte_t*)RSTRING_PTR(destination_value) + destination_length; \
|
58
|
+
size_t prev_remaining_destination_buffer_length = remaining_destination_buffer_length; \
|
59
|
+
\
|
60
|
+
result = function(__VA_ARGS__, &remaining_destination_buffer, &remaining_destination_buffer_length); \
|
61
|
+
\
|
62
|
+
if ( \
|
63
|
+
result != 0 && \
|
64
|
+
result != LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION) { \
|
65
|
+
return LZWS_EXT_ERROR_UNEXPECTED; \
|
66
|
+
} \
|
67
|
+
\
|
68
|
+
destination_length += prev_remaining_destination_buffer_length - remaining_destination_buffer_length; \
|
69
|
+
\
|
70
|
+
if (result == LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION) { \
|
71
|
+
ext_result = increase_destination_buffer( \
|
72
|
+
destination_value, destination_length, \
|
73
|
+
&remaining_destination_buffer_length, destination_buffer_length); \
|
74
|
+
\
|
75
|
+
if (ext_result != 0) { \
|
76
|
+
return ext_result; \
|
77
|
+
} \
|
78
|
+
\
|
79
|
+
continue; \
|
80
|
+
} \
|
81
|
+
\
|
82
|
+
break; \
|
83
|
+
}
|
84
|
+
|
85
|
+
static inline lzws_ext_result_t compress(
|
86
|
+
lzws_compressor_state_t* state_ptr,
|
87
|
+
const char* source, size_t source_length,
|
88
|
+
VALUE destination_value, size_t destination_buffer_length)
|
89
|
+
{
|
90
|
+
lzws_result_t result;
|
91
|
+
lzws_ext_result_t ext_result;
|
92
|
+
|
93
|
+
lzws_ext_byte_t* remaining_source = (lzws_ext_byte_t*)source;
|
94
|
+
size_t remaining_source_length = source_length;
|
95
|
+
|
96
|
+
size_t destination_length = 0;
|
97
|
+
size_t remaining_destination_buffer_length = destination_buffer_length;
|
98
|
+
|
99
|
+
BUFFERED_COMPRESS(lzws_compress, state_ptr, &remaining_source, &remaining_source_length);
|
100
|
+
BUFFERED_COMPRESS(lzws_compressor_finish, state_ptr);
|
101
|
+
|
102
|
+
int exception;
|
103
|
+
|
104
|
+
LZWS_EXT_RESIZE_STRING_BUFFER(destination_value, destination_length, exception);
|
105
|
+
if (exception != 0) {
|
106
|
+
return LZWS_EXT_ERROR_ALLOCATE_FAILED;
|
107
|
+
}
|
108
|
+
|
109
|
+
return 0;
|
110
|
+
}
|
111
|
+
|
112
|
+
VALUE lzws_ext_compress_string(VALUE LZWS_EXT_UNUSED(self), VALUE source_value, VALUE options)
|
20
113
|
{
|
21
|
-
|
114
|
+
GET_SOURCE_DATA(source_value);
|
115
|
+
Check_Type(options, T_HASH);
|
22
116
|
LZWS_EXT_GET_COMPRESSOR_OPTIONS(options);
|
117
|
+
LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
|
23
118
|
|
24
|
-
|
25
|
-
size_t destination_length;
|
119
|
+
lzws_compressor_state_t* state_ptr;
|
26
120
|
|
27
|
-
lzws_result_t result =
|
28
|
-
|
29
|
-
(uint8_t**)&destination, &destination_length, buffer_length,
|
121
|
+
lzws_result_t result = lzws_compressor_get_initial_state(
|
122
|
+
&state_ptr,
|
30
123
|
without_magic_header, max_code_bit_length, block_mode, msb, unaligned_bit_groups, quiet);
|
31
124
|
|
32
|
-
if (result
|
33
|
-
|
125
|
+
if (result != 0) {
|
126
|
+
switch (result) {
|
127
|
+
case LZWS_COMPRESSOR_ALLOCATE_FAILED:
|
128
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_ALLOCATE_FAILED);
|
129
|
+
case LZWS_COMPRESSOR_INVALID_MAX_CODE_BIT_LENGTH:
|
130
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_VALIDATE_FAILED);
|
131
|
+
default:
|
132
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_UNEXPECTED);
|
133
|
+
}
|
34
134
|
}
|
35
|
-
|
36
|
-
|
135
|
+
|
136
|
+
if (destination_buffer_length == 0) {
|
137
|
+
destination_buffer_length = LZWS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_COMPRESSOR;
|
37
138
|
}
|
38
|
-
|
39
|
-
|
139
|
+
|
140
|
+
int exception;
|
141
|
+
|
142
|
+
LZWS_EXT_CREATE_STRING_BUFFER(destination_value, destination_buffer_length, exception);
|
143
|
+
if (exception != 0) {
|
144
|
+
lzws_compressor_free_state(state_ptr);
|
145
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_ALLOCATE_FAILED);
|
40
146
|
}
|
41
147
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
148
|
+
lzws_ext_result_t ext_result = compress(
|
149
|
+
state_ptr,
|
150
|
+
source, source_length,
|
151
|
+
destination_value, destination_buffer_length);
|
152
|
+
|
153
|
+
lzws_compressor_free_state(state_ptr);
|
154
|
+
|
155
|
+
if (ext_result != 0) {
|
156
|
+
lzws_ext_raise_error(ext_result);
|
157
|
+
}
|
158
|
+
|
159
|
+
return destination_value;
|
46
160
|
}
|
47
161
|
|
48
|
-
|
162
|
+
// -- decompress --
|
163
|
+
|
164
|
+
static inline lzws_ext_result_t decompress(
|
165
|
+
lzws_decompressor_state_t* state_ptr,
|
166
|
+
const char* source, size_t source_length,
|
167
|
+
VALUE destination_value, size_t destination_buffer_length)
|
49
168
|
{
|
50
|
-
|
169
|
+
lzws_result_t result;
|
170
|
+
lzws_ext_result_t ext_result;
|
171
|
+
|
172
|
+
lzws_ext_byte_t* remaining_source = (lzws_ext_byte_t*)source;
|
173
|
+
size_t remaining_source_length = source_length;
|
174
|
+
|
175
|
+
size_t destination_length = 0;
|
176
|
+
size_t remaining_destination_buffer_length = destination_buffer_length;
|
177
|
+
|
178
|
+
while (true) {
|
179
|
+
lzws_ext_byte_t* remaining_destination_buffer = (lzws_ext_byte_t*)RSTRING_PTR(destination_value) + destination_length;
|
180
|
+
size_t prev_remaining_destination_buffer_length = remaining_destination_buffer_length;
|
181
|
+
|
182
|
+
result = lzws_decompress(
|
183
|
+
state_ptr,
|
184
|
+
&remaining_source, &remaining_source_length,
|
185
|
+
&remaining_destination_buffer, &remaining_destination_buffer_length);
|
186
|
+
|
187
|
+
if (
|
188
|
+
result != 0 &&
|
189
|
+
result != LZWS_DECOMPRESSOR_NEEDS_MORE_DESTINATION) {
|
190
|
+
switch (result) {
|
191
|
+
case LZWS_DECOMPRESSOR_INVALID_MAGIC_HEADER:
|
192
|
+
case LZWS_DECOMPRESSOR_INVALID_MAX_CODE_BIT_LENGTH:
|
193
|
+
return LZWS_EXT_ERROR_VALIDATE_FAILED;
|
194
|
+
case LZWS_DECOMPRESSOR_CORRUPTED_SOURCE:
|
195
|
+
return LZWS_EXT_ERROR_DECOMPRESSOR_CORRUPTED_SOURCE;
|
196
|
+
default:
|
197
|
+
return LZWS_EXT_ERROR_UNEXPECTED;
|
198
|
+
}
|
199
|
+
}
|
200
|
+
|
201
|
+
destination_length += prev_remaining_destination_buffer_length - remaining_destination_buffer_length;
|
202
|
+
|
203
|
+
if (result == LZWS_DECOMPRESSOR_NEEDS_MORE_DESTINATION) {
|
204
|
+
ext_result = increase_destination_buffer(
|
205
|
+
destination_value, destination_length,
|
206
|
+
&remaining_destination_buffer_length, destination_buffer_length);
|
207
|
+
|
208
|
+
if (ext_result != 0) {
|
209
|
+
return ext_result;
|
210
|
+
}
|
211
|
+
|
212
|
+
continue;
|
213
|
+
}
|
214
|
+
|
215
|
+
break;
|
216
|
+
}
|
217
|
+
|
218
|
+
int exception;
|
219
|
+
|
220
|
+
LZWS_EXT_RESIZE_STRING_BUFFER(destination_value, destination_length, exception);
|
221
|
+
if (exception != 0) {
|
222
|
+
return LZWS_EXT_ERROR_ALLOCATE_FAILED;
|
223
|
+
}
|
224
|
+
|
225
|
+
return 0;
|
226
|
+
}
|
227
|
+
|
228
|
+
VALUE lzws_ext_decompress_string(VALUE LZWS_EXT_UNUSED(self), VALUE source_value, VALUE options)
|
229
|
+
{
|
230
|
+
GET_SOURCE_DATA(source_value);
|
231
|
+
Check_Type(options, T_HASH);
|
51
232
|
LZWS_EXT_GET_DECOMPRESSOR_OPTIONS(options);
|
233
|
+
LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
|
52
234
|
|
53
|
-
|
54
|
-
size_t destination_length;
|
235
|
+
lzws_decompressor_state_t* state_ptr;
|
55
236
|
|
56
|
-
lzws_result_t result =
|
57
|
-
|
58
|
-
(uint8_t**)&destination, &destination_length, buffer_length,
|
237
|
+
lzws_result_t result = lzws_decompressor_get_initial_state(
|
238
|
+
&state_ptr,
|
59
239
|
without_magic_header, msb, unaligned_bit_groups, quiet);
|
60
240
|
|
61
|
-
if (result
|
62
|
-
|
241
|
+
if (result != 0) {
|
242
|
+
switch (result) {
|
243
|
+
case LZWS_DECOMPRESSOR_ALLOCATE_FAILED:
|
244
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_ALLOCATE_FAILED);
|
245
|
+
default:
|
246
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_UNEXPECTED);
|
247
|
+
}
|
63
248
|
}
|
64
|
-
|
65
|
-
|
249
|
+
|
250
|
+
if (destination_buffer_length == 0) {
|
251
|
+
destination_buffer_length = LZWS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_DECOMPRESSOR;
|
66
252
|
}
|
67
|
-
|
68
|
-
|
253
|
+
|
254
|
+
int exception;
|
255
|
+
|
256
|
+
LZWS_EXT_CREATE_STRING_BUFFER(destination_value, destination_buffer_length, exception);
|
257
|
+
if (exception != 0) {
|
258
|
+
lzws_decompressor_free_state(state_ptr);
|
259
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_ALLOCATE_FAILED);
|
69
260
|
}
|
70
|
-
|
71
|
-
|
261
|
+
|
262
|
+
lzws_ext_result_t ext_result = decompress(
|
263
|
+
state_ptr,
|
264
|
+
source, source_length,
|
265
|
+
destination_value, destination_buffer_length);
|
266
|
+
|
267
|
+
lzws_decompressor_free_state(state_ptr);
|
268
|
+
|
269
|
+
if (ext_result != 0) {
|
270
|
+
lzws_ext_raise_error(ext_result);
|
72
271
|
}
|
73
272
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
273
|
+
return destination_value;
|
274
|
+
}
|
275
|
+
|
276
|
+
void lzws_ext_string_exports(VALUE root_module)
|
277
|
+
{
|
278
|
+
rb_define_module_function(root_module, "_native_compress_string", RUBY_METHOD_FUNC(lzws_ext_compress_string), 2);
|
279
|
+
rb_define_module_function(root_module, "_native_decompress_string", RUBY_METHOD_FUNC(lzws_ext_decompress_string), 2);
|
78
280
|
}
|
data/ext/lzws_ext/string.h
CHANGED
data/lib/lzws.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
-
|
1
|
+
# Ruby bindings for lzws library.
|
2
|
+
# Copyright (c) 2019 AUTHORS, MIT License.
|
3
|
+
|
2
4
|
require_relative "lzws/stream/reader"
|
3
5
|
require_relative "lzws/stream/writer"
|
6
|
+
require_relative "lzws/file"
|
4
7
|
require_relative "lzws/string"
|
8
|
+
require_relative "lzws/version"
|
data/lib/lzws/error.rb
CHANGED
@@ -4,17 +4,18 @@
|
|
4
4
|
module LZWS
|
5
5
|
class BaseError < ::StandardError; end
|
6
6
|
|
7
|
-
class
|
8
|
-
class
|
9
|
-
class UnexpectedError < BaseError; end
|
10
|
-
|
11
|
-
class NotEnoughDestinationError < BaseError; end
|
12
|
-
class UsedAfterCloseError < BaseError; end
|
7
|
+
class AllocateError < BaseError; end
|
8
|
+
class ValidateError < BaseError; end
|
13
9
|
|
10
|
+
class UsedAfterCloseError < BaseError; end
|
11
|
+
class NotEnoughSourceBufferError < BaseError; end
|
12
|
+
class NotEnoughDestinationBufferError < BaseError; end
|
13
|
+
class NotEnoughDestinationError < BaseError; end
|
14
14
|
class DecompressorCorruptedSourceError < BaseError; end
|
15
15
|
|
16
|
-
class OpenFileError < BaseError; end
|
17
16
|
class AccessIOError < BaseError; end
|
18
17
|
class ReadIOError < BaseError; end
|
19
18
|
class WriteIOError < BaseError; end
|
19
|
+
|
20
|
+
class UnexpectedError < BaseError; end
|
20
21
|
end
|
data/lib/lzws/file.rb
CHANGED
@@ -9,11 +9,13 @@ require_relative "validation"
|
|
9
9
|
|
10
10
|
module LZWS
|
11
11
|
module File
|
12
|
+
BUFFER_LENGTH_NAMES = %i[source_buffer_length destination_buffer_length].freeze
|
13
|
+
|
12
14
|
def self.compress(source, destination, options = {})
|
13
15
|
Validation.validate_string source
|
14
16
|
Validation.validate_string destination
|
15
17
|
|
16
|
-
options = Option.get_compressor_options options
|
18
|
+
options = Option.get_compressor_options options, BUFFER_LENGTH_NAMES
|
17
19
|
|
18
20
|
open_files(source, destination) do |source_io, destination_io|
|
19
21
|
LZWS._native_compress_io source_io, destination_io, options
|
@@ -24,7 +26,7 @@ module LZWS
|
|
24
26
|
Validation.validate_string source
|
25
27
|
Validation.validate_string destination
|
26
28
|
|
27
|
-
options = Option.get_decompressor_options options
|
29
|
+
options = Option.get_decompressor_options options, BUFFER_LENGTH_NAMES
|
28
30
|
|
29
31
|
open_files(source, destination) do |source_io, destination_io|
|
30
32
|
LZWS._native_decompress_io source_io, destination_io, options
|
@@ -32,25 +34,11 @@ module LZWS
|
|
32
34
|
end
|
33
35
|
|
34
36
|
private_class_method def self.open_files(source, destination, &_block)
|
35
|
-
|
36
|
-
|
37
|
+
::File.open source, "rb" do |source_io|
|
38
|
+
::File.open destination, "wb" do |destination_io|
|
37
39
|
yield source_io, destination_io
|
38
40
|
end
|
39
41
|
end
|
40
42
|
end
|
41
|
-
|
42
|
-
private_class_method def self.open_file(path, mode, &_block)
|
43
|
-
begin
|
44
|
-
io = ::File.open path, mode
|
45
|
-
rescue ::StandardError
|
46
|
-
raise OpenFileError, "open file failed"
|
47
|
-
end
|
48
|
-
|
49
|
-
begin
|
50
|
-
yield io
|
51
|
-
ensure
|
52
|
-
io.close
|
53
|
-
end
|
54
|
-
end
|
55
43
|
end
|
56
44
|
end
|