extzstd 0.1.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
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
  }