ruby-bzs 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/bzs_ext/io.c ADDED
@@ -0,0 +1,592 @@
1
+ // Ruby bindings for bzip2 library.
2
+ // Copyright (c) 2022 AUTHORS, MIT License.
3
+
4
+ #include "bzs_ext/io.h"
5
+
6
+ #include <bzlib.h>
7
+ #include <stdio.h>
8
+ #include <string.h>
9
+
10
+ #include "bzs_ext/buffer.h"
11
+ #include "bzs_ext/error.h"
12
+ #include "bzs_ext/gvl.h"
13
+ #include "bzs_ext/macro.h"
14
+ #include "bzs_ext/option.h"
15
+ #include "bzs_ext/utils.h"
16
+ #include "ruby/io.h"
17
+
18
+ // Additional possible results:
19
+ enum
20
+ {
21
+ BZS_EXT_FILE_READ_FINISHED = 128
22
+ };
23
+
24
+ // -- file --
25
+
26
+ static inline bzs_ext_result_t
27
+ read_file(FILE* source_file, bzs_ext_byte_t* source_buffer, size_t* source_length_ptr, size_t source_buffer_length)
28
+ {
29
+ size_t read_length = fread(source_buffer, 1, source_buffer_length, source_file);
30
+ if (read_length == 0 && feof(source_file)) {
31
+ return BZS_EXT_FILE_READ_FINISHED;
32
+ }
33
+
34
+ if (read_length != source_buffer_length && ferror(source_file)) {
35
+ return BZS_EXT_ERROR_READ_IO;
36
+ }
37
+
38
+ *source_length_ptr = read_length;
39
+
40
+ return 0;
41
+ }
42
+
43
+ static inline bzs_ext_result_t
44
+ write_file(FILE* destination_file, bzs_ext_byte_t* destination_buffer, size_t destination_length)
45
+ {
46
+ size_t written_length = fwrite(destination_buffer, 1, destination_length, destination_file);
47
+ if (written_length != destination_length) {
48
+ return BZS_EXT_ERROR_WRITE_IO;
49
+ }
50
+
51
+ return 0;
52
+ }
53
+
54
+ // -- buffer --
55
+
56
+ static inline bzs_ext_result_t create_buffers(
57
+ bzs_ext_byte_t** source_buffer_ptr,
58
+ size_t source_buffer_length,
59
+ bzs_ext_byte_t** destination_buffer_ptr,
60
+ size_t destination_buffer_length)
61
+ {
62
+ bzs_ext_byte_t* source_buffer = malloc(source_buffer_length);
63
+ if (source_buffer == NULL) {
64
+ return BZS_EXT_ERROR_ALLOCATE_FAILED;
65
+ }
66
+
67
+ bzs_ext_byte_t* destination_buffer = malloc(destination_buffer_length);
68
+ if (destination_buffer == NULL) {
69
+ free(source_buffer);
70
+ return BZS_EXT_ERROR_ALLOCATE_FAILED;
71
+ }
72
+
73
+ *source_buffer_ptr = source_buffer;
74
+ *destination_buffer_ptr = destination_buffer;
75
+
76
+ return 0;
77
+ }
78
+
79
+ // We have read some source from file into source buffer.
80
+ // Than algorithm has read part of this source.
81
+ // We need to move remaining source to the top of source buffer.
82
+ // Than we can read more source from file.
83
+ // Algorithm can use same buffer again.
84
+
85
+ static inline bzs_ext_result_t read_more_source(
86
+ FILE* source_file,
87
+ const bzs_ext_byte_t** source_ptr,
88
+ size_t* source_length_ptr,
89
+ bzs_ext_byte_t* source_buffer,
90
+ size_t source_buffer_length)
91
+ {
92
+ const bzs_ext_byte_t* source = *source_ptr;
93
+ size_t source_length = *source_length_ptr;
94
+
95
+ if (source != source_buffer) {
96
+ if (source_length != 0) {
97
+ memmove(source_buffer, source, source_length);
98
+ }
99
+
100
+ // Source can be accessed even if next code will fail.
101
+ *source_ptr = source_buffer;
102
+ }
103
+
104
+ size_t remaining_source_buffer_length = source_buffer_length - source_length;
105
+ if (remaining_source_buffer_length == 0) {
106
+ // We want to read more data at once, than buffer has.
107
+ return BZS_EXT_ERROR_NOT_ENOUGH_SOURCE_BUFFER;
108
+ }
109
+
110
+ bzs_ext_byte_t* remaining_source_buffer = source_buffer + source_length;
111
+ size_t new_source_length;
112
+
113
+ bzs_ext_result_t ext_result =
114
+ read_file(source_file, remaining_source_buffer, &new_source_length, remaining_source_buffer_length);
115
+
116
+ if (ext_result != 0) {
117
+ return ext_result;
118
+ }
119
+
120
+ *source_length_ptr = source_length + new_source_length;
121
+
122
+ return 0;
123
+ }
124
+
125
+ #define BUFFERED_READ_SOURCE(function, ...) \
126
+ do { \
127
+ bool is_function_called = false; \
128
+ \
129
+ while (true) { \
130
+ ext_result = read_more_source(source_file, &source, &source_length, source_buffer, source_buffer_length); \
131
+ if (ext_result == BZS_EXT_FILE_READ_FINISHED) { \
132
+ break; \
133
+ } else if (ext_result != 0) { \
134
+ return ext_result; \
135
+ } \
136
+ \
137
+ ext_result = function(__VA_ARGS__); \
138
+ if (ext_result != 0) { \
139
+ return ext_result; \
140
+ } \
141
+ \
142
+ is_function_called = true; \
143
+ } \
144
+ \
145
+ if (!is_function_called) { \
146
+ /* Function should be called at least once. */ \
147
+ ext_result = function(__VA_ARGS__); \
148
+ if (ext_result != 0) { \
149
+ return ext_result; \
150
+ } \
151
+ } \
152
+ } while (false);
153
+
154
+ // Algorithm has written data into destination buffer.
155
+ // We need to write this data into file.
156
+ // Than algorithm can use same buffer again.
157
+
158
+ static inline bzs_ext_result_t flush_destination_buffer(
159
+ FILE* destination_file,
160
+ bzs_ext_byte_t* destination_buffer,
161
+ size_t* destination_length_ptr,
162
+ size_t destination_buffer_length)
163
+ {
164
+ if (*destination_length_ptr == 0) {
165
+ // We want to write more data at once, than buffer has.
166
+ return BZS_EXT_ERROR_NOT_ENOUGH_DESTINATION_BUFFER;
167
+ }
168
+
169
+ bzs_ext_result_t ext_result = write_file(destination_file, destination_buffer, *destination_length_ptr);
170
+ if (ext_result != 0) {
171
+ return ext_result;
172
+ }
173
+
174
+ *destination_length_ptr = 0;
175
+
176
+ return 0;
177
+ }
178
+
179
+ static inline bzs_ext_result_t
180
+ write_remaining_destination(FILE* destination_file, bzs_ext_byte_t* destination_buffer, size_t destination_length)
181
+ {
182
+ if (destination_length == 0) {
183
+ return 0;
184
+ }
185
+
186
+ return write_file(destination_file, destination_buffer, destination_length);
187
+ }
188
+
189
+ // -- utils --
190
+
191
+ #define GET_FILE(target) \
192
+ Check_Type(target, T_FILE); \
193
+ \
194
+ rb_io_t* target##_io; \
195
+ GetOpenFile(target, target##_io); \
196
+ \
197
+ FILE* target##_file = rb_io_stdio_file(target##_io); \
198
+ if (target##_file == NULL) { \
199
+ bzs_ext_raise_error(BZS_EXT_ERROR_ACCESS_IO); \
200
+ }
201
+
202
+ // -- buffered compress --
203
+
204
+ typedef struct
205
+ {
206
+ bz_stream* stream_ptr;
207
+ int stream_action;
208
+ bzs_ext_byte_t** remaining_source_ptr;
209
+ size_t* remaining_source_length_ptr;
210
+ bzs_ext_byte_t* remaining_destination_buffer;
211
+ size_t* remaining_destination_buffer_length_ptr;
212
+ bzs_result_t result;
213
+ } compress_args_t;
214
+
215
+ static inline void* compress_wrapper(void* data)
216
+ {
217
+ compress_args_t* args = data;
218
+
219
+ args->stream_ptr->next_in = (char*) *args->remaining_source_ptr;
220
+ args->stream_ptr->avail_in = bzs_consume_size(*args->remaining_source_length_ptr);
221
+ args->stream_ptr->next_out = (char*) args->remaining_destination_buffer;
222
+ args->stream_ptr->avail_out = bzs_consume_size(*args->remaining_destination_buffer_length_ptr);
223
+
224
+ args->result = BZ2_bzCompress(args->stream_ptr, args->stream_action);
225
+
226
+ *args->remaining_source_ptr = (bzs_ext_byte_t*) args->stream_ptr->next_in;
227
+ *args->remaining_source_length_ptr = args->stream_ptr->avail_in;
228
+ *args->remaining_destination_buffer_length_ptr = args->stream_ptr->avail_out;
229
+
230
+ return NULL;
231
+ }
232
+
233
+ #define BUFFERED_COMPRESS(gvl, args, RUN_OK) \
234
+ bzs_ext_result_t ext_result; \
235
+ \
236
+ while (true) { \
237
+ bzs_ext_byte_t* remaining_destination_buffer = destination_buffer + *destination_length_ptr; \
238
+ size_t remaining_destination_buffer_length = destination_buffer_length - *destination_length_ptr; \
239
+ size_t prev_remaining_destination_buffer_length = remaining_destination_buffer_length; \
240
+ \
241
+ args.remaining_destination_buffer = remaining_destination_buffer; \
242
+ args.remaining_destination_buffer_length_ptr = &remaining_destination_buffer_length; \
243
+ \
244
+ BZS_EXT_GVL_WRAP(gvl, compress_wrapper, &args); \
245
+ if (args.result != RUN_OK && args.result != BZ_PARAM_ERROR && args.result != BZ_STREAM_END) { \
246
+ return bzs_ext_get_error(args.result); \
247
+ } \
248
+ \
249
+ *destination_length_ptr += prev_remaining_destination_buffer_length - remaining_destination_buffer_length; \
250
+ \
251
+ if (args.result == BZ_STREAM_END) { \
252
+ break; \
253
+ } \
254
+ \
255
+ if (*args.remaining_source_length_ptr != 0 || remaining_destination_buffer_length == 0) { \
256
+ ext_result = flush_destination_buffer( \
257
+ destination_file, destination_buffer, destination_length_ptr, destination_buffer_length); \
258
+ \
259
+ if (ext_result != 0) { \
260
+ return ext_result; \
261
+ } \
262
+ \
263
+ continue; \
264
+ } \
265
+ \
266
+ break; \
267
+ } \
268
+ \
269
+ return 0;
270
+
271
+ static inline bzs_ext_result_t buffered_compress(
272
+ bz_stream* stream_ptr,
273
+ const bzs_ext_byte_t** source_ptr,
274
+ size_t* source_length_ptr,
275
+ FILE* destination_file,
276
+ bzs_ext_byte_t* destination_buffer,
277
+ size_t* destination_length_ptr,
278
+ size_t destination_buffer_length,
279
+ bool gvl)
280
+ {
281
+ compress_args_t run_args = {
282
+ .stream_ptr = stream_ptr,
283
+ .stream_action = BZ_RUN,
284
+ .remaining_source_ptr = (bzs_ext_byte_t**) source_ptr,
285
+ .remaining_source_length_ptr = source_length_ptr};
286
+ BUFFERED_COMPRESS(gvl, run_args, BZ_RUN_OK);
287
+ }
288
+
289
+ // -- buffered compressor finish --
290
+
291
+ static inline bzs_ext_result_t buffered_compressor_finish(
292
+ bz_stream* stream_ptr,
293
+ FILE* destination_file,
294
+ bzs_ext_byte_t* destination_buffer,
295
+ size_t* destination_length_ptr,
296
+ size_t destination_buffer_length,
297
+ bool gvl)
298
+ {
299
+ bzs_ext_byte_t* remaining_source = NULL;
300
+ size_t remaining_source_length = 0;
301
+
302
+ compress_args_t finish_args = {
303
+ .stream_ptr = stream_ptr,
304
+ .stream_action = BZ_FINISH,
305
+ .remaining_source_ptr = &remaining_source,
306
+ .remaining_source_length_ptr = &remaining_source_length};
307
+ BUFFERED_COMPRESS(gvl, finish_args, BZ_FINISH_OK);
308
+ }
309
+
310
+ // -- compress --
311
+
312
+ static inline bzs_ext_result_t compress(
313
+ bz_stream* stream_ptr,
314
+ FILE* source_file,
315
+ bzs_ext_byte_t* source_buffer,
316
+ size_t source_buffer_length,
317
+ FILE* destination_file,
318
+ bzs_ext_byte_t* destination_buffer,
319
+ size_t destination_buffer_length,
320
+ bool gvl)
321
+ {
322
+ bzs_ext_result_t ext_result;
323
+ const bzs_ext_byte_t* source = source_buffer;
324
+ size_t source_length = 0;
325
+ size_t destination_length = 0;
326
+
327
+ BUFFERED_READ_SOURCE(
328
+ buffered_compress,
329
+ stream_ptr,
330
+ &source,
331
+ &source_length,
332
+ destination_file,
333
+ destination_buffer,
334
+ &destination_length,
335
+ destination_buffer_length,
336
+ gvl);
337
+
338
+ ext_result = buffered_compressor_finish(
339
+ stream_ptr, destination_file, destination_buffer, &destination_length, destination_buffer_length, gvl);
340
+
341
+ if (ext_result != 0) {
342
+ return ext_result;
343
+ }
344
+
345
+ return write_remaining_destination(destination_file, destination_buffer, destination_length);
346
+ }
347
+
348
+ VALUE bzs_ext_compress_io(VALUE BZS_EXT_UNUSED(self), VALUE source, VALUE destination, VALUE options)
349
+ {
350
+ GET_FILE(source);
351
+ GET_FILE(destination);
352
+ Check_Type(options, T_HASH);
353
+ BZS_EXT_GET_SIZE_OPTION(options, source_buffer_length);
354
+ BZS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
355
+ BZS_EXT_GET_BOOL_OPTION(options, gvl);
356
+ BZS_EXT_RESOLVE_COMPRESSOR_OPTIONS(options);
357
+
358
+ bz_stream stream = {
359
+ .bzalloc = NULL,
360
+ .bzfree = NULL,
361
+ .opaque = NULL,
362
+ };
363
+
364
+ bzs_result_t result = BZ2_bzCompressInit(&stream, block_size, verbosity, work_factor);
365
+ if (result != BZ_OK) {
366
+ bzs_ext_raise_error(bzs_ext_get_error(result));
367
+ }
368
+
369
+ if (source_buffer_length == 0) {
370
+ source_buffer_length = BZS_DEFAULT_SOURCE_BUFFER_LENGTH_FOR_COMPRESSOR;
371
+ }
372
+ if (destination_buffer_length == 0) {
373
+ destination_buffer_length = BZS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_COMPRESSOR;
374
+ }
375
+
376
+ bzs_ext_byte_t* source_buffer;
377
+ bzs_ext_byte_t* destination_buffer;
378
+
379
+ bzs_ext_result_t ext_result =
380
+ create_buffers(&source_buffer, source_buffer_length, &destination_buffer, destination_buffer_length);
381
+ if (ext_result != 0) {
382
+ BZ2_bzCompressEnd(&stream);
383
+ bzs_ext_raise_error(ext_result);
384
+ }
385
+
386
+ ext_result = compress(
387
+ &stream,
388
+ source_file,
389
+ source_buffer,
390
+ source_buffer_length,
391
+ destination_file,
392
+ destination_buffer,
393
+ destination_buffer_length,
394
+ gvl);
395
+
396
+ free(source_buffer);
397
+ free(destination_buffer);
398
+ BZ2_bzCompressEnd(&stream);
399
+
400
+ if (ext_result != 0) {
401
+ bzs_ext_raise_error(ext_result);
402
+ }
403
+
404
+ // Ruby itself won't flush stdio file before closing fd, flush is required.
405
+ fflush(destination_file);
406
+
407
+ return Qnil;
408
+ }
409
+
410
+ // -- buffered decompress --
411
+
412
+ typedef struct
413
+ {
414
+ bz_stream* stream_ptr;
415
+ bzs_ext_byte_t** remaining_source_ptr;
416
+ size_t* remaining_source_length_ptr;
417
+ bzs_ext_byte_t* remaining_destination_buffer;
418
+ size_t* remaining_destination_buffer_length_ptr;
419
+ bzs_result_t result;
420
+ } decompress_args_t;
421
+
422
+ static inline void* decompress_wrapper(void* data)
423
+ {
424
+ decompress_args_t* args = data;
425
+
426
+ args->stream_ptr->next_in = (char*) *args->remaining_source_ptr;
427
+ args->stream_ptr->avail_in = bzs_consume_size(*args->remaining_source_length_ptr);
428
+ args->stream_ptr->next_out = (char*) args->remaining_destination_buffer;
429
+ args->stream_ptr->avail_out = bzs_consume_size(*args->remaining_destination_buffer_length_ptr);
430
+
431
+ args->result = BZ2_bzDecompress(args->stream_ptr);
432
+
433
+ *args->remaining_source_ptr = (bzs_ext_byte_t*) args->stream_ptr->next_in;
434
+ *args->remaining_source_length_ptr = args->stream_ptr->avail_in;
435
+ *args->remaining_destination_buffer_length_ptr = args->stream_ptr->avail_out;
436
+
437
+ return NULL;
438
+ }
439
+
440
+ static inline bzs_ext_result_t buffered_decompress(
441
+ bz_stream* stream_ptr,
442
+ const bzs_ext_byte_t** source_ptr,
443
+ size_t* source_length_ptr,
444
+ FILE* destination_file,
445
+ bzs_ext_byte_t* destination_buffer,
446
+ size_t* destination_length_ptr,
447
+ size_t destination_buffer_length,
448
+ bool gvl)
449
+ {
450
+ bzs_ext_result_t ext_result;
451
+
452
+ decompress_args_t args = {
453
+ .stream_ptr = stream_ptr,
454
+ .remaining_source_ptr = (bzs_ext_byte_t**) source_ptr,
455
+ .remaining_source_length_ptr = source_length_ptr};
456
+
457
+ while (true) {
458
+ bzs_ext_byte_t* remaining_destination_buffer = destination_buffer + *destination_length_ptr;
459
+ size_t remaining_destination_buffer_length = destination_buffer_length - *destination_length_ptr;
460
+ size_t prev_remaining_destination_buffer_length = remaining_destination_buffer_length;
461
+
462
+ args.remaining_destination_buffer = remaining_destination_buffer;
463
+ args.remaining_destination_buffer_length_ptr = &remaining_destination_buffer_length;
464
+
465
+ BZS_EXT_GVL_WRAP(gvl, decompress_wrapper, &args);
466
+ if (args.result != BZ_OK && args.result != BZ_PARAM_ERROR && args.result != BZ_STREAM_END) {
467
+ return bzs_ext_get_error(args.result);
468
+ }
469
+
470
+ *destination_length_ptr += prev_remaining_destination_buffer_length - remaining_destination_buffer_length;
471
+
472
+ if (args.result == BZ_STREAM_END) {
473
+ break;
474
+ }
475
+
476
+ if (*args.remaining_source_length_ptr != 0 || remaining_destination_buffer_length == 0) {
477
+ ext_result = flush_destination_buffer(
478
+ destination_file, destination_buffer, destination_length_ptr, destination_buffer_length);
479
+
480
+ if (ext_result != 0) {
481
+ return ext_result;
482
+ }
483
+
484
+ continue;
485
+ }
486
+
487
+ break;
488
+ }
489
+
490
+ return 0;
491
+ }
492
+
493
+ // -- decompress --
494
+
495
+ static inline bzs_ext_result_t decompress(
496
+ bz_stream* stream_ptr,
497
+ FILE* source_file,
498
+ bzs_ext_byte_t* source_buffer,
499
+ size_t source_buffer_length,
500
+ FILE* destination_file,
501
+ bzs_ext_byte_t* destination_buffer,
502
+ size_t destination_buffer_length,
503
+ bool gvl)
504
+ {
505
+ bzs_ext_result_t ext_result;
506
+ const bzs_ext_byte_t* source = source_buffer;
507
+ size_t source_length = 0;
508
+ size_t destination_length = 0;
509
+
510
+ BUFFERED_READ_SOURCE(
511
+ buffered_decompress,
512
+ stream_ptr,
513
+ &source,
514
+ &source_length,
515
+ destination_file,
516
+ destination_buffer,
517
+ &destination_length,
518
+ destination_buffer_length,
519
+ gvl);
520
+
521
+ return write_remaining_destination(destination_file, destination_buffer, destination_length);
522
+ }
523
+
524
+ VALUE bzs_ext_decompress_io(VALUE BZS_EXT_UNUSED(self), VALUE source, VALUE destination, VALUE options)
525
+ {
526
+ GET_FILE(source);
527
+ GET_FILE(destination);
528
+ Check_Type(options, T_HASH);
529
+ BZS_EXT_GET_SIZE_OPTION(options, source_buffer_length);
530
+ BZS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
531
+ BZS_EXT_GET_BOOL_OPTION(options, gvl);
532
+ BZS_EXT_RESOLVE_DECOMPRESSOR_OPTIONS(options);
533
+
534
+ bz_stream stream = {
535
+ .bzalloc = NULL,
536
+ .bzfree = NULL,
537
+ .opaque = NULL,
538
+ };
539
+
540
+ bzs_result_t result = BZ2_bzDecompressInit(&stream, verbosity, small);
541
+ if (result != BZ_OK) {
542
+ bzs_ext_raise_error(bzs_ext_get_error(result));
543
+ }
544
+
545
+ if (source_buffer_length == 0) {
546
+ source_buffer_length = BZS_DEFAULT_SOURCE_BUFFER_LENGTH_FOR_DECOMPRESSOR;
547
+ }
548
+ if (destination_buffer_length == 0) {
549
+ destination_buffer_length = BZS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_DECOMPRESSOR;
550
+ }
551
+
552
+ bzs_ext_byte_t* source_buffer;
553
+ bzs_ext_byte_t* destination_buffer;
554
+
555
+ bzs_ext_result_t ext_result =
556
+ create_buffers(&source_buffer, source_buffer_length, &destination_buffer, destination_buffer_length);
557
+ if (ext_result != 0) {
558
+ BZ2_bzDecompressEnd(&stream);
559
+ bzs_ext_raise_error(ext_result);
560
+ }
561
+
562
+ ext_result = decompress(
563
+ &stream,
564
+ source_file,
565
+ source_buffer,
566
+ source_buffer_length,
567
+ destination_file,
568
+ destination_buffer,
569
+ destination_buffer_length,
570
+ gvl);
571
+
572
+ free(source_buffer);
573
+ free(destination_buffer);
574
+ BZ2_bzDecompressEnd(&stream);
575
+
576
+ if (ext_result != 0) {
577
+ bzs_ext_raise_error(ext_result);
578
+ }
579
+
580
+ // Ruby itself won't flush stdio file before closing fd, flush is required.
581
+ fflush(destination_file);
582
+
583
+ return Qnil;
584
+ }
585
+
586
+ // -- exports --
587
+
588
+ void bzs_ext_io_exports(VALUE root_module)
589
+ {
590
+ rb_define_module_function(root_module, "_native_compress_io", RUBY_METHOD_FUNC(bzs_ext_compress_io), 3);
591
+ rb_define_module_function(root_module, "_native_decompress_io", RUBY_METHOD_FUNC(bzs_ext_decompress_io), 3);
592
+ }
data/ext/bzs_ext/io.h ADDED
@@ -0,0 +1,14 @@
1
+ // Ruby bindings for bzip2 library.
2
+ // Copyright (c) 2022 AUTHORS, MIT License.
3
+
4
+ #if !defined(BZS_EXT_IO_H)
5
+ #define BZS_EXT_IO_H
6
+
7
+ #include "ruby.h"
8
+
9
+ VALUE bzs_ext_compress_io(VALUE self, VALUE source, VALUE destination, VALUE options);
10
+ VALUE bzs_ext_decompress_io(VALUE self, VALUE source, VALUE destination, VALUE options);
11
+
12
+ void bzs_ext_io_exports(VALUE root_module);
13
+
14
+ #endif // BZS_EXT_IO_H
@@ -0,0 +1,13 @@
1
+ // Ruby bindings for bzip2 library.
2
+ // Copyright (c) 2022 AUTHORS, MIT License.
3
+
4
+ #if !defined(BZS_EXT_MACRO_H)
5
+ #define BZS_EXT_MACRO_H
6
+
7
+ #if defined(__GNUC__)
8
+ #define BZS_EXT_UNUSED(x) x __attribute__((__unused__))
9
+ #else
10
+ #define BZS_EXT_UNUSED(x) x
11
+ #endif // __GNUC__
12
+
13
+ #endif // BZS_EXT_MACRO_H
@@ -0,0 +1,27 @@
1
+ // Ruby bindings for bzip2 library.
2
+ // Copyright (c) 2022 AUTHORS, MIT License.
3
+
4
+ #include <bzlib.h>
5
+
6
+ #include "bzs_ext/buffer.h"
7
+ #include "bzs_ext/common.h"
8
+ #include "bzs_ext/io.h"
9
+ #include "bzs_ext/option.h"
10
+ #include "bzs_ext/stream/compressor.h"
11
+ #include "bzs_ext/stream/decompressor.h"
12
+ #include "bzs_ext/string.h"
13
+
14
+ void Init_bzs_ext()
15
+ {
16
+ VALUE root_module = rb_define_module(BZS_EXT_MODULE_NAME);
17
+
18
+ bzs_ext_buffer_exports(root_module);
19
+ bzs_ext_io_exports(root_module);
20
+ bzs_ext_option_exports(root_module);
21
+ bzs_ext_compressor_exports(root_module);
22
+ bzs_ext_decompressor_exports(root_module);
23
+ bzs_ext_string_exports(root_module);
24
+
25
+ VALUE version = rb_str_new2(BZ2_bzlibVersion());
26
+ rb_define_const(root_module, "LIBRARY_VERSION", version);
27
+ }