ruby-lzws 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,217 @@
1
+ // Ruby bindings for lzws library.
2
+ // Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ #include <lzws/buffer.h>
5
+ #include <lzws/compressor/common.h>
6
+ #include <lzws/compressor/header.h>
7
+ #include <lzws/compressor/main.h>
8
+ #include <lzws/compressor/state.h>
9
+
10
+ #include "ruby.h"
11
+
12
+ #include "lzws_ext/error.h"
13
+ #include "lzws_ext/macro.h"
14
+ #include "lzws_ext/option.h"
15
+ #include "lzws_ext/stream/compressor.h"
16
+
17
+ static void free_compressor(lzws_ext_compressor_t* compressor_ptr)
18
+ {
19
+ lzws_compressor_state_t* state_ptr = compressor_ptr->state_ptr;
20
+ if (state_ptr != NULL) {
21
+ lzws_compressor_free_state(state_ptr);
22
+ }
23
+
24
+ uint8_t* destination_buffer = compressor_ptr->destination_buffer;
25
+ if (destination_buffer != NULL) {
26
+ free(destination_buffer);
27
+ }
28
+
29
+ free(compressor_ptr);
30
+ }
31
+
32
+ VALUE lzws_ext_allocate_compressor(VALUE klass)
33
+ {
34
+ lzws_ext_compressor_t* compressor_ptr;
35
+
36
+ VALUE self = Data_Make_Struct(klass, lzws_ext_compressor_t, NULL, free_compressor, compressor_ptr);
37
+
38
+ compressor_ptr->state_ptr = NULL;
39
+ compressor_ptr->destination_buffer = NULL;
40
+ compressor_ptr->destination_buffer_length = 0;
41
+ compressor_ptr->remaining_destination_buffer = NULL;
42
+ compressor_ptr->remaining_destination_buffer_length = 0;
43
+
44
+ return self;
45
+ }
46
+
47
+ #define GET_COMPRESSOR(self) \
48
+ lzws_ext_compressor_t* compressor_ptr; \
49
+ Data_Get_Struct(self, lzws_ext_compressor_t, compressor_ptr);
50
+
51
+ VALUE lzws_ext_initialize_compressor(VALUE self, VALUE options)
52
+ {
53
+ GET_COMPRESSOR(self);
54
+ LZWS_EXT_GET_COMPRESSOR_OPTIONS(options);
55
+ LZWS_EXT_UNUSED_VARIABLE(without_magic_header);
56
+
57
+ lzws_compressor_state_t* compressor_state_ptr;
58
+
59
+ lzws_result_t result = lzws_compressor_get_initial_state(
60
+ &compressor_state_ptr,
61
+ max_code_bit_length, block_mode, msb, unaligned_bit_groups, quiet);
62
+
63
+ if (result == LZWS_COMPRESSOR_ALLOCATE_FAILED) {
64
+ lzws_ext_raise_error("AllocateError", "allocate error");
65
+ }
66
+ else if (result == LZWS_COMPRESSOR_INVALID_MAX_CODE_BIT_LENGTH) {
67
+ lzws_ext_raise_error("ValidateError", "validate error");
68
+ }
69
+ else if (result != 0) {
70
+ lzws_ext_raise_error("UnexpectedError", "unexpected error");
71
+ }
72
+
73
+ compressor_ptr->state_ptr = compressor_state_ptr;
74
+
75
+ // -----
76
+
77
+ uint8_t* destination_buffer;
78
+ size_t destination_buffer_length = buffer_length;
79
+
80
+ result = lzws_create_buffer_for_compressor(&destination_buffer, &destination_buffer_length, quiet);
81
+ if (result != 0) {
82
+ lzws_ext_raise_error("AllocateError", "allocate error");
83
+ }
84
+
85
+ compressor_ptr->destination_buffer = destination_buffer;
86
+ compressor_ptr->destination_buffer_length = destination_buffer_length;
87
+ compressor_ptr->remaining_destination_buffer = destination_buffer;
88
+ compressor_ptr->remaining_destination_buffer_length = destination_buffer_length;
89
+
90
+ return Qnil;
91
+ }
92
+
93
+ #define DO_NOT_USE_AFTER_CLOSE(compressor_ptr) \
94
+ if (compressor_ptr->state_ptr == NULL || compressor_ptr->destination_buffer == NULL) { \
95
+ lzws_ext_raise_error("UsedAfterCloseError", "compressor used after closed"); \
96
+ }
97
+
98
+ VALUE lzws_ext_compressor_write_magic_header(VALUE self)
99
+ {
100
+ GET_COMPRESSOR(self);
101
+ DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
102
+
103
+ lzws_result_t result = lzws_compressor_write_magic_header(
104
+ &compressor_ptr->remaining_destination_buffer,
105
+ &compressor_ptr->remaining_destination_buffer_length);
106
+
107
+ if (result == 0) {
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)
125
+ {
126
+ GET_COMPRESSOR(self);
127
+ DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
128
+ GET_STRING(source);
129
+
130
+ uint8_t* remaining_source_data = (uint8_t*)source_data;
131
+ size_t remaining_source_length = source_length;
132
+
133
+ lzws_result_t result = lzws_compress(
134
+ compressor_ptr->state_ptr,
135
+ &remaining_source_data,
136
+ &remaining_source_length,
137
+ &compressor_ptr->remaining_destination_buffer,
138
+ &compressor_ptr->remaining_destination_buffer_length);
139
+
140
+ VALUE bytes_written = INT2NUM(source_length - remaining_source_length);
141
+
142
+ if (result == LZWS_COMPRESSOR_NEEDS_MORE_SOURCE) {
143
+ return rb_ary_new_from_args(2, bytes_written, Qfalse);
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");
150
+ }
151
+ }
152
+
153
+ VALUE lzws_ext_flush_compressor(VALUE self)
154
+ {
155
+ GET_COMPRESSOR(self);
156
+ DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
157
+
158
+ lzws_result_t result = lzws_flush_compressor(
159
+ compressor_ptr->state_ptr,
160
+ &compressor_ptr->remaining_destination_buffer,
161
+ &compressor_ptr->remaining_destination_buffer_length);
162
+
163
+ if (result == 0) {
164
+ return Qfalse;
165
+ }
166
+ else if (result == LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION) {
167
+ return Qtrue;
168
+ }
169
+ else {
170
+ lzws_ext_raise_error("UnexpectedError", "unexpected error");
171
+ }
172
+ }
173
+
174
+ VALUE lzws_ext_compressor_read_result(VALUE self)
175
+ {
176
+ GET_COMPRESSOR(self);
177
+ DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
178
+
179
+ uint8_t* destination_buffer = compressor_ptr->destination_buffer;
180
+ size_t destination_buffer_length = compressor_ptr->destination_buffer_length;
181
+ size_t remaining_destination_buffer_length = compressor_ptr->remaining_destination_buffer_length;
182
+
183
+ const char* result_data = (const char*)destination_buffer;
184
+ size_t result_length = destination_buffer_length - remaining_destination_buffer_length;
185
+
186
+ VALUE result = rb_str_new(result_data, result_length);
187
+
188
+ compressor_ptr->remaining_destination_buffer = destination_buffer;
189
+ compressor_ptr->remaining_destination_buffer_length = destination_buffer_length;
190
+
191
+ return result;
192
+ }
193
+
194
+ VALUE lzws_ext_compressor_close(VALUE self)
195
+ {
196
+ GET_COMPRESSOR(self);
197
+ DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
198
+
199
+ lzws_compressor_state_t* state_ptr = compressor_ptr->state_ptr;
200
+ if (state_ptr != NULL) {
201
+ lzws_compressor_free_state(state_ptr);
202
+
203
+ compressor_ptr->state_ptr = NULL;
204
+ }
205
+
206
+ uint8_t* destination_buffer = compressor_ptr->destination_buffer;
207
+ if (destination_buffer != NULL) {
208
+ free(destination_buffer);
209
+
210
+ compressor_ptr->destination_buffer = NULL;
211
+ }
212
+
213
+ // It is possible to keep "destination_buffer_length", "remaining_destination_buffer"
214
+ // and "remaining_destination_buffer_length" as is.
215
+
216
+ return Qnil;
217
+ }
@@ -0,0 +1,27 @@
1
+ // Ruby bindings for lzws library.
2
+ // Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ #if !defined(LZWS_EXT_STREAM_COMPRESSOR_H)
5
+ #define LZWS_EXT_STREAM_COMPRESSOR_H
6
+
7
+ #include <lzws/compressor/state.h>
8
+
9
+ #include "ruby.h"
10
+
11
+ typedef struct {
12
+ lzws_compressor_state_t* state_ptr;
13
+ uint8_t* destination_buffer;
14
+ size_t destination_buffer_length;
15
+ uint8_t* remaining_destination_buffer;
16
+ size_t remaining_destination_buffer_length;
17
+ } lzws_ext_compressor_t;
18
+
19
+ VALUE lzws_ext_allocate_compressor(VALUE klass);
20
+ VALUE lzws_ext_initialize_compressor(VALUE self, VALUE options);
21
+ VALUE lzws_ext_compressor_write_magic_header(VALUE self);
22
+ VALUE lzws_ext_compress(VALUE self, VALUE source);
23
+ VALUE lzws_ext_flush_compressor(VALUE self);
24
+ VALUE lzws_ext_compressor_read_result(VALUE self);
25
+ VALUE lzws_ext_compressor_close(VALUE self);
26
+
27
+ #endif // LZWS_EXT_STREAM_COMPRESSOR_H
@@ -0,0 +1,206 @@
1
+ // Ruby bindings for lzws library.
2
+ // Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ #include <lzws/buffer.h>
5
+ #include <lzws/decompressor/common.h>
6
+ #include <lzws/decompressor/header.h>
7
+ #include <lzws/decompressor/main.h>
8
+ #include <lzws/decompressor/state.h>
9
+
10
+ #include "ruby.h"
11
+
12
+ #include "lzws_ext/error.h"
13
+ #include "lzws_ext/macro.h"
14
+ #include "lzws_ext/option.h"
15
+ #include "lzws_ext/stream/decompressor.h"
16
+
17
+ static void free_decompressor(lzws_ext_decompressor_t* decompressor_ptr)
18
+ {
19
+ lzws_decompressor_state_t* state_ptr = decompressor_ptr->state_ptr;
20
+ if (state_ptr != NULL) {
21
+ lzws_decompressor_free_state(state_ptr);
22
+ }
23
+
24
+ uint8_t* destination_buffer = decompressor_ptr->destination_buffer;
25
+ if (destination_buffer != NULL) {
26
+ free(destination_buffer);
27
+ }
28
+
29
+ free(decompressor_ptr);
30
+ }
31
+
32
+ VALUE lzws_ext_allocate_decompressor(VALUE klass)
33
+ {
34
+ lzws_ext_decompressor_t* decompressor_ptr;
35
+
36
+ VALUE self = Data_Make_Struct(klass, lzws_ext_decompressor_t, NULL, free_decompressor, decompressor_ptr);
37
+
38
+ decompressor_ptr->state_ptr = NULL;
39
+ decompressor_ptr->destination_buffer = NULL;
40
+ decompressor_ptr->destination_buffer_length = 0;
41
+ decompressor_ptr->remaining_destination_buffer = NULL;
42
+ decompressor_ptr->remaining_destination_buffer_length = 0;
43
+
44
+ return self;
45
+ }
46
+
47
+ #define GET_DECOMPRESSOR(self) \
48
+ lzws_ext_decompressor_t* decompressor_ptr; \
49
+ Data_Get_Struct(self, lzws_ext_decompressor_t, decompressor_ptr);
50
+
51
+ VALUE lzws_ext_initialize_decompressor(VALUE self, VALUE options)
52
+ {
53
+ GET_DECOMPRESSOR(self);
54
+ LZWS_EXT_GET_DECOMPRESSOR_OPTIONS(options);
55
+ LZWS_EXT_UNUSED_VARIABLE(without_magic_header);
56
+
57
+ lzws_decompressor_state_t* decompressor_state_ptr;
58
+
59
+ lzws_result_t result = lzws_decompressor_get_initial_state(
60
+ &decompressor_state_ptr,
61
+ msb, unaligned_bit_groups, quiet);
62
+
63
+ if (result == LZWS_DECOMPRESSOR_ALLOCATE_FAILED) {
64
+ lzws_ext_raise_error("AllocateError", "allocate error");
65
+ }
66
+ else if (result != 0) {
67
+ lzws_ext_raise_error("UnexpectedError", "unexpected error");
68
+ }
69
+
70
+ decompressor_ptr->state_ptr = decompressor_state_ptr;
71
+
72
+ // -----
73
+
74
+ uint8_t* destination_buffer;
75
+ size_t destination_buffer_length = buffer_length;
76
+
77
+ result = lzws_create_buffer_for_decompressor(&destination_buffer, &destination_buffer_length, quiet);
78
+ if (result != 0) {
79
+ lzws_ext_raise_error("AllocateError", "allocate error");
80
+ }
81
+
82
+ decompressor_ptr->destination_buffer = destination_buffer;
83
+ decompressor_ptr->destination_buffer_length = destination_buffer_length;
84
+ decompressor_ptr->remaining_destination_buffer = destination_buffer;
85
+ decompressor_ptr->remaining_destination_buffer_length = destination_buffer_length;
86
+
87
+ return Qnil;
88
+ }
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
+ #define DO_NOT_USE_AFTER_CLOSE(decompressor_ptr) \
97
+ if (decompressor_ptr->state_ptr == NULL || decompressor_ptr->destination_buffer == NULL) { \
98
+ lzws_ext_raise_error("UsedAfterCloseError", "decompressor used after close"); \
99
+ }
100
+
101
+ VALUE lzws_ext_decompressor_read_magic_header(VALUE self, VALUE source)
102
+ {
103
+ GET_DECOMPRESSOR(self);
104
+ DO_NOT_USE_AFTER_CLOSE(decompressor_ptr);
105
+ GET_STRING(source);
106
+
107
+ uint8_t* remaining_source_data = (uint8_t*)source_data;
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);
114
+
115
+ VALUE bytes_read = INT2NUM(source_length - remaining_source_length);
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)
129
+ {
130
+ GET_DECOMPRESSOR(self);
131
+ DO_NOT_USE_AFTER_CLOSE(decompressor_ptr);
132
+ GET_STRING(source);
133
+
134
+ uint8_t* remaining_source_data = (uint8_t*)source_data;
135
+ size_t remaining_source_length = source_length;
136
+
137
+ lzws_result_t result = lzws_decompress(
138
+ decompressor_ptr->state_ptr,
139
+ &remaining_source_data,
140
+ &remaining_source_length,
141
+ &decompressor_ptr->remaining_destination_buffer,
142
+ &decompressor_ptr->remaining_destination_buffer_length);
143
+
144
+ VALUE bytes_read = INT2NUM(source_length - remaining_source_length);
145
+
146
+ if (result == LZWS_DECOMPRESSOR_NEEDS_MORE_SOURCE) {
147
+ return rb_ary_new_from_args(2, bytes_read, Qfalse);
148
+ }
149
+ else if (result == LZWS_DECOMPRESSOR_NEEDS_MORE_DESTINATION) {
150
+ return rb_ary_new_from_args(2, bytes_read, Qtrue);
151
+ }
152
+ else if (result == LZWS_DECOMPRESSOR_INVALID_MAX_CODE_BIT_LENGTH) {
153
+ lzws_ext_raise_error("ValidateError", "validate error");
154
+ }
155
+ else if (result == LZWS_DECOMPRESSOR_CORRUPTED_SOURCE) {
156
+ lzws_ext_raise_error("DecompressorCorruptedSourceError", "decompressor received corrupted source");
157
+ }
158
+ else {
159
+ lzws_ext_raise_error("UnexpectedError", "unexpected error");
160
+ }
161
+ }
162
+
163
+ VALUE lzws_ext_decompressor_read_result(VALUE self)
164
+ {
165
+ GET_DECOMPRESSOR(self);
166
+ DO_NOT_USE_AFTER_CLOSE(decompressor_ptr);
167
+
168
+ uint8_t* destination_buffer = decompressor_ptr->destination_buffer;
169
+ size_t destination_buffer_length = decompressor_ptr->destination_buffer_length;
170
+ size_t remaining_destination_buffer_length = decompressor_ptr->remaining_destination_buffer_length;
171
+
172
+ const char* result_data = (const char*)destination_buffer;
173
+ size_t result_length = destination_buffer_length - remaining_destination_buffer_length;
174
+
175
+ VALUE result = rb_str_new(result_data, result_length);
176
+
177
+ decompressor_ptr->remaining_destination_buffer = destination_buffer;
178
+ decompressor_ptr->remaining_destination_buffer_length = destination_buffer_length;
179
+
180
+ return result;
181
+ }
182
+
183
+ VALUE lzws_ext_decompressor_close(VALUE self)
184
+ {
185
+ GET_DECOMPRESSOR(self);
186
+ DO_NOT_USE_AFTER_CLOSE(decompressor_ptr);
187
+
188
+ lzws_decompressor_state_t* state_ptr = decompressor_ptr->state_ptr;
189
+ if (state_ptr != NULL) {
190
+ lzws_decompressor_free_state(state_ptr);
191
+
192
+ decompressor_ptr->state_ptr = NULL;
193
+ }
194
+
195
+ uint8_t* destination_buffer = decompressor_ptr->destination_buffer;
196
+ if (destination_buffer != NULL) {
197
+ free(destination_buffer);
198
+
199
+ decompressor_ptr->destination_buffer = NULL;
200
+ }
201
+
202
+ // It is possible to keep "destination_buffer_length", "remaining_destination_buffer"
203
+ // and "remaining_destination_buffer_length" as is.
204
+
205
+ return Qnil;
206
+ }
@@ -0,0 +1,26 @@
1
+ // Ruby bindings for lzws library.
2
+ // Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ #if !defined(LZWS_EXT_STREAM_DECOMPRESSOR_H)
5
+ #define LZWS_EXT_STREAM_DECOMPRESSOR_H
6
+
7
+ #include <lzws/decompressor/state.h>
8
+
9
+ #include "ruby.h"
10
+
11
+ typedef struct {
12
+ lzws_decompressor_state_t* state_ptr;
13
+ uint8_t* destination_buffer;
14
+ size_t destination_buffer_length;
15
+ uint8_t* remaining_destination_buffer;
16
+ size_t remaining_destination_buffer_length;
17
+ } lzws_ext_decompressor_t;
18
+
19
+ VALUE lzws_ext_allocate_decompressor(VALUE klass);
20
+ VALUE lzws_ext_initialize_decompressor(VALUE self, VALUE options);
21
+ VALUE lzws_ext_decompressor_read_magic_header(VALUE self, VALUE source);
22
+ VALUE lzws_ext_decompress(VALUE self, VALUE source);
23
+ VALUE lzws_ext_decompressor_read_result(VALUE self);
24
+ VALUE lzws_ext_decompressor_close(VALUE self);
25
+
26
+ #endif // LZWS_EXT_STREAM_DECOMPRESSOR_H
@@ -0,0 +1,78 @@
1
+ // Ruby bindings for lzws library.
2
+ // Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ #include <lzws/string.h>
5
+
6
+ #include "ruby.h"
7
+
8
+ #include "lzws_ext/error.h"
9
+ #include "lzws_ext/macro.h"
10
+ #include "lzws_ext/option.h"
11
+ #include "lzws_ext/string.h"
12
+
13
+ #define GET_STRING(source) \
14
+ Check_Type(source, T_STRING); \
15
+ \
16
+ const char* source_data = RSTRING_PTR(source); \
17
+ size_t source_length = RSTRING_LEN(source);
18
+
19
+ VALUE lzws_ext_compress_string(VALUE LZWS_EXT_UNUSED(self), VALUE source, VALUE options)
20
+ {
21
+ GET_STRING(source);
22
+ LZWS_EXT_GET_COMPRESSOR_OPTIONS(options);
23
+
24
+ char* destination;
25
+ size_t destination_length;
26
+
27
+ lzws_result_t result = lzws_compress_string(
28
+ (uint8_t*)source_data, source_length,
29
+ (uint8_t**)&destination, &destination_length, buffer_length,
30
+ without_magic_header, max_code_bit_length, block_mode, msb, unaligned_bit_groups, quiet);
31
+
32
+ if (result == LZWS_STRING_ALLOCATE_FAILED) {
33
+ lzws_ext_raise_error("AllocateError", "allocate error");
34
+ }
35
+ else if (result == LZWS_STRING_VALIDATE_FAILED) {
36
+ lzws_ext_raise_error("ValidateError", "validate error");
37
+ }
38
+ else if (result != 0) {
39
+ lzws_ext_raise_error("UnexpectedError", "unexpected error");
40
+ }
41
+
42
+ // Ruby copies string on initialization.
43
+ VALUE result_string = rb_str_new(destination, destination_length);
44
+ free(destination);
45
+ return result_string;
46
+ }
47
+
48
+ VALUE lzws_ext_decompress_string(VALUE LZWS_EXT_UNUSED(self), VALUE source, VALUE options)
49
+ {
50
+ GET_STRING(source);
51
+ LZWS_EXT_GET_DECOMPRESSOR_OPTIONS(options);
52
+
53
+ char* destination;
54
+ size_t destination_length;
55
+
56
+ lzws_result_t result = lzws_decompress_string(
57
+ (uint8_t*)source_data, source_length,
58
+ (uint8_t**)&destination, &destination_length, buffer_length,
59
+ without_magic_header, msb, unaligned_bit_groups, quiet);
60
+
61
+ if (result == LZWS_STRING_ALLOCATE_FAILED) {
62
+ lzws_ext_raise_error("AllocateError", "allocate error");
63
+ }
64
+ else if (result == LZWS_STRING_VALIDATE_FAILED) {
65
+ lzws_ext_raise_error("ValidateError", "validate error");
66
+ }
67
+ else if (result == LZWS_STRING_DECOMPRESSOR_CORRUPTED_SOURCE) {
68
+ lzws_ext_raise_error("DecompressorCorruptedSourceError", "decompressor received corrupted source");
69
+ }
70
+ else if (result != 0) {
71
+ lzws_ext_raise_error("UnexpectedError", "unexpected error");
72
+ }
73
+
74
+ // Ruby copies string on initialization.
75
+ VALUE result_string = rb_str_new(destination, destination_length);
76
+ free(destination);
77
+ return result_string;
78
+ }
@@ -0,0 +1,12 @@
1
+ // Ruby bindings for lzws library.
2
+ // Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ #if !defined(LZWS_EXT_STRING_H)
5
+ #define LZWS_EXT_STRING_H
6
+
7
+ #include "ruby.h"
8
+
9
+ VALUE lzws_ext_compress_string(VALUE self, VALUE source, VALUE options);
10
+ VALUE lzws_ext_decompress_string(VALUE self, VALUE source, VALUE options);
11
+
12
+ #endif // LZWS_EXT_STRING_H
data/lib/lzws/error.rb ADDED
@@ -0,0 +1,20 @@
1
+ # Ruby bindings for lzws library.
2
+ # Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ module LZWS
5
+ class BaseError < ::StandardError; end
6
+
7
+ class ValidateError < BaseError; end
8
+ class AllocateError < BaseError; end
9
+ class UnexpectedError < BaseError; end
10
+
11
+ class NotEnoughDestinationError < BaseError; end
12
+ class UsedAfterCloseError < BaseError; end
13
+
14
+ class DecompressorCorruptedSourceError < BaseError; end
15
+
16
+ class OpenFileError < BaseError; end
17
+ class AccessIOError < BaseError; end
18
+ class ReadIOError < BaseError; end
19
+ class WriteIOError < BaseError; end
20
+ end
data/lib/lzws/file.rb ADDED
@@ -0,0 +1,56 @@
1
+ # Ruby bindings for lzws library.
2
+ # Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ require "lzws_ext"
5
+
6
+ require_relative "error"
7
+ require_relative "option"
8
+ require_relative "validation"
9
+
10
+ module LZWS
11
+ module File
12
+ def self.compress(source, destination, options = {})
13
+ Validation.validate_string source
14
+ Validation.validate_string destination
15
+
16
+ options = Option.get_compressor_options options
17
+
18
+ open_files(source, destination) do |source_io, destination_io|
19
+ LZWS._native_compress_io source_io, destination_io, options
20
+ end
21
+ end
22
+
23
+ def self.decompress(source, destination, options = {})
24
+ Validation.validate_string source
25
+ Validation.validate_string destination
26
+
27
+ options = Option.get_decompressor_options options
28
+
29
+ open_files(source, destination) do |source_io, destination_io|
30
+ LZWS._native_decompress_io source_io, destination_io, options
31
+ end
32
+ end
33
+
34
+ private_class_method def self.open_files(source, destination, &_block)
35
+ open_file(source, "rb") do |source_io|
36
+ open_file(destination, "wb") do |destination_io|
37
+ yield source_io, destination_io
38
+ end
39
+ end
40
+ 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
+ end
56
+ end