extzstd 0.1.1 → 0.2

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.
Files changed (85) hide show
  1. checksums.yaml +5 -5
  2. data/HISTORY.ja.md +18 -0
  3. data/README.md +15 -50
  4. data/contrib/zstd/CONTRIBUTING.md +1 -1
  5. data/contrib/zstd/COPYING +339 -0
  6. data/contrib/zstd/Makefile +82 -51
  7. data/contrib/zstd/NEWS +92 -5
  8. data/contrib/zstd/README.md +50 -41
  9. data/contrib/zstd/appveyor.yml +164 -102
  10. data/contrib/zstd/circle.yml +10 -22
  11. data/contrib/zstd/lib/BUCK +31 -10
  12. data/contrib/zstd/lib/Makefile +57 -31
  13. data/contrib/zstd/lib/README.md +68 -37
  14. data/contrib/zstd/lib/common/bitstream.h +130 -76
  15. data/contrib/zstd/lib/common/compiler.h +86 -0
  16. data/contrib/zstd/lib/common/error_private.c +15 -11
  17. data/contrib/zstd/lib/common/error_private.h +8 -8
  18. data/contrib/zstd/lib/common/fse.h +19 -9
  19. data/contrib/zstd/lib/common/fse_decompress.c +3 -22
  20. data/contrib/zstd/lib/common/huf.h +68 -26
  21. data/contrib/zstd/lib/common/mem.h +23 -35
  22. data/contrib/zstd/lib/common/pool.c +123 -63
  23. data/contrib/zstd/lib/common/pool.h +19 -10
  24. data/contrib/zstd/lib/common/threading.c +11 -16
  25. data/contrib/zstd/lib/common/threading.h +52 -33
  26. data/contrib/zstd/lib/common/xxhash.c +28 -22
  27. data/contrib/zstd/lib/common/zstd_common.c +40 -27
  28. data/contrib/zstd/lib/common/zstd_errors.h +43 -34
  29. data/contrib/zstd/lib/common/zstd_internal.h +131 -123
  30. data/contrib/zstd/lib/compress/fse_compress.c +17 -33
  31. data/contrib/zstd/lib/compress/huf_compress.c +15 -9
  32. data/contrib/zstd/lib/compress/zstd_compress.c +2096 -2363
  33. data/contrib/zstd/lib/compress/zstd_compress_internal.h +462 -0
  34. data/contrib/zstd/lib/compress/zstd_double_fast.c +309 -0
  35. data/contrib/zstd/lib/compress/zstd_double_fast.h +29 -0
  36. data/contrib/zstd/lib/compress/zstd_fast.c +243 -0
  37. data/contrib/zstd/lib/compress/zstd_fast.h +31 -0
  38. data/contrib/zstd/lib/compress/zstd_lazy.c +765 -0
  39. data/contrib/zstd/lib/compress/zstd_lazy.h +39 -0
  40. data/contrib/zstd/lib/compress/zstd_ldm.c +707 -0
  41. data/contrib/zstd/lib/compress/zstd_ldm.h +68 -0
  42. data/contrib/zstd/lib/compress/zstd_opt.c +785 -0
  43. data/contrib/zstd/lib/compress/zstd_opt.h +19 -908
  44. data/contrib/zstd/lib/compress/zstdmt_compress.c +737 -327
  45. data/contrib/zstd/lib/compress/zstdmt_compress.h +88 -26
  46. data/contrib/zstd/lib/decompress/huf_decompress.c +158 -50
  47. data/contrib/zstd/lib/decompress/zstd_decompress.c +884 -699
  48. data/contrib/zstd/lib/deprecated/zbuff.h +5 -4
  49. data/contrib/zstd/lib/deprecated/zbuff_common.c +5 -5
  50. data/contrib/zstd/lib/deprecated/zbuff_compress.c +6 -4
  51. data/contrib/zstd/lib/deprecated/zbuff_decompress.c +5 -4
  52. data/contrib/zstd/lib/dictBuilder/cover.c +93 -77
  53. data/contrib/zstd/lib/dictBuilder/zdict.c +107 -92
  54. data/contrib/zstd/lib/dictBuilder/zdict.h +112 -102
  55. data/contrib/zstd/lib/legacy/zstd_legacy.h +9 -4
  56. data/contrib/zstd/lib/legacy/zstd_v01.c +7 -6
  57. data/contrib/zstd/lib/legacy/zstd_v01.h +5 -4
  58. data/contrib/zstd/lib/legacy/zstd_v02.c +27 -99
  59. data/contrib/zstd/lib/legacy/zstd_v02.h +5 -4
  60. data/contrib/zstd/lib/legacy/zstd_v03.c +26 -98
  61. data/contrib/zstd/lib/legacy/zstd_v03.h +5 -4
  62. data/contrib/zstd/lib/legacy/zstd_v04.c +22 -91
  63. data/contrib/zstd/lib/legacy/zstd_v04.h +5 -4
  64. data/contrib/zstd/lib/legacy/zstd_v05.c +23 -99
  65. data/contrib/zstd/lib/legacy/zstd_v05.h +5 -4
  66. data/contrib/zstd/lib/legacy/zstd_v06.c +22 -96
  67. data/contrib/zstd/lib/legacy/zstd_v06.h +5 -4
  68. data/contrib/zstd/lib/legacy/zstd_v07.c +19 -95
  69. data/contrib/zstd/lib/legacy/zstd_v07.h +5 -4
  70. data/contrib/zstd/lib/zstd.h +895 -271
  71. data/ext/extconf.rb +11 -2
  72. data/ext/extzstd.c +45 -128
  73. data/ext/extzstd.h +74 -31
  74. data/ext/extzstd_stream.c +401 -142
  75. data/ext/zstd_common.c +5 -0
  76. data/ext/zstd_compress.c +8 -0
  77. data/ext/zstd_decompress.c +1 -0
  78. data/ext/zstd_dictbuilder.c +2 -0
  79. data/lib/extzstd/version.rb +1 -1
  80. data/lib/extzstd.rb +48 -1
  81. data/test/test_basic.rb +9 -1
  82. metadata +17 -7
  83. data/HISTORY.ja +0 -10
  84. data/contrib/zstd/LICENSE-examples +0 -11
  85. data/contrib/zstd/PATENTS +0 -33
