extlzham 0.0.1.PROTOTYPE

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 (59) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.md +27 -0
  3. data/README.md +21 -0
  4. data/Rakefile +143 -0
  5. data/contrib/lzham/LICENSE +22 -0
  6. data/contrib/lzham/README.md +209 -0
  7. data/contrib/lzham/include/lzham.h +781 -0
  8. data/contrib/lzham/lzhamcomp/lzham_comp.h +38 -0
  9. data/contrib/lzham/lzhamcomp/lzham_lzbase.cpp +244 -0
  10. data/contrib/lzham/lzhamcomp/lzham_lzbase.h +45 -0
  11. data/contrib/lzham/lzhamcomp/lzham_lzcomp.cpp +608 -0
  12. data/contrib/lzham/lzhamcomp/lzham_lzcomp_internal.cpp +1966 -0
  13. data/contrib/lzham/lzhamcomp/lzham_lzcomp_internal.h +472 -0
  14. data/contrib/lzham/lzhamcomp/lzham_lzcomp_state.cpp +1413 -0
  15. data/contrib/lzham/lzhamcomp/lzham_match_accel.cpp +562 -0
  16. data/contrib/lzham/lzhamcomp/lzham_match_accel.h +146 -0
  17. data/contrib/lzham/lzhamcomp/lzham_null_threading.h +97 -0
  18. data/contrib/lzham/lzhamcomp/lzham_pthreads_threading.cpp +229 -0
  19. data/contrib/lzham/lzhamcomp/lzham_pthreads_threading.h +520 -0
  20. data/contrib/lzham/lzhamcomp/lzham_threading.h +12 -0
  21. data/contrib/lzham/lzhamcomp/lzham_win32_threading.cpp +220 -0
  22. data/contrib/lzham/lzhamcomp/lzham_win32_threading.h +368 -0
  23. data/contrib/lzham/lzhamdecomp/lzham_assert.cpp +66 -0
  24. data/contrib/lzham/lzhamdecomp/lzham_assert.h +40 -0
  25. data/contrib/lzham/lzhamdecomp/lzham_checksum.cpp +73 -0
  26. data/contrib/lzham/lzhamdecomp/lzham_checksum.h +13 -0
  27. data/contrib/lzham/lzhamdecomp/lzham_config.h +23 -0
  28. data/contrib/lzham/lzhamdecomp/lzham_core.h +264 -0
  29. data/contrib/lzham/lzhamdecomp/lzham_decomp.h +37 -0
  30. data/contrib/lzham/lzhamdecomp/lzham_helpers.h +54 -0
  31. data/contrib/lzham/lzhamdecomp/lzham_huffman_codes.cpp +262 -0
  32. data/contrib/lzham/lzhamdecomp/lzham_huffman_codes.h +14 -0
  33. data/contrib/lzham/lzhamdecomp/lzham_lzdecomp.cpp +1527 -0
  34. data/contrib/lzham/lzhamdecomp/lzham_lzdecompbase.cpp +131 -0
  35. data/contrib/lzham/lzhamdecomp/lzham_lzdecompbase.h +89 -0
  36. data/contrib/lzham/lzhamdecomp/lzham_math.h +142 -0
  37. data/contrib/lzham/lzhamdecomp/lzham_mem.cpp +284 -0
  38. data/contrib/lzham/lzhamdecomp/lzham_mem.h +112 -0
  39. data/contrib/lzham/lzhamdecomp/lzham_platform.cpp +157 -0
  40. data/contrib/lzham/lzhamdecomp/lzham_platform.h +284 -0
  41. data/contrib/lzham/lzhamdecomp/lzham_prefix_coding.cpp +351 -0
  42. data/contrib/lzham/lzhamdecomp/lzham_prefix_coding.h +146 -0
  43. data/contrib/lzham/lzhamdecomp/lzham_symbol_codec.cpp +1484 -0
  44. data/contrib/lzham/lzhamdecomp/lzham_symbol_codec.h +556 -0
  45. data/contrib/lzham/lzhamdecomp/lzham_timer.cpp +147 -0
  46. data/contrib/lzham/lzhamdecomp/lzham_timer.h +99 -0
  47. data/contrib/lzham/lzhamdecomp/lzham_traits.h +141 -0
  48. data/contrib/lzham/lzhamdecomp/lzham_types.h +97 -0
  49. data/contrib/lzham/lzhamdecomp/lzham_utils.h +58 -0
  50. data/contrib/lzham/lzhamdecomp/lzham_vector.cpp +75 -0
  51. data/contrib/lzham/lzhamdecomp/lzham_vector.h +588 -0
  52. data/contrib/lzham/lzhamlib/lzham_lib.cpp +179 -0
  53. data/examples/basic.rb +48 -0
  54. data/ext/extconf.rb +26 -0
  55. data/ext/extlzham.c +741 -0
  56. data/gemstub.rb +22 -0
  57. data/lib/extlzham/version.rb +5 -0
  58. data/lib/extlzham.rb +153 -0
  59. metadata +135 -0
