ruby-brs 1.0.1

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.
@@ -0,0 +1,80 @@
1
+ // Ruby bindings for brotli library.
2
+ // Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ #if !defined(BRS_EXT_OPTIONS_H)
5
+ #define BRS_EXT_OPTIONS_H
6
+
7
+ #include <brotli/decode.h>
8
+ #include <brotli/encode.h>
9
+ #include <stdbool.h>
10
+ #include <stdint.h>
11
+ #include <stdlib.h>
12
+
13
+ #include "brs_ext/common.h"
14
+ #include "ruby.h"
15
+
16
+ // Default option values depends on brotli library.
17
+ // We will set only user defined values.
18
+
19
+ enum {
20
+ BRS_EXT_OPTION_TYPE_BOOL = 1,
21
+ BRS_EXT_OPTION_TYPE_FIXNUM,
22
+ BRS_EXT_OPTION_TYPE_MODE
23
+ };
24
+
25
+ typedef uint_fast8_t brs_ext_option_type_t;
26
+ typedef uint32_t brs_ext_option_value_t;
27
+
28
+ typedef struct {
29
+ bool has_value;
30
+ brs_ext_option_value_t value;
31
+ } brs_ext_option_t;
32
+
33
+ typedef struct {
34
+ brs_ext_option_t mode;
35
+ brs_ext_option_t quality;
36
+ brs_ext_option_t lgwin;
37
+ brs_ext_option_t lgblock;
38
+ brs_ext_option_t disable_literal_context_modeling;
39
+ brs_ext_option_t size_hint;
40
+ brs_ext_option_t large_window;
41
+ } brs_ext_compressor_options_t;
42
+
43
+ typedef struct {
44
+ brs_ext_option_t disable_ring_buffer_reallocation;
45
+ brs_ext_option_t large_window;
46
+ } brs_ext_decompressor_options_t;
47
+
48
+ void brs_ext_get_option(VALUE options, brs_ext_option_t* option, brs_ext_option_type_t type, const char* name);
49
+
50
+ #define BRS_EXT_GET_OPTION(options, target_options, type, name) \
51
+ brs_ext_get_option(options, &target_options.name, type, #name);
52
+
53
+ #define BRS_EXT_GET_COMPRESSOR_OPTIONS(options) \
54
+ brs_ext_compressor_options_t compressor_options; \
55
+ \
56
+ BRS_EXT_GET_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_MODE, mode); \
57
+ BRS_EXT_GET_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_FIXNUM, quality); \
58
+ BRS_EXT_GET_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_FIXNUM, lgwin); \
59
+ BRS_EXT_GET_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_FIXNUM, lgblock); \
60
+ BRS_EXT_GET_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_BOOL, disable_literal_context_modeling); \
61
+ BRS_EXT_GET_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_FIXNUM, size_hint); \
62
+ BRS_EXT_GET_OPTION(options, compressor_options, BRS_EXT_OPTION_TYPE_BOOL, large_window);
63
+
64
+ #define BRS_EXT_GET_DECOMPRESSOR_OPTIONS(options) \
65
+ brs_ext_decompressor_options_t decompressor_options; \
66
+ \
67
+ BRS_EXT_GET_OPTION(options, decompressor_options, BRS_EXT_OPTION_TYPE_BOOL, disable_ring_buffer_reallocation); \
68
+ BRS_EXT_GET_OPTION(options, decompressor_options, BRS_EXT_OPTION_TYPE_BOOL, large_window);
69
+
70
+ unsigned long brs_ext_get_fixnum_option_value(VALUE options, const char* name);
71
+
72
+ #define BRS_EXT_GET_BUFFER_LENGTH_OPTION(options, name) \
73
+ size_t name = brs_ext_get_fixnum_option_value(options, #name);
74
+
75
+ brs_ext_result_t brs_ext_set_compressor_options(BrotliEncoderState* state_ptr, brs_ext_compressor_options_t* options);
76
+ brs_ext_result_t brs_ext_set_decompressor_options(BrotliDecoderState* state_ptr, brs_ext_decompressor_options_t* options);
77
+
78
+ void brs_ext_option_exports(VALUE root_module);
79
+
80
+ #endif // BRS_EXT_OPTIONS_H
@@ -0,0 +1,234 @@
1
+ // Ruby bindings for brotli library.
2
+ // Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ #include "brs_ext/stream/compressor.h"
5
+
6
+ #include <brotli/encode.h>
7
+ #include <stdint.h>
8
+ #include <stdlib.h>
9
+
10
+ #include "brs_ext/buffer.h"
11
+ #include "brs_ext/common.h"
12
+ #include "brs_ext/error.h"
13
+ #include "brs_ext/option.h"
14
+ #include "ruby.h"
15
+
16
+ static void free_compressor(brs_ext_compressor_t* compressor_ptr)
17
+ {
18
+ BrotliEncoderState* state_ptr = compressor_ptr->state_ptr;
19
+ if (state_ptr != NULL) {
20
+ BrotliEncoderDestroyInstance(state_ptr);
21
+ }
22
+
23
+ uint8_t* destination_buffer = compressor_ptr->destination_buffer;
24
+ if (destination_buffer != NULL) {
25
+ free(destination_buffer);
26
+ }
27
+
28
+ free(compressor_ptr);
29
+ }
30
+
31
+ VALUE brs_ext_allocate_compressor(VALUE klass)
32
+ {
33
+ brs_ext_compressor_t* compressor_ptr;
34
+
35
+ VALUE self = Data_Make_Struct(klass, brs_ext_compressor_t, NULL, free_compressor, compressor_ptr);
36
+
37
+ compressor_ptr->state_ptr = NULL;
38
+ compressor_ptr->destination_buffer = NULL;
39
+ compressor_ptr->destination_buffer_length = 0;
40
+ compressor_ptr->remaining_destination_buffer = NULL;
41
+ compressor_ptr->remaining_destination_buffer_length = 0;
42
+
43
+ return self;
44
+ }
45
+
46
+ #define GET_COMPRESSOR(self) \
47
+ brs_ext_compressor_t* compressor_ptr; \
48
+ Data_Get_Struct(self, brs_ext_compressor_t, compressor_ptr);
49
+
50
+ VALUE brs_ext_initialize_compressor(VALUE self, VALUE options)
51
+ {
52
+ GET_COMPRESSOR(self);
53
+ Check_Type(options, T_HASH);
54
+ BRS_EXT_GET_COMPRESSOR_OPTIONS(options);
55
+ BRS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
56
+
57
+ BrotliEncoderState* state_ptr = BrotliEncoderCreateInstance(NULL, NULL, NULL);
58
+ if (state_ptr == NULL) {
59
+ brs_ext_raise_error(BRS_EXT_ERROR_ALLOCATE_FAILED);
60
+ }
61
+
62
+ brs_ext_result_t ext_result = brs_ext_set_compressor_options(state_ptr, &compressor_options);
63
+ if (ext_result != 0) {
64
+ BrotliEncoderDestroyInstance(state_ptr);
65
+ brs_ext_raise_error(ext_result);
66
+ }
67
+
68
+ if (destination_buffer_length == 0) {
69
+ destination_buffer_length = BRS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_COMPRESSOR;
70
+ }
71
+
72
+ uint8_t* destination_buffer = malloc(destination_buffer_length);
73
+ if (destination_buffer == NULL) {
74
+ BrotliEncoderDestroyInstance(state_ptr);
75
+ brs_ext_raise_error(BRS_EXT_ERROR_ALLOCATE_FAILED);
76
+ }
77
+
78
+ compressor_ptr->state_ptr = state_ptr;
79
+ compressor_ptr->destination_buffer = destination_buffer;
80
+ compressor_ptr->destination_buffer_length = destination_buffer_length;
81
+ compressor_ptr->remaining_destination_buffer = destination_buffer;
82
+ compressor_ptr->remaining_destination_buffer_length = destination_buffer_length;
83
+
84
+ return Qnil;
85
+ }
86
+
87
+ #define DO_NOT_USE_AFTER_CLOSE(compressor_ptr) \
88
+ if (compressor_ptr->state_ptr == NULL || compressor_ptr->destination_buffer == NULL) { \
89
+ brs_ext_raise_error(BRS_EXT_ERROR_USED_AFTER_CLOSE); \
90
+ }
91
+
92
+ #define GET_SOURCE_DATA(source_value) \
93
+ Check_Type(source_value, T_STRING); \
94
+ \
95
+ const char* source = RSTRING_PTR(source_value); \
96
+ size_t source_length = RSTRING_LEN(source_value); \
97
+ const uint8_t* remaining_source = (const uint8_t*)source; \
98
+ size_t remaining_source_length = source_length;
99
+
100
+ VALUE brs_ext_compress(VALUE self, VALUE source_value)
101
+ {
102
+ GET_COMPRESSOR(self);
103
+ DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
104
+ GET_SOURCE_DATA(source_value);
105
+
106
+ BrotliEncoderState* state_ptr = compressor_ptr->state_ptr;
107
+
108
+ BROTLI_BOOL result = BrotliEncoderCompressStream(
109
+ state_ptr,
110
+ BROTLI_OPERATION_PROCESS,
111
+ &remaining_source_length, &remaining_source,
112
+ &compressor_ptr->remaining_destination_buffer_length, &compressor_ptr->remaining_destination_buffer,
113
+ NULL);
114
+
115
+ if (!result) {
116
+ brs_ext_raise_error(BRS_EXT_ERROR_UNEXPECTED);
117
+ }
118
+
119
+ VALUE bytes_written = UINT2NUM(source_length - remaining_source_length);
120
+ VALUE needs_more_destination = BrotliEncoderHasMoreOutput(state_ptr) ? Qtrue : Qfalse;
121
+
122
+ return rb_ary_new_from_args(2, bytes_written, needs_more_destination);
123
+ }
124
+
125
+ VALUE brs_ext_flush_compressor(VALUE self)
126
+ {
127
+ GET_COMPRESSOR(self);
128
+ DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
129
+
130
+ BrotliEncoderState* state_ptr = compressor_ptr->state_ptr;
131
+
132
+ const uint8_t* remaining_source = NULL;
133
+ size_t remaining_source_length = 0;
134
+
135
+ BROTLI_BOOL result = BrotliEncoderCompressStream(
136
+ state_ptr,
137
+ BROTLI_OPERATION_FLUSH,
138
+ &remaining_source_length, &remaining_source,
139
+ &compressor_ptr->remaining_destination_buffer_length, &compressor_ptr->remaining_destination_buffer,
140
+ NULL);
141
+
142
+ if (!result) {
143
+ brs_ext_raise_error(BRS_EXT_ERROR_UNEXPECTED);
144
+ }
145
+
146
+ VALUE needs_more_destination = BrotliEncoderHasMoreOutput(state_ptr) ? Qtrue : Qfalse;
147
+
148
+ return needs_more_destination;
149
+ }
150
+
151
+ VALUE brs_ext_finish_compressor(VALUE self)
152
+ {
153
+ GET_COMPRESSOR(self);
154
+ DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
155
+
156
+ BrotliEncoderState* state_ptr = compressor_ptr->state_ptr;
157
+
158
+ const uint8_t* remaining_source = NULL;
159
+ size_t remaining_source_length = 0;
160
+
161
+ BROTLI_BOOL result = BrotliEncoderCompressStream(
162
+ state_ptr,
163
+ BROTLI_OPERATION_FINISH,
164
+ &remaining_source_length, &remaining_source,
165
+ &compressor_ptr->remaining_destination_buffer_length, &compressor_ptr->remaining_destination_buffer,
166
+ NULL);
167
+
168
+ if (!result) {
169
+ brs_ext_raise_error(BRS_EXT_ERROR_UNEXPECTED);
170
+ }
171
+
172
+ VALUE needs_more_destination = (BrotliEncoderHasMoreOutput(state_ptr) || !BrotliEncoderIsFinished(state_ptr)) ? Qtrue : Qfalse;
173
+
174
+ return needs_more_destination;
175
+ }
176
+
177
+ VALUE brs_ext_compressor_read_result(VALUE self)
178
+ {
179
+ GET_COMPRESSOR(self);
180
+ DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
181
+
182
+ uint8_t* destination_buffer = compressor_ptr->destination_buffer;
183
+ size_t destination_buffer_length = compressor_ptr->destination_buffer_length;
184
+ size_t remaining_destination_buffer_length = compressor_ptr->remaining_destination_buffer_length;
185
+
186
+ const char* result = (const char*)destination_buffer;
187
+ size_t result_length = destination_buffer_length - remaining_destination_buffer_length;
188
+
189
+ VALUE result_value = rb_str_new(result, result_length);
190
+
191
+ compressor_ptr->remaining_destination_buffer = destination_buffer;
192
+ compressor_ptr->remaining_destination_buffer_length = destination_buffer_length;
193
+
194
+ return result_value;
195
+ }
196
+
197
+ VALUE brs_ext_compressor_close(VALUE self)
198
+ {
199
+ GET_COMPRESSOR(self);
200
+ DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
201
+
202
+ BrotliEncoderState* state_ptr = compressor_ptr->state_ptr;
203
+ if (state_ptr != NULL) {
204
+ BrotliEncoderDestroyInstance(state_ptr);
205
+
206
+ compressor_ptr->state_ptr = NULL;
207
+ }
208
+
209
+ uint8_t* destination_buffer = compressor_ptr->destination_buffer;
210
+ if (destination_buffer != NULL) {
211
+ free(destination_buffer);
212
+
213
+ compressor_ptr->destination_buffer = NULL;
214
+ }
215
+
216
+ // It is possible to keep "destination_buffer_length", "remaining_destination_buffer"
217
+ // and "remaining_destination_buffer_length" as is.
218
+
219
+ return Qnil;
220
+ }
221
+
222
+ void brs_ext_compressor_exports(VALUE root_module)
223
+ {
224
+ VALUE stream = rb_define_module_under(root_module, "Stream");
225
+
226
+ VALUE compressor = rb_define_class_under(stream, "NativeCompressor", rb_cObject);
227
+ rb_define_alloc_func(compressor, brs_ext_allocate_compressor);
228
+ rb_define_method(compressor, "initialize", brs_ext_initialize_compressor, 1);
229
+ rb_define_method(compressor, "write", brs_ext_compress, 1);
230
+ rb_define_method(compressor, "flush", brs_ext_flush_compressor, 0);
231
+ rb_define_method(compressor, "finish", brs_ext_finish_compressor, 0);
232
+ rb_define_method(compressor, "read_result", brs_ext_compressor_read_result, 0);
233
+ rb_define_method(compressor, "close", brs_ext_compressor_close, 0);
234
+ }
@@ -0,0 +1,31 @@
1
+ // Ruby bindings for brotli library.
2
+ // Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ #if !defined(BRS_EXT_STREAM_COMPRESSOR_H)
5
+ #define BRS_EXT_STREAM_COMPRESSOR_H
6
+
7
+ #include <brotli/encode.h>
8
+ #include <stdint.h>
9
+ #include <stdlib.h>
10
+
11
+ #include "ruby.h"
12
+
13
+ typedef struct {
14
+ BrotliEncoderState* state_ptr;
15
+ uint8_t* destination_buffer;
16
+ size_t destination_buffer_length;
17
+ uint8_t* remaining_destination_buffer;
18
+ size_t remaining_destination_buffer_length;
19
+ } brs_ext_compressor_t;
20
+
21
+ VALUE brs_ext_allocate_compressor(VALUE klass);
22
+ VALUE brs_ext_initialize_compressor(VALUE self, VALUE options);
23
+ VALUE brs_ext_compress(VALUE self, VALUE source);
24
+ VALUE brs_ext_flush_compressor(VALUE self);
25
+ VALUE brs_ext_finish_compressor(VALUE self);
26
+ VALUE brs_ext_compressor_read_result(VALUE self);
27
+ VALUE brs_ext_compressor_close(VALUE self);
28
+
29
+ void brs_ext_compressor_exports(VALUE root_module);
30
+
31
+ #endif // BRS_EXT_STREAM_COMPRESSOR_H
@@ -0,0 +1,181 @@
1
+ // Ruby bindings for brotli library.
2
+ // Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ #include "brs_ext/stream/decompressor.h"
5
+
6
+ #include <brotli/decode.h>
7
+ #include <stdint.h>
8
+ #include <stdlib.h>
9
+
10
+ #include "brs_ext/buffer.h"
11
+ #include "brs_ext/common.h"
12
+ #include "brs_ext/error.h"
13
+ #include "brs_ext/option.h"
14
+ #include "ruby.h"
15
+
16
+ static void free_decompressor(brs_ext_decompressor_t* decompressor_ptr)
17
+ {
18
+ BrotliDecoderState* state_ptr = decompressor_ptr->state_ptr;
19
+ if (state_ptr != NULL) {
20
+ BrotliDecoderDestroyInstance(state_ptr);
21
+ }
22
+
23
+ uint8_t* destination_buffer = decompressor_ptr->destination_buffer;
24
+ if (destination_buffer != NULL) {
25
+ free(destination_buffer);
26
+ }
27
+
28
+ free(decompressor_ptr);
29
+ }
30
+
31
+ VALUE brs_ext_allocate_decompressor(VALUE klass)
32
+ {
33
+ brs_ext_decompressor_t* decompressor_ptr;
34
+
35
+ VALUE self = Data_Make_Struct(klass, brs_ext_decompressor_t, NULL, free_decompressor, decompressor_ptr);
36
+
37
+ decompressor_ptr->state_ptr = NULL;
38
+ decompressor_ptr->destination_buffer = NULL;
39
+ decompressor_ptr->destination_buffer_length = 0;
40
+ decompressor_ptr->remaining_destination_buffer = NULL;
41
+ decompressor_ptr->remaining_destination_buffer_length = 0;
42
+
43
+ return self;
44
+ }
45
+
46
+ #define GET_DECOMPRESSOR(self) \
47
+ brs_ext_decompressor_t* decompressor_ptr; \
48
+ Data_Get_Struct(self, brs_ext_decompressor_t, decompressor_ptr);
49
+
50
+ VALUE brs_ext_initialize_decompressor(VALUE self, VALUE options)
51
+ {
52
+ GET_DECOMPRESSOR(self);
53
+ Check_Type(options, T_HASH);
54
+ BRS_EXT_GET_DECOMPRESSOR_OPTIONS(options);
55
+ BRS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
56
+
57
+ BrotliDecoderState* state_ptr = BrotliDecoderCreateInstance(NULL, NULL, NULL);
58
+ if (state_ptr == NULL) {
59
+ brs_ext_raise_error(BRS_EXT_ERROR_ALLOCATE_FAILED);
60
+ }
61
+
62
+ brs_ext_result_t ext_result = brs_ext_set_decompressor_options(state_ptr, &decompressor_options);
63
+ if (ext_result != 0) {
64
+ BrotliDecoderDestroyInstance(state_ptr);
65
+ brs_ext_raise_error(ext_result);
66
+ }
67
+
68
+ if (destination_buffer_length == 0) {
69
+ destination_buffer_length = BRS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_DECOMPRESSOR;
70
+ }
71
+
72
+ uint8_t* destination_buffer = malloc(destination_buffer_length);
73
+ if (destination_buffer == NULL) {
74
+ BrotliDecoderDestroyInstance(state_ptr);
75
+ brs_ext_raise_error(BRS_EXT_ERROR_ALLOCATE_FAILED);
76
+ }
77
+
78
+ decompressor_ptr->state_ptr = state_ptr;
79
+ decompressor_ptr->destination_buffer = destination_buffer;
80
+ decompressor_ptr->destination_buffer_length = destination_buffer_length;
81
+ decompressor_ptr->remaining_destination_buffer = destination_buffer;
82
+ decompressor_ptr->remaining_destination_buffer_length = destination_buffer_length;
83
+
84
+ return Qnil;
85
+ }
86
+
87
+ #define DO_NOT_USE_AFTER_CLOSE(decompressor_ptr) \
88
+ if (decompressor_ptr->state_ptr == NULL || decompressor_ptr->destination_buffer == NULL) { \
89
+ brs_ext_raise_error(BRS_EXT_ERROR_USED_AFTER_CLOSE); \
90
+ }
91
+
92
+ #define GET_SOURCE_DATA(source_value) \
93
+ Check_Type(source_value, T_STRING); \
94
+ \
95
+ const char* source = RSTRING_PTR(source_value); \
96
+ size_t source_length = RSTRING_LEN(source_value); \
97
+ const uint8_t* remaining_source = (const uint8_t*)source; \
98
+ size_t remaining_source_length = source_length;
99
+
100
+ VALUE brs_ext_decompress(VALUE self, VALUE source_value)
101
+ {
102
+ GET_DECOMPRESSOR(self);
103
+ DO_NOT_USE_AFTER_CLOSE(decompressor_ptr);
104
+ GET_SOURCE_DATA(source_value);
105
+
106
+ BrotliDecoderResult result = BrotliDecoderDecompressStream(
107
+ decompressor_ptr->state_ptr,
108
+ &remaining_source_length, &remaining_source,
109
+ &decompressor_ptr->remaining_destination_buffer_length, &decompressor_ptr->remaining_destination_buffer,
110
+ NULL);
111
+
112
+ if (
113
+ result != BROTLI_DECODER_RESULT_SUCCESS &&
114
+ result != BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT &&
115
+ result != BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
116
+ BrotliDecoderErrorCode error_code = BrotliDecoderGetErrorCode(decompressor_ptr->state_ptr);
117
+ brs_ext_raise_error(brs_ext_get_decompressor_error(error_code));
118
+ }
119
+
120
+ VALUE bytes_written = UINT2NUM(source_length - remaining_source_length);
121
+ VALUE needs_more_destination = result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT ? Qtrue : Qfalse;
122
+
123
+ return rb_ary_new_from_args(2, bytes_written, needs_more_destination);
124
+ }
125
+
126
+ VALUE brs_ext_decompressor_read_result(VALUE self)
127
+ {
128
+ GET_DECOMPRESSOR(self);
129
+ DO_NOT_USE_AFTER_CLOSE(decompressor_ptr);
130
+
131
+ uint8_t* destination_buffer = decompressor_ptr->destination_buffer;
132
+ size_t destination_buffer_length = decompressor_ptr->destination_buffer_length;
133
+ size_t remaining_destination_buffer_length = decompressor_ptr->remaining_destination_buffer_length;
134
+
135
+ const char* result = (const char*)destination_buffer;
136
+ size_t result_length = destination_buffer_length - remaining_destination_buffer_length;
137
+
138
+ VALUE result_value = rb_str_new(result, result_length);
139
+
140
+ decompressor_ptr->remaining_destination_buffer = destination_buffer;
141
+ decompressor_ptr->remaining_destination_buffer_length = destination_buffer_length;
142
+
143
+ return result_value;
144
+ }
145
+
146
+ VALUE brs_ext_decompressor_close(VALUE self)
147
+ {
148
+ GET_DECOMPRESSOR(self);
149
+ DO_NOT_USE_AFTER_CLOSE(decompressor_ptr);
150
+
151
+ BrotliDecoderState* state_ptr = decompressor_ptr->state_ptr;
152
+ if (state_ptr != NULL) {
153
+ BrotliDecoderDestroyInstance(state_ptr);
154
+
155
+ decompressor_ptr->state_ptr = NULL;
156
+ }
157
+
158
+ uint8_t* destination_buffer = decompressor_ptr->destination_buffer;
159
+ if (destination_buffer != NULL) {
160
+ free(destination_buffer);
161
+
162
+ decompressor_ptr->destination_buffer = NULL;
163
+ }
164
+
165
+ // It is possible to keep "destination_buffer_length", "remaining_destination_buffer"
166
+ // and "remaining_destination_buffer_length" as is.
167
+
168
+ return Qnil;
169
+ }
170
+
171
+ void brs_ext_decompressor_exports(VALUE root_module)
172
+ {
173
+ VALUE stream = rb_define_module_under(root_module, "Stream");
174
+
175
+ VALUE decompressor = rb_define_class_under(stream, "NativeDecompressor", rb_cObject);
176
+ rb_define_alloc_func(decompressor, brs_ext_allocate_decompressor);
177
+ rb_define_method(decompressor, "initialize", brs_ext_initialize_decompressor, 1);
178
+ rb_define_method(decompressor, "read", brs_ext_decompress, 1);
179
+ rb_define_method(decompressor, "read_result", brs_ext_decompressor_read_result, 0);
180
+ rb_define_method(decompressor, "close", brs_ext_decompressor_close, 0);
181
+ }
@@ -0,0 +1,29 @@
1
+ // Ruby bindings for brotli library.
2
+ // Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ #if !defined(BRS_EXT_STREAM_DECOMPRESSOR_H)
5
+ #define BRS_EXT_STREAM_DECOMPRESSOR_H
6
+
7
+ #include <brotli/decode.h>
8
+ #include <stdint.h>
9
+ #include <stdlib.h>
10
+
11
+ #include "ruby.h"
12
+
13
+ typedef struct {
14
+ BrotliDecoderState* state_ptr;
15
+ uint8_t* destination_buffer;
16
+ size_t destination_buffer_length;
17
+ uint8_t* remaining_destination_buffer;
18
+ size_t remaining_destination_buffer_length;
19
+ } brs_ext_decompressor_t;
20
+
21
+ VALUE brs_ext_allocate_decompressor(VALUE klass);
22
+ VALUE brs_ext_initialize_decompressor(VALUE self, VALUE options);
23
+ VALUE brs_ext_decompress(VALUE self, VALUE source);
24
+ VALUE brs_ext_decompressor_read_result(VALUE self);
25
+ VALUE brs_ext_decompressor_close(VALUE self);
26
+
27
+ void brs_ext_decompressor_exports(VALUE root_module);
28
+
29
+ #endif // BRS_EXT_STREAM_DECOMPRESSOR_H