zstd-ruby 1.5.6.5 → 1.5.6.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 63e93f85ee472c512ed26f0e7da7fd352b143fab32dcf5e902772bc1f202c7b0
4
- data.tar.gz: 681ea9a091527554620a032b003f578684a743ecba43c66dfb1682b1e15db794
3
+ metadata.gz: 9acf1d7797f3431d0df130388295910e47c9bdaf36df29e1f116a55b993c130d
4
+ data.tar.gz: c58e20e6f0c2d270a21481b8ac2ba1c427d8cc6b1c2e52305e5b7540fcda41bc
5
5
  SHA512:
6
- metadata.gz: 4245143daaf4a8c905e7c82eec53c60fcf391f55e21fa1f39c9aca76cccefedc6c90a25a9c581255f6fc3ea909501eb83a219c461b1b24b1f2e6552c4281d16e
7
- data.tar.gz: 6294213e536fd3117e6f2de7efdb58d9754344bc9d4aff83ec6943e0958dfe4e1cdae9316c6ca2a778e08f6573390fdf026f053677def60aa92abf8e5c98518f
6
+ metadata.gz: 9fad54c87b430ddbd437dd5e238b873c7572b2ed23e7b2a6409b817e1a823ab943bd49278c989abc1470a30c7fc8ad983fcf18a0b1dad84f8b99625fee2e6097
7
+ data.tar.gz: d8dd762266849d491ac971bd7eb764ea9bda42da6ef6fbd351bc91ab792e18009f1d52f8005734489776c049b4ef82bd25042020be8cb286c73f94af86b1a2c7
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ .DS_Store
1
2
  /.bundle/
2
3
  /.yardoc
3
4
  /Gemfile.lock
data/README.md CHANGED
@@ -49,6 +49,22 @@ compressed_data = Zstd.compress(data, level: complession_level) # default compre
49
49
  compressed_using_dict = Zstd.compress("", dict: File.read('dictionary_file'))
50
50
  ```
51
51
 
52
+ #### Compression with CDict
53
+
54
+ If you use the same dictionary repeatedly, you can speed up the setup by creating CDict in advance:
55
+
56
+ ```ruby
57
+ cdict = Zstd::CDict.new(File.read('dictionary_file'))
58
+ compressed_using_dict = Zstd.compress("", dict: cdict)
59
+ ```
60
+
61
+ The compression_level can be specified on creating CDict.
62
+
63
+ ```ruby
64
+ cdict = Zstd::CDict.new(File.read('dictionary_file'), 5)
65
+ compressed_using_dict = Zstd.compress("", dict: cdict)
66
+ ```
67
+
52
68
  #### Streaming Compression
53
69
  ```ruby
54
70
  stream = Zstd::StreamingCompress.new
@@ -86,6 +102,16 @@ stream << "ghi"
86
102
  res << stream.finish