data/ext/extlzham.c ADDED
@@ -0,0 +1,741 @@
1
+ #include <stdint.h>
2
+ #include <ruby.h>
3
+ #include <ruby/thread.h>
4
+ #include <lzham.h>
5
+
6
+ static VALUE mLZHAM;
7
+ static VALUE eError;
8
+ static VALUE cEncoder;
9
+ static VALUE cDecoder;
10
+ static VALUE mConsts;
11
+
12
+ static ID ID_op_lshift;
13
+ static ID IDdictsize;
14
+ static ID IDlevel;
15
+ static ID IDtable_update_rate;
16
+ static ID IDthreads;
17
+ static ID IDflags;
18
+ static ID IDtable_max_update_interval;
19
+ static ID IDtable_update_interval_slow_rate;
20
+
21
+ enum {
22
+ WORKBUF_SIZE = 256 * 1024, /* 256 KiB */
23
+ };
24
+
25
+ #define SET_MESSAGE(MESG, CONST) \
26
+ case CONST: \
27
+ MESG = #CONST; \
28
+ break \
29
+
30
+ static inline void
31
+ aux_encode_error(lzham_compress_status_t status)
32
+ {
33
+ const char *mesg;
34
+ switch (status) {
35
+ SET_MESSAGE(mesg, LZHAM_COMP_STATUS_NOT_FINISHED);
36
+ SET_MESSAGE(mesg, LZHAM_COMP_STATUS_NEEDS_MORE_INPUT);
37
+ SET_MESSAGE(mesg, LZHAM_COMP_STATUS_HAS_MORE_OUTPUT);
38
+ SET_MESSAGE(mesg, LZHAM_COMP_STATUS_FIRST_SUCCESS_OR_FAILURE_CODE);
39
+ SET_MESSAGE(mesg, LZHAM_COMP_STATUS_FIRST_FAILURE_CODE);
40
+ SET_MESSAGE(mesg, LZHAM_COMP_STATUS_FAILED_INITIALIZING);
41
+ SET_MESSAGE(mesg, LZHAM_COMP_STATUS_INVALID_PARAMETER);
42
+ SET_MESSAGE(mesg, LZHAM_COMP_STATUS_OUTPUT_BUF_TOO_SMALL);
43
+ default:
44
+ mesg = "unknown code";
45
+ break;
46
+ }
47
+
48
+ rb_raise(eError,
49
+ "LZHAM encode error - %s (0x%04X)",
50
+ mesg, status);
51
+ }
52
+
53
+ static inline void
54
+ aux_decode_error(lzham_decompress_status_t status)
55
+ {
56
+ const char *mesg;
57
+ switch (status) {
58
+ SET_MESSAGE(mesg, LZHAM_DECOMP_STATUS_NOT_FINISHED);
59
+ SET_MESSAGE(mesg, LZHAM_DECOMP_STATUS_HAS_MORE_OUTPUT);
60
+ SET_MESSAGE(mesg, LZHAM_DECOMP_STATUS_NEEDS_MORE_INPUT);
61
+ SET_MESSAGE(mesg, LZHAM_DECOMP_STATUS_FIRST_SUCCESS_OR_FAILURE_CODE);
62
+ SET_MESSAGE(mesg, LZHAM_DECOMP_STATUS_FIRST_FAILURE_CODE);
63
+ SET_MESSAGE(mesg, LZHAM_DECOMP_STATUS_FAILED_DEST_BUF_TOO_SMALL);
64
+ SET_MESSAGE(mesg, LZHAM_DECOMP_STATUS_FAILED_EXPECTED_MORE_RAW_BYTES);
65
+ SET_MESSAGE(mesg, LZHAM_DECOMP_STATUS_FAILED_BAD_CODE);
66
+ SET_MESSAGE(mesg, LZHAM_DECOMP_STATUS_FAILED_ADLER32);
67
+ SET_MESSAGE(mesg, LZHAM_DECOMP_STATUS_FAILED_BAD_RAW_BLOCK);
68
+ SET_MESSAGE(mesg, LZHAM_DECOMP_STATUS_FAILED_BAD_COMP_BLOCK_SYNC_CHECK);
69
+ SET_MESSAGE(mesg, LZHAM_DECOMP_STATUS_FAILED_BAD_ZLIB_HEADER);
70
+ SET_MESSAGE(mesg, LZHAM_DECOMP_STATUS_FAILED_NEED_SEED_BYTES);
71
+ SET_MESSAGE(mesg, LZHAM_DECOMP_STATUS_FAILED_BAD_SEED_BYTES);
72
+ SET_MESSAGE(mesg, LZHAM_DECOMP_STATUS_FAILED_BAD_SYNC_BLOCK);
73
+ SET_MESSAGE(mesg, LZHAM_DECOMP_STATUS_INVALID_PARAMETER);
74
+ default:
75
+ mesg = "unknown code";
76
+ break;
77
+ }
78
+
79
+ rb_raise(eError,
80
+ "LZHAM decode error - %s (0x%04X)",
81
+ mesg, status);
82
+ }
83
+
84
+ static inline uint32_t
85
+ aux_hash_lookup_to_u32(VALUE hash, ID key, uint32_t defaultvalue)
86
+ {
87
+ VALUE d = rb_hash_lookup2(hash, ID2SYM(key), Qundef);
88
+ if (d == Qundef) { return defaultvalue; }
89
+ return NUM2UINT(d);
90
+ }
91
+
92
+ static inline lzham_compress_params
93
+ aux_conv_encode_params(VALUE opts)
94
+ {
95
+ lzham_compress_params p;
96
+ memset(&p, 0, sizeof(p));
97
+ p.m_struct_size = sizeof(p);
98
+ if (NIL_P(opts)) {
99
+ p.m_dict_size_log2 = LZHAM_MIN_DICT_SIZE_LOG2;
100
+ p.m_level = LZHAM_COMP_LEVEL_DEFAULT;
101
+ p.m_table_update_rate = 0;
102
+ p.m_max_helper_threads = -1;
103
+ p.m_compress_flags = 0; // (see lzham_compress_flags enum)
104
+ p.m_num_seed_bytes = 0;
105
+ p.m_pSeed_bytes = NULL;
106
+ p.m_table_max_update_interval = 0;
107
+ p.m_table_update_interval_slow_rate = 0;
108
+ } else {
109
+ p.m_dict_size_log2 = aux_hash_lookup_to_u32(opts, IDdictsize, LZHAM_MIN_DICT_SIZE_LOG2);
110
+ p.m_level = aux_hash_lookup_to_u32(opts, IDlevel, LZHAM_COMP_LEVEL_DEFAULT);
111
+ p.m_table_update_rate = aux_hash_lookup_to_u32(opts, IDtable_update_rate, 0);
112
+ p.m_max_helper_threads = aux_hash_lookup_to_u32(opts, IDthreads, -1);
113
+ p.m_compress_flags = aux_hash_lookup_to_u32(opts, IDflags, 0);
114
+ p.m_num_seed_bytes = 0;
115
+ p.m_pSeed_bytes = NULL;
116
+ p.m_table_max_update_interval = aux_hash_lookup_to_u32(opts, IDtable_max_update_interval, 0);
117
+ p.m_table_update_interval_slow_rate = aux_hash_lookup_to_u32(opts, IDtable_update_interval_slow_rate, 0);
118
+ }
119
+ return p;
120
+ }
121
+
122
+ /*
123
+ * call-seq:
124
+ * encode(string, opts = {}) -> encoded string
125
+ */
126
+ static VALUE
127
+ ext_s_encode(int argc, VALUE argv[], VALUE mod)
128
+ {
129
+ VALUE src, opts;
130
+ rb_scan_args(argc, argv, "1:", &src, &opts);
131
+ rb_check_type(src, RUBY_T_STRING);
132
+ rb_str_locktmp(src);
133
+ size_t srcsize = RSTRING_LEN(src);
134
+ size_t destsize = lzham_z_compressBound(srcsize);
135
+ VALUE dest = rb_str_buf_new(destsize);
136
+ lzham_compress_params params = aux_conv_encode_params(opts);
137
+ lzham_compress_status_t s;
138
+ s = lzham_compress_memory(&params,
139
+ (lzham_uint8 *)RSTRING_PTR(dest), &destsize,
140
+ (lzham_uint8 *)RSTRING_PTR(src), srcsize, NULL);
141
+
142
+ rb_str_unlocktmp(src);
143
+
144
+ if (s != LZHAM_COMP_STATUS_SUCCESS) {
145
+ rb_str_resize(dest, 0);
146
+ aux_encode_error(s);
147
+ }
148
+
149
+ rb_str_resize(dest, destsize);
150
+ rb_str_set_len(dest, destsize);
151
+
152
+ return dest;
153
+ }
154
+
155
+ struct encoder
156
+ {
157
+ lzham_compress_state_ptr encoder;
158
+ VALUE outport;
159
+ VALUE outbuf;
160
+ };
161
+
162
+ static void
163
+ ext_enc_mark(struct encoder *p)
164
+ {
165
+ if (p) {
166
+ rb_gc_mark(p->outport);
167
+ rb_gc_mark(p->outbuf);
168
+ }
169
+ }
170
+
171
+ static void
172
+ ext_enc_free(struct encoder *p)
173
+ {
174
+ if (p) {
175
+ if (p->encoder) {
176
+ lzham_compress_deinit(p->encoder);
177
+ }
178
+ }
179
+ }
180
+
181
+ static VALUE
182
+ ext_enc_alloc(VALUE klass)
183
+ {
184
+ struct encoder *p;
185
+ VALUE obj = Data_Make_Struct(klass, struct encoder, ext_enc_mark, ext_enc_free, p);
186
+ return obj;
187
+ }
188
+
189
+ static inline struct encoder *
190
+ aux_encoder_refp(VALUE obj)
191
+ {
192
+ struct encoder *p;
193
+ Data_Get_Struct(obj, struct encoder, p);
194
+ return p;
195
+ }
196
+
197
+ static inline struct encoder *
198
+ aux_encoder_ref(VALUE obj)
199
+ {
200
+ struct encoder *p = aux_encoder_refp(obj);
201
+ if (!p || !p->encoder) {
202
+ rb_raise(eError,
203
+ "not initialized - #<%s:%p>",
204
+ rb_obj_classname(obj), (void *)obj);
205
+ }
206
+ return p;
207
+ }
208
+
209
+ /*
210
+ * call-seq:
211
+ * initialize(outport, opts = {})
212
+ */
213
+ static VALUE
214
+ ext_enc_init(int argc, VALUE argv[], VALUE enc)
215
+ {
216
+ struct encoder *p = DATA_PTR(enc);
217
+ if (p->encoder) {
218
+ rb_raise(eError,
219
+ "already initialized - #<%s:%p>",
220
+ rb_obj_classname(enc), (void *)enc);
221
+ }
222
+
223
+ VALUE outport, opts;
224
+ rb_scan_args(argc, argv, "1:", &outport, &opts);
225
+ lzham_compress_params params = aux_conv_encode_params(opts);
226
+ p->encoder = lzham_compress_init(&params);
227
+ if (!p->encoder) {
228
+ rb_raise(eError,
229
+ "failed lzham_compress_init - #<%s:%p>",
230
+ rb_obj_classname(enc), (void *)enc);
231
+ }
232
+
233
+ p->outbuf = rb_str_buf_new(WORKBUF_SIZE);
234
+ p->outport = outport;
235
+
236
+ return enc;
237
+ }
238
+
239
+ struct enc_update_args
240
+ {
241
+ VALUE encoder;
242
+ VALUE src;
243
+ int flush;
244
+ };
245
+
246
+ struct aux_lzham_compress2_nogvl
247
+ {
248
+ lzham_compress_state_ptr state;
249
+ const lzham_uint8 *inbuf;
250
+ size_t *insize;
251
+ lzham_uint8 *outbuf;
252
+ size_t *outsize;
253
+ lzham_flush_t flush;
254
+ };
255
+
256
+ static void *
257
+ aux_lzham_compress2_nogvl(void *px)
258
+ {
259
+ struct aux_lzham_compress2_nogvl *p = px;
260
+ return (void *)lzham_compress2(p->state,
261
+ p->inbuf, p->insize, p->outbuf, p->outsize, p->flush);
262
+ }
263
+
264
+ static inline lzham_compress_status_t
265
+ aux_lzham_compress2(lzham_compress_state_ptr state,
266
+ const lzham_uint8 *inbuf, size_t *insize,
267
+ lzham_uint8 *outbuf, size_t *outsize,
268
+ lzham_flush_t flush)
269
+ {
270
+ struct aux_lzham_compress2_nogvl p = {
271
+ .state = state,
272
+ .inbuf = inbuf,
273
+ .insize = insize,
274
+ .outbuf = outbuf,
275
+ .outsize = outsize,
276
+ .flush = flush,
277
+ };
278
+
279
+ return (lzham_compress_status_t)rb_thread_call_without_gvl(aux_lzham_compress2_nogvl, &p, 0, 0);
280
+ }
281
+
282
+ static VALUE
283
+ enc_update_protected(struct enc_update_args *args)
284
+ {
285
+ struct encoder *p = aux_encoder_ref(args->encoder);
286
+ const char *inbuf, *intail;
287
+
288
+ if (NIL_P(args->src)) {
289
+ inbuf = NULL;
290
+ intail = NULL;
291
+ } else {
292
+ inbuf = RSTRING_PTR(args->src);
293
+ intail = inbuf + RSTRING_LEN(args->src);
294
+ }
295
+
296
+ for (;;) {
297
+ size_t insize = intail - inbuf;
298
+ rb_str_locktmp(p->outbuf);
299
+ size_t outsize = rb_str_capacity(p->outbuf);
300
+ lzham_compress_status_t s;
301
+ s = aux_lzham_compress2(p->encoder,
302
+ (lzham_uint8 *)inbuf, &insize,
303
+ (lzham_uint8 *)RSTRING_PTR(p->outbuf), &outsize, args->flush);
304
+ rb_str_unlocktmp(p->outbuf);
305
+ if (!NIL_P(args->src)) {
306
+ inbuf += insize;
307
+ if (inbuf == intail) {
308
+ inbuf = intail = NULL;
309
+ }
310
+ }
311
+ //fprintf(stderr, "%s:%d:%s: status=%d, insize=%zu, outsize=%zu\n", __FILE__, __LINE__, __func__, s, insize, outsize);
312
+ if (s != LZHAM_COMP_STATUS_SUCCESS &&
313
+ s != LZHAM_COMP_STATUS_NEEDS_MORE_INPUT &&
314
+ s != LZHAM_COMP_STATUS_NOT_FINISHED &&
315
+ s != LZHAM_COMP_STATUS_HAS_MORE_OUTPUT) {
316
+
317
+ aux_encode_error(s);
318
+ }
319
+ if (outsize > 0) {
320
+ rb_str_set_len(p->outbuf, outsize);
321
+ rb_funcall2(p->outport, ID_op_lshift, 1, &p->outbuf);
322
+ }
323
+ if (s != LZHAM_COMP_STATUS_HAS_MORE_OUTPUT) {
324
+ break;
325
+ }
326
+ }
327
+
328
+ return 0;
329
+ }
330
+
331
+ static inline void
332
+ enc_update(VALUE enc, VALUE src, int flush)
333
+ {
334
+ struct enc_update_args args = { enc, src, flush };
335
+ if (NIL_P(src)) {
336
+ enc_update_protected(&args);
337
+ } else {
338
+ rb_str_locktmp(src);
339
+ int state;
340
+ rb_protect((VALUE (*)(VALUE))enc_update_protected, (VALUE)&args, &state);
341
+ rb_str_unlocktmp(src);
342
+ if (state) {
343
+ rb_jump_tag(state);
344
+ }
345
+ }
346
+ }
347
+
348
+ /*
349
+ * call-seq:
350
+ * update(src, flush = LZHAM::NO_FLUSH) -> self
351
+ */
352
+ static VALUE
353
+ ext_enc_update(int argc, VALUE argv[], VALUE enc)
354
+ {
355
+ VALUE src, flush;
356
+ rb_scan_args(argc, argv, "11", &src, &flush);
357
+ rb_check_type(src, RUBY_T_STRING);
358
+ if (NIL_P(flush)) {
359
+ enc_update(enc, src, 0);
360
+ } else {
361
+ enc_update(enc, src, NUM2INT(flush));
362
+ }
363
+ return enc;
364
+ }
365
+
366
+ static VALUE
367
+ ext_enc_finish(VALUE enc)
368
+ {
369
+ enc_update(enc, Qnil, LZHAM_FINISH);
370
+ return enc;
371
+ }
372
+
373
+ /*
374
+ * same as <tt>enc.update(src)</tt>
375
+ */
376
+ static VALUE
377
+ ext_enc_op_lshift(VALUE enc, VALUE src)
378
+ {
379
+ rb_check_type(src, RUBY_T_STRING);
380
+ enc_update(enc, src, 0);
381
+ return enc;
382
+ }
383
+
384
+ /*
385
+ * decoder
386
+ */
387
+
388
+ static inline lzham_decompress_params
389
+ aux_conv_decode_params(VALUE opts)
390
+ {
391
+ lzham_decompress_params p;
392
+ memset(&p, 0, sizeof(p));
393
+ p.m_struct_size = sizeof(p);
394
+ if (NIL_P(opts)) {
395
+ p.m_dict_size_log2 = LZHAM_MIN_DICT_SIZE_LOG2;
396
+ p.m_table_update_rate = 0;
397
+ p.m_decompress_flags = 0; // (see lzham_decompress_flags enum)
398
+ p.m_num_seed_bytes = 0;
399
+ p.m_pSeed_bytes = NULL;
400
+ p.m_table_max_update_interval = 0;
401
+ p.m_table_update_interval_slow_rate = 0;
402
+ } else {
403
+ p.m_dict_size_log2 = aux_hash_lookup_to_u32(opts, IDdictsize, LZHAM_MIN_DICT_SIZE_LOG2);
404
+ p.m_table_update_rate = aux_hash_lookup_to_u32(opts, IDtable_update_rate, 0);
405
+ p.m_decompress_flags = aux_hash_lookup_to_u32(opts, IDflags, 0);
406
+ p.m_num_seed_bytes = 0;
407
+ p.m_pSeed_bytes = NULL;
408
+ p.m_table_max_update_interval = aux_hash_lookup_to_u32(opts, IDtable_max_update_interval, 0);
409
+ p.m_table_update_interval_slow_rate = aux_hash_lookup_to_u32(opts, IDtable_update_interval_slow_rate, 0);
410
+ }
411
+
412
+ return p;
413
+ }
414
+
415
+ /*
416
+ * call-seq:
417
+ * decode(string, max_decoded_size, opts = {}) -> decoded string
418
+ */
419
+ static VALUE
420
+ ext_s_decode(int argc, VALUE argv[], VALUE mod)
421
+ {
422
+ VALUE src, size, opts;
423
+ rb_scan_args(argc, argv, "2:", &src, &size, &opts);
424
+ rb_check_type(src, RUBY_T_STRING);
425
+ rb_str_locktmp(src);
426
+ size_t srcsize = RSTRING_LEN(src);
427
+ size_t destsize = NUM2SIZET(size);
428
+ VALUE dest = rb_str_buf_new(destsize);
429
+ lzham_decompress_params p = aux_conv_decode_params(opts);
430
+ lzham_decompress_status_t s;
431
+ s = lzham_decompress_memory(&p,
432
+ (lzham_uint8 *)RSTRING_PTR(dest), &destsize,
433
+ (lzham_uint8 *)RSTRING_PTR(src), srcsize, NULL);
434
+
435
+ rb_str_unlocktmp(src);
436
+
437
+ if (s != LZHAM_DECOMP_STATUS_SUCCESS) {
438
+ rb_str_resize(dest, 0);
439
+ aux_decode_error(s);
440
+ }
441
+
442
+ rb_str_resize(dest, destsize);
443
+ rb_str_set_len(dest, destsize);
444
+
445
+ return dest;
446
+ }
447
+
448
+ struct decoder
449
+ {
450
+ lzham_decompress_state_ptr decoder;
451
+ VALUE outport;
452
+ VALUE outbuf;
453
+ };
454
+
455
+ static void
456
+ ext_dec_mark(struct decoder *p)
457
+ {
458
+ if (p) {
459
+ rb_gc_mark(p->outport);
460
+ rb_gc_mark(p->outbuf);
461
+ }
462
+ }
463
+
464
+ static void
465
+ ext_dec_free(struct decoder *p)
466
+ {
467
+ if (p) {
468
+ if (p->decoder) {
469
+ lzham_decompress_deinit(p->decoder);
470
+ }
471
+ }
472
+ }
473
+
474
+ static VALUE
475
+ ext_dec_alloc(VALUE klass)
476
+ {
477
+ struct decoder *p;
478
+ VALUE obj = Data_Make_Struct(klass, struct decoder, ext_dec_mark, ext_dec_free, p);
479
+ return obj;
480
+ }
481
+
482
+ static inline struct decoder *
483
+ aux_decoder_refp(VALUE obj)
484
+ {
485
+ struct decoder *p;
486
+ Data_Get_Struct(obj, struct decoder, p);
487
+ return p;
488
+ }
489
+
490
+ static inline struct decoder *
491
+ aux_decoder_ref(VALUE obj)
492
+ {
493
+ struct decoder *p = aux_decoder_refp(obj);
494
+ if (!p || !p->decoder) {
495
+ rb_raise(eError,
496
+ "not initialized - #<%s:%p>",
497
+ rb_obj_classname(obj), (void *)obj);
498
+ }
499
+ return p;
500
+ }
501
+
502
+ static VALUE
503
+ ext_dec_init(int argc, VALUE argv[], VALUE dec)
504
+ {
505
+ struct decoder *p = DATA_PTR(dec);
506
+ if (p->decoder) {
507
+ rb_raise(eError,
508
+ "already initialized - #<%s:%p>",
509
+ rb_obj_classname(dec), (void *)dec);
510
+ }
511
+
512
+ VALUE outport, opts;
513
+ rb_scan_args(argc, argv, "1:", &outport, &opts);
514
+ lzham_decompress_params params = aux_conv_decode_params(opts);
515
+ p->decoder = lzham_decompress_init(&params);
516
+ if (!p->decoder) {
517
+ rb_raise(eError,
518
+ "failed lzham_decompress_init - #<%s:%p>",
519
+ rb_obj_classname(dec), (void *)dec);
520
+ }
521
+
522
+ p->outbuf = rb_str_buf_new(WORKBUF_SIZE);
523
+ p->outport = outport;
524
+
525
+ return dec;
526
+ }
527
+
528
+ struct aux_lzham_decompress_nogvl
529
+ {
530
+ lzham_decompress_state_ptr state;
531
+ const lzham_uint8 *inbuf;
532
+ size_t *insize;
533
+ lzham_uint8 *outbuf;
534
+ size_t *outsize;
535
+ lzham_bool flags;
536
+ };
537
+
538
+ static void *
539
+ aux_lzham_decompress_nogvl(void *px)
540
+ {
541
+ struct aux_lzham_decompress_nogvl *p = px;
542
+ return (void *)lzham_decompress(p->state, p->inbuf, p->insize, p->outbuf, p->outsize, p->flags);
543
+ }
544
+
545
+ static inline lzham_decompress_status_t
546
+ aux_lzham_decompress(lzham_decompress_state_ptr state,
547
+ const lzham_uint8 *inbuf, size_t *insize,
548
+ lzham_uint8 *outbuf, size_t *outsize,
549
+ lzham_bool flags)
550
+ {
551
+ struct aux_lzham_decompress_nogvl p = {
552
+ .state = state,
553
+ .inbuf = inbuf,
554
+ .insize = insize,
555
+ .outbuf = outbuf,
556
+ .outsize = outsize,
557
+ .flags = flags,
558
+ };
559
+
560
+ return (lzham_decompress_status_t)rb_thread_call_without_gvl(aux_lzham_decompress_nogvl, &p, 0, 0);
561
+ }
562
+
563
+ struct dec_update_args
564
+ {
565
+ VALUE decoder;
566
+ VALUE src;
567
+ int flush;
568
+ };
569
+
570
+ static VALUE
571
+ dec_update_protected(struct dec_update_args *args)
572
+ {
573
+ struct decoder *p = aux_decoder_ref(args->decoder);
574
+ const char *inbuf, *intail;
575
+
576
+ if (NIL_P(args->src)) {
577
+ inbuf = NULL;
578
+ intail = NULL;
579
+ } else {
580
+ inbuf = RSTRING_PTR(args->src);
581
+ intail = inbuf + RSTRING_LEN(args->src);
582
+ }
583
+
584
+ for (;;) {
585
+ size_t insize = intail - inbuf;
586
+ rb_str_locktmp(p->outbuf);
587
+ size_t outsize = rb_str_capacity(p->outbuf);
588
+ lzham_decompress_status_t s;
589
+ //fprintf(stderr, "%s:%d:%s: inbuf=%p, insize=%zu, outbuf=%p, outsize=%zu\n", __FILE__, __LINE__, __func__, inbuf, insize, RSTRING_PTR(p->outbuf), outsize);
590
+ s = aux_lzham_decompress(p->decoder,
591
+ (lzham_uint8 *)inbuf, &insize,
592
+ (lzham_uint8 *)RSTRING_PTR(p->outbuf), &outsize, args->flush);
593
+ rb_str_unlocktmp(p->outbuf);
594
+ //fprintf(stderr, "%s:%d:%s: status=%d, insize=%zu, outsize=%zu\n", __FILE__, __LINE__, __func__, s, insize, outsize);
595
+ if (!NIL_P(args->src)) {
596
+ inbuf += insize;
597
+ }
598
+ if (s != LZHAM_DECOMP_STATUS_NOT_FINISHED &&
599
+ s != LZHAM_DECOMP_STATUS_HAS_MORE_OUTPUT &&
600
+ s != LZHAM_DECOMP_STATUS_NEEDS_MORE_INPUT &&
601
+ s != LZHAM_DECOMP_STATUS_SUCCESS) {
602
+
603
+ aux_decode_error(s);
604
+ }
605
+ if (outsize > 0) {
606
+ rb_str_set_len(p->outbuf, outsize);
607
+ rb_funcall2(p->outport, ID_op_lshift, 1, &p->outbuf);
608
+ }
609
+ if (s != LZHAM_DECOMP_STATUS_NOT_FINISHED) {
610
+ break;
611
+ }
612
+ }
613
+
614
+ return 0;
615
+ }
616
+
617
+ static inline void
618
+ dec_update(VALUE dec, VALUE src, int flush)
619
+ {
620
+ struct dec_update_args args = { dec, src, flush };
621
+ if (NIL_P(src)) {
622
+ dec_update_protected(&args);
623
+ } else {
624
+ rb_str_locktmp(src);
625
+ int state;
626
+ rb_protect((VALUE (*)(VALUE))dec_update_protected, (VALUE)&args, &state);
627
+ rb_str_unlocktmp(src);
628
+ if (state) {
629
+ rb_jump_tag(state);
630
+ }
631
+ }
632
+ }
633
+
634
+ /*
635
+ * call-seq:
636
+ * update(src, flush = false) -> self
637
+ */
638
+ static VALUE
639
+ ext_dec_update(int argc, VALUE argv[], VALUE dec)
640
+ {
641
+ VALUE src, flush;
642
+ rb_scan_args(argc, argv, "11", &src, &flush);
643
+ rb_check_type(src, RUBY_T_STRING);
644
+ dec_update(dec, src, RTEST(flush) ? 1 : 0);
645
+ return dec;
646
+ }
647
+
648
+ static VALUE
649
+ ext_dec_finish(VALUE dec)
650
+ {
651
+ dec_update(dec, Qnil, 1);
652
+ return dec;
653
+ }
654
+
655
+ static VALUE
656
+ ext_dec_op_lshift(VALUE dec, VALUE src)
657
+ {
658
+ rb_check_type(src, RUBY_T_STRING);
659
+ dec_update(dec, src, 0);
660
+ return dec;
661
+ }
662
+
663
+ void
664
+ Init_extlzham(void)
665
+ {
666
+ ID_op_lshift = rb_intern("<<");
667
+ IDdictsize = rb_intern("dictsize");
668
+ IDlevel = rb_intern("level");
669
+ IDtable_update_rate = rb_intern("table_update_rate");
670
+ IDthreads = rb_intern("threads");
671
+ IDflags = rb_intern("flags");
672
+ IDtable_max_update_interval = rb_intern("table_max_update_interval");
673
+ IDtable_update_interval_slow_rate = rb_intern("table_update_interval_slow_rate");
674
+
675
+ mLZHAM = rb_define_module("LZHAM");
676
+ rb_define_const(mLZHAM, "LZHAM", mLZHAM);
677
+ rb_define_const(mLZHAM, "LIBVERSION", UINT2NUM(lzham_get_version()));
678
+
679
+ mConsts = rb_define_module_under(mLZHAM, "Constants");
680
+ rb_include_module(mLZHAM, mConsts);
681
+ rb_define_const(mConsts, "NO_FLUSH", INT2FIX(LZHAM_NO_FLUSH));
682
+ rb_define_const(mConsts, "SYNC_FLUSH", INT2FIX(LZHAM_SYNC_FLUSH));
683
+ rb_define_const(mConsts, "FULL_FLUSH", INT2FIX(LZHAM_FULL_FLUSH));
684
+ rb_define_const(mConsts, "FINISH", INT2FIX(LZHAM_FINISH));
685
+ rb_define_const(mConsts, "TABLE_FLUSH", INT2FIX(LZHAM_TABLE_FLUSH));
686
+ rb_define_const(mConsts, "MIN_DICT_SIZE_LOG2", INT2FIX(LZHAM_MIN_DICT_SIZE_LOG2));
687
+ rb_define_const(mConsts, "MAX_DICT_SIZE_LOG2_X86", INT2FIX(LZHAM_MAX_DICT_SIZE_LOG2_X86));
688
+ rb_define_const(mConsts, "MAX_DICT_SIZE_LOG2_X64", INT2FIX(LZHAM_MAX_DICT_SIZE_LOG2_X64));
689
+ rb_define_const(mConsts, "MAX_HELPER_THREADS", INT2FIX(LZHAM_MAX_HELPER_THREADS));
690
+ rb_define_const(mConsts, "COMP_FLAG_EXTREME_PARSING", INT2FIX(LZHAM_COMP_FLAG_EXTREME_PARSING));
691
+ rb_define_const(mConsts, "COMP_FLAG_DETERMINISTIC_PARSING", INT2FIX(LZHAM_COMP_FLAG_DETERMINISTIC_PARSING));
692
+ rb_define_const(mConsts, "COMP_FLAG_TRADEOFF_DECOMPRESSION_RATE_FOR_COMP_RATIO", INT2FIX(LZHAM_COMP_FLAG_TRADEOFF_DECOMPRESSION_RATE_FOR_COMP_RATIO));
693
+ rb_define_const(mConsts, "COMP_FLAG_WRITE_ZLIB_STREAM", INT2FIX(LZHAM_COMP_FLAG_WRITE_ZLIB_STREAM));
694
+ rb_define_const(mConsts, "INSANELY_SLOW_TABLE_UPDATE_RATE", INT2FIX(LZHAM_INSANELY_SLOW_TABLE_UPDATE_RATE));
695
+ rb_define_const(mConsts, "SLOWEST_TABLE_UPDATE_RATE", INT2FIX(LZHAM_SLOWEST_TABLE_UPDATE_RATE));
696
+ rb_define_const(mConsts, "DEFAULT_TABLE_UPDATE_RATE", INT2FIX(LZHAM_DEFAULT_TABLE_UPDATE_RATE));
697
+ rb_define_const(mConsts, "FASTEST_TABLE_UPDATE_RATE", INT2FIX(LZHAM_FASTEST_TABLE_UPDATE_RATE));
698
+ rb_define_const(mConsts, "DECOMP_FLAG_OUTPUT_UNBUFFERED", INT2FIX(LZHAM_DECOMP_FLAG_OUTPUT_UNBUFFERED));
699
+ rb_define_const(mConsts, "DECOMP_FLAG_COMPUTE_ADLER32", INT2FIX(LZHAM_DECOMP_FLAG_COMPUTE_ADLER32));
700
+ rb_define_const(mConsts, "DECOMP_FLAG_READ_ZLIB_STREAM", INT2FIX(LZHAM_DECOMP_FLAG_READ_ZLIB_STREAM));
701
+ rb_define_const(mConsts, "LZHAM_NO_FLUSH", INT2FIX(LZHAM_NO_FLUSH));
702
+ rb_define_const(mConsts, "LZHAM_SYNC_FLUSH", INT2FIX(LZHAM_SYNC_FLUSH));
703
+ rb_define_const(mConsts, "LZHAM_FULL_FLUSH", INT2FIX(LZHAM_FULL_FLUSH));
704
+ rb_define_const(mConsts, "LZHAM_FINISH", INT2FIX(LZHAM_FINISH));
705
+ rb_define_const(mConsts, "LZHAM_TABLE_FLUSH", INT2FIX(LZHAM_TABLE_FLUSH));
706
+ rb_define_const(mConsts, "LZHAM_MIN_DICT_SIZE_LOG2", INT2FIX(LZHAM_MIN_DICT_SIZE_LOG2));
707
+ rb_define_const(mConsts, "LZHAM_MAX_DICT_SIZE_LOG2_X86", INT2FIX(LZHAM_MAX_DICT_SIZE_LOG2_X86));
708
+ rb_define_const(mConsts, "LZHAM_MAX_DICT_SIZE_LOG2_X64", INT2FIX(LZHAM_MAX_DICT_SIZE_LOG2_X64));
709
+ rb_define_const(mConsts, "LZHAM_MAX_HELPER_THREADS", INT2FIX(LZHAM_MAX_HELPER_THREADS));
710
+ rb_define_const(mConsts, "LZHAM_COMP_FLAG_EXTREME_PARSING", INT2FIX(LZHAM_COMP_FLAG_EXTREME_PARSING));
711
+ rb_define_const(mConsts, "LZHAM_COMP_FLAG_DETERMINISTIC_PARSING", INT2FIX(LZHAM_COMP_FLAG_DETERMINISTIC_PARSING));
712
+ rb_define_const(mConsts, "LZHAM_COMP_FLAG_TRADEOFF_DECOMPRESSION_RATE_FOR_COMP_RATIO", INT2FIX(LZHAM_COMP_FLAG_TRADEOFF_DECOMPRESSION_RATE_FOR_COMP_RATIO));
713
+ rb_define_const(mConsts, "LZHAM_COMP_FLAG_WRITE_ZLIB_STREAM", INT2FIX(LZHAM_COMP_FLAG_WRITE_ZLIB_STREAM));
714
+ rb_define_const(mConsts, "LZHAM_INSANELY_SLOW_TABLE_UPDATE_RATE", INT2FIX(LZHAM_INSANELY_SLOW_TABLE_UPDATE_RATE));
715
+ rb_define_const(mConsts, "LZHAM_SLOWEST_TABLE_UPDATE_RATE", INT2FIX(LZHAM_SLOWEST_TABLE_UPDATE_RATE));
716
+ rb_define_const(mConsts, "LZHAM_DEFAULT_TABLE_UPDATE_RATE", INT2FIX(LZHAM_DEFAULT_TABLE_UPDATE_RATE));
717
+ rb_define_const(mConsts, "LZHAM_FASTEST_TABLE_UPDATE_RATE", INT2FIX(LZHAM_FASTEST_TABLE_UPDATE_RATE));
718
+ rb_define_const(mConsts, "LZHAM_DECOMP_FLAG_OUTPUT_UNBUFFERED", INT2FIX(LZHAM_DECOMP_FLAG_OUTPUT_UNBUFFERED));
719
+ rb_define_const(mConsts, "LZHAM_DECOMP_FLAG_COMPUTE_ADLER32", INT2FIX(LZHAM_DECOMP_FLAG_COMPUTE_ADLER32));
720
+ rb_define_const(mConsts, "LZHAM_DECOMP_FLAG_READ_ZLIB_STREAM", INT2FIX(LZHAM_DECOMP_FLAG_READ_ZLIB_STREAM));
721
+
722
+ cEncoder = rb_define_class_under(mLZHAM, "Encoder", rb_cObject);
723
+ rb_include_module(cEncoder, mConsts);
724
+ rb_define_alloc_func(cEncoder, ext_enc_alloc);
725
+ rb_define_singleton_method(cEncoder, "encode", RUBY_METHOD_FUNC(ext_s_encode), -1);
726
+ rb_define_method(cEncoder, "initialize", RUBY_METHOD_FUNC(ext_enc_init), -1);
727
+ rb_define_method(cEncoder, "update", RUBY_METHOD_FUNC(ext_enc_update), -1);
728
+ rb_define_method(cEncoder, "finish", RUBY_METHOD_FUNC(ext_enc_finish), 0);
729
+ rb_define_method(cEncoder, "<<", RUBY_METHOD_FUNC(ext_enc_op_lshift), 1);
730
+
731
+ cDecoder = rb_define_class_under(mLZHAM, "Decoder", rb_cObject);
732
+ rb_include_module(cDecoder, mConsts);
733
+ rb_define_alloc_func(cDecoder, ext_dec_alloc);
734
+ rb_define_singleton_method(cDecoder, "decode", RUBY_METHOD_FUNC(ext_s_decode), -1);
735
+ rb_define_method(cDecoder, "initialize", RUBY_METHOD_FUNC(ext_dec_init), -1);
736
+ rb_define_method(cDecoder, "update", RUBY_METHOD_FUNC(ext_dec_update), -1);
737
+ rb_define_method(cDecoder, "finish", RUBY_METHOD_FUNC(ext_dec_finish), 0);
738
+ rb_define_method(cDecoder, "<<", RUBY_METHOD_FUNC(ext_dec_op_lshift), 1);
739
+
740
+ eError = rb_define_class_under(mLZHAM, "Error", rb_eRuntimeError);
741
+ }