zstd-ruby 2.0.0 → 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: c217e3eae21252b6af27b109769b412d7f2e527366b7f197c16ceb1a5c9b7374
4
- data.tar.gz: 67f593fa170baaf3b1a87e0683794da2d2bbd7b89d6eb58c2ac8e513f18aba84
3
+ metadata.gz: 91a2e54ff93b0c602d6b2d064f6f8c615a59f0ef963c20b24e4db6d17643163e
4
+ data.tar.gz: cbeb4c7c21187336a284cb714765fb80b02b982c6b4fafa60784d8f7950fe528
5
5
  SHA512:
6
- metadata.gz: cdea0867d22baff1f4d1992103b0afd851495f7cb1ab6cbf6fcbaec9fc90f427e4c856fc7cbce47eea70a17165b43e3ad5410199c9a7c7abd71a6c62b69042ee
7
- data.tar.gz: b2a4087ac5eabdde754f4b9eb2f33e5409022856d617787f4d2f920b9143de930f5a6ed5a91e52a205743c18031e90bc859679fd70584215fedf454140dfd12b
6
+ metadata.gz: 70190b1a1233782dc440e5ef913f4a83b6bc936ea96d744f5a44b3dbceb41f8a1ef9c3264746eb251356b95c13c5503b2b2567076bc45c28d628ee278b9c2522
7
+ data.tar.gz: 600bc166bef41126b93a0e78190bbf6b5698259797e166ee4d787a113d6c4e27e7c6c927135e54b33a7e4cc25a74b2df4cb19413f74618892191863cc4c9b4fb
@@ -105,13 +105,13 @@ static VALUE
105
105
  no_compress(struct streaming_compress_t* sc, ZSTD_EndDirective endOp)
106
106
  {
107
107
  ZSTD_inBuffer input = { NULL, 0, 0 };
108
- const char* output_data = RSTRING_PTR(sc->buf);
109
108
  VALUE result = rb_str_new(0, 0);
110
109
  size_t ret;
111
110
  do {
111
+ const char* output_data = RSTRING_PTR(sc->buf);
112
112
  ZSTD_outBuffer output = { (void*)output_data, sc->buf_size, 0 };
113
113
 
114
- size_t const ret = zstd_stream_compress(sc->ctx, &output, &input, endOp, false);
114
+ ret = zstd_stream_compress(sc->ctx, &output, &input, endOp, false);
115
115
  if (ZSTD_isError(ret)) {
116
116
  rb_raise(rb_eRuntimeError, "flush error error code: %s", ZSTD_getErrorName(ret));
117
117
  }
@@ -131,9 +131,9 @@ rb_streaming_compress_compress(VALUE obj, VALUE src)
131
131
  struct streaming_compress_t* sc;
132
132
  TypedData_Get_Struct(obj, struct streaming_compress_t, &streaming_compress_type, sc);
133
133
 
134
- const char* output_data = RSTRING_PTR(sc->buf);
135
134
  VALUE result = rb_str_new(0, 0);
136
135
  while (input.pos < input.size) {
136
+ const char* output_data = RSTRING_PTR(sc->buf);
137
137
  ZSTD_outBuffer output = { (void*)output_data, sc->buf_size, 0 };
138
138
  size_t const ret = zstd_stream_compress(sc->ctx, &output, &input, ZSTD_e_continue, false);
139
139
  if (ZSTD_isError(ret)) {
@@ -150,7 +150,6 @@ rb_streaming_compress_write(int argc, VALUE *argv, VALUE obj)
150
150
  size_t total = 0;
151
151
  struct streaming_compress_t* sc;
152
152
  TypedData_Get_Struct(obj, struct streaming_compress_t, &streaming_compress_type, sc);
153
- const char* output_data = RSTRING_PTR(sc->buf);
154
153
 
155
154
  while (argc-- > 0) {
156
155
  VALUE str = *argv++;
@@ -160,18 +159,20 @@ rb_streaming_compress_write(int argc, VALUE *argv, VALUE obj)
160
159
  ZSTD_inBuffer input = { input_data, input_size, 0 };
161
160
 
162
161
  while (input.pos < input.size) {
162
+ const char* output_data = RSTRING_PTR(sc->buf);
163
163
  ZSTD_outBuffer output = { (void*)output_data, sc->buf_size, 0 };
164
164
  size_t const ret = zstd_stream_compress(sc->ctx, &output, &input, ZSTD_e_continue, false);
165
165
  if (ZSTD_isError(ret)) {
166
166
  rb_raise(rb_eRuntimeError, "compress error error code: %s", ZSTD_getErrorName(ret));
167
167
  }
168
- /* collect produced bytes */
168
+ /* Directly append to the pending buffer */
169
169
  if (output.pos > 0) {
170
170
  rb_str_cat(sc->pending, output.dst, output.pos);
171
171
  }
172
- total += RSTRING_LEN(str);
173
172
  }
173
+ total += RSTRING_LEN(str);
174
174
  }
175
+
175
176
  return SIZET2NUM(total);
176
177
  }
177
178
 
@@ -202,9 +203,9 @@ rb_streaming_compress_flush(VALUE obj)
202
203
  struct streaming_compress_t* sc;
203
204
  TypedData_Get_Struct(obj, struct streaming_compress_t, &streaming_compress_type, sc);
204
205
  VALUE drained = no_compress(sc, ZSTD_e_flush);
205
- rb_str_cat(sc->pending, RSTRING_PTR(drained), RSTRING_LEN(drained));
206
- VALUE out = sc->pending;
207
- sc->pending = rb_str_new(0, 0);
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);
208
209
  return out;
209
210
  }
210
211
 
@@ -214,9 +215,9 @@ rb_streaming_compress_finish(VALUE obj)
214
215
  struct streaming_compress_t* sc;
215
216
  TypedData_Get_Struct(obj, struct streaming_compress_t, &streaming_compress_type, sc);
216
217
  VALUE drained = no_compress(sc, ZSTD_e_end);
217
- rb_str_cat(sc->pending, RSTRING_PTR(drained), RSTRING_LEN(drained));
218
- VALUE out = sc->pending;
219
- sc->pending = rb_str_new(0, 0);
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);
220
221
  return out;
221
222
  }
222
223
 
@@ -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"
2
+ VERSION = "2.0.1"
3
3
  end
metadata CHANGED
@@ -1,13 +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
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - SpringMT
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-09-26 00:00:00.000000000 Z
10
+ date: 2025-09-29 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: bundler