data/ext/extzstd_stream.c CHANGED
@@ -2,48 +2,97 @@
2
2
  #include "extzstd_nogvls.h"
3
3
  #include <errno.h>
4
4
 
5
+ enum {
6
+ EXT_PARTIAL_READ_SIZE = 256 * 1024, /* 256 KiB */
7
+ EXT_READ_GROWUP_SIZE = 256 * 1024, /* 256 KiB */
8
+ EXT_READ_DOUBLE_GROWUP_LIMIT_SIZE = 4 * 1024 * 1024, /* 4 MiB */
9
+ };
10
+
11
+ static inline VALUE
12
+ aux_str_buf_recycle(VALUE str, size_t capacity)
13
+ {
14
+ if (!RTEST(str) || rb_obj_frozen_p(str) || !rb_type_p(str, RUBY_T_STRING)) {
15
+ return rb_str_buf_new(capacity);
16
+ } else {
17
+ return aux_str_modify_expand(str, capacity);
18
+ }
19
+ }
20
+
21
+ static ID id_op_lsh, id_read;
22
+
5
23
  /*
6
- * class Zstd::StreamEncoder
24
+ * class Zstd::Encoder
7
25
  */
8
26
 
9
27
  static VALUE cStreamEncoder;
10
28
 
29
+ struct encoder
30
+ {
31
+ ZSTD_CStream *context;
32
+ VALUE outport;
33
+ VALUE predict;
34
+ VALUE destbuf;
35
+ int reached_eof;
36
+ };
37
+
11
38
  static void
12
- enc_free(void *p)
39
+ enc_gc_mark(void *pp)
13
40
  {
14
- ZSTD_freeCStream(p);
41
+ if (pp) {
42
+ struct encoder *p = (struct encoder *)pp;
43
+ rb_gc_mark(p->outport);
44
+ rb_gc_mark(p->predict);
45
+ rb_gc_mark(p->destbuf);
46
+ }
47
+ }
48
+
49
+ static void
50
+ enc_free(void *pp)
51
+ {
52
+ if (pp) {
53
+ struct encoder *p = (struct encoder *)pp;
54
+ if (p->context) {
55
+ ZSTD_freeCStream(p->context);
56
+ p->context = NULL;
57
+ }
58
+ xfree(p);
59
+ }
15
60
  }
16
61
 
17
62
  AUX_IMPLEMENT_CONTEXT(
18
- ZSTD_CStream, encoder_type, "extzstd.Zstd::StreamEncoder",
19
- encoder_alloc_dummy, NULL, enc_free, NULL,
63
+ struct encoder, encoder_type, "extzstd.Zstd::Encoder",
64
+ encoder_alloc_dummy, enc_gc_mark, enc_free, NULL,
20
65
  getencoderp, getencoder, encoder_p);
21
66
 
22
67
  static VALUE
23
68
  enc_alloc(VALUE mod)
