zstd-ruby 2.0.0.pre.preview1 → 2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b3fef282bc259f5b954abd4641462fcab60068f0e08ed0d166478c8de4c2005c
4
- data.tar.gz: 543f92bc5984e4e9ced2ed89d23ce6ba091746605f22a19af0465dcdf22f98c6
3
+ metadata.gz: 91a2e54ff93b0c602d6b2d064f6f8c615a59f0ef963c20b24e4db6d17643163e
4
+ data.tar.gz: cbeb4c7c21187336a284cb714765fb80b02b982c6b4fafa60784d8f7950fe528
5
5
  SHA512:
6
- metadata.gz: 40fb6622a2cc3b8df4eee5218ad2bad4f130c910bf8b0ba838f9dd578be95b27e578b0cc77ec92511bbf717834e0034850ffc969b7b749618f316f13b7cd6c0a
7
- data.tar.gz: f2f877a787c617e6ab76a66b2492b631b5a19c6cc09f0fc5e075c58badc6e0228cfa94926f32289525a96d23f40de853c9ceeb5ee0ba01d917ecdc5bc8529bd2
6
+ metadata.gz: 70190b1a1233782dc440e5ef913f4a83b6bc936ea96d744f5a44b3dbceb41f8a1ef9c3264746eb251356b95c13c5503b2b2567076bc45c28d628ee278b9c2522
7
+ data.tar.gz: 600bc166bef41126b93a0e78190bbf6b5698259797e166ee4d787a113d6c4e27e7c6c927135e54b33a7e4cc25a74b2df4cb19413f74618892191863cc4c9b4fb
@@ -4,6 +4,7 @@ struct streaming_compress_t {
4
4
  ZSTD_CCtx* ctx;
5
5
  VALUE buf;
6
6
  size_t buf_size;
7
+ VALUE pending; /* accumulate compressed bytes produced by write() */
7
8
  };
8
9
 
9
10
  static void
@@ -12,8 +13,10 @@ streaming_compress_mark(void *p)
12
13
  struct streaming_compress_t *sc = p;
13
14
  #ifdef HAVE_RB_GC_MARK_MOVABLE
14
15
  rb_gc_mark_movable(sc->buf);
16
+ rb_gc_mark_movable(sc->pending);
15
17
  #else
16
18
  rb_gc_mark(sc->buf);
19
+ rb_gc_mark(sc->pending);
17
20
  #endif
18
21
  }
19
22
 
@@ -40,6 +43,7 @@ streaming_compress_compact(void *p)
40
43
  {
41
44
  struct streaming_compress_t *sc = p;
42
45
  sc->buf = rb_gc_location(sc->buf);
46
+ sc->pending = rb_gc_location(sc->pending);
43
47
  }
44
48
  #endif
45
49
 
@@ -64,6 +68,7 @@ rb_streaming_compress_allocate(VALUE klass)
64
68
  sc->ctx = NULL;
65
69
  sc->buf = Qnil;
66
70
  sc->buf_size = 0;
71
+ sc->pending = Qnil;
67
72
  return obj;
68
73
  }
69
74
 
@@ -86,6 +91,7 @@ rb_streaming_compress_initialize(int argc, VALUE *argv, VALUE obj)
86
91
  sc->ctx = ctx;
87
92
  sc->buf = rb_str_new(NULL, buffOutSize);
88
93
  sc->buf_size = buffOutSize;
94
+ sc->pending = rb_str_new(0, 0);
89
95
 
90
96
  return obj;
91
97
  }
@@ -99,13 +105,13 @@ static VALUE
99
105
  no_compress(struct streaming_compress_t* sc, ZSTD_EndDirective endOp)
