ruby-zstds 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/AUTHORS +1 -0
  3. data/LICENSE +21 -0
  4. data/README.md +498 -0
  5. data/ext/extconf.rb +82 -0
  6. data/ext/zstds_ext/buffer.c +30 -0
  7. data/ext/zstds_ext/buffer.h +23 -0
  8. data/ext/zstds_ext/common.h +16 -0
  9. data/ext/zstds_ext/dictionary.c +106 -0
  10. data/ext/zstds_ext/dictionary.h +16 -0
  11. data/ext/zstds_ext/error.c +81 -0
  12. data/ext/zstds_ext/error.h +35 -0
  13. data/ext/zstds_ext/io.c +512 -0
  14. data/ext/zstds_ext/io.h +14 -0
  15. data/ext/zstds_ext/macro.h +13 -0
  16. data/ext/zstds_ext/main.c +25 -0
  17. data/ext/zstds_ext/option.c +287 -0
  18. data/ext/zstds_ext/option.h +122 -0
  19. data/ext/zstds_ext/stream/compressor.c +241 -0
  20. data/ext/zstds_ext/stream/compressor.h +31 -0
  21. data/ext/zstds_ext/stream/decompressor.c +183 -0
  22. data/ext/zstds_ext/stream/decompressor.h +29 -0
  23. data/ext/zstds_ext/string.c +254 -0
  24. data/ext/zstds_ext/string.h +14 -0
  25. data/lib/zstds.rb +9 -0
  26. data/lib/zstds/dictionary.rb +47 -0
  27. data/lib/zstds/error.rb +22 -0
  28. data/lib/zstds/file.rb +46 -0
  29. data/lib/zstds/option.rb +194 -0
  30. data/lib/zstds/stream/abstract.rb +153 -0
  31. data/lib/zstds/stream/delegates.rb +36 -0
  32. data/lib/zstds/stream/raw/abstract.rb +55 -0
  33. data/lib/zstds/stream/raw/compressor.rb +101 -0
  34. data/lib/zstds/stream/raw/decompressor.rb +70 -0
  35. data/lib/zstds/stream/reader.rb +166 -0
  36. data/lib/zstds/stream/reader_helpers.rb +192 -0
  37. data/lib/zstds/stream/stat.rb +78 -0
  38. data/lib/zstds/stream/writer.rb +145 -0
  39. data/lib/zstds/stream/writer_helpers.rb +93 -0
  40. data/lib/zstds/string.rb +31 -0
  41. data/lib/zstds/validation.rb +48 -0
  42. data/lib/zstds/version.rb +6 -0
  43. metadata +182 -0