24
69
  {
25
- VALUE obj = TypedData_Wrap_Struct(mod, &encoder_type, NULL);
26
-
27
- ZSTD_CStream *p = ZSTD_createCStream();
28
- if (!p) {
29
- rb_gc();
30
- p = ZSTD_createCStream();
31
- if (!p) {
32
- errno = ENOMEM;
33
- rb_sys_fail("failed ZSTD_createCStream()");
34
- }
35
- }
36
- DATA_PTR(obj) = p;
37
-
70
+ struct encoder *p;
71
+ VALUE obj = TypedData_Make_Struct(mod, struct encoder, &encoder_type, p);
72
+ p->outport = Qnil;
73
+ p->predict = Qnil;
74
+ p->destbuf = Qnil;
38
75
  return obj;
39
76
  }
40
77
 
78
+ static struct encoder *
79
+ encoder_context(VALUE self)
80
+ {
81
+ struct encoder *p = getencoder(self);
82
+ if (!p->context) {
83
+ rb_raise(rb_eTypeError,
84
+ "wrong initialized context - #<%s:%p>",
85
+ rb_obj_classname(self), (void *)self);
86
+ }
87
+ return p;
88
+ }
89
+
41
90
  /*
42
91
  * call-seq:
43
- * initialize(compression_parameters, predict)
92
+ * initialize(outport, compression_parameters = nil, predict = nil)
44
93
  */
45
94
  static VALUE
46
- enc_init(VALUE self, VALUE params, VALUE predict)
95
+ enc_init(int argc, VALUE argv[], VALUE self)
47
96
  {
48
97
  /*
49
98
  * ZSTDLIB_API size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel);
@@ -52,7 +101,37 @@ enc_init(VALUE self, VALUE params, VALUE predict)
52
101
  * ZSTD_parameters params, unsigned long long pledgedSrcSize);
53
102
  */
54
103
 
55
- ZSTD_CStream *p = getencoder(self);
104
+ VALUE outport, params, predict;
105
+ switch (argc) {
106
+ case 1:
107
+ outport = argv[0];
108
+ params = predict = Qnil;
109
+ break;
110
+ case 2:
111
+ outport = argv[0];
112
+ params = argv[1];
113
+ predict = Qnil;
114
+ break;
115
+ case 3:
116
+ outport = argv[0];
117
+ params = argv[1];
118
+ predict = argv[2];
119
+ break;
120
+ default:
121
+ rb_error_arity(argc, 1, 3);
122
+ }
123
+
124
+ struct encoder *p = getencoder(self);
125
+ if (p->context) {
126
+ rb_raise(rb_eTypeError,
127
+ "initialized already - #<%s:%p>",
128
+ rb_obj_classname(self), (void *)self);
129
+ }
130
+
131
+ AUX_TRY_WITH_GC(
132
+ p->context = ZSTD_createCStream(),
133
+ "failed ZSTD_createCStream()");
134
+
56
135
  const void *predictp;
57
136
  size_t predictsize;
58
137
  if (NIL_P(predict)) {
@@ -60,107 +139,102 @@ enc_init(VALUE self, VALUE params, VALUE predict)
60
139
  predictsize = 0;
61
140
  } else {
62
141
  rb_check_type(predict, RUBY_T_STRING);
142
+ predict = rb_str_new_frozen(predict);
63
143
  RSTRING_GETMEM(predict, predictp, predictsize);
64
144
  }
65
145
 
66
146
  if (extzstd_params_p(params)) {
67
147
  ZSTD_parameters *paramsp = extzstd_getparams(params);
68
- size_t s = ZSTD_initCStream_advanced(p, predictp, predictsize, *paramsp, 0);
148
+ size_t s = ZSTD_initCStream_advanced(p->context, predictp, predictsize, *paramsp, 0);
69
149
  extzstd_check_error(s);
70
150
  } else {
71
- size_t s = ZSTD_initCStream_usingDict(p, predictp, predictsize, aux_num2int(params, 1));
151
+ size_t s = ZSTD_initCStream_usingDict(p->context, predictp, predictsize, aux_num2int(params, 1));
72
152
  extzstd_check_error(s);
73
153
  }
154
+
155
+ p->predict = predict;
156
+ p->outport = outport;
157
+
74
158
  return self;
75
159
  }
76
160
 
77
161
  static VALUE
