extlzham 0.0.1.PROTOTYPE

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