zstd-ruby 1.5.6.1 → 1.5.6.3
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 +4 -4
- data/README.md +40 -9
- data/ext/zstdruby/common.h +110 -1
- data/ext/zstdruby/extconf.rb +1 -1
- data/ext/zstdruby/main.c +2 -1
- data/ext/zstdruby/skippable_frame.c +1 -1
- data/ext/zstdruby/streaming_compress.c +52 -20
- data/ext/zstdruby/streaming_decompress.c +18 -37
- data/ext/zstdruby/zstdruby.c +59 -48
- data/lib/zstd-ruby/stream_reader.rb +22 -0
- data/lib/zstd-ruby/stream_writer.rb +23 -0
- data/lib/zstd-ruby/version.rb +1 -1
- data/zstd-ruby.gemspec +2 -1
- metadata +18 -3
- data/ext/zstdruby/streaming_compress.h +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 729474c9a3f3196fe69a06dfdd280c5879bc368b1884b8d508b75164aa7e1dcd
|
4
|
+
data.tar.gz: 1cdf1b0554dd89aa1f7b6450be8eb183773a0f3b895024715ae7b3243cec598b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d69bc35190b5dbc8ce36f9e5acf6ef26a2c85a899ddd409f8eee4a83b005166b20d22e2659cae1b101fb1b97f6a7bf12cf4066e3da94b2a1991d41bf255cd1ce
|
7
|
+
data.tar.gz: 2ee85e56a8ae268da1e4b69bf35a016a5d9bc677f240435725e082b5c5279e60d7f8be32dbe57283e618b7cf59b3937b57aa859f6cbb0aafa64458a903747fa2
|
data/README.md
CHANGED
@@ -34,20 +34,22 @@ Or install it yourself as:
|
|
34
34
|
require 'zstd-ruby'
|
35
35
|
```
|
36
36
|
|
37
|
-
###
|
37
|
+
### Compression
|
38
|
+
|
39
|
+
#### Simple Compression
|
38
40
|
|
39
41
|
```ruby
|
40
42
|
compressed_data = Zstd.compress(data)
|
41
|
-
compressed_data = Zstd.compress(data, complession_level) # default compression_level is
|
43
|
+
compressed_data = Zstd.compress(data, level: complession_level) # default compression_level is 3
|
42
44
|
```
|
43
45
|
|
44
|
-
|
46
|
+
#### Compression with Dictionary
|
45
47
|
```ruby
|
46
48
|
# dictionary is supposed to have been created using `zstd --train`
|
47
|
-
compressed_using_dict = Zstd.
|
49
|
+
compressed_using_dict = Zstd.compress("", dict: File.read('dictionary_file'))
|
48
50
|
```
|
49
51
|
|
50
|
-
|
52
|
+
#### Streaming Compression
|
51
53
|
```ruby
|
52
54
|
stream = Zstd::StreamingCompress.new
|
53
55
|
stream << "abc" << "def"
|
@@ -66,19 +68,39 @@ res << stream.compress("def")
|
|
66
68
|
res << stream.finish
|
67
69
|
```
|
68
70
|
|
69
|
-
|
71
|
+
#### Streaming Compression with Dictionary
|
72
|
+
```ruby
|
73
|
+
stream = Zstd::StreamingCompress.new(dict: File.read('dictionary_file'))
|
74
|
+
stream << "abc" << "def"
|
75
|
+
res = stream.flush
|
76
|
+
stream << "ghi"
|
77
|
+
res << stream.finish
|
78
|
+
```
|
79
|
+
|
80
|
+
#### Streaming Compression with level and Dictionary
|
81
|
+
```ruby
|
82
|
+
stream = Zstd::StreamingCompress.new(level: 5, dict: File.read('dictionary_file'))
|
83
|
+
stream << "abc" << "def"
|
84
|
+
res = stream.flush
|
85
|
+
stream << "ghi"
|
86
|
+
res << stream.finish
|
87
|
+
```
|
88
|
+
|
89
|
+
### Decompression
|
90
|
+
|
91
|
+
#### Simple Decompression
|
70
92
|
|
71
93
|
```ruby
|
72
94
|
data = Zstd.decompress(compressed_data)
|
73
95
|
```
|
74
96
|
|
75
|
-
|
97
|
+
#### Decompression with Dictionary
|
76
98
|
```ruby
|
77
99
|
# dictionary is supposed to have been created using `zstd --train`
|
78
|
-
Zstd.
|
100
|
+
Zstd.decompress(compressed_using_dict, dict: File.read('dictionary_file'))
|
79
101
|
```
|
80
102
|
|
81
|
-
|
103
|
+
#### Streaming Decompression
|
82
104
|
```ruby
|
83
105
|
cstr = "" # Compressed data
|
84
106
|
stream = Zstd::StreamingDecompress.new
|
@@ -87,6 +109,15 @@ result << stream.decompress(cstr[0, 10])
|
|
87
109
|
result << stream.decompress(cstr[10..-1])
|
88
110
|
```
|
89
111
|
|
112
|
+
#### Streaming Decompression with dictionary
|
113
|
+
```ruby
|
114
|
+
cstr = "" # Compressed data
|
115
|
+
stream = Zstd::StreamingDecompress.new(dict: File.read('dictionary_file'))
|
116
|
+
result = ''
|
117
|
+
result << stream.decompress(cstr[0, 10])
|
118
|
+
result << stream.decompress(cstr[10..-1])
|
119
|
+
```
|
120
|
+
|
90
121
|
### Skippable frame
|
91
122
|
|
92
123
|
```ruby
|
data/ext/zstdruby/common.h
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
#ifndef ZSTD_RUBY_H
|
2
2
|
#define ZSTD_RUBY_H 1
|
3
3
|
|
4
|
-
#include
|
4
|
+
#include <ruby.h>
|
5
|
+
#ifdef HAVE_RUBY_THREAD_H
|
6
|
+
#include <ruby/thread.h>
|
7
|
+
#endif
|
8
|
+
#include <stdbool.h>
|
5
9
|
#include "./libzstd/zstd.h"
|
6
10
|
|
7
11
|
static int convert_compression_level(VALUE compression_level_value)
|
@@ -12,4 +16,109 @@ static int convert_compression_level(VALUE compression_level_value)
|
|
12
16
|
return NUM2INT(compression_level_value);
|
13
17
|
}
|
14
18
|
|
19
|
+
static void set_compress_params(ZSTD_CCtx* const ctx, VALUE level_from_args, VALUE kwargs)
|
20
|
+
{
|
21
|
+
ID kwargs_keys[2];
|
22
|
+
kwargs_keys[0] = rb_intern("level");
|
23
|
+
kwargs_keys[1] = rb_intern("dict");
|
24
|
+
VALUE kwargs_values[2];
|
25
|
+
rb_get_kwargs(kwargs, kwargs_keys, 0, 2, kwargs_values);
|
26
|
+
|
27
|
+
int compression_level = ZSTD_CLEVEL_DEFAULT;
|
28
|
+
if (kwargs_values[0] != Qundef && kwargs_values[0] != Qnil) {
|
29
|
+
compression_level = convert_compression_level(kwargs_values[0]);
|
30
|
+
} else if (!NIL_P(level_from_args)) {
|
31
|
+
rb_warn("`level` in args is deprecated; use keyword args `level:` instead.");
|
32
|
+
compression_level = convert_compression_level(level_from_args);
|
33
|
+
}
|
34
|
+
ZSTD_CCtx_setParameter(ctx, ZSTD_c_compressionLevel, compression_level);
|
35
|
+
|
36
|
+
if (kwargs_values[1] != Qundef && kwargs_values[1] != Qnil) {
|
37
|
+
char* dict_buffer = RSTRING_PTR(kwargs_values[1]);
|
38
|
+
size_t dict_size = RSTRING_LEN(kwargs_values[1]);
|
39
|
+
size_t load_dict_ret = ZSTD_CCtx_loadDictionary(ctx, dict_buffer, dict_size);
|
40
|
+
if (ZSTD_isError(load_dict_ret)) {
|
41
|
+
ZSTD_freeCCtx(ctx);
|
42
|
+
rb_raise(rb_eRuntimeError, "%s", "ZSTD_CCtx_loadDictionary failed");
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
struct compress_params {
|
48
|
+
ZSTD_CCtx* ctx;
|
49
|
+
ZSTD_outBuffer* output;
|
50
|
+
ZSTD_inBuffer* input;
|
51
|
+
ZSTD_EndDirective endOp;
|
52
|
+
size_t ret;
|
53
|
+
};
|
54
|
+
|
55
|
+
static void* compress_wrapper(void* args)
|
56
|
+
{
|
57
|
+
struct compress_params* params = args;
|
58
|
+
params->ret = ZSTD_compressStream2(params->ctx, params->output, params->input, params->endOp);
|
59
|
+
return NULL;
|
60
|
+
}
|
61
|
+
|
62
|
+
static size_t zstd_compress(ZSTD_CCtx* const ctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input, ZSTD_EndDirective endOp, bool gvl)
|
63
|
+
{
|
64
|
+
#ifdef HAVE_RUBY_THREAD_H
|
65
|
+
if (gvl) {
|
66
|
+
return ZSTD_compressStream2(ctx, output, input, endOp);
|
67
|
+
} else {
|
68
|
+
struct compress_params params = { ctx, output, input, endOp };
|
69
|
+
rb_thread_call_without_gvl(compress_wrapper, ¶ms, NULL, NULL);
|
70
|
+
return params.ret;
|
71
|
+
}
|
72
|
+
#else
|
73
|
+
return ZSTD_compressStream2(ctx, output, input, endOp);
|
74
|
+
#endif
|
75
|
+
}
|
76
|
+
|
77
|
+
static void set_decompress_params(ZSTD_DCtx* const dctx, VALUE kwargs)
|
78
|
+
{
|
79
|
+
ID kwargs_keys[1];
|
80
|
+
kwargs_keys[0] = rb_intern("dict");
|
81
|
+
VALUE kwargs_values[1];
|
82
|
+
rb_get_kwargs(kwargs, kwargs_keys, 0, 1, kwargs_values);
|
83
|
+
|
84
|
+
if (kwargs_values[0] != Qundef && kwargs_values[0] != Qnil) {
|
85
|
+
char* dict_buffer = RSTRING_PTR(kwargs_values[0]);
|
86
|
+
size_t dict_size = RSTRING_LEN(kwargs_values[0]);
|
87
|
+
size_t load_dict_ret = ZSTD_DCtx_loadDictionary(dctx, dict_buffer, dict_size);
|
88
|
+
if (ZSTD_isError(load_dict_ret)) {
|
89
|
+
ZSTD_freeDCtx(dctx);
|
90
|
+
rb_raise(rb_eRuntimeError, "%s", "ZSTD_CCtx_loadDictionary failed");
|
91
|
+
}
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
struct decompress_params {
|
96
|
+
ZSTD_DCtx* dctx;
|
97
|
+
ZSTD_outBuffer* output;
|
98
|
+
ZSTD_inBuffer* input;
|
99
|
+
size_t ret;
|
100
|
+
};
|
101
|
+
|
102
|
+
static void* decompress_wrapper(void* args)
|
103
|
+
{
|
104
|
+
struct decompress_params* params = args;
|
105
|
+
params->ret = ZSTD_decompressStream(params->dctx, params->output, params->input);
|
106
|
+
return NULL;
|
107
|
+
}
|
108
|
+
|
109
|
+
static size_t zstd_decompress(ZSTD_DCtx* const dctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input, bool gvl)
|
110
|
+
{
|
111
|
+
#ifdef HAVE_RUBY_THREAD_H
|
112
|
+
if (gvl) {
|
113
|
+
return ZSTD_decompressStream(dctx, output, input);
|
114
|
+
} else {
|
115
|
+
struct decompress_params params = { dctx, output, input };
|
116
|
+
rb_thread_call_without_gvl(decompress_wrapper, ¶ms, NULL, NULL);
|
117
|
+
return params.ret;
|
118
|
+
}
|
119
|
+
#else
|
120
|
+
return ZSTD_decompressStream(dctx, output, input);
|
121
|
+
#endif
|
122
|
+
}
|
123
|
+
|
15
124
|
#endif /* ZSTD_RUBY_H */
|
data/ext/zstdruby/extconf.rb
CHANGED
@@ -2,7 +2,7 @@ require "mkmf"
|
|
2
2
|
|
3
3
|
have_func('rb_gc_mark_movable')
|
4
4
|
|
5
|
-
$CFLAGS = '-I. -O3 -std=c99 -DZSTD_STATIC_LINKING_ONLY'
|
5
|
+
$CFLAGS = '-I. -O3 -std=c99 -DZSTD_STATIC_LINKING_ONLY -DZSTD_MULTITHREAD -pthread -DDEBUGLEVEL=0'
|
6
6
|
$CPPFLAGS += " -fdeclspec" if CONFIG['CXX'] =~ /clang/
|
7
7
|
|
8
8
|
Dir.chdir File.expand_path('..', __FILE__) do
|
data/ext/zstdruby/main.c
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
#include
|
2
|
-
#include <streaming_compress.h>
|
1
|
+
#include "common.h"
|
3
2
|
|
4
3
|
struct streaming_compress_t {
|
5
4
|
ZSTD_CCtx* ctx;
|
@@ -71,9 +70,9 @@ rb_streaming_compress_allocate(VALUE klass)
|
|
71
70
|
static VALUE
|
72
71
|
rb_streaming_compress_initialize(int argc, VALUE *argv, VALUE obj)
|
73
72
|
{
|
73
|
+
VALUE kwargs;
|
74
74
|
VALUE compression_level_value;
|
75
|
-
rb_scan_args(argc, argv, "01", &compression_level_value);
|
76
|
-
int compression_level = convert_compression_level(compression_level_value);
|
75
|
+
rb_scan_args(argc, argv, "01:", &compression_level_value, &kwargs);
|
77
76
|
|
78
77
|
struct streaming_compress_t* sc;
|
79
78
|
TypedData_Get_Struct(obj, struct streaming_compress_t, &streaming_compress_type, sc);
|
@@ -83,7 +82,8 @@ rb_streaming_compress_initialize(int argc, VALUE *argv, VALUE obj)
|
|
83
82
|
if (ctx == NULL) {
|
84
83
|
rb_raise(rb_eRuntimeError, "%s", "ZSTD_createCCtx error");
|
85
84
|
}
|
86
|
-
|
85
|
+
set_compress_params(ctx, compression_level_value, kwargs);
|
86
|
+
|
87
87
|
sc->ctx = ctx;
|
88
88
|
sc->buf = rb_str_new(NULL, buffOutSize);
|
89
89
|
sc->buf_size = buffOutSize;
|
@@ -106,7 +106,7 @@ no_compress(struct streaming_compress_t* sc, ZSTD_EndDirective endOp)
|
|
106
106
|
do {
|
107
107
|
ZSTD_outBuffer output = { (void*)output_data, sc->buf_size, 0 };
|
108
108
|
|
109
|
-
size_t const ret =
|
109
|
+
size_t const ret = zstd_compress(sc->ctx, &output, &input, endOp, false);
|
110
110
|
if (ZSTD_isError(ret)) {
|
111
111
|
rb_raise(rb_eRuntimeError, "flush error error code: %s", ZSTD_getErrorName(ret));
|
112
112
|
}
|
@@ -125,11 +125,12 @@ rb_streaming_compress_compress(VALUE obj, VALUE src)
|
|
125
125
|
|
126
126
|
struct streaming_compress_t* sc;
|
127
127
|
TypedData_Get_Struct(obj, struct streaming_compress_t, &streaming_compress_type, sc);
|
128
|
+
|
128
129
|
const char* output_data = RSTRING_PTR(sc->buf);
|
129
130
|
VALUE result = rb_str_new(0, 0);
|
130
131
|
while (input.pos < input.size) {
|
131
132
|
ZSTD_outBuffer output = { (void*)output_data, sc->buf_size, 0 };
|
132
|
-
size_t const ret =
|
133
|
+
size_t const ret = zstd_compress(sc->ctx, &output, &input, ZSTD_e_continue, false);
|
133
134
|
if (ZSTD_isError(ret)) {
|
134
135
|
rb_raise(rb_eRuntimeError, "compress error error code: %s", ZSTD_getErrorName(ret));
|
135
136
|
}
|
@@ -139,27 +140,54 @@ rb_streaming_compress_compress(VALUE obj, VALUE src)
|
|
139
140
|
}
|
140
141
|
|
141
142
|
static VALUE
|
142
|
-
|
143
|
+
rb_streaming_compress_write(int argc, VALUE *argv, VALUE obj)
|
143
144
|
{
|
144
|
-
|
145
|
-
|
146
|
-
size_t input_size = RSTRING_LEN(src);
|
147
|
-
ZSTD_inBuffer input = { input_data, input_size, 0 };
|
148
|
-
|
145
|
+
size_t total = 0;
|
146
|
+
VALUE result = rb_str_new(0, 0);
|
149
147
|
struct streaming_compress_t* sc;
|
150
148
|
TypedData_Get_Struct(obj, struct streaming_compress_t, &streaming_compress_type, sc);
|
151
149
|
const char* output_data = RSTRING_PTR(sc->buf);
|
152
150
|
|
153
|
-
while (
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
151
|
+
while (argc-- > 0) {
|
152
|
+
VALUE str = *argv++;
|
153
|
+
StringValue(str);
|
154
|
+
const char* input_data = RSTRING_PTR(str);
|
155
|
+
size_t input_size = RSTRING_LEN(str);
|
156
|
+
ZSTD_inBuffer input = { input_data, input_size, 0 };
|
157
|
+
|
158
|
+
while (input.pos < input.size) {
|
159
|
+
ZSTD_outBuffer output = { (void*)output_data, sc->buf_size, 0 };
|
160
|
+
size_t const ret = zstd_compress(sc->ctx, &output, &input, ZSTD_e_continue, false);
|
161
|
+
if (ZSTD_isError(ret)) {
|
162
|
+
rb_raise(rb_eRuntimeError, "compress error error code: %s", ZSTD_getErrorName(ret));
|
163
|
+
}
|
164
|
+
total += RSTRING_LEN(str);
|
158
165
|
}
|
159
166
|
}
|
160
|
-
return
|
167
|
+
return SIZET2NUM(total);
|
161
168
|
}
|
162
169
|
|
170
|
+
/*
|
171
|
+
* Document-method: <<
|
172
|
+
* Same as IO.
|
173
|
+
*/
|
174
|
+
#define rb_streaming_compress_addstr rb_io_addstr
|
175
|
+
/*
|
176
|
+
* Document-method: printf
|
177
|
+
* Same as IO.
|
178
|
+
*/
|
179
|
+
#define rb_streaming_compress_printf rb_io_printf
|
180
|
+
/*
|
181
|
+
* Document-method: print
|
182
|
+
* Same as IO.
|
183
|
+
*/
|
184
|
+
#define rb_streaming_compress_print rb_io_print
|
185
|
+
/*
|
186
|
+
* Document-method: puts
|
187
|
+
* Same as IO.
|
188
|
+
*/
|
189
|
+
#define rb_streaming_compress_puts rb_io_puts
|
190
|
+
|
163
191
|
static VALUE
|
164
192
|
rb_streaming_compress_flush(VALUE obj)
|
165
193
|
{
|
@@ -186,7 +214,12 @@ zstd_ruby_streaming_compress_init(void)
|
|
186
214
|
rb_define_alloc_func(cStreamingCompress, rb_streaming_compress_allocate);
|
187
215
|
rb_define_method(cStreamingCompress, "initialize", rb_streaming_compress_initialize, -1);
|
188
216
|
rb_define_method(cStreamingCompress, "compress", rb_streaming_compress_compress, 1);
|
217
|
+
rb_define_method(cStreamingCompress, "write", rb_streaming_compress_write, -1);
|
189
218
|
rb_define_method(cStreamingCompress, "<<", rb_streaming_compress_addstr, 1);
|
219
|
+
rb_define_method(cStreamingCompress, "printf", rb_streaming_compress_printf, -1);
|
220
|
+
rb_define_method(cStreamingCompress, "print", rb_streaming_compress_print, -1);
|
221
|
+
rb_define_method(cStreamingCompress, "puts", rb_streaming_compress_puts, -1);
|
222
|
+
|
190
223
|
rb_define_method(cStreamingCompress, "flush", rb_streaming_compress_flush, 0);
|
191
224
|
rb_define_method(cStreamingCompress, "finish", rb_streaming_compress_finish, 0);
|
192
225
|
|
@@ -194,4 +227,3 @@ zstd_ruby_streaming_compress_init(void)
|
|
194
227
|
rb_define_const(cStreamingCompress, "FLUSH", INT2FIX(ZSTD_e_flush));
|
195
228
|
rb_define_const(cStreamingCompress, "END", INT2FIX(ZSTD_e_end));
|
196
229
|
}
|
197
|
-
|
@@ -1,7 +1,7 @@
|
|
1
|
-
#include
|
1
|
+
#include "common.h"
|
2
2
|
|
3
3
|
struct streaming_decompress_t {
|
4
|
-
ZSTD_DCtx*
|
4
|
+
ZSTD_DCtx* dctx;
|
5
5
|
VALUE buf;
|
6
6
|
size_t buf_size;
|
7
7
|
};
|
@@ -21,9 +21,9 @@ static void
|
|
21
21
|
streaming_decompress_free(void *p)
|
22
22
|
{
|
23
23
|
struct streaming_decompress_t *sd = p;
|
24
|
-
ZSTD_DCtx*
|
25
|
-
if (
|
26
|
-
ZSTD_freeDCtx(
|
24
|
+
ZSTD_DCtx* dctx = sd->dctx;
|
25
|
+
if (dctx != NULL) {
|
26
|
+
ZSTD_freeDCtx(dctx);
|
27
27
|
}
|
28
28
|
xfree(sd);
|
29
29
|
}
|
@@ -61,24 +61,29 @@ rb_streaming_decompress_allocate(VALUE klass)
|
|
61
61
|
{
|
62
62
|
struct streaming_decompress_t* sd;
|
63
63
|
VALUE obj = TypedData_Make_Struct(klass, struct streaming_decompress_t, &streaming_decompress_type, sd);
|
64
|
-
sd->
|
64
|
+
sd->dctx = NULL;
|
65
65
|
sd->buf = Qnil;
|
66
66
|
sd->buf_size = 0;
|
67
67
|
return obj;
|
68
68
|
}
|
69
69
|
|
70
70
|
static VALUE
|
71
|
-
rb_streaming_decompress_initialize(VALUE obj)
|
71
|
+
rb_streaming_decompress_initialize(int argc, VALUE *argv, VALUE obj)
|
72
72
|
{
|
73
|
+
VALUE kwargs;
|
74
|
+
rb_scan_args(argc, argv, "00:", &kwargs);
|
75
|
+
|
73
76
|
struct streaming_decompress_t* sd;
|
74
77
|
TypedData_Get_Struct(obj, struct streaming_decompress_t, &streaming_decompress_type, sd);
|
75
78
|
size_t const buffOutSize = ZSTD_DStreamOutSize();
|
76
79
|
|
77
|
-
ZSTD_DCtx*
|
78
|
-
if (
|
80
|
+
ZSTD_DCtx* dctx = ZSTD_createDCtx();
|
81
|
+
if (dctx == NULL) {
|
79
82
|
rb_raise(rb_eRuntimeError, "%s", "ZSTD_createDCtx error");
|
80
83
|
}
|
81
|
-
|
84
|
+
set_decompress_params(dctx, kwargs);
|
85
|
+
|
86
|
+
sd->dctx = dctx;
|
82
87
|
sd->buf = rb_str_new(NULL, buffOutSize);
|
83
88
|
sd->buf_size = buffOutSize;
|
84
89
|
|
@@ -99,45 +104,21 @@ rb_streaming_decompress_decompress(VALUE obj, VALUE src)
|
|
99
104
|
VALUE result = rb_str_new(0, 0);
|
100
105
|
while (input.pos < input.size) {
|
101
106
|
ZSTD_outBuffer output = { (void*)output_data, sd->buf_size, 0 };
|
102
|
-
size_t const ret =
|
107
|
+
size_t const ret = zstd_decompress(sd->dctx, &output, &input, false);
|
103
108
|
if (ZSTD_isError(ret)) {
|
104
|
-
rb_raise(rb_eRuntimeError, "
|
109
|
+
rb_raise(rb_eRuntimeError, "decompress error error code: %s", ZSTD_getErrorName(ret));
|
105
110
|
}
|
106
111
|
rb_str_cat(result, output.dst, output.pos);
|
107
112
|
}
|
108
113
|
return result;
|
109
114
|
}
|
110
115
|
|
111
|
-
static VALUE
|
112
|
-
rb_streaming_decompress_addstr(VALUE obj, VALUE src)
|
113
|
-
{
|
114
|
-
StringValue(src);
|
115
|
-
const char* input_data = RSTRING_PTR(src);
|
116
|
-
size_t input_size = RSTRING_LEN(src);
|
117
|
-
ZSTD_inBuffer input = { input_data, input_size, 0 };
|
118
|
-
|
119
|
-
struct streaming_decompress_t* sd;
|
120
|
-
TypedData_Get_Struct(obj, struct streaming_decompress_t, &streaming_decompress_type, sd);
|
121
|
-
const char* output_data = RSTRING_PTR(sd->buf);
|
122
|
-
|
123
|
-
while (input.pos < input.size) {
|
124
|
-
ZSTD_outBuffer output = { (void*)output_data, sd->buf_size, 0 };
|
125
|
-
size_t const result = ZSTD_decompressStream(sd->ctx, &output, &input);
|
126
|
-
if (ZSTD_isError(result)) {
|
127
|
-
rb_raise(rb_eRuntimeError, "compress error error code: %s", ZSTD_getErrorName(result));
|
128
|
-
}
|
129
|
-
}
|
130
|
-
return obj;
|
131
|
-
}
|
132
|
-
|
133
116
|
extern VALUE rb_mZstd, cStreamingDecompress;
|
134
117
|
void
|
135
118
|
zstd_ruby_streaming_decompress_init(void)
|
136
119
|
{
|
137
120
|
VALUE cStreamingDecompress = rb_define_class_under(rb_mZstd, "StreamingDecompress", rb_cObject);
|
138
121
|
rb_define_alloc_func(cStreamingDecompress, rb_streaming_decompress_allocate);
|
139
|
-
rb_define_method(cStreamingDecompress, "initialize", rb_streaming_decompress_initialize,
|
122
|
+
rb_define_method(cStreamingDecompress, "initialize", rb_streaming_decompress_initialize, -1);
|
140
123
|
rb_define_method(cStreamingDecompress, "decompress", rb_streaming_decompress_decompress, 1);
|
141
|
-
rb_define_method(cStreamingDecompress, "<<", rb_streaming_decompress_addstr, 1);
|
142
124
|
}
|
143
|
-
|
data/ext/zstdruby/zstdruby.c
CHANGED
@@ -12,28 +12,40 @@ static VALUE rb_compress(int argc, VALUE *argv, VALUE self)
|
|
12
12
|
{
|
13
13
|
VALUE input_value;
|
14
14
|
VALUE compression_level_value;
|
15
|
-
|
16
|
-
|
15
|
+
VALUE kwargs;
|
16
|
+
rb_scan_args(argc, argv, "11:", &input_value, &compression_level_value, &kwargs);
|
17
|
+
|
18
|
+
ZSTD_CCtx* const ctx = ZSTD_createCCtx();
|
19
|
+
if (ctx == NULL) {
|
20
|
+
rb_raise(rb_eRuntimeError, "%s", "ZSTD_createCCtx error");
|
21
|
+
}
|
22
|
+
|
23
|
+
set_compress_params(ctx, compression_level_value, kwargs);
|
17
24
|
|
18
25
|
StringValue(input_value);
|
19
26
|
char* input_data = RSTRING_PTR(input_value);
|
20
27
|
size_t input_size = RSTRING_LEN(input_value);
|
28
|
+
ZSTD_inBuffer input = { input_data, input_size, 0 };
|
29
|
+
// ZSTD_compressBound causes SEGV under multi-thread
|
21
30
|
size_t max_compressed_size = ZSTD_compressBound(input_size);
|
31
|
+
VALUE buf = rb_str_new(NULL, max_compressed_size);
|
32
|
+
char* output_data = RSTRING_PTR(buf);
|
33
|
+
ZSTD_outBuffer output = { (void*)output_data, max_compressed_size, 0 };
|
22
34
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
if (ZSTD_isError(compressed_size)) {
|
28
|
-
rb_raise(rb_eRuntimeError, "%s: %s", "compress failed", ZSTD_getErrorName(compressed_size));
|
35
|
+
size_t const ret = zstd_compress(ctx, &output, &input, ZSTD_e_end, true);
|
36
|
+
if (ZSTD_isError(ret)) {
|
37
|
+
ZSTD_freeCCtx(ctx);
|
38
|
+
rb_raise(rb_eRuntimeError, "%s: %s", "compress failed", ZSTD_getErrorName(ret));
|
29
39
|
}
|
30
|
-
|
31
|
-
|
32
|
-
|
40
|
+
VALUE result = rb_str_new(0, 0);
|
41
|
+
rb_str_cat(result, output.dst, output.pos);
|
42
|
+
ZSTD_freeCCtx(ctx);
|
43
|
+
return result;
|
33
44
|
}
|
34
45
|
|
35
46
|
static VALUE rb_compress_using_dict(int argc, VALUE *argv, VALUE self)
|
36
47
|
{
|
48
|
+
rb_warn("Zstd.compress_using_dict is deprecated; use Zstd.compress with `dict:` instead.");
|
37
49
|
VALUE input_value;
|
38
50
|
VALUE dict;
|
39
51
|
VALUE compression_level_value;
|
@@ -76,61 +88,56 @@ static VALUE rb_compress_using_dict(int argc, VALUE *argv, VALUE self)
|
|
76
88
|
}
|
77
89
|
|
78
90
|
|
79
|
-
static VALUE decompress_buffered(const char* input_data, size_t input_size)
|
91
|
+
static VALUE decompress_buffered(ZSTD_DCtx* dctx, const char* input_data, size_t input_size)
|
80
92
|
{
|
81
|
-
const size_t outputBufferSize = 4096;
|
82
|
-
|
83
|
-
ZSTD_DStream* const dstream = ZSTD_createDStream();
|
84
|
-
if (dstream == NULL) {
|
85
|
-
rb_raise(rb_eRuntimeError, "%s", "ZSTD_createDStream failed");
|
86
|
-
}
|
87
|
-
|
88
|
-
size_t initResult = ZSTD_initDStream(dstream);
|
89
|
-
if (ZSTD_isError(initResult)) {
|
90
|
-
ZSTD_freeDStream(dstream);
|
91
|
-
rb_raise(rb_eRuntimeError, "%s: %s", "ZSTD_initDStream failed", ZSTD_getErrorName(initResult));
|
92
|
-
}
|
93
|
-
|
94
93
|
VALUE output_string = rb_str_new(NULL, 0);
|
95
94
|
ZSTD_outBuffer output = { NULL, 0, 0 };
|
96
95
|
|
97
96
|
ZSTD_inBuffer input = { input_data, input_size, 0 };
|
98
97
|
while (input.pos < input.size) {
|
99
|
-
output.size +=
|
98
|
+
output.size += ZSTD_DStreamOutSize();
|
100
99
|
rb_str_resize(output_string, output.size);
|
101
100
|
output.dst = RSTRING_PTR(output_string);
|
102
101
|
|
103
|
-
size_t
|
104
|
-
if (ZSTD_isError(
|
105
|
-
|
106
|
-
rb_raise(rb_eRuntimeError, "%s: %s", "ZSTD_decompressStream failed", ZSTD_getErrorName(
|
102
|
+
size_t ret = zstd_decompress(dctx, &output, &input, true);
|
103
|
+
if (ZSTD_isError(ret)) {
|
104
|
+
ZSTD_freeDCtx(dctx);
|
105
|
+
rb_raise(rb_eRuntimeError, "%s: %s", "ZSTD_decompressStream failed", ZSTD_getErrorName(ret));
|
107
106
|
}
|
108
107
|
}
|
109
|
-
|
110
|
-
ZSTD_freeDStream(dstream);
|
111
108
|
rb_str_resize(output_string, output.pos);
|
109
|
+
ZSTD_freeDCtx(dctx);
|
112
110
|
return output_string;
|
113
111
|
}
|
114
112
|
|
115
|
-
static VALUE rb_decompress(VALUE
|
113
|
+
static VALUE rb_decompress(int argc, VALUE *argv, VALUE self)
|
116
114
|
{
|
115
|
+
VALUE input_value;
|
116
|
+
VALUE kwargs;
|
117
|
+
rb_scan_args(argc, argv, "10:", &input_value, &kwargs);
|
117
118
|
StringValue(input_value);
|
118
119
|
char* input_data = RSTRING_PTR(input_value);
|
119
120
|
size_t input_size = RSTRING_LEN(input_value);
|
121
|
+
ZSTD_DCtx* const dctx = ZSTD_createDCtx();
|
122
|
+
if (dctx == NULL) {
|
123
|
+
rb_raise(rb_eRuntimeError, "%s", "ZSTD_createDCtx failed");
|
124
|
+
}
|
125
|
+
set_decompress_params(dctx, kwargs);
|
120
126
|
|
121
127
|
unsigned long long const uncompressed_size = ZSTD_getFrameContentSize(input_data, input_size);
|
122
128
|
if (uncompressed_size == ZSTD_CONTENTSIZE_ERROR) {
|
123
129
|
rb_raise(rb_eRuntimeError, "%s: %s", "not compressed by zstd", ZSTD_getErrorName(uncompressed_size));
|
124
130
|
}
|
131
|
+
// ZSTD_decompressStream may be called multiple times when ZSTD_CONTENTSIZE_UNKNOWN, causing slowness.
|
132
|
+
// Therefore, we will not standardize on ZSTD_decompressStream
|
125
133
|
if (uncompressed_size == ZSTD_CONTENTSIZE_UNKNOWN) {
|
126
|
-
return decompress_buffered(input_data, input_size);
|
134
|
+
return decompress_buffered(dctx, input_data, input_size);
|
127
135
|
}
|
128
136
|
|
129
137
|
VALUE output = rb_str_new(NULL, uncompressed_size);
|
130
138
|
char* output_data = RSTRING_PTR(output);
|
131
|
-
size_t const decompress_size = ZSTD_decompress((void*)output_data, uncompressed_size,
|
132
|
-
(void*)input_data, input_size);
|
133
139
|
|
140
|
+
size_t const decompress_size = ZSTD_decompressDCtx(dctx, output_data, uncompressed_size, input_data, input_size);
|
134
141
|
if (ZSTD_isError(decompress_size)) {
|
135
142
|
rb_raise(rb_eRuntimeError, "%s: %s", "decompress error", ZSTD_getErrorName(decompress_size));
|
136
143
|
}
|
@@ -140,6 +147,7 @@ static VALUE rb_decompress(VALUE self, VALUE input_value)
|
|
140
147
|
|
141
148
|
static VALUE rb_decompress_using_dict(int argc, VALUE *argv, VALUE self)
|
142
149
|
{
|
150
|
+
rb_warn("Zstd.decompress_using_dict is deprecated; use Zstd.decompress with `dict:` instead.");
|
143
151
|
VALUE input_value;
|
144
152
|
VALUE dict;
|
145
153
|
rb_scan_args(argc, argv, "20", &input_value, &dict);
|
@@ -147,15 +155,6 @@ static VALUE rb_decompress_using_dict(int argc, VALUE *argv, VALUE self)
|
|
147
155
|
StringValue(input_value);
|
148
156
|
char* input_data = RSTRING_PTR(input_value);
|
149
157
|
size_t input_size = RSTRING_LEN(input_value);
|
150
|
-
unsigned long long const uncompressed_size = ZSTD_getFrameContentSize(input_data, input_size);
|
151
|
-
if (uncompressed_size == ZSTD_CONTENTSIZE_ERROR) {
|
152
|
-
rb_raise(rb_eRuntimeError, "%s: %s", "not compressed by zstd", ZSTD_getErrorName(uncompressed_size));
|
153
|
-
}
|
154
|
-
if (uncompressed_size == ZSTD_CONTENTSIZE_UNKNOWN) {
|
155
|
-
return decompress_buffered(input_data, input_size);
|
156
|
-
}
|
157
|
-
VALUE output = rb_str_new(NULL, uncompressed_size);
|
158
|
-
char* output_data = RSTRING_PTR(output);
|
159
158
|
|
160
159
|
char* dict_buffer = RSTRING_PTR(dict);
|
161
160
|
size_t dict_size = RSTRING_LEN(dict);
|
@@ -163,12 +162,11 @@ static VALUE rb_decompress_using_dict(int argc, VALUE *argv, VALUE self)
|
|
163
162
|
if (ddict == NULL) {
|
164
163
|
rb_raise(rb_eRuntimeError, "%s", "ZSTD_createDDict failed");
|
165
164
|
}
|
166
|
-
|
167
165
|
unsigned const expected_dict_id = ZSTD_getDictID_fromDDict(ddict);
|
168
166
|
unsigned const actual_dict_id = ZSTD_getDictID_fromFrame(input_data, input_size);
|
169
167
|
if (expected_dict_id != actual_dict_id) {
|
170
168
|
ZSTD_freeDDict(ddict);
|
171
|
-
rb_raise(rb_eRuntimeError, "
|
169
|
+
rb_raise(rb_eRuntimeError, "DictID mismatch");
|
172
170
|
}
|
173
171
|
|
174
172
|
ZSTD_DCtx* const ctx = ZSTD_createDCtx();
|
@@ -176,6 +174,19 @@ static VALUE rb_decompress_using_dict(int argc, VALUE *argv, VALUE self)
|
|
176
174
|
ZSTD_freeDDict(ddict);
|
177
175
|
rb_raise(rb_eRuntimeError, "%s", "ZSTD_createDCtx failed");
|
178
176
|
}
|
177
|
+
|
178
|
+
unsigned long long const uncompressed_size = ZSTD_getFrameContentSize(input_data, input_size);
|
179
|
+
if (uncompressed_size == ZSTD_CONTENTSIZE_ERROR) {
|
180
|
+
ZSTD_freeDDict(ddict);
|
181
|
+
ZSTD_freeDCtx(ctx);
|
182
|
+
rb_raise(rb_eRuntimeError, "%s: %s", "not compressed by zstd", ZSTD_getErrorName(uncompressed_size));
|
183
|
+
}
|
184
|
+
if (uncompressed_size == ZSTD_CONTENTSIZE_UNKNOWN) {
|
185
|
+
return decompress_buffered(ctx, input_data, input_size);
|
186
|
+
}
|
187
|
+
|
188
|
+
VALUE output = rb_str_new(NULL, uncompressed_size);
|
189
|
+
char* output_data = RSTRING_PTR(output);
|
179
190
|
size_t const decompress_size = ZSTD_decompress_usingDDict(ctx, output_data, uncompressed_size, input_data, input_size, ddict);
|
180
191
|
if (ZSTD_isError(decompress_size)) {
|
181
192
|
ZSTD_freeDDict(ddict);
|
@@ -193,6 +204,6 @@ zstd_ruby_init(void)
|
|
193
204
|
rb_define_module_function(rb_mZstd, "zstd_version", zstdVersion, 0);
|
194
205
|
rb_define_module_function(rb_mZstd, "compress", rb_compress, -1);
|
195
206
|
rb_define_module_function(rb_mZstd, "compress_using_dict", rb_compress_using_dict, -1);
|
196
|
-
rb_define_module_function(rb_mZstd, "decompress", rb_decompress, 1);
|
207
|
+
rb_define_module_function(rb_mZstd, "decompress", rb_decompress, -1);
|
197
208
|
rb_define_module_function(rb_mZstd, "decompress_using_dict", rb_decompress_using_dict, -1);
|
198
209
|
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Zstd
|
2
|
+
# @todo Exprimental
|
3
|
+
class StreamReader
|
4
|
+
def initialize(io)
|
5
|
+
@io = io
|
6
|
+
@stream = Zstd::StreamingDecompress.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def read(length)
|
10
|
+
if @io.eof?
|
11
|
+
raise StandardError, "EOF"
|
12
|
+
end
|
13
|
+
data = @io.read(length)
|
14
|
+
@stream.decompress(data)
|
15
|
+
end
|
16
|
+
|
17
|
+
def close
|
18
|
+
@io.write(@stream.finish)
|
19
|
+
@io.close
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Zstd
|
2
|
+
# @todo Exprimental
|
3
|
+
class StreamWriter
|
4
|
+
def initialize(io, level: nil)
|
5
|
+
@io = io
|
6
|
+
@stream = Zstd::StreamingCompress.new(level)
|
7
|
+
end
|
8
|
+
|
9
|
+
def write(*data)
|
10
|
+
@stream.write(*data)
|
11
|
+
@io.write(@stream.flush)
|
12
|
+
end
|
13
|
+
|
14
|
+
def finish
|
15
|
+
@io.write(@stream.finish)
|
16
|
+
end
|
17
|
+
|
18
|
+
def close
|
19
|
+
@io.write(@stream.finish)
|
20
|
+
@io.close
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/zstd-ruby/version.rb
CHANGED
data/zstd-ruby.gemspec
CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
|
|
24
24
|
#end
|
25
25
|
|
26
26
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
27
|
-
f.match(%r{^(test|spec|features|benchmarks|zstd|.github)/})
|
27
|
+
f.match(%r{^(test|spec|features|benchmarks|zstd|.github|examples)/})
|
28
28
|
end
|
29
29
|
spec.bindir = "exe"
|
30
30
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
@@ -35,4 +35,5 @@ Gem::Specification.new do |spec|
|
|
35
35
|
spec.add_development_dependency "rake", "~> 13.0"
|
36
36
|
spec.add_development_dependency "rake-compiler", '~> 1'
|
37
37
|
spec.add_development_dependency "rspec", "~> 3.0"
|
38
|
+
spec.add_development_dependency "pry"
|
38
39
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zstd-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.5.6.
|
4
|
+
version: 1.5.6.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- SpringMT
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-04-
|
11
|
+
date: 2024-04-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '3.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
description: Ruby binding for zstd(Zstandard - Fast real-time compression algorithm).
|
70
84
|
See https://github.com/facebook/zstd
|
71
85
|
email:
|
@@ -159,10 +173,11 @@ files:
|
|
159
173
|
- ext/zstdruby/main.c
|
160
174
|
- ext/zstdruby/skippable_frame.c
|
161
175
|
- ext/zstdruby/streaming_compress.c
|
162
|
-
- ext/zstdruby/streaming_compress.h
|
163
176
|
- ext/zstdruby/streaming_decompress.c
|
164
177
|
- ext/zstdruby/zstdruby.c
|
165
178
|
- lib/zstd-ruby.rb
|
179
|
+
- lib/zstd-ruby/stream_reader.rb
|
180
|
+
- lib/zstd-ruby/stream_writer.rb
|
166
181
|
- lib/zstd-ruby/version.rb
|
167
182
|
- renovate.json
|
168
183
|
- zstd-ruby.gemspec
|