@@ -0,0 +1,241 @@
1
+ // Ruby bindings for zstd library.
2
+ // Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ #include "zstds_ext/stream/compressor.h"
5
+
6
+ #include <stdint.h>
7
+ #include <stdlib.h>
8
+ #include <zstd.h>
9
+
10
+ #include "ruby.h"
11
+ #include "zstds_ext/common.h"
12
+ #include "zstds_ext/error.h"
13
+ #include "zstds_ext/option.h"
14
+
15
+ static void free_compressor(zstds_ext_compressor_t* compressor_ptr)
16
+ {
17
+ ZSTD_CCtx* ctx = compressor_ptr->ctx;
18
+ if (ctx != NULL) {
19
+ ZSTD_freeCCtx(ctx);
20
+ }
21
+
22
+ uint8_t* destination_buffer = compressor_ptr->destination_buffer;
23
+ if (destination_buffer != NULL) {
24
+ free(destination_buffer);
25
+ }
26
+
27
+ free(compressor_ptr);
28
+ }
29
+
30
+ VALUE zstds_ext_allocate_compressor(VALUE klass)
31
+ {
32
+ zstds_ext_compressor_t* compressor_ptr;
33
+
34
+ VALUE self = Data_Make_Struct(klass, zstds_ext_compressor_t, NULL, free_compressor, compressor_ptr);
35
+
36
+ compressor_ptr->ctx = NULL;
37
+ compressor_ptr->destination_buffer = NULL;
38
+ compressor_ptr->destination_buffer_length = 0;
39
+ compressor_ptr->remaining_destination_buffer = NULL;
40
+ compressor_ptr->remaining_destination_buffer_length = 0;
41
+
42
+ return self;
43
+ }
44
+
45
+ #define GET_COMPRESSOR(self) \
46
+ zstds_ext_compressor_t* compressor_ptr; \
47
+ Data_Get_Struct(self, zstds_ext_compressor_t, compressor_ptr);
48
+
49
+ VALUE zstds_ext_initialize_compressor(VALUE self, VALUE options)
50
+ {
51
+ GET_COMPRESSOR(self);
52
+ Check_Type(options, T_HASH);
53
+ ZSTDS_EXT_GET_COMPRESSOR_OPTIONS(options);
54
+ ZSTDS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
55
+
56
+ ZSTD_CCtx* ctx = ZSTD_createCCtx();
57
+ if (ctx == NULL) {
58
+ zstds_ext_raise_error(ZSTDS_EXT_ERROR_ALLOCATE_FAILED);
59
+ }
60
+
61
+ zstds_ext_result_t ext_result = zstds_ext_set_compressor_options(ctx, &compressor_options);
62
+ if (ext_result != 0) {
63
+ ZSTD_freeCCtx(ctx);
64
+ zstds_ext_raise_error(ext_result);
65
+ }
66
+
67
+ if (destination_buffer_length == 0) {
68
+ destination_buffer_length = ZSTD_CStreamOutSize();
69
+ }
70
+
71
+ uint8_t* destination_buffer = malloc(destination_buffer_length);
72
+ if (destination_buffer == NULL) {
73
+ ZSTD_freeCCtx(ctx);
74
+ zstds_ext_raise_error(ZSTDS_EXT_ERROR_ALLOCATE_FAILED);
75
+ }
76
+
77
+ compressor_ptr->ctx = ctx;
78
+ compressor_ptr->destination_buffer = destination_buffer;
79
+ compressor_ptr->destination_buffer_length = destination_buffer_length;
80
+ compressor_ptr->remaining_destination_buffer = destination_buffer;
81
+ compressor_ptr->remaining_destination_buffer_length = destination_buffer_length;
82
+
83
+ return Qnil;
84
+ }
85
+
86
+ #define DO_NOT_USE_AFTER_CLOSE(compressor_ptr) \
87
+ if (compressor_ptr->ctx == NULL || compressor_ptr->destination_buffer == NULL) { \
88
+ zstds_ext_raise_error(ZSTDS_EXT_ERROR_USED_AFTER_CLOSE); \
89
+ }
90
+
91
+ #define GET_SOURCE_DATA(source_value) \
92
+ Check_Type(source_value, T_STRING); \
93
+ \
94
+ const char* source = RSTRING_PTR(source_value); \
95
+ size_t source_length = RSTRING_LEN(source_value);
96
+
97
+ VALUE zstds_ext_compress(VALUE self, VALUE source_value)
98
+ {
99
+ GET_COMPRESSOR(self);
100
+ DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
101
+ GET_SOURCE_DATA(source_value);
102
+
103
+ ZSTD_inBuffer in_buffer;
104
+ in_buffer.src = source;
105
+ in_buffer.size = source_length;
106
+ in_buffer.pos = 0;
107
+
108
+ ZSTD_outBuffer out_buffer;
109
+ out_buffer.dst = compressor_ptr->remaining_destination_buffer;
110
+ out_buffer.size = compressor_ptr->remaining_destination_buffer_length;
111
+ out_buffer.pos = 0;
112
+
113
+ zstds_result_t result = ZSTD_compressStream2(compressor_ptr->ctx, &out_buffer, &in_buffer, ZSTD_e_continue);
114
+ if (ZSTD_isError(result)) {
115
+ zstds_ext_raise_error(zstds_ext_get_error(ZSTD_getErrorCode(result)));
116
+ }
117
+
118
+ compressor_ptr->remaining_destination_buffer += out_buffer.pos;
119
+ compressor_ptr->remaining_destination_buffer_length -= out_buffer.pos;
120
+
121
+ VALUE bytes_written = SIZET2NUM(in_buffer.pos);
122
+ VALUE needs_more_destination = compressor_ptr->remaining_destination_buffer_length == 0 ? Qtrue : Qfalse;
123
+
124
+ return rb_ary_new_from_args(2, bytes_written, needs_more_destination);
125
+ }
126
+
127
+ VALUE zstds_ext_flush_compressor(VALUE self)
128
+ {
129
+ GET_COMPRESSOR(self);
130
+ DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
131
+
132
+ ZSTD_inBuffer in_buffer;
133
+ in_buffer.src = NULL;
134
+ in_buffer.size = 0;
135
+ in_buffer.pos = 0;
136
+
137
+ ZSTD_outBuffer out_buffer;
138
+ out_buffer.dst = compressor_ptr->remaining_destination_buffer;
139
+ out_buffer.size = compressor_ptr->remaining_destination_buffer_length;
140
+ out_buffer.pos = 0;
141
+
142
+ zstds_result_t result = ZSTD_compressStream2(compressor_ptr->ctx, &out_buffer, &in_buffer, ZSTD_e_flush);
143
+ if (ZSTD_isError(result)) {
144
+ zstds_ext_raise_error(zstds_ext_get_error(ZSTD_getErrorCode(result)));
145
+ }
146
+
147
+ compressor_ptr->remaining_destination_buffer += out_buffer.pos;
148
+ compressor_ptr->remaining_destination_buffer_length -= out_buffer.pos;
149
+
150
+ VALUE needs_more_destination = result != 0 ? Qtrue : Qfalse;
151
+
152
+ return needs_more_destination;
153
+ }
154
+
155
+ VALUE zstds_ext_finish_compressor(VALUE self)
156
+ {
157
+ GET_COMPRESSOR(self);
158
+ DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
159
+
160
+ ZSTD_inBuffer in_buffer;
161
+ in_buffer.src = NULL;
162
+ in_buffer.size = 0;
163
+ in_buffer.pos = 0;
164
+
165
+ ZSTD_outBuffer out_buffer;
166
+ out_buffer.dst = compressor_ptr->remaining_destination_buffer;
167
+ out_buffer.size = compressor_ptr->remaining_destination_buffer_length;
168
+ out_buffer.pos = 0;
169
+
170
+ zstds_result_t result = ZSTD_compressStream2(compressor_ptr->ctx, &out_buffer, &in_buffer, ZSTD_e_end);
171
+ if (ZSTD_isError(result)) {
172
+ zstds_ext_raise_error(zstds_ext_get_error(ZSTD_getErrorCode(result)));
173
+ }
174
+
175
+ compressor_ptr->remaining_destination_buffer += out_buffer.pos;
176
+ compressor_ptr->remaining_destination_buffer_length -= out_buffer.pos;
177
+
178
+ VALUE needs_more_destination = result != 0 ? Qtrue : Qfalse;
179
+
180
+ return needs_more_destination;
181
+ }
182
+
183
+ VALUE zstds_ext_compressor_read_result(VALUE self)
184
+ {
185
+ GET_COMPRESSOR(self);
186
+ DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
187
+
188
+ uint8_t* destination_buffer = compressor_ptr->destination_buffer;
189
+ size_t destination_buffer_length = compressor_ptr->destination_buffer_length;
190
+ size_t remaining_destination_buffer_length = compressor_ptr->remaining_destination_buffer_length;
191
+
192
+ const char* result = (const char*)destination_buffer;
193
+ size_t result_length = destination_buffer_length - remaining_destination_buffer_length;
194
+
195
+ VALUE result_value = rb_str_new(result, result_length);
196
+
197
+ compressor_ptr->remaining_destination_buffer = destination_buffer;
198
+ compressor_ptr->remaining_destination_buffer_length = destination_buffer_length;
199
+
200
+ return result_value;
201
+ }
202
+
203
+ VALUE zstds_ext_compressor_close(VALUE self)
204
+ {
205
+ GET_COMPRESSOR(self);
206
+ DO_NOT_USE_AFTER_CLOSE(compressor_ptr);
207
+
208
+ ZSTD_CCtx* ctx = compressor_ptr->ctx;
209
+ if (ctx != NULL) {
210
+ ZSTD_freeCCtx(ctx);
211
+
212
+ compressor_ptr->ctx = NULL;
213
+ }
214
+
215
+ uint8_t* destination_buffer = compressor_ptr->destination_buffer;
216
+ if (destination_buffer != NULL) {
217
+ free(destination_buffer);
218
+
219
+ compressor_ptr->destination_buffer = NULL;
220
+ }
221
+
222
+ // It is possible to keep "destination_buffer_length", "remaining_destination_buffer"
223
+ // and "remaining_destination_buffer_length" as is.
224
+
225
+ return Qnil;
226
+ }
227
+
228
+ void zstds_ext_compressor_exports(VALUE root_module)
229
+ {
230
+ VALUE module = rb_define_module_under(root_module, "Stream");
231
+
232
+ VALUE compressor = rb_define_class_under(module, "NativeCompressor", rb_cObject);
233
+
234
+ rb_define_alloc_func(compressor, zstds_ext_allocate_compressor);
235
+ rb_define_method(compressor, "initialize", zstds_ext_initialize_compressor, 1);
236
+ rb_define_method(compressor, "write", zstds_ext_compress, 1);
237
+ rb_define_method(compressor, "flush", zstds_ext_flush_compressor, 0);
238
+ rb_define_method(compressor, "finish", zstds_ext_finish_compressor, 0);
239
+ rb_define_method(compressor, "read_result", zstds_ext_compressor_read_result, 0);
240
+ rb_define_method(compressor, "close", zstds_ext_compressor_close, 0);
241
+ }
@@ -0,0 +1,31 @@
1
+ // Ruby bindings for zstd library.
2
+ // Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ #if !defined(ZSTDS_EXT_STREAM_COMPRESSOR_H)
5
+ #define ZSTDS_EXT_STREAM_COMPRESSOR_H
6
+
7
+ #include <stdint.h>
8
+ #include <stdlib.h>
9
+ #include <zstd.h>
10
+
11
+ #include "ruby.h"
12
+
13
+ typedef struct {
14
+ ZSTD_CCtx* ctx;
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
+ } zstds_ext_compressor_t;
20
+
21
+ VALUE zstds_ext_allocate_compressor(VALUE klass);
22
+ VALUE zstds_ext_initialize_compressor(VALUE self, VALUE options);
23
+ VALUE zstds_ext_compress(VALUE self, VALUE source);
24
+ VALUE zstds_ext_flush_compressor(VALUE self);
25
+ VALUE zstds_ext_finish_compressor(VALUE self);
26
+ VALUE zstds_ext_compressor_read_result(VALUE self);
27
+ VALUE zstds_ext_compressor_close(VALUE self);
28
+
29
+ void zstds_ext_compressor_exports(VALUE root_module);
30
+
31
+ #endif // ZSTDS_EXT_STREAM_COMPRESSOR_H
@@ -0,0 +1,183 @@
1
+ // Ruby bindings for zstd library.
2
+ // Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ #include "zstds_ext/stream/decompressor.h"
5
+
6
+ #include <stdint.h>
7
+ #include <stdlib.h>
8
+ #include <zstd.h>
9
+
10
+ #include "ruby.h"
11
+ #include "zstds_ext/common.h"
12
+ #include "zstds_ext/error.h"
13
+ #include "zstds_ext/option.h"
14
+
15
+ static void free_decompressor(zstds_ext_decompressor_t* decompressor_ptr)
16
+ {
17
+ ZSTD_DCtx* ctx = decompressor_ptr->ctx;
18
+ if (ctx != NULL) {
19
+ ZSTD_freeDCtx(ctx);
20
+ }
21
+
22
+ uint8_t* destination_buffer = decompressor_ptr->destination_buffer;
23
+ if (destination_buffer != NULL) {
24
+ free(destination_buffer);
25
+ }
26
+
27
+ free(decompressor_ptr);
28
+ }
29
+
30
+ VALUE zstds_ext_allocate_decompressor(VALUE klass)
31
+ {
32
+ zstds_ext_decompressor_t* decompressor_ptr;
33
+
34
+ VALUE self = Data_Make_Struct(klass, zstds_ext_decompressor_t, NULL, free_decompressor, decompressor_ptr);
35
+
36
+ decompressor_ptr->ctx = NULL;
37
+ decompressor_ptr->destination_buffer = NULL;
38
+ decompressor_ptr->destination_buffer_length = 0;
39
+ decompressor_ptr->remaining_destination_buffer = NULL;
40
+ decompressor_ptr->remaining_destination_buffer_length = 0;
41
+
42
+ return self;
43
+ }
44
+
45
+ #define GET_DECOMPRESSOR(self) \
46
+ zstds_ext_decompressor_t* decompressor_ptr; \
47
+ Data_Get_Struct(self, zstds_ext_decompressor_t, decompressor_ptr);
48
+
49
+ VALUE zstds_ext_initialize_decompressor(VALUE self, VALUE options)
50
+ {
51
+ GET_DECOMPRESSOR(self);
52
+ Check_Type(options, T_HASH);
53
+ ZSTDS_EXT_GET_DECOMPRESSOR_OPTIONS(options);
54
+ ZSTDS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
55
+
56
+ ZSTD_DCtx* ctx = ZSTD_createDCtx();
57
+ if (ctx == NULL) {
58
+ zstds_ext_raise_error(ZSTDS_EXT_ERROR_ALLOCATE_FAILED);
59
+ }
60
+
61
+ zstds_ext_result_t ext_result = zstds_ext_set_decompressor_options(ctx, &decompressor_options);
62
+ if (ext_result != 0) {
63
+ ZSTD_freeDCtx(ctx);
64
+ zstds_ext_raise_error(ext_result);
65
+ }
66
+
67
+ if (destination_buffer_length == 0) {
68
+ destination_buffer_length = ZSTD_DStreamOutSize();
69
+ }
70
+
71
+ uint8_t* destination_buffer = malloc(destination_buffer_length);
72
+ if (destination_buffer == NULL) {
73
+ ZSTD_freeDCtx(ctx);
74
+ zstds_ext_raise_error(ZSTDS_EXT_ERROR_ALLOCATE_FAILED);
75
+ }
76
+
77
+ decompressor_ptr->ctx = ctx;
78
+ decompressor_ptr->destination_buffer = destination_buffer;
79
+ decompressor_ptr->destination_buffer_length = destination_buffer_length;
80
+ decompressor_ptr->remaining_destination_buffer = destination_buffer;
81
+ decompressor_ptr->remaining_destination_buffer_length = destination_buffer_length;
82
+
83
+ return Qnil;
84
+ }
85
+
86
+ #define DO_NOT_USE_AFTER_CLOSE(decompressor_ptr) \
87
+ if (decompressor_ptr->ctx == NULL || decompressor_ptr->destination_buffer == NULL) { \
88
+ zstds_ext_raise_error(ZSTDS_EXT_ERROR_USED_AFTER_CLOSE); \
89
+ }
90
+
91
+ #define GET_SOURCE_DATA(source_value) \
92
+ Check_Type(source_value, T_STRING); \
93
+ \
94
+ const char* source = RSTRING_PTR(source_value); \
95
+ size_t source_length = RSTRING_LEN(source_value);
96
+
97
+ VALUE zstds_ext_decompress(VALUE self, VALUE source_value)
98
+ {
99
+ GET_DECOMPRESSOR(self);
100
+ DO_NOT_USE_AFTER_CLOSE(decompressor_ptr);
101
+ GET_SOURCE_DATA(source_value);
102
+
103
+ ZSTD_inBuffer in_buffer;
104
+ in_buffer.src = source;
105
+ in_buffer.size = source_length;
106
+ in_buffer.pos = 0;
107
+
108
+ ZSTD_outBuffer out_buffer;
109
+ out_buffer.dst = decompressor_ptr->remaining_destination_buffer;
110
+ out_buffer.size = decompressor_ptr->remaining_destination_buffer_length;
111
+ out_buffer.pos = 0;
112
+
113
+ zstds_result_t result = ZSTD_decompressStream(decompressor_ptr->ctx, &out_buffer, &in_buffer);
114
+ if (ZSTD_isError(result)) {
115
+ zstds_ext_raise_error(zstds_ext_get_error(ZSTD_getErrorCode(result)));
116
+ }
117
+
118
+ decompressor_ptr->remaining_destination_buffer += out_buffer.pos;
119
+ decompressor_ptr->remaining_destination_buffer_length -= out_buffer.pos;
120
+
121
+ VALUE bytes_read = SIZET2NUM(in_buffer.pos);
122
+ VALUE needs_more_destination = decompressor_ptr->remaining_destination_buffer_length == 0 ? Qtrue : Qfalse;
123
+
124
+ return rb_ary_new_from_args(2, bytes_read, needs_more_destination);
125
+ }
126
+
127
+ VALUE zstds_ext_decompressor_read_result(VALUE self)
128
+ {
129
+ GET_DECOMPRESSOR(self);
130
+ DO_NOT_USE_AFTER_CLOSE(decompressor_ptr);
131
+
132
+ uint8_t* destination_buffer = decompressor_ptr->destination_buffer;
133
+ size_t destination_buffer_length = decompressor_ptr->destination_buffer_length;
134
+ size_t remaining_destination_buffer_length = decompressor_ptr->remaining_destination_buffer_length;
135
+
136
+ const char* result = (const char*)destination_buffer;
137
+ size_t result_length = destination_buffer_length - remaining_destination_buffer_length;
138
+
139
+ VALUE result_value = rb_str_new(result, result_length);
140
+
141
+ decompressor_ptr->remaining_destination_buffer = destination_buffer;
142
+ decompressor_ptr->remaining_destination_buffer_length = destination_buffer_length;
143
+
144
+ return result_value;
145
+ }
146
+
147
+ VALUE zstds_ext_decompressor_close(VALUE self)
148
+ {
149
+ GET_DECOMPRESSOR(self);
150
+ DO_NOT_USE_AFTER_CLOSE(decompressor_ptr);
151
+
152
+ ZSTD_DCtx* ctx = decompressor_ptr->ctx;
153
+ if (ctx != NULL) {
154
+ ZSTD_freeDCtx(ctx);
155
+
156
+ decompressor_ptr->ctx = NULL;
157
+ }
158
+
159
+ uint8_t* destination_buffer = decompressor_ptr->destination_buffer;
160
+ if (destination_buffer != NULL) {
161
+ free(destination_buffer);
162
+
163
+ decompressor_ptr->destination_buffer = NULL;
164
+ }
165
+
166
+ // It is possible to keep "destination_buffer_length", "remaining_destination_buffer"
167
+ // and "remaining_destination_buffer_length" as is.
168
+
169
+ return Qnil;
170
+ }
171
+
172
+ void zstds_ext_decompressor_exports(VALUE root_module)
173
+ {
174
+ VALUE module = rb_define_module_under(root_module, "Stream");
175
+
176
+ VALUE decompressor = rb_define_class_under(module, "NativeDecompressor", rb_cObject);
177
+
178
+ rb_define_alloc_func(decompressor, zstds_ext_allocate_decompressor);
179
+ rb_define_method(decompressor, "initialize", zstds_ext_initialize_decompressor, 1);
180
+ rb_define_method(decompressor, "read", zstds_ext_decompress, 1);
181
+ rb_define_method(decompressor, "read_result", zstds_ext_decompressor_read_result, 0);
182
+ rb_define_method(decompressor, "close", zstds_ext_decompressor_close, 0);
183
+ }