ruby-lzws 1.0.0 → 1.1.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 +176 -27
- data/ext/extconf.rb +11 -17
- data/ext/lzws_ext/buffer.c +18 -0
- data/ext/lzws_ext/buffer.h +11 -0
- data/ext/lzws_ext/common.h +4 -0
- data/ext/lzws_ext/error.c +33 -3
- data/ext/lzws_ext/error.h +20 -1
- data/ext/lzws_ext/io.c +60 -47
- data/ext/lzws_ext/io.h +2 -0
- data/ext/lzws_ext/macro.h +0 -2
- data/ext/lzws_ext/main.c +8 -29
- data/ext/lzws_ext/option.c +23 -10
- data/ext/lzws_ext/option.h +27 -50
- data/ext/lzws_ext/stream/compressor.c +71 -84
- data/ext/lzws_ext/stream/compressor.h +5 -2
- data/ext/lzws_ext/stream/decompressor.c +67 -84
- data/ext/lzws_ext/stream/decompressor.h +4 -1
- data/ext/lzws_ext/string.c +261 -44
- data/ext/lzws_ext/string.h +2 -0
- data/lib/lzws/error.rb +8 -7
- data/lib/lzws/file.rb +6 -18
- data/lib/lzws/option.rb +10 -7
- data/lib/lzws/stream/abstract.rb +2 -2
- data/lib/lzws/stream/raw/abstract.rb +24 -9
- data/lib/lzws/stream/raw/compressor.rb +7 -31
- data/lib/lzws/stream/raw/decompressor.rb +6 -24
- data/lib/lzws/stream/reader.rb +14 -11
- data/lib/lzws/stream/reader_helpers.rb +3 -3
- data/lib/lzws/stream/writer_helpers.rb +2 -2
- data/lib/lzws/string.rb +4 -2
- data/lib/lzws/version.rb +1 -1
- data/lib/lzws.rb +4 -1
- metadata +5 -3
data/ext/lzws_ext/main.c
CHANGED
@@ -1,42 +1,21 @@
|
|
1
1
|
// Ruby bindings for lzws library.
|
2
2
|
// Copyright (c) 2019 AUTHORS, MIT License.
|
3
3
|
|
4
|
-
#include "
|
5
|
-
|
4
|
+
#include "lzws_ext/buffer.h"
|
6
5
|
#include "lzws_ext/common.h"
|
7
6
|
#include "lzws_ext/io.h"
|
8
7
|
#include "lzws_ext/stream/compressor.h"
|
9
8
|
#include "lzws_ext/stream/decompressor.h"
|
10
9
|
#include "lzws_ext/string.h"
|
10
|
+
#include "ruby.h"
|
11
11
|
|
12
12
|
void Init_lzws_ext()
|
13
13
|
{
|
14
|
-
VALUE
|
15
|
-
|
16
|
-
// It is better to use these functions internally and prepare pretty wrappers for public usage.
|
17
|
-
rb_define_module_function(root, "_native_compress_io", RUBY_METHOD_FUNC(lzws_ext_compress_io), 3);
|
18
|
-
rb_define_module_function(root, "_native_decompress_io", RUBY_METHOD_FUNC(lzws_ext_decompress_io), 3);
|
19
|
-
rb_define_module_function(root, "_native_compress_string", RUBY_METHOD_FUNC(lzws_ext_compress_string), 2);
|
20
|
-
rb_define_module_function(root, "_native_decompress_string", RUBY_METHOD_FUNC(lzws_ext_decompress_string), 2);
|
21
|
-
|
22
|
-
// -----
|
23
|
-
|
24
|
-
VALUE stream = rb_define_module_under(root, "Stream");
|
25
|
-
|
26
|
-
VALUE compressor = rb_define_class_under(stream, "NativeCompressor", rb_cObject);
|
27
|
-
rb_define_alloc_func(compressor, lzws_ext_allocate_compressor);
|
28
|
-
rb_define_method(compressor, "initialize", lzws_ext_initialize_compressor, 1);
|
29
|
-
rb_define_method(compressor, "write_magic_header", lzws_ext_compressor_write_magic_header, 0);
|
30
|
-
rb_define_method(compressor, "write", lzws_ext_compress, 1);
|
31
|
-
rb_define_method(compressor, "flush", lzws_ext_flush_compressor, 0);
|
32
|
-
rb_define_method(compressor, "read_result", lzws_ext_compressor_read_result, 0);
|
33
|
-
rb_define_method(compressor, "close", lzws_ext_compressor_close, 0);
|
14
|
+
VALUE root_module = rb_define_module(LZWS_EXT_MODULE_NAME);
|
34
15
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
rb_define_method(decompressor, "read_result", lzws_ext_decompressor_read_result, 0);
|
41
|
-
rb_define_method(decompressor, "close", lzws_ext_decompressor_close, 0);
|
16
|
+
lzws_ext_buffer_exports(root_module);
|
17
|
+
lzws_ext_io_exports(root_module);
|
18
|
+
lzws_ext_compressor_exports(root_module);
|
19
|
+
lzws_ext_decompressor_exports(root_module);
|
20
|
+
lzws_ext_string_exports(root_module);
|
42
21
|
}
|
data/ext/lzws_ext/option.c
CHANGED
@@ -1,22 +1,35 @@
|
|
1
1
|
// Ruby bindings for lzws library.
|
2
2
|
// Copyright (c) 2019 AUTHORS, MIT License.
|
3
3
|
|
4
|
-
#include "ruby.h"
|
5
|
-
|
6
4
|
#include "lzws_ext/option.h"
|
7
5
|
|
8
|
-
|
6
|
+
#include <stdbool.h>
|
7
|
+
|
8
|
+
#include "lzws_ext/error.h"
|
9
|
+
#include "ruby.h"
|
10
|
+
|
11
|
+
static inline VALUE get_raw_option_value(VALUE options, const char* name)
|
9
12
|
{
|
10
|
-
|
11
|
-
return rb_funcall(options, rb_intern("[]"), 1, name_symbol);
|
13
|
+
return rb_funcall(options, rb_intern("[]"), 1, ID2SYM(rb_intern(name)));
|
12
14
|
}
|
13
15
|
|
14
|
-
|
16
|
+
bool lzws_ext_get_bool_option_value(VALUE options, const char* name)
|
15
17
|
{
|
16
|
-
|
18
|
+
VALUE raw_value = get_raw_option_value(options, name);
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
20
|
+
int raw_type = TYPE(raw_value);
|
21
|
+
if (raw_type != T_TRUE && raw_type != T_FALSE) {
|
22
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_VALIDATE_FAILED);
|
21
23
|
}
|
24
|
+
|
25
|
+
return raw_type == T_TRUE;
|
26
|
+
}
|
27
|
+
|
28
|
+
unsigned long lzws_ext_get_fixnum_option_value(VALUE options, const char* name)
|
29
|
+
{
|
30
|
+
VALUE raw_value = get_raw_option_value(options, name);
|
31
|
+
|
32
|
+
Check_Type(raw_value, T_FIXNUM);
|
33
|
+
|
34
|
+
return NUM2UINT(raw_value);
|
22
35
|
}
|
data/ext/lzws_ext/option.h
CHANGED
@@ -4,57 +4,34 @@
|
|
4
4
|
#if !defined(LZWS_EXT_OPTIONS_H)
|
5
5
|
#define LZWS_EXT_OPTIONS_H
|
6
6
|
|
7
|
+
#include <stdbool.h>
|
8
|
+
|
7
9
|
#include "ruby.h"
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
#define
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
bool block_mode = TYPE(block_mode_value) == T_TRUE; \
|
35
|
-
bool msb = TYPE(msb_value) == T_TRUE; \
|
36
|
-
bool unaligned_bit_groups = TYPE(unaligned_bit_groups_value) == T_TRUE; \
|
37
|
-
bool quiet = TYPE(quiet_value) == T_TRUE;
|
38
|
-
|
39
|
-
#define LZWS_EXT_GET_DECOMPRESSOR_OPTIONS(options) \
|
40
|
-
Check_Type(options, T_HASH); \
|
41
|
-
\
|
42
|
-
VALUE buffer_length_value = lzws_ext_get_option(options, "buffer_length"); \
|
43
|
-
VALUE without_magic_header_value = lzws_ext_get_option(options, "without_magic_header"); \
|
44
|
-
VALUE msb_value = lzws_ext_get_option(options, "msb"); \
|
45
|
-
VALUE unaligned_bit_groups_value = lzws_ext_get_option(options, "unaligned_bit_groups"); \
|
46
|
-
VALUE quiet_value = lzws_ext_get_option(options, "quiet"); \
|
47
|
-
\
|
48
|
-
Check_Type(buffer_length_value, T_FIXNUM); \
|
49
|
-
lzws_ext_check_bool_type(without_magic_header_value, "without_magic_header"); \
|
50
|
-
lzws_ext_check_bool_type(msb_value, "msb"); \
|
51
|
-
lzws_ext_check_bool_type(unaligned_bit_groups_value, "unaligned_bit_groups"); \
|
52
|
-
lzws_ext_check_bool_type(quiet_value, "quiet"); \
|
53
|
-
\
|
54
|
-
size_t buffer_length = rb_num2uint(buffer_length_value); \
|
55
|
-
bool without_magic_header = TYPE(without_magic_header_value) == T_TRUE; \
|
56
|
-
bool msb = TYPE(msb_value) == T_TRUE; \
|
57
|
-
bool unaligned_bit_groups = TYPE(unaligned_bit_groups_value) == T_TRUE; \
|
58
|
-
bool quiet = TYPE(quiet_value) == T_TRUE;
|
11
|
+
bool lzws_ext_get_bool_option_value(VALUE options, const char* name);
|
12
|
+
unsigned long lzws_ext_get_fixnum_option_value(VALUE options, const char* name);
|
13
|
+
|
14
|
+
#define LZWS_EXT_GET_BOOL_OPTION(options, name) \
|
15
|
+
bool name = lzws_ext_get_bool_option_value(options, #name);
|
16
|
+
|
17
|
+
#define LZWS_EXT_GET_FIXNUM_OPTION(options, type, name) \
|
18
|
+
type name = lzws_ext_get_fixnum_option_value(options, #name);
|
19
|
+
|
20
|
+
#define LZWS_EXT_GET_COMPRESSOR_OPTIONS(options) \
|
21
|
+
LZWS_EXT_GET_BOOL_OPTION(options, without_magic_header); \
|
22
|
+
LZWS_EXT_GET_FIXNUM_OPTION(options, uint_fast8_t, max_code_bit_length); \
|
23
|
+
LZWS_EXT_GET_BOOL_OPTION(options, block_mode); \
|
24
|
+
LZWS_EXT_GET_BOOL_OPTION(options, msb); \
|
25
|
+
LZWS_EXT_GET_BOOL_OPTION(options, unaligned_bit_groups); \
|
26
|
+
LZWS_EXT_GET_BOOL_OPTION(options, quiet);
|
27
|
+
|
28
|
+
#define LZWS_EXT_GET_DECOMPRESSOR_OPTIONS(options) \
|
29
|
+
LZWS_EXT_GET_BOOL_OPTION(options, without_magic_header); \
|
30
|
+
LZWS_EXT_GET_BOOL_OPTION(options, msb); \
|
31
|
+
LZWS_EXT_GET_BOOL_OPTION(options, unaligned_bit_groups); \
|
32
|
+
LZWS_EXT_GET_BOOL_OPTION(options, quiet);
|
33
|
+
|
34
|
+
#define LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, name) \
|
35
|
+
LZWS_EXT_GET_FIXNUM_OPTION(options, size_t, name);
|
59
36
|
|
60
37
|
#endif // LZWS_EXT_OPTIONS_H
|
@@ -1,18 +1,18 @@
|
|
1
1
|
// Ruby bindings for lzws library.
|
2
2
|
// Copyright (c) 2019 AUTHORS, MIT License.
|
3
3
|
|
4
|
+
#include "lzws_ext/stream/compressor.h"
|
5
|
+
|
4
6
|
#include <lzws/buffer.h>
|
5
7
|
#include <lzws/compressor/common.h>
|
6
|
-
#include <lzws/compressor/header.h>
|
7
8
|
#include <lzws/compressor/main.h>
|
8
9
|
#include <lzws/compressor/state.h>
|
9
|
-
|
10
|
-
#include
|
10
|
+
#include <stdint.h>
|
11
|
+
#include <stdlib.h>
|
11
12
|
|
12
13
|
#include "lzws_ext/error.h"
|
13
|
-
#include "lzws_ext/macro.h"
|
14
14
|
#include "lzws_ext/option.h"
|
15
|
-
#include "
|
15
|
+
#include "ruby.h"
|
16
16
|
|
17
17
|
static void free_compressor(lzws_ext_compressor_t* compressor_ptr)
|
18
18
|
{
|
@@ -51,37 +51,36 @@ VALUE lzws_ext_allocate_compressor(VALUE klass)
|
|
51
51
|
VALUE lzws_ext_initialize_compressor(VALUE self, VALUE options)
|
52
52
|
{
|
53
53
|
GET_COMPRESSOR(self);
|
54
|
+
Check_Type(options, T_HASH);
|
54
55
|
LZWS_EXT_GET_COMPRESSOR_OPTIONS(options);
|
55
|
-
|
56
|
+
LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
|
56
57
|
|
57
|
-
lzws_compressor_state_t*
|
58
|
+
lzws_compressor_state_t* state_ptr;
|
58
59
|
|
59
60
|
lzws_result_t result = lzws_compressor_get_initial_state(
|
60
|
-
&
|
61
|
-
max_code_bit_length, block_mode, msb, unaligned_bit_groups, quiet);
|
61
|
+
&state_ptr,
|
62
|
+
without_magic_header, max_code_bit_length, block_mode, msb, unaligned_bit_groups, quiet);
|
62
63
|
|
63
|
-
if (result
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
64
|
+
if (result != 0) {
|
65
|
+
switch (result) {
|
66
|
+
case LZWS_COMPRESSOR_ALLOCATE_FAILED:
|
67
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_ALLOCATE_FAILED);
|
68
|
+
case LZWS_COMPRESSOR_INVALID_MAX_CODE_BIT_LENGTH:
|
69
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_VALIDATE_FAILED);
|
70
|
+
default:
|
71
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_UNEXPECTED);
|
72
|
+
}
|
71
73
|
}
|
72
74
|
|
73
|
-
compressor_ptr->state_ptr = compressor_state_ptr;
|
74
|
-
|
75
|
-
// -----
|
76
|
-
|
77
75
|
uint8_t* destination_buffer;
|
78
|
-
size_t destination_buffer_length = buffer_length;
|
79
76
|
|
80
|
-
result =
|
77
|
+
result = lzws_create_destination_buffer_for_compressor(&destination_buffer, &destination_buffer_length, quiet);
|
81
78
|
if (result != 0) {
|
82
|
-
|
79
|
+
lzws_compressor_free_state(state_ptr);
|
80
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_ALLOCATE_FAILED);
|
83
81
|
}
|
84
82
|
|
83
|
+
compressor_ptr->state_ptr = state_ptr;
|
85
84
|
compressor_ptr->destination_buffer = destination_buffer;
|
86
85
|
compressor_ptr->destination_buffer_length = destination_buffer_length;
|
87
86
|
compressor_ptr->remaining_destination_buffer = destination_buffer;
|
@@ -92,83 +91,58 @@ VALUE lzws_ext_initialize_compressor(VALUE self, VALUE options)
|
|
92
91
|
|
93
92
|
#define DO_NOT_USE_AFTER_CLOSE(compressor_ptr) \
|
94
93
|
if (compressor_ptr->state_ptr == NULL || compressor_ptr->destination_buffer == NULL) { \
|
95
|
-
lzws_ext_raise_error(
|
94
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_USED_AFTER_CLOSE); \
|
96
95
|
}
|
97
96
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
&compressor_ptr->remaining_destination_buffer_length);
|
97
|
+
#define GET_SOURCE_DATA(source_value) \
|
98
|
+
Check_Type(source_value, T_STRING); \
|
99
|
+
\
|
100
|
+
const char* source = RSTRING_PTR(source_value); \
|
101
|
+
size_t source_length = RSTRING_LEN(source_value); \
|
102
|
+
uint8_t* remaining_source = (uint8_t*)source; \
|
103
|
+
size_t remaining_source_length = source_length;
|
106
104
|
|
107
|
-
|
108
|
-
return Qfalse;
|
109
|
-
}
|
110
|
-
else if (result == LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION) {
|
111
|
-
return Qtrue;
|
112
|
-
}
|
113
|
-
else {
|
114
|
-
lzws_ext_raise_error("UnexpectedError", "unexpected error");
|
115
|
-
}
|
116
|
-
}
|
117
|
-
|
118
|
-
#define GET_STRING(source) \
|
119
|
-
Check_Type(source, T_STRING); \
|
120
|
-
\
|
121
|
-
const char* source_data = RSTRING_PTR(source); \
|
122
|
-
size_t source_length = RSTRING_LEN(source);
|
123
|
-
|
124
|
-
VALUE lzws_ext_compress(VALUE self, VALUE source)
|
105
|
+
VALUE lzws_ext_compress(VALUE self, VALUE source_value)
|
125
106
|
{
|
126
107
|
GET_COMPRESSOR(self);
|
127
108
|
DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
|
128
|
-
|
129
|
-
|
130
|
-
uint8_t* remaining_source_data = (uint8_t*)source_data;
|
131
|
-
size_t remaining_source_length = source_length;
|
109
|
+
GET_SOURCE_DATA(source_value);
|
132
110
|
|
133
111
|
lzws_result_t result = lzws_compress(
|
134
112
|
compressor_ptr->state_ptr,
|
135
|
-
&
|
136
|
-
&
|
137
|
-
&compressor_ptr->remaining_destination_buffer,
|
138
|
-
&compressor_ptr->remaining_destination_buffer_length);
|
113
|
+
&remaining_source, &remaining_source_length,
|
114
|
+
&compressor_ptr->remaining_destination_buffer, &compressor_ptr->remaining_destination_buffer_length);
|
139
115
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
}
|
145
|
-
else if (result == LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION) {
|
146
|
-
return rb_ary_new_from_args(2, bytes_written, Qtrue);
|
147
|
-
}
|
148
|
-
else {
|
149
|
-
lzws_ext_raise_error("UnexpectedError", "unexpected error");
|
116
|
+
if (
|
117
|
+
result != 0 &&
|
118
|
+
result != LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION) {
|
119
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_UNEXPECTED);
|
150
120
|
}
|
121
|
+
|
122
|
+
VALUE bytes_written = UINT2NUM(source_length - remaining_source_length);
|
123
|
+
VALUE needs_more_destination = result == LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION ? Qtrue : Qfalse;
|
124
|
+
|
125
|
+
return rb_ary_new_from_args(2, bytes_written, needs_more_destination);
|
151
126
|
}
|
152
127
|
|
153
|
-
VALUE
|
128
|
+
VALUE lzws_ext_compressor_finish(VALUE self)
|
154
129
|
{
|
155
130
|
GET_COMPRESSOR(self);
|
156
131
|
DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
|
157
132
|
|
158
|
-
lzws_result_t result =
|
133
|
+
lzws_result_t result = lzws_compressor_finish(
|
159
134
|
compressor_ptr->state_ptr,
|
160
|
-
&compressor_ptr->remaining_destination_buffer,
|
161
|
-
&compressor_ptr->remaining_destination_buffer_length);
|
135
|
+
&compressor_ptr->remaining_destination_buffer, &compressor_ptr->remaining_destination_buffer_length);
|
162
136
|
|
163
|
-
if (
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
return Qtrue;
|
168
|
-
}
|
169
|
-
else {
|
170
|
-
lzws_ext_raise_error("UnexpectedError", "unexpected error");
|
137
|
+
if (
|
138
|
+
result != 0 &&
|
139
|
+
result != LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION) {
|
140
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_UNEXPECTED);
|
171
141
|
}
|
142
|
+
|
143
|
+
VALUE needs_more_destination = result == LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION ? Qtrue : Qfalse;
|
144
|
+
|
145
|
+
return needs_more_destination;
|
172
146
|
}
|
173
147
|
|
174
148
|
VALUE lzws_ext_compressor_read_result(VALUE self)
|
@@ -180,15 +154,15 @@ VALUE lzws_ext_compressor_read_result(VALUE self)
|
|
180
154
|
size_t destination_buffer_length = compressor_ptr->destination_buffer_length;
|
181
155
|
size_t remaining_destination_buffer_length = compressor_ptr->remaining_destination_buffer_length;
|
182
156
|
|
183
|
-
const char*
|
157
|
+
const char* result = (const char*)destination_buffer;
|
184
158
|
size_t result_length = destination_buffer_length - remaining_destination_buffer_length;
|
185
159
|
|
186
|
-
VALUE
|
160
|
+
VALUE result_value = rb_str_new(result, result_length);
|
187
161
|
|
188
162
|
compressor_ptr->remaining_destination_buffer = destination_buffer;
|
189
163
|
compressor_ptr->remaining_destination_buffer_length = destination_buffer_length;
|
190
164
|
|
191
|
-
return
|
165
|
+
return result_value;
|
192
166
|
}
|
193
167
|
|
194
168
|
VALUE lzws_ext_compressor_close(VALUE self)
|
@@ -215,3 +189,16 @@ VALUE lzws_ext_compressor_close(VALUE self)
|
|
215
189
|
|
216
190
|
return Qnil;
|
217
191
|
}
|
192
|
+
|
193
|
+
void lzws_ext_compressor_exports(VALUE root_module)
|
194
|
+
{
|
195
|
+
VALUE stream = rb_define_module_under(root_module, "Stream");
|
196
|
+
|
197
|
+
VALUE compressor = rb_define_class_under(stream, "NativeCompressor", rb_cObject);
|
198
|
+
rb_define_alloc_func(compressor, lzws_ext_allocate_compressor);
|
199
|
+
rb_define_method(compressor, "initialize", lzws_ext_initialize_compressor, 1);
|
200
|
+
rb_define_method(compressor, "write", lzws_ext_compress, 1);
|
201
|
+
rb_define_method(compressor, "finish", lzws_ext_compressor_finish, 0);
|
202
|
+
rb_define_method(compressor, "read_result", lzws_ext_compressor_read_result, 0);
|
203
|
+
rb_define_method(compressor, "close", lzws_ext_compressor_close, 0);
|
204
|
+
}
|
@@ -5,6 +5,8 @@
|
|
5
5
|
#define LZWS_EXT_STREAM_COMPRESSOR_H
|
6
6
|
|
7
7
|
#include <lzws/compressor/state.h>
|
8
|
+
#include <stdint.h>
|
9
|
+
#include <stdlib.h>
|
8
10
|
|
9
11
|
#include "ruby.h"
|
10
12
|
|
@@ -18,10 +20,11 @@ typedef struct {
|
|
18
20
|
|
19
21
|
VALUE lzws_ext_allocate_compressor(VALUE klass);
|
20
22
|
VALUE lzws_ext_initialize_compressor(VALUE self, VALUE options);
|
21
|
-
VALUE lzws_ext_compressor_write_magic_header(VALUE self);
|
22
23
|
VALUE lzws_ext_compress(VALUE self, VALUE source);
|
23
|
-
VALUE
|
24
|
+
VALUE lzws_ext_compressor_finish(VALUE self);
|
24
25
|
VALUE lzws_ext_compressor_read_result(VALUE self);
|
25
26
|
VALUE lzws_ext_compressor_close(VALUE self);
|
26
27
|
|
28
|
+
void lzws_ext_compressor_exports(VALUE root_module);
|
29
|
+
|
27
30
|
#endif // LZWS_EXT_STREAM_COMPRESSOR_H
|
@@ -1,18 +1,18 @@
|
|
1
1
|
// Ruby bindings for lzws library.
|
2
2
|
// Copyright (c) 2019 AUTHORS, MIT License.
|
3
3
|
|
4
|
+
#include "lzws_ext/stream/decompressor.h"
|
5
|
+
|
4
6
|
#include <lzws/buffer.h>
|
5
7
|
#include <lzws/decompressor/common.h>
|
6
|
-
#include <lzws/decompressor/header.h>
|
7
8
|
#include <lzws/decompressor/main.h>
|
8
9
|
#include <lzws/decompressor/state.h>
|
9
|
-
|
10
|
-
#include
|
10
|
+
#include <stdint.h>
|
11
|
+
#include <stdlib.h>
|
11
12
|
|
12
13
|
#include "lzws_ext/error.h"
|
13
|
-
#include "lzws_ext/macro.h"
|
14
14
|
#include "lzws_ext/option.h"
|
15
|
-
#include "
|
15
|
+
#include "ruby.h"
|
16
16
|
|
17
17
|
static void free_decompressor(lzws_ext_decompressor_t* decompressor_ptr)
|
18
18
|
{
|
@@ -51,34 +51,34 @@ VALUE lzws_ext_allocate_decompressor(VALUE klass)
|
|
51
51
|
VALUE lzws_ext_initialize_decompressor(VALUE self, VALUE options)
|
52
52
|
{
|
53
53
|
GET_DECOMPRESSOR(self);
|
54
|
+
Check_Type(options, T_HASH);
|
54
55
|
LZWS_EXT_GET_DECOMPRESSOR_OPTIONS(options);
|
55
|
-
|
56
|
+
LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
|
56
57
|
|
57
|
-
lzws_decompressor_state_t*
|
58
|
+
lzws_decompressor_state_t* state_ptr;
|
58
59
|
|
59
60
|
lzws_result_t result = lzws_decompressor_get_initial_state(
|
60
|
-
&
|
61
|
-
msb, unaligned_bit_groups, quiet);
|
61
|
+
&state_ptr,
|
62
|
+
without_magic_header, msb, unaligned_bit_groups, quiet);
|
62
63
|
|
63
|
-
if (result
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
64
|
+
if (result != 0) {
|
65
|
+
switch (result) {
|
66
|
+
case LZWS_DECOMPRESSOR_ALLOCATE_FAILED:
|
67
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_ALLOCATE_FAILED);
|
68
|
+
default:
|
69
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_UNEXPECTED);
|
70
|
+
}
|
68
71
|
}
|
69
72
|
|
70
|
-
decompressor_ptr->state_ptr = decompressor_state_ptr;
|
71
|
-
|
72
|
-
// -----
|
73
|
-
|
74
73
|
uint8_t* destination_buffer;
|
75
|
-
size_t destination_buffer_length = buffer_length;
|
76
74
|
|
77
|
-
result =
|
75
|
+
result = lzws_create_destination_buffer_for_decompressor(&destination_buffer, &destination_buffer_length, quiet);
|
78
76
|
if (result != 0) {
|
79
|
-
|
77
|
+
lzws_decompressor_free_state(state_ptr);
|
78
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_ALLOCATE_FAILED);
|
80
79
|
}
|
81
80
|
|
81
|
+
decompressor_ptr->state_ptr = state_ptr;
|
82
82
|
decompressor_ptr->destination_buffer = destination_buffer;
|
83
83
|
decompressor_ptr->destination_buffer_length = destination_buffer_length;
|
84
84
|
decompressor_ptr->remaining_destination_buffer = destination_buffer;
|
@@ -87,77 +87,48 @@ VALUE lzws_ext_initialize_decompressor(VALUE self, VALUE options)
|
|
87
87
|
return Qnil;
|
88
88
|
}
|
89
89
|
|
90
|
-
#define GET_STRING(source) \
|
91
|
-
Check_Type(source, T_STRING); \
|
92
|
-
\
|
93
|
-
const char* source_data = RSTRING_PTR(source); \
|
94
|
-
size_t source_length = RSTRING_LEN(source);
|
95
|
-
|
96
90
|
#define DO_NOT_USE_AFTER_CLOSE(decompressor_ptr) \
|
97
91
|
if (decompressor_ptr->state_ptr == NULL || decompressor_ptr->destination_buffer == NULL) { \
|
98
|
-
lzws_ext_raise_error(
|
92
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_USED_AFTER_CLOSE); \
|
99
93
|
}
|
100
94
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
size_t remaining_source_length = source_length;
|
109
|
-
|
110
|
-
lzws_result_t result = lzws_decompressor_read_magic_header(
|
111
|
-
decompressor_ptr->state_ptr,
|
112
|
-
&remaining_source_data,
|
113
|
-
&remaining_source_length);
|
95
|
+
#define GET_SOURCE_DATA(source_value) \
|
96
|
+
Check_Type(source_value, T_STRING); \
|
97
|
+
\
|
98
|
+
const char* source = RSTRING_PTR(source_value); \
|
99
|
+
size_t source_length = RSTRING_LEN(source_value); \
|
100
|
+
uint8_t* remaining_source = (uint8_t*)source; \
|
101
|
+
size_t remaining_source_length = source_length;
|
114
102
|
|
115
|
-
|
116
|
-
|
117
|
-
if (result == 0 || result == LZWS_DECOMPRESSOR_NEEDS_MORE_SOURCE) {
|
118
|
-
return bytes_read;
|
119
|
-
}
|
120
|
-
else if (result == LZWS_DECOMPRESSOR_INVALID_MAGIC_HEADER) {
|
121
|
-
lzws_ext_raise_error("ValidateError", "validate error");
|
122
|
-
}
|
123
|
-
else {
|
124
|
-
lzws_ext_raise_error("UnexpectedError", "unexpected error");
|
125
|
-
}
|
126
|
-
}
|
127
|
-
|
128
|
-
VALUE lzws_ext_decompress(VALUE self, VALUE source)
|
103
|
+
VALUE lzws_ext_decompress(VALUE self, VALUE source_value)
|
129
104
|
{
|
130
105
|
GET_DECOMPRESSOR(self);
|
131
106
|
DO_NOT_USE_AFTER_CLOSE(decompressor_ptr);
|
132
|
-
|
133
|
-
|
134
|
-
uint8_t* remaining_source_data = (uint8_t*)source_data;
|
135
|
-
size_t remaining_source_length = source_length;
|
107
|
+
GET_SOURCE_DATA(source_value);
|
136
108
|
|
137
109
|
lzws_result_t result = lzws_decompress(
|
138
110
|
decompressor_ptr->state_ptr,
|
139
|
-
&
|
140
|
-
&
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
}
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
}
|
111
|
+
&remaining_source, &remaining_source_length,
|
112
|
+
&decompressor_ptr->remaining_destination_buffer, &decompressor_ptr->remaining_destination_buffer_length);
|
113
|
+
|
114
|
+
if (
|
115
|
+
result != 0 &&
|
116
|
+
result != LZWS_DECOMPRESSOR_NEEDS_MORE_DESTINATION) {
|
117
|
+
switch (result) {
|
118
|
+
case LZWS_DECOMPRESSOR_INVALID_MAGIC_HEADER:
|
119
|
+
case LZWS_DECOMPRESSOR_INVALID_MAX_CODE_BIT_LENGTH:
|
120
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_VALIDATE_FAILED);
|
121
|
+
case LZWS_DECOMPRESSOR_CORRUPTED_SOURCE:
|
122
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_DECOMPRESSOR_CORRUPTED_SOURCE);
|
123
|
+
default:
|
124
|
+
lzws_ext_raise_error(LZWS_EXT_ERROR_UNEXPECTED);
|
125
|
+
}
|
126
|
+
}
|
127
|
+
|
128
|
+
VALUE bytes_read = UINT2NUM(source_length - remaining_source_length);
|
129
|
+
VALUE needs_more_destination = result == LZWS_DECOMPRESSOR_NEEDS_MORE_DESTINATION ? Qtrue : Qfalse;
|
130
|
+
|
131
|
+
return rb_ary_new_from_args(2, bytes_read, needs_more_destination);
|
161
132
|
}
|
162
133
|
|
163
134
|
VALUE lzws_ext_decompressor_read_result(VALUE self)
|
@@ -169,15 +140,15 @@ VALUE lzws_ext_decompressor_read_result(VALUE self)
|
|
169
140
|
size_t destination_buffer_length = decompressor_ptr->destination_buffer_length;
|
170
141
|
size_t remaining_destination_buffer_length = decompressor_ptr->remaining_destination_buffer_length;
|
171
142
|
|
172
|
-
const char*
|
143
|
+
const char* result = (const char*)destination_buffer;
|
173
144
|
size_t result_length = destination_buffer_length - remaining_destination_buffer_length;
|
174
145
|
|
175
|
-
VALUE
|
146
|
+
VALUE result_value = rb_str_new(result, result_length);
|
176
147
|
|
177
148
|
decompressor_ptr->remaining_destination_buffer = destination_buffer;
|
178
149
|
decompressor_ptr->remaining_destination_buffer_length = destination_buffer_length;
|
179
150
|
|
180
|
-
return
|
151
|
+
return result_value;
|
181
152
|
}
|
182
153
|
|
183
154
|
VALUE lzws_ext_decompressor_close(VALUE self)
|
@@ -204,3 +175,15 @@ VALUE lzws_ext_decompressor_close(VALUE self)
|
|
204
175
|
|
205
176
|
return Qnil;
|
206
177
|
}
|
178
|
+
|
179
|
+
void lzws_ext_decompressor_exports(VALUE root_module)
|
180
|
+
{
|
181
|
+
VALUE stream = rb_define_module_under(root_module, "Stream");
|
182
|
+
|
183
|
+
VALUE decompressor = rb_define_class_under(stream, "NativeDecompressor", rb_cObject);
|
184
|
+
rb_define_alloc_func(decompressor, lzws_ext_allocate_decompressor);
|
185
|
+
rb_define_method(decompressor, "initialize", lzws_ext_initialize_decompressor, 1);
|
186
|
+
rb_define_method(decompressor, "read", lzws_ext_decompress, 1);
|
187
|
+
rb_define_method(decompressor, "read_result", lzws_ext_decompressor_read_result, 0);
|
188
|
+
rb_define_method(decompressor, "close", lzws_ext_decompressor_close, 0);
|
189
|
+
}
|