78
- enc_update(VALUE self, VALUE src, VALUE srcoff, VALUE dest, VALUE maxdest)
162
+ enc_write(VALUE self, VALUE src)
79
163
  {
80
164
  /*
81
165
  * ZSTDLIB_API size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input);
82
166
  */
83
167
 
84
- ZSTD_CStream *p = getencoder(self);
85
-
168
+ struct encoder *p = encoder_context(self);
86
169
  rb_check_type(src, RUBY_T_STRING);
87
- const char *q = RSTRING_PTR(src);
88
- const char *qq = RSTRING_END(src);
89
- const char *q1 = q + NUM2SIZET(srcoff);
90
- if (q1 < q || q1 > qq) {
91
- rb_raise(rb_eArgError,
92
- "``srcoff'' is out of range (given %"PRIuSIZE", expect 0..%"PRIuSIZE")",
93
- q1 - q, qq - q);
94
- }
170
+ ZSTD_inBuffer input = { RSTRING_PTR(src), RSTRING_LEN(src), 0 };
171
+
172
+ while (input.pos < input.size) {
173
+ p->destbuf = aux_str_buf_recycle(p->destbuf, ZSTD_CStreamOutSize() * 2);
174
+ rb_str_set_len(p->destbuf, 0);
175
+ rb_obj_infect(self, src);
176
+ rb_obj_infect(p->destbuf, self);
177
+ ZSTD_outBuffer output = { RSTRING_PTR(p->destbuf), rb_str_capacity(p->destbuf), 0 };
178
+ size_t s = ZSTD_compressStream(p->context, &output, &input);
179
+ extzstd_check_error(s);
180
+ rb_str_set_len(p->destbuf, output.pos);
95
181
 
96
- rb_check_type(dest, RUBY_T_STRING);
97
- rb_str_modify(dest);
98
- rb_str_set_len(dest, 0);
99
- rb_str_modify_expand(dest, NUM2SIZET(maxdest));
100
- rb_obj_infect(self, src);
101
- rb_obj_infect(dest, self);
102
- char *r = RSTRING_PTR(dest);
103
- const char *rr = r + rb_str_capacity(dest);
104
-
105
- ZSTD_inBuffer input = { q, qq - q, q1 - q };
106
- ZSTD_outBuffer output = { r, rr - r, 0 };
107
- size_t s = ZSTD_compressStream(p, &output, &input);
108
- extzstd_check_error(s);
109
- rb_str_set_len(dest, output.pos);
110
- if (input.pos == input.size) {
111
- return Qnil;
112
- } else {
113
- return SIZET2NUM(input.pos);
182
+ // TODO: 例外や帯域脱出した場合の挙動は?
183
+ // TODO: src の途中経過状態を保存するべきか?
184
+ AUX_FUNCALL(p->outport, id_op_lsh, p->destbuf);
114
185
  }
186
+
187
+ return self;
115
188
  }
116
189
 
117
190
  static VALUE
118
- enc_flush(VALUE self, VALUE dest, VALUE maxdest)
191
+ enc_sync(VALUE self)
119
192
  {
120
193
  /*
121
194
  * ZSTDLIB_API size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output);
122
195
  */
123
196
 
124
- ZSTD_CStream *p = getencoder(self);
197
+ struct encoder *p = encoder_context(self);
198
+ aux_str_buf_recycle(p->destbuf, ZSTD_CStreamOutSize());
199
+ rb_str_set_len(p->destbuf, 0);
200
+ rb_obj_infect(p->destbuf, self);
201
+ ZSTD_outBuffer output = { RSTRING_PTR(p->destbuf), rb_str_capacity(p->destbuf), 0 };
202
+ size_t s = ZSTD_flushStream(p->context, &output);
203
+ extzstd_check_error(s);
204
+ rb_str_set_len(p->destbuf, output.pos);
125
205
 
126
- rb_check_type(dest, RUBY_T_STRING);
127
- rb_str_modify(dest);
128
- rb_str_set_len(dest, 0);
129
- rb_str_modify_expand(dest, NUM2SIZET(maxdest));
206
+ AUX_FUNCALL(p->outport, id_op_lsh, p->destbuf);
130
207
 
131
- ZSTD_outBuffer output = { RSTRING_PTR(dest), rb_str_capacity(dest), 0 };
132
- size_t s = ZSTD_flushStream(p, &output);
133
- extzstd_check_error(s);
134
- if (output.size > 0) {
135
- rb_str_set_len(dest, output.pos);
136
- return dest;
137
- } else {
138
- return Qnil;
139
- }
208
+ return self;
140
209
  }
141
210
 
142
211
  static VALUE
143
- enc_end(VALUE self, VALUE dest, VALUE maxdest)
212
+ enc_close(VALUE self)
144
213
  {
145
214
  /*
146
215
  * ZSTDLIB_API size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output);
147
216
  */
148
217
 
149
- ZSTD_CStream *p = getencoder(self);
150
- rb_check_type(dest, RUBY_T_STRING);
151
- rb_str_modify(dest);
152
- rb_str_set_len(dest, 0);
153
- rb_str_modify_expand(dest, NUM2SIZET(maxdest));
154
-
155
- ZSTD_outBuffer output = { RSTRING_PTR(dest), rb_str_capacity(dest), 0 };
156
- size_t s = ZSTD_endStream(p, &output);
218
+ struct encoder *p = encoder_context(self);
219
+ aux_str_buf_recycle(p->destbuf, ZSTD_CStreamOutSize());
220
+ rb_str_set_len(p->destbuf, 0);
221
+ rb_obj_infect(p->destbuf, self);
222
+ ZSTD_outBuffer output = { RSTRING_PTR(p->destbuf), rb_str_capacity(p->destbuf), 0 };
223
+ size_t s = ZSTD_endStream(p->context, &output);
157
224
  extzstd_check_error(s);
158
- if (output.size > 0) {
159
- rb_str_set_len(dest, output.pos);
160
- return dest;
161
- } else {
162
- return Qnil;
163
- }
225
+ rb_str_set_len(p->destbuf, output.pos);
226
+
227
+ AUX_FUNCALL(p->outport, id_op_lsh, p->destbuf);
228
+
229
+ p->reached_eof = 1;
230
+
231
+ return Qnil;
232
+ }
233
+
234
+ static VALUE
235
+ enc_eof(VALUE self)
236
+ {
237
+ return (encoder_context(self)->reached_eof == 0 ? Qfalse : Qtrue);
164
238
  }
165
239
 
166
240
  static VALUE
@@ -170,7 +244,7 @@ enc_reset(VALUE self, VALUE pledged_srcsize)
170
244
  * ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize);