87
103
  ```
88
104
 
105
+ #### Streaming Compression with CDict of level 5
106
+ ```ruby
107
+ cdict = Zstd::CDict.new(File.read('dictionary_file', 5)
108
+ stream = Zstd::StreamingCompress.new(dict: cdict)
109
+ stream << "abc" << "def"
110
+ res = stream.flush
111
+ stream << "ghi"
112
+ res << stream.finish
113
+ ```
114
+
89
115
  ### Decompression
90
116
 
91
117
  #### Simple Decompression
@@ -100,6 +126,15 @@ data = Zstd.decompress(compressed_data)
100
126
  Zstd.decompress(compressed_using_dict, dict: File.read('dictionary_file'))
101
127
  ```
102
128
 
129
+ #### Decompression with DDict
130
+
131
+ If you use the same dictionary repeatedly, you can speed up the setup by creating DDict in advance:
132
+
133
+ ```ruby
134
+ ddict = Zstd::Ddict.new(File.read('dictionary_file'))
135
+ data = Zstd.compress(compressed_using_dict, ddict)
136
+ ```
137
+
103
138
  #### Streaming Decompression
104
139
  ```ruby
105
140
  cstr = "" # Compressed data
@@ -118,6 +153,8 @@ result << stream.decompress(cstr[0, 10])
118
153
  result << stream.decompress(cstr[10..-1])
119
154
  ```
120
155
 
156
+ DDict can also be specified to `dict:`.
157
+
121
158
  ### Skippable frame
122
159
 
123
160
  ```ruby
@@ -127,6 +164,45 @@ Zstd.read_skippable_frame(compressed_data_with_skippable_frame)
127
164
  # => "sample data"
128
165
  ```
129
166
 
167
+ ### Stream Writer and Reader Wrapper
168
+ **EXPERIMENTAL**
169
+
170
+ * These features are experimental and may be subject to API changes in future releases.
171
+ * There may be performance and compatibility issues, so extensive testing is required before production use.
172
+ * If you have any questions, encounter bugs, or have suggestions, please report them via [GitHub issues](https://github.com/SpringMT/zstd-ruby/issues).
173
+
174
+ #### Zstd::StreamWriter
175
+
176
+ ```ruby
177
+ require 'stringio'
178
+ require 'zstd-ruby'
179
+
180
+ io = StringIO.new
181
+ stream = Zstd::StreamWriter.new(io)
182
+ stream.write("abc")
183
+ stream.finish
184
+
185
+ io.rewind
186
+ # Retrieve the compressed data
187
+ compressed_data = io.read
188
+ ```
189
+
190
+ #### Zstd::StreamReader
191
+
192
+ ```ruby
193
+ require 'stringio'
194
+ require 'zstd-ruby' # Add the appropriate require statement if necessary
195
+
196
+ io = StringIO.new(compressed_data)
197
+ reader = Zstd::StreamReader.new(io)
198
+
199
+ # Read and output the decompressed data
200
+ puts reader.read(10) # 'abc'
201
+ puts reader.read(10) # 'def'
202
+ puts reader.read(10) # '' (end of data)
203
+ ```
204
+
205
+
130
206
  ## JRuby
131
207
  This gem does not support JRuby.
132
208
 
@@ -1,13 +1,15 @@
1
1
  #ifndef ZSTD_RUBY_H
2
2
  #define ZSTD_RUBY_H 1
3
3
 
4
+ #include <stdbool.h>
4
5
  #include <ruby.h>
5
6
  #ifdef HAVE_RUBY_THREAD_H
6
7
  #include <ruby/thread.h>
7
8
  #endif
8
- #include <stdbool.h>
9
9
  #include "./libzstd/zstd.h"
10
10
 
11
+ extern VALUE rb_cCDict, rb_cDDict;
12
+
11
13
  static int convert_compression_level(VALUE compression_level_value)
12
14
  {
13
15
  if (NIL_P(compression_level_value)) {
@@ -34,12 +36,24 @@ static void set_compress_params(ZSTD_CCtx* const ctx, VALUE level_from_args, VAL
34
36
  ZSTD_CCtx_setParameter(ctx, ZSTD_c_compressionLevel, compression_level);
35
37
 
36
38
  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)) {
39
+ if (CLASS_OF(kwargs_values[1]) == rb_cCDict) {
40
+ ZSTD_CDict* cdict = DATA_PTR(kwargs_values[1]);
41
+ size_t ref_dict_ret = ZSTD_CCtx_refCDict(ctx, cdict);
42
+ if (ZSTD_isError(ref_dict_ret)) {
43
+ ZSTD_freeCCtx(ctx);
44
+ rb_raise(rb_eRuntimeError, "%s", "ZSTD_CCtx_refCDict failed");
45
+ }
46
+ } else if (TYPE(kwargs_values[1]) == T_STRING) {
47
+ char* dict_buffer = RSTRING_PTR(kwargs_values[1]);
48
+ size_t dict_size = RSTRING_LEN(kwargs_values[1]);
49
+ size_t load_dict_ret = ZSTD_CCtx_loadDictionary(ctx, dict_buffer, dict_size);
50
+ if (ZSTD_isError(load_dict_ret)) {
51
+ ZSTD_freeCCtx(ctx);
52
+ rb_raise(rb_eRuntimeError, "%s", "ZSTD_CCtx_loadDictionary failed");
53
+ }
54
+ } else {
41
55
  ZSTD_freeCCtx(ctx);
42
- rb_raise(rb_eRuntimeError, "%s", "ZSTD_CCtx_loadDictionary failed");
56
+ rb_raise(rb_eArgError, "`dict:` must be a Zstd::CDict or a String");
43
57
  }
44
58
  }
45
59
  }
@@ -113,12 +127,24 @@ static void set_decompress_params(ZSTD_DCtx* const dctx, VALUE kwargs)
113
127
  rb_get_kwargs(kwargs, kwargs_keys, 0, 1, kwargs_values);
114
128
 
115
129
  if (kwargs_values[0] != Qundef && kwargs_values[0] != Qnil) {
116
- char* dict_buffer = RSTRING_PTR(kwargs_values[0]);
117
- size_t dict_size = RSTRING_LEN(kwargs_values[0]);
118
- size_t load_dict_ret = ZSTD_DCtx_loadDictionary(dctx, dict_buffer, dict_size);
119
- if (ZSTD_isError(load_dict_ret)) {
130
+ if (CLASS_OF(kwargs_values[0]) == rb_cDDict) {
131
+ ZSTD_DDict* ddict = DATA_PTR(kwargs_values[0]);
132
+ size_t ref_dict_ret = ZSTD_DCtx_refDDict(dctx, ddict);
133
+ if (ZSTD_isError(ref_dict_ret)) {
134
+ ZSTD_freeDCtx(dctx);
135
+ rb_raise(rb_eRuntimeError, "%s", "ZSTD_DCtx_refDDict failed");
136
+ }
137
+ } else if (TYPE(kwargs_values[0]) == T_STRING) {
138
+ char* dict_buffer = RSTRING_PTR(kwargs_values[0]);
139
+ size_t dict_size = RSTRING_LEN(kwargs_values[0]);
140
+ size_t load_dict_ret = ZSTD_DCtx_loadDictionary(dctx, dict_buffer, dict_size);
141
+ if (ZSTD_isError(load_dict_ret)) {
142
+ ZSTD_freeDCtx(dctx);
143
+ rb_raise(rb_eRuntimeError, "%s", "ZSTD_CCtx_loadDictionary failed");
144
+ }
145
+ } else {
120
146
  ZSTD_freeDCtx(dctx);
121
- rb_raise(rb_eRuntimeError, "%s", "ZSTD_CCtx_loadDictionary failed");
147
+ rb_raise(rb_eArgError, "`dict:` must be a Zstd::DDict or a String");
122
148
  }
123
149
  }
124
150
  }
data/ext/zstdruby/main.c CHANGED
@@ -1,6 +1,8 @@
1
1
  #include "common.h"
2
2
 
3
3
  VALUE rb_mZstd;
4
+ VALUE rb_cCDict;
5
+ VALUE rb_cDDict;
4
6
  void zstd_ruby_init(void);
5
7
  void zstd_ruby_skippable_frame_init(void);
6
8
  void zstd_ruby_streaming_compress_init(void);
@@ -14,6 +16,8 @@ Init_zstdruby(void)
14
16
  #endif
15
17
 
16
18
  rb_mZstd = rb_define_module("Zstd");
19
+ rb_cCDict = rb_define_class_under(rb_mZstd, "CDict", rb_cObject);
20
+ rb_cDDict = rb_define_class_under(rb_mZstd, "DDict", rb_cObject);
17
21
  zstd_ruby_init();
18
22
  zstd_ruby_skippable_frame_init();
19
23
  zstd_ruby_streaming_compress_init();
@@ -87,13 +87,13 @@ static VALUE rb_compress_using_dict(int argc, VALUE *argv, VALUE self)
87
87
 
88
88
  static VALUE decompress_buffered(ZSTD_DCtx* dctx, const char* input_data, size_t input_size)
89
89
  {
90
- VALUE output_string = rb_str_new(NULL, 0);
91
- ZSTD_outBuffer output = { NULL, 0, 0 };
92
-
93
90
  ZSTD_inBuffer input = { input_data, input_size, 0 };
91
+ VALUE result = rb_str_new(0, 0);
92
+
94
93
  while (input.pos < input.size) {
94
+ ZSTD_outBuffer output = { NULL, 0, 0 };
95
95
  output.size += ZSTD_DStreamOutSize();
96
- rb_str_resize(output_string, output.size);
96
+ VALUE output_string = rb_str_new(NULL, output.size);
97
97
  output.dst = RSTRING_PTR(output_string);
98
98
 
99
99
  size_t ret = zstd_stream_decompress(dctx, &output, &input, false);
@@ -101,10 +101,10 @@ static VALUE decompress_buffered(ZSTD_DCtx* dctx, const char* input_data, size_t
101
101
  ZSTD_freeDCtx(dctx);
102
102
  rb_raise(rb_eRuntimeError, "%s: %s", "ZSTD_decompressStream failed", ZSTD_getErrorName(ret));
103
103
  }
104
+ rb_str_cat(result, output.dst, output.pos);
104
105
  }
105
- rb_str_resize(output_string, output.pos);
106
106
  ZSTD_freeDCtx(dctx);
107
- return output_string;
107
+ return result;
108
108
  }
109
109
 
110
110
  static VALUE rb_decompress(int argc, VALUE *argv, VALUE self)
@@ -134,7 +134,7 @@ static VALUE rb_decompress(int argc, VALUE *argv, VALUE self)
134
134
  VALUE output = rb_str_new(NULL, uncompressed_size);
135
135
  char* output_data = RSTRING_PTR(output);
136
136
 
137
- size_t const decompress_size = zstd_decompress(dctx, output_data, uncompressed_size, input_data, input_size, false);
137
+ size_t const decompress_size = zstd_decompress(dctx, output_data, uncompressed_size, input_data, input_size, false);
138
138
  if (ZSTD_isError(decompress_size)) {
139
139
  rb_raise(rb_eRuntimeError, "%s: %s", "decompress error", ZSTD_getErrorName(decompress_size));
140
140
  }
@@ -195,6 +195,90 @@ static VALUE rb_decompress_using_dict(int argc, VALUE *argv, VALUE self)
195
195
  return output;
196
196
  }
197
197
 
198
+ static void free_cdict(void *dict)
199
+ {
200
+ ZSTD_freeCDict(dict);
201
+ }
202
+
203
+ static size_t sizeof_cdict(const void *dict)
204
+ {
205
+ return ZSTD_sizeof_CDict(dict);
206
+ }
207
+
208
+ static void free_ddict(void *dict)
209
+ {
210
+ ZSTD_freeDDict(dict);
211
+ }
212
+
213
+ static size_t sizeof_ddict(const void *dict)
214
+ {
215
+ return ZSTD_sizeof_DDict(dict);
216
+ }
217
+
218
+ static const rb_data_type_t cdict_type = {
219
+ "Zstd::CDict",
220
+ {0, free_cdict, sizeof_cdict,},
221
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
222
+ };
223
+
224
+ static const rb_data_type_t ddict_type = {
225
+ "Zstd::DDict",
226
+ {0, free_ddict, sizeof_ddict,},
227
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
228
+ };
229
+
230
+ static VALUE rb_cdict_alloc(VALUE self)
231
+ {
232
+ ZSTD_CDict* cdict = NULL;
233
+ return TypedData_Wrap_Struct(self, &cdict_type, cdict);
234
+ }
235
+
236
+ static VALUE rb_cdict_initialize(int argc, VALUE *argv, VALUE self)
237
+ {
238
+ VALUE dict;
239
+ VALUE compression_level_value;
240
+ rb_scan_args(argc, argv, "11", &dict, &compression_level_value);
241
+ int compression_level = convert_compression_level(compression_level_value);
242
+
243
+ StringValue(dict);
244
+ char* dict_buffer = RSTRING_PTR(dict);
245
+ size_t dict_size = RSTRING_LEN(dict);
246
+
247
+ ZSTD_CDict* const cdict = ZSTD_createCDict(dict_buffer, dict_size, compression_level);
248
+ if (cdict == NULL) {
249
+ rb_raise(rb_eRuntimeError, "%s", "ZSTD_createCDict failed");
250
+ }
251
+
252
+ DATA_PTR(self) = cdict;
253
+ return self;
254
+ }
255
+
256
+ static VALUE rb_ddict_alloc(VALUE self)
257
+ {
258
+ ZSTD_CDict* ddict = NULL;
259
+ return TypedData_Wrap_Struct(self, &ddict_type, ddict);
260
+ }
261
+
262
+ static VALUE rb_ddict_initialize(VALUE self, VALUE dict)
263
+ {
264
+ StringValue(dict);
265
+ char* dict_buffer = RSTRING_PTR(dict);
266
+ size_t dict_size = RSTRING_LEN(dict);
267
+
268
+ ZSTD_DDict* const ddict = ZSTD_createDDict(dict_buffer, dict_size);
269
+ if (ddict == NULL) {
270
+ rb_raise(rb_eRuntimeError, "%s", "ZSTD_createDDict failed");
271
+ }
272
+
273
+ DATA_PTR(self) = ddict;
274
+ return self;
275
+ }
276
+
277
+ static VALUE rb_prohibit_copy(VALUE self, VALUE obj)
278
+ {
279
+ rb_raise(rb_eRuntimeError, "CDict cannot be duplicated");
280
+ }
281
+
198
282
  void
199
283
  zstd_ruby_init(void)
200
284
  {
@@ -203,4 +287,12 @@ zstd_ruby_init(void)
203
287
  rb_define_module_function(rb_mZstd, "compress_using_dict", rb_compress_using_dict, -1);
204
288
  rb_define_module_function(rb_mZstd, "decompress", rb_decompress, -1);
205
289
  rb_define_module_function(rb_mZstd, "decompress_using_dict", rb_decompress_using_dict, -1);
290
+
291
+ rb_define_alloc_func(rb_cCDict, rb_cdict_alloc);
292
+ rb_define_private_method(rb_cCDict, "initialize", rb_cdict_initialize, -1);
293
+ rb_define_method(rb_cCDict, "initialize_copy", rb_prohibit_copy, 1);
294
+
295
+ rb_define_alloc_func(rb_cDDict, rb_ddict_alloc);
296
+ rb_define_private_method(rb_cDDict, "initialize", rb_ddict_initialize, 1);
297
+ rb_define_method(rb_cDDict, "initialize_copy", rb_prohibit_copy, 1);
206
298
  }
@@ -3,7 +3,7 @@ module Zstd
3
3
  class StreamWriter
4
4
  def initialize(io, level: nil)
5
5
  @io = io
6
- @stream = Zstd::StreamingCompress.new(level)
6
+ @stream = Zstd::StreamingCompress.new(level: level)
7
7
  end
8
8
 
9
9
  def write(*data)
@@ -1,3 +1,3 @@
1
1
  module Zstd
2
- VERSION = "1.5.6.5"
2
+ VERSION = "1.5.6.7"
3
3
  end
data/lib/zstd-ruby.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require "zstd-ruby/version"
2
2
  require "zstd-ruby/zstdruby"
3
+ require "zstd-ruby/stream_writer"
4
+ require "zstd-ruby/stream_reader"
3
5
 
4
6
  module Zstd
5
7
  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.5
4
+ version: 1.5.6.7
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-26 00:00:00.000000000 Z
11
+ date: 2025-07-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -200,7 +200,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
200
200
  - !ruby/object:Gem::Version
201
201
  version: '0'
202
202
  requirements: []
203
- rubygems_version: 3.5.3
203
+ rubygems_version: 3.4.19
204
204
  signing_key:
205
205
  specification_version: 4
206
206
  summary: Ruby binding for zstd(Zstandard - Fast real-time compression algorithm)