ruby-bzs 1.0.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 +7 -0
- data/AUTHORS +1 -0
- data/LICENSE +21 -0
- data/README.md +368 -0
- data/ext/bzs_ext/buffer.c +40 -0
- data/ext/bzs_ext/buffer.h +29 -0
- data/ext/bzs_ext/common.h +16 -0
- data/ext/bzs_ext/error.c +62 -0
- data/ext/bzs_ext/error.h +34 -0
- data/ext/bzs_ext/gvl.h +24 -0
- data/ext/bzs_ext/io.c +592 -0
- data/ext/bzs_ext/io.h +14 -0
- data/ext/bzs_ext/macro.h +13 -0
- data/ext/bzs_ext/main.c +27 -0
- data/ext/bzs_ext/option.c +98 -0
- data/ext/bzs_ext/option.h +62 -0
- data/ext/bzs_ext/stream/compressor.c +285 -0
- data/ext/bzs_ext/stream/compressor.h +33 -0
- data/ext/bzs_ext/stream/decompressor.c +221 -0
- data/ext/bzs_ext/stream/decompressor.h +31 -0
- data/ext/bzs_ext/string.c +340 -0
- data/ext/bzs_ext/string.h +14 -0
- data/ext/bzs_ext/utils.c +15 -0
- data/ext/bzs_ext/utils.h +13 -0
- data/ext/extconf.rb +94 -0
- data/lib/bzs/error.rb +26 -0
- data/lib/bzs/file.rb +25 -0
- data/lib/bzs/option.rb +101 -0
- data/lib/bzs/stream/raw/compressor.rb +22 -0
- data/lib/bzs/stream/raw/decompressor.rb +22 -0
- data/lib/bzs/stream/reader.rb +16 -0
- data/lib/bzs/stream/writer.rb +16 -0
- data/lib/bzs/string.rb +25 -0
- data/lib/bzs/validation.rb +14 -0
- data/lib/bzs/version.rb +6 -0
- data/lib/bzs.rb +8 -0
- metadata +289 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
// Ruby bindings for bzip2 library.
|
2
|
+
// Copyright (c) 2022 AUTHORS, MIT License.
|
3
|
+
|
4
|
+
#if !defined(BZS_EXT_STREAM_DECOMPRESSOR_H)
|
5
|
+
#define BZS_EXT_STREAM_DECOMPRESSOR_H
|
6
|
+
|
7
|
+
#include <bzlib.h>
|
8
|
+
#include <stdbool.h>
|
9
|
+
|
10
|
+
#include "bzs_ext/common.h"
|
11
|
+
#include "ruby.h"
|
12
|
+
|
13
|
+
typedef struct
|
14
|
+
{
|
15
|
+
bz_stream* stream_ptr;
|
16
|
+
bzs_ext_byte_t* destination_buffer;
|
17
|
+
size_t destination_buffer_length;
|
18
|
+
bzs_ext_byte_t* remaining_destination_buffer;
|
19
|
+
size_t remaining_destination_buffer_length;
|
20
|
+
bool gvl;
|
21
|
+
} bzs_ext_decompressor_t;
|
22
|
+
|
23
|
+
VALUE bzs_ext_allocate_decompressor(VALUE klass);
|
24
|
+
VALUE bzs_ext_initialize_decompressor(VALUE self, VALUE options);
|
25
|
+
VALUE bzs_ext_decompress(VALUE self, VALUE source);
|
26
|
+
VALUE bzs_ext_decompressor_read_result(VALUE self);
|
27
|
+
VALUE bzs_ext_decompressor_close(VALUE self);
|
28
|
+
|
29
|
+
void bzs_ext_decompressor_exports(VALUE root_module);
|
30
|
+
|
31
|
+
#endif // BZS_EXT_STREAM_DECOMPRESSOR_H
|
@@ -0,0 +1,340 @@
|
|
1
|
+
// Ruby bindings for bzip2 library.
|
2
|
+
// Copyright (c) 2022 AUTHORS, MIT License.
|
3
|
+
|
4
|
+
#include "bzs_ext/string.h"
|
5
|
+
|
6
|
+
#include <bzlib.h>
|
7
|
+
|
8
|
+
#include "bzs_ext/buffer.h"
|
9
|
+
#include "bzs_ext/common.h"
|
10
|
+
#include "bzs_ext/error.h"
|
11
|
+
#include "bzs_ext/gvl.h"
|
12
|
+
#include "bzs_ext/macro.h"
|
13
|
+
#include "bzs_ext/option.h"
|
14
|
+
#include "bzs_ext/utils.h"
|
15
|
+
|
16
|
+
// -- buffer --
|
17
|
+
|
18
|
+
static inline bzs_ext_result_t increase_destination_buffer(
|
19
|
+
VALUE destination_value,
|
20
|
+
size_t destination_length,
|
21
|
+
size_t* remaining_destination_buffer_length_ptr,
|
22
|
+
size_t destination_buffer_length)
|
23
|
+
{
|
24
|
+
if (*remaining_destination_buffer_length_ptr == destination_buffer_length) {
|
25
|
+
// We want to write more data at once, than buffer has.
|
26
|
+
return BZS_EXT_ERROR_NOT_ENOUGH_DESTINATION_BUFFER;
|
27
|
+
}
|
28
|
+
|
29
|
+
int exception;
|
30
|
+
|
31
|
+
BZS_EXT_RESIZE_STRING_BUFFER(destination_value, destination_length + destination_buffer_length, exception);
|
32
|
+
if (exception != 0) {
|
33
|
+
return BZS_EXT_ERROR_ALLOCATE_FAILED;
|
34
|
+
}
|
35
|
+
|
36
|
+
*remaining_destination_buffer_length_ptr = destination_buffer_length;
|
37
|
+
|
38
|
+
return 0;
|
39
|
+
}
|
40
|
+
|
41
|
+
// -- compress --
|
42
|
+
|
43
|
+
typedef struct
|
44
|
+
{
|
45
|
+
bz_stream* stream_ptr;
|
46
|
+
int stream_action;
|
47
|
+
bzs_ext_byte_t** remaining_source_ptr;
|
48
|
+
size_t* remaining_source_length_ptr;
|
49
|
+
bzs_ext_byte_t* remaining_destination_buffer;
|
50
|
+
size_t* remaining_destination_buffer_length_ptr;
|
51
|
+
bzs_result_t result;
|
52
|
+
} compress_args_t;
|
53
|
+
|
54
|
+
static inline void* compress_wrapper(void* data)
|
55
|
+
{
|
56
|
+
compress_args_t* args = data;
|
57
|
+
|
58
|
+
args->stream_ptr->next_in = (char*) *args->remaining_source_ptr;
|
59
|
+
args->stream_ptr->avail_in = bzs_consume_size(*args->remaining_source_length_ptr);
|
60
|
+
args->stream_ptr->next_out = (char*) args->remaining_destination_buffer;
|
61
|
+
args->stream_ptr->avail_out = bzs_consume_size(*args->remaining_destination_buffer_length_ptr);
|
62
|
+
|
63
|
+
args->result = BZ2_bzCompress(args->stream_ptr, args->stream_action);
|
64
|
+
|
65
|
+
*args->remaining_source_ptr = (bzs_ext_byte_t*) args->stream_ptr->next_in;
|
66
|
+
*args->remaining_source_length_ptr = args->stream_ptr->avail_in;
|
67
|
+
*args->remaining_destination_buffer_length_ptr = args->stream_ptr->avail_out;
|
68
|
+
|
69
|
+
return NULL;
|
70
|
+
}
|
71
|
+
|
72
|
+
#define BUFFERED_COMPRESS(gvl, args, RUN_OK) \
|
73
|
+
while (true) { \
|
74
|
+
bzs_ext_byte_t* remaining_destination_buffer = \
|
75
|
+
(bzs_ext_byte_t*) RSTRING_PTR(destination_value) + destination_length; \
|
76
|
+
size_t prev_remaining_destination_buffer_length = remaining_destination_buffer_length; \
|
77
|
+
\
|
78
|
+
args.remaining_destination_buffer = remaining_destination_buffer; \
|
79
|
+
args.remaining_destination_buffer_length_ptr = &remaining_destination_buffer_length; \
|
80
|
+
\
|
81
|
+
BZS_EXT_GVL_WRAP(gvl, compress_wrapper, &args); \
|
82
|
+
if (args.result != RUN_OK && args.result != BZ_PARAM_ERROR && args.result != BZ_STREAM_END) { \
|
83
|
+
return bzs_ext_get_error(args.result); \
|
84
|
+
} \
|
85
|
+
\
|
86
|
+
destination_length += prev_remaining_destination_buffer_length - remaining_destination_buffer_length; \
|
87
|
+
\
|
88
|
+
if (args.result == BZ_STREAM_END) { \
|
89
|
+
break; \
|
90
|
+
} \
|
91
|
+
\
|
92
|
+
if (remaining_source_length != 0 || remaining_destination_buffer_length == 0) { \
|
93
|
+
ext_result = increase_destination_buffer( \
|
94
|
+
destination_value, destination_length, &remaining_destination_buffer_length, destination_buffer_length); \
|
95
|
+
\
|
96
|
+
if (ext_result != 0) { \
|
97
|
+
return ext_result; \
|
98
|
+
} \
|
99
|
+
\
|
100
|
+
continue; \
|
101
|
+
} \
|
102
|
+
\
|
103
|
+
break; \
|
104
|
+
}
|
105
|
+
|
106
|
+
static inline bzs_ext_result_t compress(
|
107
|
+
bz_stream* stream_ptr,
|
108
|
+
const char* source,
|
109
|
+
size_t source_length,
|
110
|
+
VALUE destination_value,
|
111
|
+
size_t destination_buffer_length,
|
112
|
+
bool gvl)
|
113
|
+
{
|
114
|
+
bzs_ext_result_t ext_result;
|
115
|
+
bzs_ext_byte_t* remaining_source = (bzs_ext_byte_t*) source;
|
116
|
+
size_t remaining_source_length = source_length;
|
117
|
+
size_t destination_length = 0;
|
118
|
+
size_t remaining_destination_buffer_length = destination_buffer_length;
|
119
|
+
|
120
|
+
compress_args_t run_args = {
|
121
|
+
.stream_ptr = stream_ptr,
|
122
|
+
.stream_action = BZ_RUN,
|
123
|
+
.remaining_source_ptr = &remaining_source,
|
124
|
+
.remaining_source_length_ptr = &remaining_source_length};
|
125
|
+
BUFFERED_COMPRESS(gvl, run_args, BZ_RUN_OK);
|
126
|
+
|
127
|
+
compress_args_t finish_args = {
|
128
|
+
.stream_ptr = stream_ptr,
|
129
|
+
.stream_action = BZ_FINISH,
|
130
|
+
.remaining_source_ptr = &remaining_source,
|
131
|
+
.remaining_source_length_ptr = &remaining_source_length};
|
132
|
+
BUFFERED_COMPRESS(gvl, finish_args, BZ_FINISH_OK);
|
133
|
+
|
134
|
+
int exception;
|
135
|
+
|
136
|
+
BZS_EXT_RESIZE_STRING_BUFFER(destination_value, destination_length, exception);
|
137
|
+
if (exception != 0) {
|
138
|
+
return BZS_EXT_ERROR_ALLOCATE_FAILED;
|
139
|
+
}
|
140
|
+
|
141
|
+
return 0;
|
142
|
+
}
|
143
|
+
|
144
|
+
VALUE bzs_ext_compress_string(VALUE BZS_EXT_UNUSED(self), VALUE source_value, VALUE options)
|
145
|
+
{
|
146
|
+
Check_Type(source_value, T_STRING);
|
147
|
+
Check_Type(options, T_HASH);
|
148
|
+
BZS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
|
149
|
+
BZS_EXT_GET_BOOL_OPTION(options, gvl);
|
150
|
+
BZS_EXT_RESOLVE_COMPRESSOR_OPTIONS(options);
|
151
|
+
|
152
|
+
bz_stream stream = {
|
153
|
+
.bzalloc = NULL,
|
154
|
+
.bzfree = NULL,
|
155
|
+
.opaque = NULL,
|
156
|
+
};
|
157
|
+
|
158
|
+
bzs_result_t result = BZ2_bzCompressInit(&stream, block_size, verbosity, work_factor);
|
159
|
+
if (result != BZ_OK) {
|
160
|
+
bzs_ext_raise_error(bzs_ext_get_error(result));
|
161
|
+
}
|
162
|
+
|
163
|
+
if (destination_buffer_length == 0) {
|
164
|
+
destination_buffer_length = BZS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_COMPRESSOR;
|
165
|
+
}
|
166
|
+
|
167
|
+
int exception;
|
168
|
+
|
169
|
+
BZS_EXT_CREATE_STRING_BUFFER(destination_value, destination_buffer_length, exception);
|
170
|
+
if (exception != 0) {
|
171
|
+
BZ2_bzCompressEnd(&stream);
|
172
|
+
bzs_ext_raise_error(BZS_EXT_ERROR_ALLOCATE_FAILED);
|
173
|
+
}
|
174
|
+
|
175
|
+
const char* source = RSTRING_PTR(source_value);
|
176
|
+
size_t source_length = RSTRING_LEN(source_value);
|
177
|
+
|
178
|
+
bzs_ext_result_t ext_result =
|
179
|
+
compress(&stream, source, source_length, destination_value, destination_buffer_length, gvl);
|
180
|
+
|
181
|
+
result = BZ2_bzCompressEnd(&stream);
|
182
|
+
if (result != BZ_OK) {
|
183
|
+
ext_result = bzs_ext_get_error(result);
|
184
|
+
}
|
185
|
+
|
186
|
+
if (ext_result != 0) {
|
187
|
+
bzs_ext_raise_error(ext_result);
|
188
|
+
}
|
189
|
+
|
190
|
+
return destination_value;
|
191
|
+
}
|
192
|
+
|
193
|
+
// -- decompress --
|
194
|
+
|
195
|
+
typedef struct
|
196
|
+
{
|
197
|
+
bz_stream* stream_ptr;
|
198
|
+
bzs_ext_byte_t** remaining_source_ptr;
|
199
|
+
size_t* remaining_source_length_ptr;
|
200
|
+
bzs_ext_byte_t* remaining_destination_buffer;
|
201
|
+
size_t* remaining_destination_buffer_length_ptr;
|
202
|
+
bzs_result_t result;
|
203
|
+
} decompress_args_t;
|
204
|
+
|
205
|
+
static inline void* decompress_wrapper(void* data)
|
206
|
+
{
|
207
|
+
decompress_args_t* args = data;
|
208
|
+
|
209
|
+
args->stream_ptr->next_in = (char*) *args->remaining_source_ptr;
|
210
|
+
args->stream_ptr->avail_in = bzs_consume_size(*args->remaining_source_length_ptr);
|
211
|
+
args->stream_ptr->next_out = (char*) args->remaining_destination_buffer;
|
212
|
+
args->stream_ptr->avail_out = bzs_consume_size(*args->remaining_destination_buffer_length_ptr);
|
213
|
+
|
214
|
+
args->result = BZ2_bzDecompress(args->stream_ptr);
|
215
|
+
|
216
|
+
*args->remaining_source_ptr = (bzs_ext_byte_t*) args->stream_ptr->next_in;
|
217
|
+
*args->remaining_source_length_ptr = args->stream_ptr->avail_in;
|
218
|
+
*args->remaining_destination_buffer_length_ptr = args->stream_ptr->avail_out;
|
219
|
+
|
220
|
+
return NULL;
|
221
|
+
}
|
222
|
+
|
223
|
+
static inline bzs_ext_result_t decompress(
|
224
|
+
bz_stream* stream_ptr,
|
225
|
+
const char* source,
|
226
|
+
size_t source_length,
|
227
|
+
VALUE destination_value,
|
228
|
+
size_t destination_buffer_length,
|
229
|
+
bool gvl)
|
230
|
+
{
|
231
|
+
bzs_ext_result_t ext_result;
|
232
|
+
bzs_ext_byte_t* remaining_source = (bzs_ext_byte_t*) source;
|
233
|
+
size_t remaining_source_length = source_length;
|
234
|
+
size_t destination_length = 0;
|
235
|
+
size_t remaining_destination_buffer_length = destination_buffer_length;
|
236
|
+
|
237
|
+
decompress_args_t args = {
|
238
|
+
.stream_ptr = stream_ptr,
|
239
|
+
.remaining_source_ptr = &remaining_source,
|
240
|
+
.remaining_source_length_ptr = &remaining_source_length};
|
241
|
+
|
242
|
+
while (true) {
|
243
|
+
bzs_ext_byte_t* remaining_destination_buffer =
|
244
|
+
(bzs_ext_byte_t*) RSTRING_PTR(destination_value) + destination_length;
|
245
|
+
size_t prev_remaining_destination_buffer_length = remaining_destination_buffer_length;
|
246
|
+
|
247
|
+
args.remaining_destination_buffer = remaining_destination_buffer;
|
248
|
+
args.remaining_destination_buffer_length_ptr = &remaining_destination_buffer_length;
|
249
|
+
|
250
|
+
BZS_EXT_GVL_WRAP(gvl, decompress_wrapper, &args);
|
251
|
+
if (args.result != BZ_OK && args.result != BZ_PARAM_ERROR && args.result != BZ_STREAM_END) {
|
252
|
+
return bzs_ext_get_error(args.result);
|
253
|
+
}
|
254
|
+
|
255
|
+
destination_length += prev_remaining_destination_buffer_length - remaining_destination_buffer_length;
|
256
|
+
|
257
|
+
if (args.result == BZ_STREAM_END) {
|
258
|
+
break;
|
259
|
+
}
|
260
|
+
|
261
|
+
if (remaining_source_length != 0 || remaining_destination_buffer_length == 0) {
|
262
|
+
ext_result = increase_destination_buffer(
|
263
|
+
destination_value, destination_length, &remaining_destination_buffer_length, destination_buffer_length);
|
264
|
+
|
265
|
+
if (ext_result != 0) {
|
266
|
+
return ext_result;
|
267
|
+
}
|
268
|
+
|
269
|
+
continue;
|
270
|
+
}
|
271
|
+
|
272
|
+
break;
|
273
|
+
}
|
274
|
+
|
275
|
+
int exception;
|
276
|
+
|
277
|
+
BZS_EXT_RESIZE_STRING_BUFFER(destination_value, destination_length, exception);
|
278
|
+
if (exception != 0) {
|
279
|
+
return BZS_EXT_ERROR_ALLOCATE_FAILED;
|
280
|
+
}
|
281
|
+
|
282
|
+
return 0;
|
283
|
+
}
|
284
|
+
|
285
|
+
VALUE bzs_ext_decompress_string(VALUE BZS_EXT_UNUSED(self), VALUE source_value, VALUE options)
|
286
|
+
{
|
287
|
+
Check_Type(source_value, T_STRING);
|
288
|
+
Check_Type(options, T_HASH);
|
289
|
+
BZS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
|
290
|
+
BZS_EXT_GET_BOOL_OPTION(options, gvl);
|
291
|
+
BZS_EXT_RESOLVE_DECOMPRESSOR_OPTIONS(options);
|
292
|
+
|
293
|
+
bz_stream stream = {
|
294
|
+
.bzalloc = NULL,
|
295
|
+
.bzfree = NULL,
|
296
|
+
.opaque = NULL,
|
297
|
+
};
|
298
|
+
|
299
|
+
bzs_result_t result = BZ2_bzDecompressInit(&stream, verbosity, small);
|
300
|
+
if (result != BZ_OK) {
|
301
|
+
bzs_ext_raise_error(bzs_ext_get_error(result));
|
302
|
+
}
|
303
|
+
|
304
|
+
if (destination_buffer_length == 0) {
|
305
|
+
destination_buffer_length = BZS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_DECOMPRESSOR;
|
306
|
+
}
|
307
|
+
|
308
|
+
int exception;
|
309
|
+
|
310
|
+
BZS_EXT_CREATE_STRING_BUFFER(destination_value, destination_buffer_length, exception);
|
311
|
+
if (exception != 0) {
|
312
|
+
BZ2_bzDecompressEnd(&stream);
|
313
|
+
bzs_ext_raise_error(BZS_EXT_ERROR_ALLOCATE_FAILED);
|
314
|
+
}
|
315
|
+
|
316
|
+
const char* source = RSTRING_PTR(source_value);
|
317
|
+
size_t source_length = RSTRING_LEN(source_value);
|
318
|
+
|
319
|
+
bzs_ext_result_t ext_result =
|
320
|
+
decompress(&stream, source, source_length, destination_value, destination_buffer_length, gvl);
|
321
|
+
|
322
|
+
result = BZ2_bzDecompressEnd(&stream);
|
323
|
+
if (result != BZ_OK) {
|
324
|
+
ext_result = bzs_ext_get_error(result);
|
325
|
+
}
|
326
|
+
|
327
|
+
if (ext_result != 0) {
|
328
|
+
bzs_ext_raise_error(ext_result);
|
329
|
+
}
|
330
|
+
|
331
|
+
return destination_value;
|
332
|
+
}
|
333
|
+
|
334
|
+
// -- exports --
|
335
|
+
|
336
|
+
void bzs_ext_string_exports(VALUE root_module)
|
337
|
+
{
|
338
|
+
rb_define_module_function(root_module, "_native_compress_string", RUBY_METHOD_FUNC(bzs_ext_compress_string), 2);
|
339
|
+
rb_define_module_function(root_module, "_native_decompress_string", RUBY_METHOD_FUNC(bzs_ext_decompress_string), 2);
|
340
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
// Ruby bindings for bzip2 library.
|
2
|
+
// Copyright (c) 2022 AUTHORS, MIT License.
|
3
|
+
|
4
|
+
#if !defined(BZS_EXT_STRING_H)
|
5
|
+
#define BZS_EXT_STRING_H
|
6
|
+
|
7
|
+
#include "ruby.h"
|
8
|
+
|
9
|
+
VALUE bzs_ext_compress_string(VALUE self, VALUE source, VALUE options);
|
10
|
+
VALUE bzs_ext_decompress_string(VALUE self, VALUE source, VALUE options);
|
11
|
+
|
12
|
+
void bzs_ext_string_exports(VALUE root_module);
|
13
|
+
|
14
|
+
#endif // BZS_EXT_STRING_H
|
data/ext/bzs_ext/utils.c
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
// Ruby bindings for bzip2 library.
|
2
|
+
// Copyright (c) 2022 AUTHORS, MIT License.
|
3
|
+
|
4
|
+
#include "utils.h"
|
5
|
+
|
6
|
+
#include <limits.h>
|
7
|
+
|
8
|
+
unsigned int bzs_consume_size(size_t size)
|
9
|
+
{
|
10
|
+
if (size > UINT_MAX) {
|
11
|
+
return UINT_MAX;
|
12
|
+
} else {
|
13
|
+
return (unsigned int) size;
|
14
|
+
}
|
15
|
+
}
|
data/ext/bzs_ext/utils.h
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
// Ruby bindings for bzip2 library.
|
2
|
+
// Copyright (c) 2022 AUTHORS, MIT License.
|
3
|
+
|
4
|
+
#if !defined(BZS_EXT_UTILS_H)
|
5
|
+
#define BZS_EXT_UTILS_H
|
6
|
+
|
7
|
+
#include <stdlib.h>
|
8
|
+
|
9
|
+
// Bzip2 size type may be limited to unsigned int.
|
10
|
+
// We need to prevent overflow by consuming max available unsigned int value.
|
11
|
+
unsigned int bzs_consume_size(size_t size);
|
12
|
+
|
13
|
+
#endif // BZS_EXT_UTILS_H
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
# Ruby bindings for bzip2 library.
|
2
|
+
# Copyright (c) 2022 AUTHORS, MIT License.
|
3
|
+
|
4
|
+
require "mkmf"
|
5
|
+
|
6
|
+
have_func "rb_thread_call_without_gvl", "ruby/thread.h"
|
7
|
+
|
8
|
+
def require_header(name, constants: [], types: [])
|
9
|
+
abort "Can't find #{name} header" unless find_header name
|
10
|
+
|
11
|
+
constants.each do |constant|
|
12
|
+
abort "Can't find #{constant} constant in #{name} header" unless have_const constant, name
|
13
|
+
end
|
14
|
+
|
15
|
+
types.each do |type|
|
16
|
+
abort "Can't find #{type} type in #{name} header" unless find_type type, nil, name
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
require_header(
|
21
|
+
"bzlib.h",
|
22
|
+
:constants => %w[
|
23
|
+
BZ_RUN
|
24
|
+
BZ_RUN_OK
|
25
|
+
BZ_FINISH
|
26
|
+
BZ_FINISH_OK
|
27
|
+
BZ_FLUSH
|
28
|
+
BZ_FLUSH_OK
|
29
|
+
BZ_OK
|
30
|
+
BZ_PARAM_ERROR
|
31
|
+
BZ_STREAM_END
|
32
|
+
BZ_MEM_ERROR
|
33
|
+
BZ_DATA_ERROR
|
34
|
+
BZ_DATA_ERROR_MAGIC
|
35
|
+
BZ_UNEXPECTED_EOF
|
36
|
+
],
|
37
|
+
:types => %w[
|
38
|
+
bz_stream
|
39
|
+
]
|
40
|
+
)
|
41
|
+
|
42
|
+
def require_library(name, functions)
|
43
|
+
functions.each do |function|
|
44
|
+
abort "Can't find #{function} function in #{name} library" unless find_library name, function
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
require_library(
|
49
|
+
"bz2",
|
50
|
+
%w[
|
51
|
+
BZ2_bzCompressInit
|
52
|
+
BZ2_bzCompress
|
53
|
+
BZ2_bzCompressEnd
|
54
|
+
BZ2_bzDecompressInit
|
55
|
+
BZ2_bzDecompress
|
56
|
+
BZ2_bzDecompressEnd
|
57
|
+
BZ2_bzlibVersion
|
58
|
+
]
|
59
|
+
)
|
60
|
+
|
61
|
+
extension_name = "bzs_ext".freeze
|
62
|
+
dir_config extension_name
|
63
|
+
|
64
|
+
# rubocop:disable Style/GlobalVars
|
65
|
+
$srcs = %w[
|
66
|
+
stream/compressor
|
67
|
+
stream/decompressor
|
68
|
+
buffer
|
69
|
+
error
|
70
|
+
io
|
71
|
+
main
|
72
|
+
option
|
73
|
+
string
|
74
|
+
utils
|
75
|
+
]
|
76
|
+
.map { |name| "src/#{extension_name}/#{name}.c" }
|
77
|
+
.freeze
|
78
|
+
|
79
|
+
# Removing library duplicates.
|
80
|
+
$libs = $libs.split(%r{\s})
|
81
|
+
.reject(&:empty?)
|
82
|
+
.sort
|
83
|
+
.uniq
|
84
|
+
.join " "
|
85
|
+
|
86
|
+
if ENV["CI"]
|
87
|
+
$CFLAGS << " --coverage"
|
88
|
+
$LDFLAGS << " --coverage"
|
89
|
+
end
|
90
|
+
|
91
|
+
$VPATH << "$(srcdir)/#{extension_name}:$(srcdir)/#{extension_name}/stream"
|
92
|
+
# rubocop:enable Style/GlobalVars
|
93
|
+
|
94
|
+
create_makefile extension_name
|
data/lib/bzs/error.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# Ruby bindings for bzip2 library.
|
2
|
+
# Copyright (c) 2022 AUTHORS, MIT License.
|
3
|
+
|
4
|
+
require "adsp"
|
5
|
+
|
6
|
+
module BZS
|
7
|
+
class BaseError < ::StandardError; end
|
8
|
+
|
9
|
+
class AllocateError < BaseError; end
|
10
|
+
|
11
|
+
class NotEnoughSourceBufferError < BaseError; end
|
12
|
+
class NotEnoughDestinationBufferError < BaseError; end
|
13
|
+
class DecompressorCorruptedSourceError < BaseError; end
|
14
|
+
|
15
|
+
class AccessIOError < BaseError; end
|
16
|
+
class ReadIOError < BaseError; end
|
17
|
+
class WriteIOError < BaseError; end
|
18
|
+
|
19
|
+
ValidateError = ADSP::ValidateError
|
20
|
+
|
21
|
+
NotEnoughDestinationError = ADSP::NotEnoughDestinationError
|
22
|
+
UsedAfterCloseError = ADSP::UsedAfterCloseError
|
23
|
+
|
24
|
+
NotImplementedError = ADSP::NotImplementedError
|
25
|
+
UnexpectedError = ADSP::UnexpectedError
|
26
|
+
end
|
data/lib/bzs/file.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# Ruby bindings for bzip2 library.
|
2
|
+
# Copyright (c) 2022 AUTHORS, MIT License.
|
3
|
+
|
4
|
+
require "adsp/file"
|
5
|
+
require "bzs_ext"
|
6
|
+
|
7
|
+
require_relative "option"
|
8
|
+
|
9
|
+
module BZS
|
10
|
+
# BZS::File class.
|
11
|
+
class File < ADSP::File
|
12
|
+
# Current option class.
|
13
|
+
Option = BZS::Option
|
14
|
+
|
15
|
+
# Bypass native compress.
|
16
|
+
def self.native_compress_io(*args)
|
17
|
+
BZS._native_compress_io(*args)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Bypass native decompress.
|
21
|
+
def self.native_decompress_io(*args)
|
22
|
+
BZS._native_decompress_io(*args)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/bzs/option.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
# Ruby bindings for bzip2 library.
|
2
|
+
# Copyright (c) 2022 AUTHORS, MIT License.
|
3
|
+
|
4
|
+
require "bzs_ext"
|
5
|
+
|
6
|
+
require_relative "error"
|
7
|
+
require_relative "validation"
|
8
|
+
|
9
|
+
module BZS
|
10
|
+
# BZS::Option module.
|
11
|
+
module Option
|
12
|
+
# Current default buffer length.
|
13
|
+
DEFAULT_BUFFER_LENGTH = 0
|
14
|
+
|
15
|
+
# Current compressor defaults.
|
16
|
+
COMPRESSOR_DEFAULTS = {
|
17
|
+
# Enables global VM lock where possible.
|
18
|
+
:gvl => false,
|
19
|
+
# Block size to be used for compression.
|
20
|
+
:block_size => nil,
|
21
|
+
# Controls threshold for switching from standard to fallback algorithm.
|
22
|
+
:work_factor => nil,
|
23
|
+
# Disables bzip2 library logging.
|
24
|
+
:quiet => nil
|
25
|
+
}
|
26
|
+
.freeze
|
27
|
+
|
28
|
+
# Current decompressor defaults.
|
29
|
+
DECOMPRESSOR_DEFAULTS = {
|
30
|
+
# Enables global VM lock where possible.
|
31
|
+
:gvl => false,
|
32
|
+
# Enables alternative decompression algorithm with less memory.
|
33
|
+
:small => nil,
|
34
|
+
# Disables bzip2 library logging.
|
35
|
+
:quiet => nil
|
36
|
+
}
|
37
|
+
.freeze
|
38
|
+
|
39
|
+
# Processes compressor +options+ and +buffer_length_names+.
|
40
|
+
# Option: +:source_buffer_length+ source buffer length.
|
41
|
+
# Option: +:destination_buffer_length+ destination buffer length.
|
42
|
+
# Option: +:gvl+ enables global VM lock where possible.
|
43
|
+
# Option: +:block_size+ block size to be used for compression.
|
44
|
+
# Option: +:work_factor+ controls threshold for switching from standard to fallback algorithm.
|
45
|
+
# Option: +:quiet+ disables bzip2 library logging.
|
46
|
+
# Returns processed compressor options.
|
47
|
+
def self.get_compressor_options(options, buffer_length_names)
|
48
|
+
Validation.validate_hash options
|
49
|
+
|
50
|
+
buffer_length_defaults = buffer_length_names.each_with_object({}) do |name, defaults|
|
51
|
+
defaults[name] = DEFAULT_BUFFER_LENGTH
|
52
|
+
end
|
53
|
+
|
54
|
+
options = COMPRESSOR_DEFAULTS.merge(buffer_length_defaults).merge options
|
55
|
+
|
56
|
+
buffer_length_names.each { |name| Validation.validate_not_negative_integer options[name] }
|
57
|
+
|
58
|
+
Validation.validate_bool options[:gvl]
|
59
|
+
|
60
|
+
block_size = options[:block_size]
|
61
|
+
Validation.validate_not_negative_integer block_size unless block_size.nil?
|
62
|
+
|
63
|
+
work_factor = options[:work_factor]
|
64
|
+
Validation.validate_not_negative_integer work_factor unless work_factor.nil?
|
65
|
+
|
66
|
+
quiet = options[:quiet]
|
67
|
+
Validation.validate_bool quiet unless quiet.nil?
|
68
|
+
|
69
|
+
options
|
70
|
+
end
|
71
|
+
|
72
|
+
# Processes decompressor +options+ and +buffer_length_names+.
|
73
|
+
# Option: +:source_buffer_length+ source buffer length.
|
74
|
+
# Option: +:destination_buffer_length+ destination buffer length.
|
75
|
+
# Option: +:gvl+ enables global VM lock where possible.
|
76
|
+
# Option: +:small+ enables alternative decompression algorithm with less memory.
|
77
|
+
# Option: +:quiet+ disables bzip2 library logging.
|
78
|
+
# Returns processed decompressor options.
|
79
|
+
def self.get_decompressor_options(options, buffer_length_names)
|
80
|
+
Validation.validate_hash options
|
81
|
+
|
82
|
+
buffer_length_defaults = buffer_length_names.each_with_object({}) do |name, defaults|
|
83
|
+
defaults[name] = DEFAULT_BUFFER_LENGTH
|
84
|
+
end
|
85
|
+
|
86
|
+
options = DECOMPRESSOR_DEFAULTS.merge(buffer_length_defaults).merge options
|
87
|
+
|
88
|
+
buffer_length_names.each { |name| Validation.validate_not_negative_integer options[name] }
|
89
|
+
|
90
|
+
Validation.validate_bool options[:gvl]
|
91
|
+
|
92
|
+
small = options[:small]
|
93
|
+
Validation.validate_bool small unless small.nil?
|
94
|
+
|
95
|
+
quiet = options[:quiet]
|
96
|
+
Validation.validate_bool quiet unless quiet.nil?
|
97
|
+
|
98
|
+
options
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Ruby bindings for bzip2 library.
|
2
|
+
# Copyright (c) 2022 AUTHORS, MIT License.
|
3
|
+
|
4
|
+
require "adsp/stream/raw/compressor"
|
5
|
+
require "bzs_ext"
|
6
|
+
|
7
|
+
require_relative "../../option"
|
8
|
+
|
9
|
+
module BZS
|
10
|
+
module Stream
|
11
|
+
module Raw
|
12
|
+
# BZS::Stream::Raw::Compressor class.
|
13
|
+
class Compressor < ADSP::Stream::Raw::Compressor
|
14
|
+
# Current native compressor class.
|
15
|
+
NativeCompressor = Stream::NativeCompressor
|
16
|
+
|
17
|
+
# Current option class.
|
18
|
+
Option = BZS::Option
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|