171
245
  */
172
246
 
173
- size_t s = ZSTD_resetCStream(getencoder(self), NUM2ULL(pledged_srcsize));
247
+ size_t s = ZSTD_resetCStream(encoder_context(self)->context, NUM2ULL(pledged_srcsize));
174
248
  extzstd_check_error(s);
175
249
  return self;
176
250
  }
@@ -182,7 +256,7 @@ enc_sizeof(VALUE self)
182
256
  * ZSTDLIB_API size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs);
183
257
  */
184
258
 
185
- size_t s = ZSTD_sizeof_CStream(getencoder(self));
259
+ size_t s = ZSTD_sizeof_CStream(encoder_context(self)->context);
186
260
  extzstd_check_error(s);
187
261
  return SIZET2NUM(s);
188
262
  }
@@ -190,113 +264,293 @@ enc_sizeof(VALUE self)
190
264
  static void
191
265
  init_encoder(void)
192
266
  {
193
- cStreamEncoder = rb_define_class_under(extzstd_mZstd, "StreamEncoder", rb_cObject);
267
+ cStreamEncoder = rb_define_class_under(extzstd_mZstd, "Encoder", rb_cObject);
194
268
  rb_define_alloc_func(cStreamEncoder, enc_alloc);
195
269
  rb_define_const(cStreamEncoder, "INSIZE", SIZET2NUM(ZSTD_CStreamInSize()));
196
270
  rb_define_const(cStreamEncoder, "OUTSIZE", SIZET2NUM(ZSTD_CStreamOutSize()));
197
- rb_define_method(cStreamEncoder, "initialize", enc_init, 2);
198
- rb_define_method(cStreamEncoder, "update", enc_update, 4);
199
- rb_define_method(cStreamEncoder, "flush", enc_flush, 2);
200
- rb_define_method(cStreamEncoder, "end", enc_end, 2);
271
+ rb_define_method(cStreamEncoder, "initialize", enc_init, -1);
272
+ rb_define_method(cStreamEncoder, "write", enc_write, 1);
273
+ rb_define_method(cStreamEncoder, "sync", enc_sync, 0);
274
+ rb_define_method(cStreamEncoder, "close", enc_close, 0);
275
+ rb_define_method(cStreamEncoder, "eof", enc_eof, 0);
276
+ rb_define_alias(cStreamEncoder, "eof?", "eof");
201
277
  rb_define_method(cStreamEncoder, "reset", enc_reset, 1);
202
278
  rb_define_method(cStreamEncoder, "sizeof", enc_sizeof, 0);
279
+ rb_define_alias(cStreamEncoder, "<<", "write");
280
+ rb_define_alias(cStreamEncoder, "update", "write");
281
+ rb_define_alias(cStreamEncoder, "flush", "sync");
282
+ rb_define_alias(cStreamEncoder, "end", "close");
283
+ rb_define_alias(cStreamEncoder, "finish", "close");
203
284
  }
204
285
 
205
286
  /*
206
- * class Zstd::StreamDecoder
287
+ * class Zstd::Decoder
207
288
  */
208
289
 
209
290
  static VALUE cStreamDecoder;
210
291
 
292
+ struct decoder
293
+ {
294
+ ZSTD_DStream *context;
295
+ VALUE inport;
296
+ VALUE readbuf;
297
+ VALUE predict;
298
+ ZSTD_inBuffer inbuf;
299
+ int reached_eof;
300
+ };
301
+
302
+ static void
303
+ dec_mark(void *pp)
304
+ {
305
+ struct decoder *p = (struct decoder *)pp;
306
+ rb_gc_mark(p->inport);
307
+ rb_gc_mark(p->readbuf);
308
+ rb_gc_mark(p->predict);
309
+ }
310
+
211
311
  static void