100
106
  {
101
107
  ZSTD_inBuffer input = { NULL, 0, 0 };
102
- const char* output_data = RSTRING_PTR(sc->buf);
103
108
  VALUE result = rb_str_new(0, 0);
104
109
  size_t ret;
105
110
  do {
111
+ const char* output_data = RSTRING_PTR(sc->buf);
106
112
  ZSTD_outBuffer output = { (void*)output_data, sc->buf_size, 0 };
107
113
 
108
- size_t const ret = zstd_stream_compress(sc->ctx, &output, &input, endOp, false);
114
+ ret = zstd_stream_compress(sc->ctx, &output, &input, endOp, false);
109
115
  if (ZSTD_isError(ret)) {
110
116
  rb_raise(rb_eRuntimeError, "flush error error code: %s", ZSTD_getErrorName(ret));
111
117
  }
@@ -125,9 +131,9 @@ rb_streaming_compress_compress(VALUE obj, VALUE src)
125
131
  struct streaming_compress_t* sc;
126
132
  TypedData_Get_Struct(obj, struct streaming_compress_t, &streaming_compress_type, sc);
127
133
 
128
- const char* output_data = RSTRING_PTR(sc->buf);
129
134
  VALUE result = rb_str_new(0, 0);
130
135
  while (input.pos < input.size) {
136
+ const char* output_data = RSTRING_PTR(sc->buf);
131
137
  ZSTD_outBuffer output = { (void*)output_data, sc->buf_size, 0 };
132
138
  size_t const ret = zstd_stream_compress(sc->ctx, &output, &input, ZSTD_e_continue, false);
133
139
  if (ZSTD_isError(ret)) {
@@ -142,10 +148,8 @@ static VALUE
142
148
  rb_streaming_compress_write(int argc, VALUE *argv, VALUE obj)
143
149
  {
144
150
  size_t total = 0;
145
- VALUE result = rb_str_new(0, 0);
146
151
  struct streaming_compress_t* sc;
147
152
  TypedData_Get_Struct(obj, struct streaming_compress_t, &streaming_compress_type, sc);
148
- const char* output_data = RSTRING_PTR(sc->buf);
149
153
 
150
154
  while (argc-- > 0) {
151
155
  VALUE str = *argv++;
@@ -155,14 +159,20 @@ rb_streaming_compress_write(int argc, VALUE *argv, VALUE obj)
155
159
  ZSTD_inBuffer input = { input_data, input_size, 0 };
156
160
 
157
161
  while (input.pos < input.size) {
162
+ const char* output_data = RSTRING_PTR(sc->buf);
158
163
  ZSTD_outBuffer output = { (void*)output_data, sc->buf_size, 0 };
159
164
  size_t const ret = zstd_stream_compress(sc->ctx, &output, &input, ZSTD_e_continue, false);
160
165
  if (ZSTD_isError(ret)) {
161
166
  rb_raise(rb_eRuntimeError, "compress error error code: %s", ZSTD_getErrorName(ret));
162
167
  }
163
- total += RSTRING_LEN(str);
168
+ /* Directly append to the pending buffer */
169
+ if (output.pos > 0) {
170
+ rb_str_cat(sc->pending, output.dst, output.pos);
171
+ }
164
172
  }
173
+ total += RSTRING_LEN(str);
165
174
  }
175
+
166
176
  return SIZET2NUM(total);
167
177
  }
168
178
 
@@ -192,8 +202,11 @@ rb_streaming_compress_flush(VALUE obj)
192
202
  {
193
203
  struct streaming_compress_t* sc;
194
204
  TypedData_Get_Struct(obj, struct streaming_compress_t, &streaming_compress_type, sc);
195
- VALUE result = no_compress(sc, ZSTD_e_flush);
196
- return result;
205
+ VALUE drained = no_compress(sc, ZSTD_e_flush);
206
+ VALUE out = rb_str_dup(sc->pending);
207
+ rb_str_cat(out, RSTRING_PTR(drained), RSTRING_LEN(drained));
208
+ rb_str_resize(sc->pending, 0);
209
+ return out;
197
210
  }
198
211
 
199
212
  static VALUE
@@ -201,8 +214,11 @@ rb_streaming_compress_finish(VALUE obj)
201
214
  {
202
215
  struct streaming_compress_t* sc;
203
216
  TypedData_Get_Struct(obj, struct streaming_compress_t, &streaming_compress_type, sc);
204
- VALUE result = no_compress(sc, ZSTD_e_end);
205
- return result;
217
+ VALUE drained = no_compress(sc, ZSTD_e_end);
218
+ VALUE out = rb_str_dup(sc->pending);
219
+ rb_str_cat(out, RSTRING_PTR(drained), RSTRING_LEN(drained));
220
+ rb_str_resize(sc->pending, 0);
221
+ return out;
206
222
  }
207
223
 
208
224
  extern VALUE rb_mZstd, cStreamingCompress;
@@ -100,15 +100,22 @@ rb_streaming_decompress_decompress(VALUE obj, VALUE src)
100
100
 
101
101
  struct streaming_decompress_t* sd;
102
102
  TypedData_Get_Struct(obj, struct streaming_decompress_t, &streaming_decompress_type, sd);
103
- const char* output_data = RSTRING_PTR(sd->buf);
104
103
  VALUE result = rb_str_new(0, 0);
104
+
105
105
  while (input.pos < input.size) {
106
+ const char* output_data = RSTRING_PTR(sd->buf);
106
107
  ZSTD_outBuffer output = { (void*)output_data, sd->buf_size, 0 };
107
108
  size_t const ret = zstd_stream_decompress(sd->dctx, &output, &input, false);
109
+
108
110
  if (ZSTD_isError(ret)) {
109
111
  rb_raise(rb_eRuntimeError, "decompress error error code: %s", ZSTD_getErrorName(ret));
110
112
  }
111
- rb_str_cat(result, output.dst, output.pos);
113
+ if (output.pos > 0) {
114
+ rb_str_cat(result, output.dst, output.pos);
115
+ }
116
+ if (ret == 0 && output.pos == 0) {
117
+ break;
118
+ }
112
119
  }
113
120
  return result;
114
121
  }
@@ -39,61 +39,91 @@ static VALUE rb_compress(int argc, VALUE *argv, VALUE self)
39
39
  return output;
40
40
  }
41
41
 
42
- static VALUE decompress_buffered(ZSTD_DCtx* dctx, const char* input_data, size_t input_size)
43
- {
44
- ZSTD_inBuffer input = { input_data, input_size, 0 };
45
- VALUE result = rb_str_new(0, 0);
42
+ static VALUE decode_one_frame(ZSTD_DCtx* dctx, const unsigned char* src, size_t size, VALUE kwargs) {
43
+ VALUE out = rb_str_buf_new(0);
44
+ size_t cap = ZSTD_DStreamOutSize();
45
+ char *buf = ALLOC_N(char, cap);
46
+ ZSTD_inBuffer in = (ZSTD_inBuffer){ src, size, 0 };
46
47
 
47
- while (input.pos < input.size) {
48
- ZSTD_outBuffer output = { NULL, 0, 0 };
49
- output.size += ZSTD_DStreamOutSize();
50
- VALUE output_string = rb_str_new(NULL, output.size);
51
- output.dst = RSTRING_PTR(output_string);
48
+ ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only);
49
+ set_decompress_params(dctx, kwargs);
52
50
 
53
- size_t ret = zstd_stream_decompress(dctx, &output, &input, false);
51
+ for (;;) {
52
+ ZSTD_outBuffer o = (ZSTD_outBuffer){ buf, cap, 0 };
53
+ size_t ret = ZSTD_decompressStream(dctx, &o, &in);
54
54
  if (ZSTD_isError(ret)) {
55
- ZSTD_freeDCtx(dctx);
56
- rb_raise(rb_eRuntimeError, "%s: %s", "ZSTD_decompressStream failed", ZSTD_getErrorName(ret));
55
+ xfree(buf);
56
+ rb_raise(rb_eRuntimeError, "ZSTD_decompressStream failed: %s", ZSTD_getErrorName(ret));
57
+ }
58
+ if (o.pos) {
59
+ rb_str_cat(out, buf, o.pos);
60
+ }
61
+ if (ret == 0) {
62
+ break;
57
63
  }
58
- rb_str_cat(result, output.dst, output.pos);
59
64
  }
60
- ZSTD_freeDCtx(dctx);
61
- return result;
65
+ xfree(buf);
66
+ return out;
67
+ }
68
+
69
+ static VALUE decompress_buffered(ZSTD_DCtx* dctx, const char* data, size_t len) {
70
+ return decode_one_frame(dctx, (const unsigned char*)data, len, Qnil);
62
71
  }
63
72
 
64
73
  static VALUE rb_decompress(int argc, VALUE *argv, VALUE self)
65
74
  {
66
- VALUE input_value;
67
- VALUE kwargs;
75
+ VALUE input_value, kwargs;
68
76
  rb_scan_args(argc, argv, "10:", &input_value, &kwargs);
69
77
  StringValue(input_value);
70
- char* input_data = RSTRING_PTR(input_value);
71
- size_t input_size = RSTRING_LEN(input_value);
72
- ZSTD_DCtx* const dctx = ZSTD_createDCtx();
73
- if (dctx == NULL) {
74
- rb_raise(rb_eRuntimeError, "%s", "ZSTD_createDCtx failed");
75
- }
76
- set_decompress_params(dctx, kwargs);
77
78
 
78
- unsigned long long const uncompressed_size = ZSTD_getFrameContentSize(input_data, input_size);
79
- if (uncompressed_size == ZSTD_CONTENTSIZE_ERROR) {
80
- rb_raise(rb_eRuntimeError, "%s: %s", "not compressed by zstd", ZSTD_getErrorName(uncompressed_size));
81
- }
82
- // ZSTD_decompressStream may be called multiple times when ZSTD_CONTENTSIZE_UNKNOWN, causing slowness.
83
- // Therefore, we will not standardize on ZSTD_decompressStream
84
- if (uncompressed_size == ZSTD_CONTENTSIZE_UNKNOWN) {
85
- return decompress_buffered(dctx, input_data, input_size);
86
- }
79
+ size_t in_size = RSTRING_LEN(input_value);
80
+ const unsigned char *in_r = (const unsigned char *)RSTRING_PTR(input_value);
81
+ unsigned char *in = ALLOC_N(unsigned char, in_size);
82
+ memcpy(in, in_r, in_size);
83
+
84
+ size_t off = 0;
85
+ const uint32_t ZSTD_MAGIC = 0xFD2FB528U;
86
+ const uint32_t SKIP_LO = 0x184D2A50U; /* ...5F */
87
+
88
+ while (off + 4 <= in_size) {
89
+ uint32_t magic = (uint32_t)in[off]
90
+ | ((uint32_t)in[off+1] << 8)
91
+ | ((uint32_t)in[off+2] << 16)
92
+ | ((uint32_t)in[off+3] << 24);
93
+
94
+ if ((magic & 0xFFFFFFF0U) == (SKIP_LO & 0xFFFFFFF0U)) {
95
+ if (off + 8 > in_size) break;
96
+ uint32_t skipLen = (uint32_t)in[off+4]
97
+ | ((uint32_t)in[off+5] << 8)
98
+ | ((uint32_t)in[off+6] << 16)
99
+ | ((uint32_t)in[off+7] << 24);
100
+ size_t adv = (size_t)8 + (size_t)skipLen;
101
+ if (off + adv > in_size) break;
102
+ off += adv;
103
+ continue;
104
+ }
87
105
 
88
- VALUE output = rb_str_new(NULL, uncompressed_size);
89
- char* output_data = RSTRING_PTR(output);
106
+ if (magic == ZSTD_MAGIC) {
107
+ ZSTD_DCtx *dctx = ZSTD_createDCtx();
108
+ if (!dctx) {
109
+ xfree(in);
110
+ rb_raise(rb_eRuntimeError, "ZSTD_createDCtx failed");
111
+ }
112
+
113
+ VALUE out = decode_one_frame(dctx, in + off, in_size - off, kwargs);
90
114
 
91
- size_t const decompress_size = zstd_decompress(dctx, output_data, uncompressed_size, input_data, input_size, false);
92
- if (ZSTD_isError(decompress_size)) {
93
- rb_raise(rb_eRuntimeError, "%s: %s", "decompress error", ZSTD_getErrorName(decompress_size));
115
+ ZSTD_freeDCtx(dctx);
116
+ xfree(in);
117
+ RB_GC_GUARD(input_value);
118
+ return out;
119
+ }
120
+
121
+ off += 1;
94
122
  }
95
- ZSTD_freeDCtx(dctx);
96
- return output;
123
+
124
+ xfree(in);
125
+ RB_GC_GUARD(input_value);
126
+ rb_raise(rb_eRuntimeError, "not a zstd frame (magic not found)");
97
127
  }
98
128
 
99
129
  static void free_cdict(void *dict)
@@ -1,3 +1,3 @@
1
1
  module Zstd
2
- VERSION = "2.0.0-preview1"
2
+ VERSION = "2.0.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zstd-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.pre.preview1
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - SpringMT
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2025-07-26 00:00:00.000000000 Z
10
+ date: 2025-09-29 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: bundler
@@ -188,7 +187,6 @@ homepage: https://github.com/SpringMT/zstd-ruby
188
187
  licenses:
189
188
  - MIT
190
189
  metadata: {}
191
- post_install_message:
192
190
  rdoc_options: []
193
191
  require_paths:
194
192
  - lib
@@ -199,12 +197,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
199
197
  version: '0'
200
198
  required_rubygems_version: !ruby/object:Gem::Requirement
201
199
  requirements:
202
- - - ">"
200
+ - - ">="
203
201
  - !ruby/object:Gem::Version
204
- version: 1.3.1
202
+ version: '0'
205
203
  requirements: []
206
- rubygems_version: 3.4.19
207
- signing_key:
204
+ rubygems_version: 3.6.2
208
205
  specification_version: 4
209
206
  summary: Ruby binding for zstd(Zstandard - Fast real-time compression algorithm)
210
207
  test_files: []