212
- dec_free(void *p)
312
+ dec_free(void *pp)
213
313
  {
214
- ZSTD_freeDStream(p);
314
+ struct decoder *p = (struct decoder *)pp;
315
+ if (p->context) {
316
+ ZSTD_freeDStream(p->context);
317
+ p->context = NULL;
318
+ }
319
+ xfree(p);
215
320
  }
216
321
 
217
322
  AUX_IMPLEMENT_CONTEXT(
218
- ZSTD_DStream, decoder_type, "extzstd.Zstd::StreamDecoder",
219
- decoder_alloc_dummy, NULL, dec_free, NULL,
323
+ struct decoder, decoder_type, "extzstd.Zstd::Decoder",
324
+ decoder_alloc_dummy, dec_mark, dec_free, NULL,
220
325
  getdecoderp, getdecoder, decoder_p);
221
326
 
222
- static VALUE
223
- dec_alloc(VALUE mod)
327
+ static struct decoder *
328
+ decoder_context(VALUE self)
224
329
  {
225
- VALUE obj = TypedData_Wrap_Struct(mod, &decoder_type, NULL);
226
-
227
- ZSTD_DStream *p = ZSTD_createDStream();
228
- if (!p) {
229
- rb_gc();
230
- p = ZSTD_createDStream();
231
- if (!p) {
232
- errno = ENOMEM;
233
- rb_sys_fail("failed ZSTD_createDStream()");
234
- }
330
+ struct decoder *p = getdecoder(self);
331
+ if (!p->context) {
332
+ rb_raise(rb_eTypeError,
333
+ "uninitialized context - #<%s:%p>",
334
+ rb_obj_classname(self), (void *)self);
235
335
  }
236
- DATA_PTR(obj) = p;
336
+ return p;
337
+ }
237
338
 
339
+ static VALUE
340
+ dec_alloc(VALUE mod)
341
+ {
342
+ struct decoder *p;
343
+ VALUE obj = TypedData_Make_Struct(mod, struct decoder, &decoder_type, p);
238
344
  return obj;
239
345
  }
240
346
 
241
347
  /*
242
348
  * call-seq:
243
- * initialize(predict)
349
+ * initialize(inport, predict = Qnil)
244
350
  */
245
351
  static VALUE
246
- dec_init(VALUE self, VALUE predict)
352
+ dec_init(int argc, VALUE argv[], VALUE self)
247
353
  {
248
354
  /*
249
355
  * ZSTDLIB_API size_t ZSTD_initDStream(ZSTD_DStream* zds);
250
356
  * ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize);
251
357
  */
252
358
 
253
- ZSTD_DStream *p = getdecoder(self);
359
+ VALUE inport, predict;
360
+
361
+ switch (argc) {
362
+ case 1:
363
+ inport = argv[0];
364
+ predict = Qnil;
365
+ break;
366
+ case 2:
367
+ inport = argv[0];
368
+ predict = argv[1];
369
+ break;
370
+ default:
371
+ rb_error_arity(argc, 1, 2);
372
+ }
373
+
374
+ struct decoder *p = getdecoder(self);
375
+ if (p->context) {
376
+ rb_raise(rb_eTypeError,
377
+ "initialized context already - #<%s:%p>",
378
+ rb_obj_classname(self), (void *)self);
379
+ }
380
+
381
+ AUX_TRY_WITH_GC(
382
+ p->context = ZSTD_createDStream(),
383
+ "failed ZSTD_createDStream()");
254
384
 
255
385
  if (NIL_P(predict)) {
256
- size_t s = ZSTD_initDStream(p);
386
+ size_t s = ZSTD_initDStream(p->context);
257
387
  extzstd_check_error(s);
258
388
  } else {
259
389
  rb_check_type(predict, RUBY_T_STRING);
260
- size_t s = ZSTD_initDStream_usingDict(p, RSTRING_PTR(predict), RSTRING_LEN(predict));
390
+ predict = rb_str_new_frozen(predict);
391
+ size_t s = ZSTD_initDStream_usingDict(p->context, RSTRING_PTR(predict), RSTRING_LEN(predict));
261
392
  extzstd_check_error(s);
262
393
  }
394
+
395
+ p->inport = inport;
396
+ p->predict = predict;
397
+
263
398
  return self;
264
399
  }
265
400
 
401
+ static int
402
+ dec_read_fetch(VALUE o, struct decoder *p)
403
+ {
404
+ if (!p->inbuf.src || NIL_P(p->readbuf) || p->inbuf.pos >= RSTRING_LEN(p->readbuf)) {
405
+ p->readbuf = aux_str_buf_recycle(p->readbuf, EXT_PARTIAL_READ_SIZE);
406
+ VALUE st = AUX_FUNCALL(p->inport, id_read, INT2FIX(EXT_PARTIAL_READ_SIZE), p->readbuf);
407
+ if (NIL_P(st)) { return -1; }
408
+ rb_check_type(st, RUBY_T_STRING);
409
+ p->readbuf = st;
410
+ rb_obj_infect(o, p->readbuf);
411
+ p->inbuf.size = RSTRING_LEN(p->readbuf);
412
+ p->inbuf.pos = 0;
413
+ }
414
+
415
+ p->inbuf.src = RSTRING_PTR(p->readbuf);
416
+
417
+ return 0;
418
+ }
419
+
420
+ static size_t
421
+ dec_read_decode(VALUE o, struct decoder *p, char *buf, ssize_t size)
422
+ {
423
+ if (p->reached_eof != 0) {
424
+ return 0;
425
+ }
426
+
427
+ ZSTD_outBuffer output = { buf, size, 0 };
428
+
429
+ while (size < 0 || output.pos < size) {
430
+ if (dec_read_fetch(o, p) != 0) {
431
+ if (p->reached_eof == 0) {
432
+ rb_raise(rb_eRuntimeError,
433
+ "unexpected EOF - #<%s:%p>",
434
+ rb_obj_classname(p->inport), (void *)p->inport);
435
+ }
436
+
437
+ break;
438
+ }
439
+
440
+ rb_thread_check_ints();
441
+ size_t s = ZSTD_decompressStream(p->context, &output, &p->inbuf);
442
+ extzstd_check_error(s);
443
+ if (s == 0) {
444
+ p->reached_eof = 1;
445
+ break;
446
+ }
447
+ }
448
+
449
+ return output.pos;
450
+ }
451
+
452
+ static void
453
+ dec_read_args(int argc, VALUE argv[], VALUE self, VALUE *buf, ssize_t *size)
454
+ {
455
+ switch (argc) {
456
+ case 0:
457
+ *size = -1;
458
+ *buf = rb_str_buf_new(EXT_READ_GROWUP_SIZE);
459
+ break;
460
+ case 1:
461
+ case 2:
462
+ {
463
+ if (NIL_P(argv[0])) {
464
+ *size = -1;
465
+
466
+ if (argc == 1) {
467
+ *buf = rb_str_buf_new(EXT_READ_GROWUP_SIZE);
468
+ } else {
469
+ rb_check_type(argv[1], RUBY_T_STRING);
470
+ *buf = aux_str_modify_expand(argv[1], EXT_READ_GROWUP_SIZE);
471
+ rb_str_set_len(*buf, 0);
472
+ }
473
+ } else {
474
+ *size = NUM2SIZET(argv[0]);
475
+
476
+ if (*size < 0) {
477
+ rb_raise(rb_eArgError,
478
+ "``size'' is negative or too large (%"PRIdPTR")",
479
+ (intptr_t)*size);
480
+ }
481
+
482
+ if (argc == 1) {
483
+ *buf = rb_str_buf_new(*size);
484
+ } else {
485
+ rb_check_type(argv[1], RUBY_T_STRING);
486
+ *buf = aux_str_modify_expand(argv[1], *size);
487
+ rb_str_set_len(*buf, 0);
488
+ }
489
+ }
490
+ }
491
+ break;
492
+ default:
493
+ rb_error_arity(argc, 0, 2);
494
+ }
495
+ }
496
+
497
+ /*
498
+ * call-seq:
499
+ * read -> read_data
500
+ * read(readsize, buf = "".b) -> buf
501
+ */
266
502
  static VALUE
267
- dec_update(VALUE self, VALUE src, VALUE srcoff, VALUE dest, VALUE maxdest)
503
+ dec_read(int argc, VALUE argv[], VALUE self)
268
504
  {
269
505
  /*
270
506
  * ZSTDLIB_API size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input);
271
507
  */
272
508
 
273
- ZSTD_DStream *p = getdecoder(self);
509
+ ssize_t size;
510
+ VALUE buf;
511
+ dec_read_args(argc, argv, self, &buf, &size);
274
512
 
275
- rb_check_type(src, RUBY_T_STRING);
276
- const char *q = RSTRING_PTR(src);
277
- const char *qq = RSTRING_END(src);
278
- const char *q1 = q + NUM2SIZET(srcoff);
279
- if (q1 < q || q1 > qq) {
280
- rb_raise(rb_eArgError,
281
- "``srcoff'' is out of range (given %"PRIuSIZE", expect 0..%"PRIuSIZE")",
282
- q1 - q, qq - q);
513
+ struct decoder *p = decoder_context(self);
514
+
515
+ if (size == 0) {
516
+ rb_str_set_len(buf, 0);
517
+ return buf;
518
+ } else if (size > 0) {
519
+ size = dec_read_decode(self, p, RSTRING_PTR(buf), size);
520
+ rb_str_set_len(buf, size);
521
+ } else {
522
+ /* if (size < 0) */
523
+
524
+ size_t capa = EXT_READ_GROWUP_SIZE;
525
+
526
+ for (;;) {
527
+ aux_str_modify_expand(buf, capa);
528
+ size = dec_read_decode(self, p, RSTRING_PTR(buf) + RSTRING_LEN(buf), capa - RSTRING_LEN(buf));
529
+ rb_str_set_len(buf, RSTRING_LEN(buf) + size);
530
+ if (size == 0) { break; }
531
+ size = rb_str_capacity(buf);
532
+ if (size > RSTRING_LEN(buf)) { break; }
533
+ if (size > EXT_READ_DOUBLE_GROWUP_LIMIT_SIZE) {
534
+ capa += EXT_READ_DOUBLE_GROWUP_LIMIT_SIZE;
535
+ } else {
536
+ capa *= 2;
537
+ }
538
+ }
283
539
  }
284
540
 
285
- rb_check_type(dest, RUBY_T_STRING);
286
- rb_str_modify(dest);
287
- rb_str_set_len(dest, 0);
288
- rb_str_modify_expand(dest, NUM2SIZET(maxdest));
289
- rb_obj_infect(self, src);
290
- rb_obj_infect(dest, self);
291
- char *r = RSTRING_PTR(dest);
292
- const char *rr = r + rb_str_capacity(dest);
293
-
294
- ZSTD_inBuffer input = { q, qq - q, q1 - q };
295
- ZSTD_outBuffer output = { r, rr - r, 0 };
296
- size_t s = ZSTD_decompressStream(p, &output, &input);
297
- extzstd_check_error(s);
298
- rb_str_set_len(dest, output.pos);
299
- return SIZET2NUM(input.pos);
541
+ rb_obj_infect(buf, self);
542
+
543
+ if (RSTRING_LEN(buf) == 0) {
544
+ return Qnil;
545
+ } else {
546
+ return buf;
547
+ }
548
+ }
549
+
550
+ static VALUE
551
+ dec_eof(VALUE self)
552
+ {
553
+ return (decoder_context(self)->reached_eof == 0 ? Qfalse : Qtrue);
300
554
  }
301
555
 
302
556
  static VALUE
@@ -305,7 +559,7 @@ dec_reset(VALUE self)
305
559
  /*
306
560
  * ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);
307
561
  */
308
- size_t s = ZSTD_resetDStream(getdecoder(self));
562
+ size_t s = ZSTD_resetDStream(decoder_context(self)->context);
309
563
  extzstd_check_error(s);
310
564
  return self;
311
565
  }
@@ -317,7 +571,7 @@ dec_sizeof(VALUE self)
317
571
  * ZSTDLIB_API size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds);
318
572
  */
319
573
 
320
- size_t s = ZSTD_sizeof_DStream(getdecoder(self));
574
+ size_t s = ZSTD_sizeof_DStream(decoder_context(self)->context);
321
575
  extzstd_check_error(s);
322
576
  return SIZET2NUM(s);
323
577
  }
@@ -325,12 +579,14 @@ dec_sizeof(VALUE self)
325
579
  static void
326
580
  init_decoder(void)
327
581
  {
328
- cStreamDecoder = rb_define_class_under(extzstd_mZstd, "StreamDecoder", rb_cObject);
582
+ cStreamDecoder = rb_define_class_under(extzstd_mZstd, "Decoder", rb_cObject);
329
583
  rb_define_alloc_func(cStreamDecoder, dec_alloc);
330
584
  rb_define_const(cStreamDecoder, "INSIZE", SIZET2NUM(ZSTD_DStreamInSize()));
331
585
  rb_define_const(cStreamDecoder, "OUTSIZE", SIZET2NUM(ZSTD_DStreamOutSize()));
332
- rb_define_method(cStreamDecoder, "initialize", dec_init, 1);
333
- rb_define_method(cStreamDecoder, "update", dec_update, 4);
586
+ rb_define_method(cStreamDecoder, "initialize", dec_init, -1);
587
+ rb_define_method(cStreamDecoder, "read", dec_read, -1);
588
+ rb_define_method(cStreamDecoder, "eof", dec_eof, 0);
589
+ rb_define_alias(cStreamDecoder, "eof?", "eof");
334
590
  rb_define_method(cStreamDecoder, "reset", dec_reset, 0);
335
591
  rb_define_method(cStreamDecoder, "sizeof", dec_sizeof, 0);
336
592
  }
@@ -342,6 +598,9 @@ init_decoder(void)
342
598
  void
343
599
  extzstd_init_stream(void)
344
600
  {
601
+ id_op_lsh = rb_intern("<<");
602
+ id_read = rb_intern("read");
603
+
345
604
  init_encoder();
346
605
  init_decoder();
347
606
  }