libbin 1.0.5 → 2.0.0

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.
@@ -1,65 +1,1940 @@
1
1
  #include "ruby.h"
2
- #include "./half.h"
3
- #include "./pghalf.h"
2
+ #include "./libbin_c.h"
4
3
 
5
- union float_u {
6
- float f;
7
- uint32_t i;
4
+ VALUE cField;
5
+ VALUE mLibBin;
6
+ VALUE cStructure;
7
+
8
+ static VALUE rb_str_dot_dot;
9
+ static VALUE rb_str___parent;
10
+ static VALUE rb_str_backslash;
11
+ static VALUE rb_str_dot;
12
+
13
+ struct cField_data {
14
+ VALUE name;
15
+ VALUE type;
16
+ VALUE length;
17
+ VALUE count;
18
+ VALUE offset;
19
+ VALUE sequence;
20
+ VALUE condition;
21
+ VALUE relative_offset;
22
+ VALUE align;
23
+ VALUE expect;
24
+ ID getter;
25
+ ID setter;
26
+ };
27
+
28
+ static void cField_mark(void* data) {
29
+ void *start = data;
30
+ void *end = &((struct cField_data*)data)->getter;
31
+ rb_gc_mark_locations((VALUE *)start, (VALUE *)end);
32
+ }
33
+
34
+ static size_t cField_size(const void* data) {
35
+ (void)data;
36
+ return sizeof(struct cField_data);
37
+ }
38
+
39
+ static const rb_data_type_t cField_type = {
40
+ .wrap_struct_name = "cField_data",
41
+ .function = {
42
+ .dmark = cField_mark,
43
+ .dfree = RUBY_DEFAULT_FREE,
44
+ .dsize = cField_size,
45
+ },
46
+ .data = NULL,
47
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY
48
+ };
49
+
50
+ static VALUE cField_alloc(VALUE self) {
51
+ struct cField_data *data;
52
+ VALUE res = TypedData_Make_Struct(self, struct cField_data, &cField_type, data);
53
+ return res;
54
+ }
55
+
56
+ static ID id_gsub;
57
+
58
+ static inline VALUE cField_preprocess_expression(VALUE self, VALUE expression) {
59
+ if (T_STRING == TYPE(expression)) {
60
+ VALUE proc = rb_str_new_cstr("proc {");
61
+ rb_str_buf_append(proc, rb_funcall(rb_funcall(expression, id_gsub, 2, rb_str_dot_dot, rb_str___parent), id_gsub, 2, rb_str_backslash, rb_str_dot));
62
+ rb_str_cat_cstr(proc, "}");
63
+ return rb_obj_instance_eval(1, &proc, self);
64
+ } else
65
+ return expression;
66
+ }
67
+
68
+ static VALUE cField_initialize(
69
+ VALUE self,
70
+ VALUE name,
71
+ VALUE type,
72
+ VALUE length,
73
+ VALUE count,
74
+ VALUE offset,
75
+ VALUE sequence,
76
+ VALUE condition,
77
+ VALUE relative_offset,
78
+ VALUE align,
79
+ VALUE expect) {
80
+ VALUE tmp;
81
+ struct cField_data *data;
82
+ TypedData_Get_Struct(self, struct cField_data, &cField_type, data);
83
+ if (RTEST(align)) {
84
+ size_t a = NUM2LL(align);
85
+ if (a & (a-1))
86
+ rb_raise(rb_eRuntimeError, "alignment is not a power of 2: %zu", a);
87
+ }
88
+ data->name = name;
89
+ tmp = rb_str_dup(rb_obj_as_string(name));
90
+ data->getter = rb_intern_str(tmp);
91
+ data->setter = rb_intern_str(rb_str_cat(tmp, "=", 1));
92
+ data->type = cField_preprocess_expression(self, type);
93
+ data->length = cField_preprocess_expression(self, length);
94
+ data->count = cField_preprocess_expression(self, count);
95
+ data->offset = cField_preprocess_expression(self, offset);
96
+ data->sequence = sequence;
97
+ data->condition = cField_preprocess_expression(self, condition);
98
+ data->relative_offset = relative_offset;
99
+ data->align = align;
100
+ data->expect = expect;
101
+ return self;
102
+ }
103
+
104
+ #define FIELD_STATE_GETTER(propname) cField_get_ ## propname
105
+
106
+ #define CREATE_FIELD_STATE_GETTER(propname) \
107
+ static VALUE FIELD_STATE_GETTER(propname) (VALUE self) { \
108
+ struct cField_data *data; \
109
+ TypedData_Get_Struct(self, struct cField_data, &cField_type, data); \
110
+ return data->propname ; \
111
+ }
112
+
113
+ #define DEFINE_FIELD_STATE_GETTER(propname) \
114
+ rb_define_method(cField, #propname, FIELD_STATE_GETTER(propname), 0)
115
+
116
+ #define DEFINE_FIELD_STATE_GETTER_BOOL(propname) \
117
+ rb_define_method(cField, #propname "?", FIELD_STATE_GETTER(propname), 0)
118
+
119
+ CREATE_FIELD_STATE_GETTER(name)
120
+ CREATE_FIELD_STATE_GETTER(type)
121
+ CREATE_FIELD_STATE_GETTER(length)
122
+ CREATE_FIELD_STATE_GETTER(count)
123
+ CREATE_FIELD_STATE_GETTER(offset)
124
+ CREATE_FIELD_STATE_GETTER(sequence)
125
+ CREATE_FIELD_STATE_GETTER(condition)
126
+ CREATE_FIELD_STATE_GETTER(relative_offset)
127
+ CREATE_FIELD_STATE_GETTER(align)
128
+ CREATE_FIELD_STATE_GETTER(expect)
129
+
130
+ struct cStructure_data {
131
+ VALUE __input;
132
+ VALUE __output;
133
+ VALUE __input_big;
134
+ VALUE __output_big;
135
+ VALUE __parent;
136
+ VALUE __index;
137
+ VALUE __position;
138
+ VALUE __cur_position;
139
+ // field specific data
140
+ VALUE __offset;
141
+ VALUE __condition;
142
+ VALUE __type;
143
+ VALUE __length;
144
+ VALUE __count;
145
+ VALUE __iterator;
146
+ VALUE __value;
147
+ };
148
+
149
+ static void cStructure_mark(void* data) {
150
+ void *start = data;
151
+ void *end = (char *)data + sizeof(struct cStructure_data);
152
+ rb_gc_mark_locations((VALUE *)start, (VALUE *)end);
153
+ }
154
+
155
+ static size_t cStructure_size(const void* data) {
156
+ (void)data;
157
+ return sizeof(struct cStructure_data);
158
+ }
159
+
160
+ static const rb_data_type_t cStructure_type = {
161
+ .wrap_struct_name = "cStructure_data",
162
+ .function = {
163
+ .dmark = cStructure_mark,
164
+ .dfree = RUBY_DEFAULT_FREE,
165
+ .dsize = cStructure_size,
166
+ },
167
+ .data = NULL,
168
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY
169
+ };
170
+
171
+ static VALUE cStructure_alloc(VALUE self) {
172
+ struct cStructure_data *data;
173
+ VALUE res = TypedData_Make_Struct(self, struct cStructure_data, &cStructure_type, data);
174
+ return res;
175
+ }
176
+
177
+ static VALUE cStructure_initialize(VALUE self) {
178
+ struct cStructure_data *data;
179
+ TypedData_Get_Struct(self, struct cStructure_data, &cStructure_type, data);
180
+ data->__input = Qnil;
181
+ data->__output = Qnil;
182
+ data->__input_big = Qnil;
183
+ data->__output_big = Qnil;
184
+ data->__parent = Qnil;
185
+ data->__index = Qnil;
186
+ data->__position = Qnil;
187
+ data->__cur_position = Qnil;
188
+ data->__offset = Qnil;
189
+ data->__condition = Qnil;
190
+ data->__type = Qnil;
191
+ data->__length = Qnil;
192
+ data->__count = Qnil;
193
+ data->__iterator = Qnil;
194
+ return self;
195
+ }
196
+
197
+ #define STRUCT_STATE_GETTER(propname) cStructure_get_ ## propname
198
+ #define STRUCT_STATE_SETTER(propname) cStructure_set_ ## propname
199
+
200
+ #define CREATE_STRUCT_STATE_ACCESSORS(propname) \
201
+ static VALUE STRUCT_STATE_GETTER(propname) (VALUE self) { \
202
+ struct cStructure_data *data; \
203
+ TypedData_Get_Struct(self, struct cStructure_data, &cStructure_type, data); \
204
+ return data->__ ## propname ; \
205
+ } \
206
+ static VALUE STRUCT_STATE_SETTER(propname) (VALUE self, VALUE propname) { \
207
+ struct cStructure_data *data; \
208
+ TypedData_Get_Struct(self, struct cStructure_data, &cStructure_type, data); \
209
+ return data->__ ## propname = propname; \
210
+ }
211
+
212
+ #define DEFINE_STRUCT_STATE_ACCESSORS(propname) \
213
+ do { \
214
+ rb_define_method(cStructure, "__" #propname, STRUCT_STATE_GETTER(propname), 0); \
215
+ rb_define_method(cStructure, "__" #propname "=", STRUCT_STATE_SETTER(propname), 1); \
216
+ } while(0)
217
+
218
+ CREATE_STRUCT_STATE_ACCESSORS(parent)
219
+ CREATE_STRUCT_STATE_ACCESSORS(index)
220
+ CREATE_STRUCT_STATE_ACCESSORS(position)
221
+ CREATE_STRUCT_STATE_ACCESSORS(cur_position)
222
+ CREATE_STRUCT_STATE_ACCESSORS(input)
223
+ CREATE_STRUCT_STATE_ACCESSORS(output)
224
+ CREATE_STRUCT_STATE_ACCESSORS(input_big)
225
+ CREATE_STRUCT_STATE_ACCESSORS(output_big)
226
+
227
+ CREATE_STRUCT_STATE_ACCESSORS(offset)
228
+ CREATE_STRUCT_STATE_ACCESSORS(condition)
229
+ CREATE_STRUCT_STATE_ACCESSORS(type)
230
+ CREATE_STRUCT_STATE_ACCESSORS(length)
231
+ CREATE_STRUCT_STATE_ACCESSORS(count)
232
+ CREATE_STRUCT_STATE_ACCESSORS(iterator)
233
+ CREATE_STRUCT_STATE_ACCESSORS(value)
234
+
235
+ static ID id_tell;
236
+
237
+ static ID id___set_convert_state;
238
+
239
+ static VALUE cStructure_set_convert_state(
240
+ VALUE self,
241
+ VALUE input,
242
+ VALUE output,
243
+ VALUE input_big,
244
+ VALUE output_big,
245
+ VALUE parent,
246
+ VALUE index)
247
+ {
248
+ struct cStructure_data *data;
249
+ TypedData_Get_Struct(self, struct cStructure_data, &cStructure_type, data);
250
+ data->__input = input;
251
+ data->__output = output;
252
+ data->__input_big = input_big;
253
+ data->__output_big = output_big;
254
+ data->__parent = parent;
255
+ data->__index = index;
256
+ data->__position = rb_funcall(input, id_tell, 0);
257
+ data->__cur_position = data->__position;
258
+ return Qnil;
259
+ }
260
+
261
+ static ID id___unset_convert_state;
262
+
263
+ static VALUE cStructure_unset_convert_state(VALUE self) {
264
+ struct cStructure_data *data;
265
+ TypedData_Get_Struct(self, struct cStructure_data, &cStructure_type, data);
266
+ data->__input = Qnil;
267
+ data->__output = Qnil;
268
+ data->__input_big = Qnil;
269
+ data->__output_big = Qnil;
270
+ data->__parent = Qnil;
271
+ data->__index = Qnil;
272
+ data->__position = Qnil;
273
+ data->__cur_position = Qnil;
274
+ return Qnil;
275
+ }
276
+
277
+ static ID id___set_size_state;
278
+
279
+ static VALUE cStructure_set_size_state(
280
+ VALUE self,
281
+ VALUE position,
282
+ VALUE parent,
283
+ VALUE index)
284
+ {
285
+ struct cStructure_data *data;
286
+ TypedData_Get_Struct(self, struct cStructure_data, &cStructure_type, data);
287
+ data->__parent = parent;
288
+ data->__index = index;
289
+ data->__position = position;
290
+ data->__cur_position = data->__position;
291
+ return Qnil;
292
+ }
293
+
294
+ static ID id___unset_size_state;
295
+
296
+ static VALUE cStructure_unset_size_state(VALUE self) {
297
+ struct cStructure_data *data;
298
+ TypedData_Get_Struct(self, struct cStructure_data, &cStructure_type, data);
299
+ data->__parent = Qnil;
300
+ data->__index = Qnil;
301
+ data->__position = Qnil;
302
+ data->__cur_position = Qnil;
303
+ return Qnil;
304
+ }
305
+
306
+ static ID id___set_load_state;
307
+
308
+ static VALUE cStructure_set_load_state(
309
+ VALUE self,
310
+ VALUE input,
311
+ VALUE input_big,
312
+ VALUE parent,
313
+ VALUE index)
314
+ {
315
+ struct cStructure_data *data;
316
+ TypedData_Get_Struct(self, struct cStructure_data, &cStructure_type, data);
317
+ data->__input = input;
318
+ data->__input_big = input_big;
319
+ data->__parent = parent;
320
+ data->__index = index;
321
+ data->__position = rb_funcall(input, id_tell, 0);
322
+ data->__cur_position = data->__position;
323
+ return Qnil;
324
+ }
325
+
326
+ static ID id___unset_load_state;
327
+
328
+ static VALUE cStructure_unset_load_state(VALUE self) {
329
+ struct cStructure_data *data;
330
+ TypedData_Get_Struct(self, struct cStructure_data, &cStructure_type, data);
331
+ data->__input = Qnil;
332
+ data->__input_big = Qnil;
333
+ data->__parent = Qnil;
334
+ data->__index = Qnil;
335
+ data->__position = Qnil;
336
+ data->__cur_position = Qnil;
337
+ return Qnil;
338
+ }
339
+
340
+ static ID id___set_dump_state;
341
+
342
+ static VALUE cStructure_set_dump_state(
343
+ VALUE self,
344
+ VALUE output,
345
+ VALUE output_big,
346
+ VALUE parent,
347
+ VALUE index)
348
+ {
349
+ struct cStructure_data *data;
350
+ TypedData_Get_Struct(self, struct cStructure_data, &cStructure_type, data);
351
+ data->__output = output;
352
+ data->__output_big = output_big;
353
+ data->__parent = parent;
354
+ data->__index = index;
355
+ data->__position = rb_funcall(output, id_tell, 0);
356
+ data->__cur_position = data->__position;
357
+ return Qnil;
358
+ }
359
+
360
+ static ID id___unset_dump_state;
361
+
362
+ static VALUE cStructure_unset_dump_state(VALUE self) {
363
+ struct cStructure_data *data;
364
+ TypedData_Get_Struct(self, struct cStructure_data, &cStructure_type, data);
365
+ data->__output = Qnil;
366
+ data->__output_big = Qnil;
367
+ data->__parent = Qnil;
368
+ data->__index = Qnil;
369
+ data->__position = Qnil;
370
+ data->__cur_position = Qnil;
371
+ return Qnil;
372
+ }
373
+
374
+ static ID id_instance_exec;
375
+
376
+ static inline VALUE cStructure_decode_expression(VALUE self, VALUE expression) {
377
+ if (rb_obj_is_proc(expression))
378
+ return rb_funcall_with_block(self, id_instance_exec, 0, NULL, expression);
379
+ else
380
+ return expression;
381
+ }
382
+
383
+ static inline VALUE cStructure_decode_expect(VALUE self, VALUE expect, VALUE val) {
384
+ if (NIL_P(expect))
385
+ return val;
386
+ if (rb_obj_is_proc(expect)) {
387
+ if (!RTEST(rb_funcall_with_block(self, id_instance_exec, 1, &val, expect)))
388
+ rb_raise(rb_eRuntimeError, "could not validate field value: %"PRIsVALUE, val);
389
+ } else
390
+ if (!RTEST(rb_equal(expect, val)))
391
+ rb_raise(rb_eRuntimeError, "could not validate field value: %"PRIsVALUE" expected: %"PRIsVALUE, val, expect);
392
+ return val;
393
+ }
394
+
395
+ ID id_seek;
396
+
397
+ static inline VALUE cStructure_decode_seek_offset(VALUE self, VALUE offset, VALUE relative_offset, VALUE align) {
398
+ struct cStructure_data *data;
399
+ TypedData_Get_Struct(self, struct cStructure_data, &cStructure_type, data);
400
+ ptrdiff_t cur_pos;
401
+ if (!RTEST(offset)) {
402
+ if (!RTEST(align))
403
+ return Qnil;
404
+ if (RTEST(data->__input))
405
+ cur_pos = NUM2LL(rb_funcall(data->__input, id_tell, 0));
406
+ else if (RTEST(data->__output))
407
+ cur_pos = NUM2LL(rb_funcall(data->__output, id_tell, 0));
408
+ else
409
+ cur_pos = NUM2LL(data->__cur_position);
410
+ ptrdiff_t al = NUM2LL(align);
411
+ ptrdiff_t pad;
412
+ if ((pad = ((-cur_pos) & (al - 1))) == 0)
413
+ return Qnil;
414
+ cur_pos += pad;
415
+ } else {
416
+ cur_pos = NUM2LL(cStructure_decode_expression(self, offset));
417
+ if (cur_pos == 0)
418
+ return Qfalse;
419
+ if (RTEST(relative_offset))
420
+ cur_pos += NUM2LL(data->__position);
421
+ if (RTEST(align)) {
422
+ ptrdiff_t al = NUM2LL(align);
423
+ cur_pos += (-cur_pos) & (al - 1);
424
+ }
425
+ }
426
+ data->__cur_position = LL2NUM(cur_pos);
427
+ if (RTEST(data->__input))
428
+ rb_funcall(data->__input, id_seek, 1, data->__cur_position);
429
+ if (RTEST(data->__output))
430
+ rb_funcall(data->__output, id_seek, 1, data->__cur_position);
431
+ return data->__cur_position;
432
+ }
433
+
434
+ static inline VALUE cStructure_decode_condition(VALUE self, VALUE condition) {
435
+ if (!RTEST(condition))
436
+ return Qtrue;
437
+ return cStructure_decode_expression(self, condition);
438
+ }
439
+
440
+ static inline VALUE cStructure_decode_count(VALUE self, VALUE count) {
441
+ if (!RTEST(count))
442
+ return INT2FIX(1);
443
+ return cStructure_decode_expression(self, count);
444
+ }
445
+
446
+ static inline VALUE cStructure_decode_type(VALUE self, VALUE type) {
447
+ return cStructure_decode_expression(self, type);
448
+ }
449
+
450
+ static inline VALUE cStructure_decode_length(VALUE self, VALUE length) {
451
+ if (NIL_P(length))
452
+ return Qnil;
453
+ return cStructure_decode_expression(self, length);
454
+ }
455
+
456
+ static inline VALUE cStructure_decode_static_conditions(VALUE self, VALUE field) {
457
+ struct cStructure_data *data;
458
+ struct cField_data *field_data;
459
+ TypedData_Get_Struct(self, struct cStructure_data, &cStructure_type, data);
460
+ TypedData_Get_Struct(field, struct cField_data, &cField_type, field_data);
461
+ data->__offset = Qnil;
462
+ data->__condition = Qnil;
463
+ data->__type = Qnil;
464
+ data->__length = Qnil;
465
+ data->__count = Qnil;
466
+ if (!RTEST(field_data->sequence)) {
467
+ data->__offset = cStructure_decode_seek_offset(self, field_data->offset, field_data->relative_offset, field_data->align);
468
+ if (!data->__offset)
469
+ return Qnil;
470
+ data->__condition = cStructure_decode_condition(self, field_data->condition);
471
+ if (!RTEST(data->__condition))
472
+ return Qnil;
473
+ data->__type = cStructure_decode_type(self, field_data->type);
474
+ data->__length = cStructure_decode_length(self, field_data->length);
475
+ }
476
+ data->__count = cStructure_decode_count(self, field_data->count);
477
+ return Qtrue;
478
+ }
479
+
480
+ static inline VALUE cStructure_decode_dynamic_conditions(VALUE self, VALUE field) {
481
+ struct cStructure_data *data;
482
+ struct cField_data *field_data;
483
+ TypedData_Get_Struct(field, struct cField_data, &cField_type, field_data);
484
+ if (!RTEST(field_data->sequence))
485
+ return Qtrue;
486
+ TypedData_Get_Struct(self, struct cStructure_data, &cStructure_type, data);
487
+ data->__offset = Qnil;
488
+ data->__condition = Qnil;
489
+ data->__type = Qnil;
490
+ data->__length = Qnil;
491
+ data->__offset = cStructure_decode_seek_offset(self, field_data->offset, field_data->relative_offset, field_data->align);
492
+ if (!data->__offset)
493
+ return Qfalse;
494
+ data->__condition = cStructure_decode_condition(self, field_data->condition);
495
+ if (!RTEST(data->__condition))
496
+ return Qfalse;
497
+ data->__type = cStructure_decode_type(self, field_data->type);
498
+ data->__length = cStructure_decode_length(self, field_data->length);
499
+ return Qtrue;
500
+ }
501
+
502
+ static inline VALUE cStructure_restore_context(VALUE self) {
503
+ struct cStructure_data *data;
504
+ TypedData_Get_Struct(self, struct cStructure_data, &cStructure_type, data);
505
+ data->__iterator = Qnil;
506
+ data->__type = Qnil;
507
+ data->__length = Qnil;
508
+ data->__count = Qnil;
509
+ data->__offset = Qnil;
510
+ data->__condition = Qnil;
511
+ data->__value = Qnil;
512
+ return Qnil;
513
+ }
514
+
515
+ static ID id_convert;
516
+ static ID id___convert_field;
517
+
518
+ static inline VALUE cStructure_convert_field(VALUE self, VALUE field) {
519
+ VALUE res;
520
+ struct cStructure_data *data;
521
+ struct cField_data *field_data;
522
+ if (NIL_P(cStructure_decode_static_conditions(self, field)))
523
+ return Qnil;
524
+ TypedData_Get_Struct(self, struct cStructure_data, &cStructure_type, data);
525
+ TypedData_Get_Struct(field, struct cField_data, &cField_type, field_data);
526
+
527
+ if (RTEST(field_data->count)) {
528
+ long count = NUM2LONG(data->__count);
529
+ res = rb_ary_new_capa(count);
530
+
531
+ for (long i = 0; i < count; i++) {
532
+ data->__iterator = LONG2NUM(i);
533
+ if (RTEST(cStructure_decode_dynamic_conditions(self, field))) {
534
+ data->__value = rb_funcall(data->__type, id_convert, 7,
535
+ data->__input,
536
+ data->__output,
537
+ data->__input_big,
538
+ data->__output_big,
539
+ self,
540
+ data->__iterator,
541
+ data->__length);
542
+ rb_ary_store(res, i,
543
+ cStructure_decode_expect(self, field_data->expect, data->__value));
544
+ } else
545
+ rb_ary_store(res, i, Qnil);
546
+ }
547
+ } else {
548
+ data->__iterator = INT2FIX(0);
549
+ if (RTEST(cStructure_decode_dynamic_conditions(self, field))) {
550
+ data->__value = rb_funcall(data->__type, id_convert, 7,
551
+ data->__input,
552
+ data->__output,
553
+ data->__input_big,
554
+ data->__output_big,
555
+ self,
556
+ data->__iterator,
557
+ data->__length);
558
+ res = cStructure_decode_expect(self, field_data->expect, data->__value);
559
+ } else
560
+ res = Qnil;
561
+ }
562
+
563
+ cStructure_restore_context(self);
564
+ return res;
565
+ }
566
+
567
+ static ID id_load;
568
+ static ID id___load_field;
569
+
570
+ static inline VALUE cStructure_load_field(VALUE self, VALUE field) {
571
+ VALUE res;
572
+ struct cStructure_data *data;
573
+ struct cField_data *field_data;
574
+ if (NIL_P(cStructure_decode_static_conditions(self, field)))
575
+ return Qnil;
576
+ TypedData_Get_Struct(self, struct cStructure_data, &cStructure_type, data);
577
+ TypedData_Get_Struct(field, struct cField_data, &cField_type, field_data);
578
+
579
+ if (RTEST(field_data->count)) {
580
+ long count = NUM2LONG(data->__count);
581
+ res = rb_ary_new_capa(count);
582
+
583
+ for (long i = 0; i < count; i++) {
584
+ data->__iterator = LONG2NUM(i);
585
+ if (RTEST(cStructure_decode_dynamic_conditions(self, field))) {
586
+ data->__value = rb_funcall(data->__type, id_load, 5,
587
+ data->__input,
588
+ data->__input_big,
589
+ self,
590
+ data->__iterator,
591
+ data->__length);
592
+ rb_ary_store(res, i,
593
+ cStructure_decode_expect(self, field_data->expect, data->__value));
594
+ } else
595
+ rb_ary_store(res, i, Qnil);
596
+ }
597
+ } else {
598
+ data->__iterator = INT2FIX(0);
599
+ if (RTEST(cStructure_decode_dynamic_conditions(self, field))) {
600
+ data->__value = rb_funcall(data->__type, id_load, 5,
601
+ data->__input,
602
+ data->__input_big,
603
+ self,
604
+ data->__iterator,
605
+ data->__length);
606
+ res = cStructure_decode_expect(self, field_data->expect, data->__value);
607
+ } else
608
+ res = Qnil;
609
+ }
610
+ cStructure_restore_context(self);
611
+ return res;
612
+ }
613
+
614
+ static ID id_dump;
615
+ static ID id___dump_field;
616
+
617
+ static inline VALUE cStructure_dump_field(VALUE self, VALUE values, VALUE field) {
618
+ struct cStructure_data *data;
619
+ struct cField_data *field_data;
620
+ if (NIL_P(cStructure_decode_static_conditions(self, field)))
621
+ return Qnil;
622
+ TypedData_Get_Struct(self, struct cStructure_data, &cStructure_type, data);
623
+ TypedData_Get_Struct(field, struct cField_data, &cField_type, field_data);
624
+
625
+ if (RTEST(field_data->count)) {
626
+ long count = RARRAY_LEN(values);
627
+
628
+ for (long i = 0; i < count; i++) {
629
+ data->__iterator = LONG2NUM(i);
630
+ if (RTEST(cStructure_decode_dynamic_conditions(self, field))) {
631
+ data->__value = rb_ary_entry(values, i);
632
+ cStructure_decode_expect(self, field_data->expect, data->__value);
633
+ rb_funcall(data->__type, id_dump, 6,
634
+ data->__value,
635
+ data->__output,
636
+ data->__output_big,
637
+ self,
638
+ data->__iterator,
639
+ data->__length);
640
+ }
641
+ }
642
+ } else {
643
+ data->__iterator = INT2FIX(0);
644
+ if (RTEST(cStructure_decode_dynamic_conditions(self, field))) {
645
+ data->__value = values;
646
+ cStructure_decode_expect(self, field_data->expect, data->__value);
647
+ rb_funcall(data->__type, id_dump, 6,
648
+ data->__value,
649
+ data->__output,
650
+ data->__output_big,
651
+ self,
652
+ data->__iterator,
653
+ data->__length);
654
+ }
655
+ }
656
+ cStructure_restore_context(self);
657
+ return Qnil;
658
+ }
659
+
660
+ static ID id_shape;
661
+ static ID id___shape_field;
662
+
663
+ static inline VALUE cStructure_shape_field(
664
+ VALUE self,
665
+ VALUE values,
666
+ VALUE kind,
667
+ VALUE field)
668
+ {
669
+ VALUE res = Qnil;
670
+ struct cStructure_data *data;
671
+ struct cField_data *field_data;
672
+ if (NIL_P(cStructure_decode_static_conditions(self, field)))
673
+ return Qnil;
674
+ TypedData_Get_Struct(self, struct cStructure_data, &cStructure_type, data);
675
+ TypedData_Get_Struct(field, struct cField_data, &cField_type, field_data);
676
+
677
+ if (RTEST(field_data->count)) {
678
+ long count = RARRAY_LEN(values);
679
+ res = rb_ary_new_capa(count);
680
+
681
+ for (long i = 0; i < count; i++) {
682
+ data->__iterator = LONG2NUM(i);
683
+ if (RTEST(cStructure_decode_dynamic_conditions(self, field))) {
684
+ VALUE shape = rb_funcall(data->__type, id_shape, 6,
685
+ rb_ary_entry(values, i),
686
+ data->__cur_position,
687
+ self,
688
+ data->__iterator,
689
+ kind,
690
+ data->__length);
691
+ rb_ary_store(res, i, shape);
692
+ VALUE last = rb_funcall(shape, rb_intern("last"), 0);
693
+ if (RTEST(last)) {
694
+ ptrdiff_t pos = NUM2LL(last);
695
+ if (pos >= 0)
696
+ data->__cur_position = LL2NUM(pos + 1);
697
+ }
698
+ }
699
+ }
700
+ res = rb_class_new_instance(1, &res, kind);
701
+ } else {
702
+ data->__iterator = INT2FIX(0);
703
+ if (RTEST(cStructure_decode_dynamic_conditions(self, field))) {
704
+ res = rb_funcall(data->__type, id_shape, 6,
705
+ values,
706
+ data->__cur_position,
707
+ self,
708
+ data->__iterator,
709
+ kind,
710
+ data->__length);
711
+ VALUE last = rb_funcall(res, rb_intern("last"), 0);
712
+ if (RTEST(last)) {
713
+ ptrdiff_t pos = NUM2LL(last);
714
+ if (pos >= 0)
715
+ data->__cur_position = LL2NUM(pos + 1);
716
+ }
717
+ }
718
+ }
719
+ cStructure_restore_context(self);
720
+ return res;
721
+ }
722
+
723
+ static ID id_fields;
724
+
725
+ struct fields_state {
726
+ VALUE self;
727
+ VALUE fields;
728
+ VALUE field;
729
+ };
730
+
731
+ static inline VALUE cStructure_fields_rescue(VALUE state_p, VALUE exception) {
732
+ struct fields_state *state = (struct fields_state *)state_p;
733
+ if (NIL_P(state->field)) {
734
+ struct cStructure_data *data;
735
+ TypedData_Get_Struct(state->self, struct cStructure_data, &cStructure_type, data);
736
+ if (!NIL_P(rb_funcall(mLibBin, rb_intern("output"), 0)))
737
+ rb_funcall(rb_funcall(mLibBin, rb_intern("output"), 0), rb_intern("print"), 6,
738
+ rb_obj_class(state->self),
739
+ rb_str_new_cstr(": could not load fields, index: "),
740
+ data->__index,
741
+ rb_str_new_cstr(", current position: "),
742
+ data->__cur_position,
743
+ rb_str_new_cstr("\n"));
744
+ } else {
745
+ struct cField_data *field_data;
746
+ TypedData_Get_Struct(state->field, struct cField_data, &cField_type, field_data);
747
+ if (!NIL_P(rb_funcall(mLibBin, rb_intern("output"), 0)))
748
+ rb_funcall(rb_funcall(mLibBin, rb_intern("output"), 0), rb_intern("print"), 6,
749
+ rb_obj_class(state->self),
750
+ rb_str_new_cstr(": "),
751
+ field_data->name,
752
+ rb_str_new_cstr("("),
753
+ field_data->type,
754
+ rb_str_new_cstr(")\n"));
755
+ }
756
+ rb_exc_raise(exception);
757
+ return state->self;
758
+ }
759
+
760
+ static inline VALUE cStructure_load_fields_wrapper(VALUE state_p) {
761
+ struct fields_state *state = (struct fields_state *)state_p;
762
+ state->fields = rb_ivar_get(rb_obj_class(state->self), id_fields);
763
+ for (long i = 0; i < RARRAY_LEN(state->fields); i++) {
764
+ state->field = rb_ary_entry(state->fields, i);
765
+ struct cField_data *field_data;
766
+ TypedData_Get_Struct(state->field, struct cField_data, &cField_type, field_data);
767
+ rb_funcall(state->self, field_data->setter, 1, rb_funcall(state->self, id___load_field, 1, state->field));
768
+ }
769
+ return state->self;
770
+ }
771
+
772
+ static ID id___load_fields;
773
+
774
+ static VALUE cStructure_load_fields(VALUE self) {
775
+ struct fields_state state = {self, Qnil, Qnil};
776
+ rb_rescue(&cStructure_load_fields_wrapper, (VALUE)&state,
777
+ &cStructure_fields_rescue, (VALUE)&state);
778
+ return self;
779
+ }
780
+
781
+ static inline VALUE cStructure_dump_fields_wrapper(VALUE state_p) {
782
+ struct fields_state *state = (struct fields_state *)state_p;
783
+ state->fields = rb_ivar_get(rb_obj_class(state->self), id_fields);
784
+ for (long i = 0; i < RARRAY_LEN(state->fields); i++) {
785
+ state->field = rb_ary_entry(state->fields, i);
786
+ struct cField_data *field_data;
787
+ TypedData_Get_Struct(state->field, struct cField_data, &cField_type, field_data);
788
+ rb_funcall(state->self, id___dump_field, 2, rb_funcall(state->self, field_data->getter, 0), state->field);
789
+ }
790
+ return state->self;
791
+ }
792
+
793
+ static ID id___dump_fields;
794
+
795
+ static VALUE cStructure_dump_fields(VALUE self) {
796
+ struct fields_state state = {self, Qnil, Qnil};
797
+ rb_rescue(&cStructure_dump_fields_wrapper, (VALUE)&state,
798
+ &cStructure_fields_rescue, (VALUE)&state);
799
+ return self;
800
+ }
801
+
802
+ static inline VALUE cStructure_convert_fields_wrapper(VALUE state_p) {
803
+ struct fields_state *state = (struct fields_state *)state_p;
804
+ state->fields = rb_ivar_get(rb_obj_class(state->self), id_fields);
805
+ for (long i = 0; i < RARRAY_LEN(state->fields); i++) {
806
+ state->field = rb_ary_entry(state->fields, i);
807
+ struct cField_data *field_data;
808
+ TypedData_Get_Struct(state->field, struct cField_data, &cField_type, field_data);
809
+ rb_funcall(state->self, field_data->setter, 1, rb_funcall(state->self, id___convert_field, 1, state->field));
810
+ }
811
+ return state->self;
812
+ }
813
+
814
+ static ID id___convert_fields;
815
+
816
+ static VALUE cStructure_convert_fields(VALUE self) {
817
+ struct fields_state state = {self, Qnil, Qnil};
818
+ rb_rescue(&cStructure_convert_fields_wrapper, (VALUE)&state,
819
+ &cStructure_fields_rescue, (VALUE)&state);
820
+ return self;
821
+ }
822
+
823
+ struct shape_fields_state {
824
+ VALUE self;
825
+ VALUE fields;
826
+ VALUE field;
827
+ VALUE kind;
8
828
  };
9
829
 
830
+ static inline VALUE cStructure_shape_fields_wrapper(VALUE state_p) {
831
+ struct shape_fields_state *state = (struct shape_fields_state *)state_p;
832
+ state->fields = rb_ivar_get(rb_obj_class(state->self), id_fields);
833
+ VALUE members = rb_hash_new();
834
+ for (long i = 0; i < RARRAY_LEN(state->fields); i++) {
835
+ state->field = rb_ary_entry(state->fields, i);
836
+ struct cField_data *field_data;
837
+ TypedData_Get_Struct(state->field, struct cField_data, &cField_type, field_data);
838
+ rb_hash_aset(members, ID2SYM(field_data->getter),
839
+ rb_funcall(state->self, id___shape_field, 3, rb_funcall(state->self, field_data->getter, 0), state->kind, state->field));
840
+ }
841
+ return members;
842
+ }
843
+
844
+ static ID id___shape_fields;
845
+
846
+ static VALUE cStructure_shape_fields(VALUE self, VALUE kind) {
847
+ struct shape_fields_state state = {self, Qnil, Qnil, kind};
848
+ return rb_rescue(&cStructure_shape_fields_wrapper, (VALUE)&state,
849
+ &cStructure_fields_rescue, (VALUE)&state);
850
+ }
851
+
852
+ static ID id___load;
853
+
854
+ static inline VALUE cStructure_load(int argc, VALUE *argv, VALUE self) {
855
+ VALUE input;
856
+ VALUE input_big;
857
+ VALUE parent;
858
+ VALUE index;
859
+ rb_scan_args(argc, argv, "22", &input, &input_big, &parent, &index);
860
+ rb_funcall(self, id___set_load_state, 4, input, input_big, parent, index);
861
+ rb_funcall(self, id___load_fields, 0);
862
+ rb_funcall(self, id___unset_load_state, 0);
863
+ return self;
864
+ }
865
+
866
+ static ID id___dump;
867
+
868
+ static inline VALUE cStructure_dump(int argc, VALUE *argv, VALUE self) {
869
+ VALUE output;
870
+ VALUE output_big;
871
+ VALUE parent;
872
+ VALUE index;
873
+ rb_scan_args(argc, argv, "22", &output, &output_big, &parent, &index);
874
+ rb_funcall(self, id___set_dump_state, 4, output, output_big, parent, index);
875
+ rb_funcall(self, id___dump_fields, 0);
876
+ rb_funcall(self, id___unset_dump_state, 0);
877
+ return self;
878
+ }
879
+
880
+ static ID id___convert;
881
+
882
+ static VALUE cStructure_convert(int argc, VALUE *argv, VALUE self) {
883
+ VALUE input;
884
+ VALUE output;
885
+ VALUE input_big;
886
+ VALUE output_big;
887
+ VALUE parent;
888
+ VALUE index;
889
+ rb_scan_args(argc, argv, "42", &input, &output, &input_big, &output_big, &parent, &index);
890
+ rb_funcall(self, id___set_convert_state, 6, input, output, input_big, output_big, parent, index);
891
+ rb_funcall(self, id___convert_fields, 0);
892
+ rb_funcall(self, id___unset_convert_state, 0);
893
+ return self;
894
+ }
895
+
896
+ static ID id___shape;
897
+
898
+ static VALUE cStructure_shape(int argc, VALUE *argv, VALUE self) {
899
+ VALUE previous_offset;
900
+ VALUE parent;
901
+ VALUE index;
902
+ VALUE kind;
903
+ rb_scan_args(argc, argv, "04", &previous_offset, &parent, &index, &kind);
904
+ if (NIL_P(previous_offset))
905
+ previous_offset = INT2FIX(0);
906
+ if (NIL_P(kind))
907
+ kind = cDataShape;
908
+ rb_funcall(self, id___set_size_state, 3, previous_offset, parent, index);
909
+ VALUE members = rb_funcall(self, id___shape_fields, 1, kind);
910
+ rb_funcall(self, id___unset_size_state, 0);
911
+ if (RARRAY_LEN(rb_funcall(rb_funcall(members, rb_intern("values"), 0), rb_intern("compact"), 0)) <= 0)
912
+ return Qnil;
913
+ return rb_class_new_instance(1, &members, kind);
914
+ }
915
+
916
+ static VALUE cStructure_singl_load(int argc, VALUE *argv, VALUE self) {
917
+ VALUE input;
918
+ VALUE input_big;
919
+ VALUE parent;
920
+ VALUE index;
921
+ VALUE length;
922
+ rb_scan_args(argc, argv, "14", &input, &input_big, &parent, &index, &length);
923
+ if (NIL_P(input_big))
924
+ input_big = rb_funcall(mLibBin, rb_intern("default_big?"), 0);
925
+ VALUE res;
926
+ if (!NIL_P(length)) {
927
+ long l = NUM2LONG(length);
928
+ res = rb_ary_new_capa(l);
929
+ for (long i = 0; i < l; i++) {
930
+ VALUE obj = rb_class_new_instance(0, NULL, self);
931
+ rb_funcall(obj, id___load, 4, input, input_big, parent, index);
932
+ rb_ary_store(res, i, obj);
933
+ }
934
+ return res;
935
+ } else {
936
+ res = rb_class_new_instance(0, NULL, self);
937
+ rb_funcall(res, id___load, 4, input, input_big, parent, index);
938
+ }
939
+ return res;
940
+ }
941
+
942
+ static VALUE cStructure_singl_dump(int argc, VALUE *argv, VALUE self) {
943
+ VALUE value;
944
+ VALUE output;
945
+ VALUE output_big;
946
+ VALUE parent;
947
+ VALUE index;
948
+ VALUE length;
949
+ rb_scan_args(argc, argv, "24", &value, &output, &output_big, &parent, &index, &length);
950
+ if (NIL_P(output_big))
951
+ output_big = rb_funcall(mLibBin, rb_intern("default_big?"), 0);
952
+ if (!NIL_P(length)) {
953
+ long l = NUM2LONG(length);
954
+ for (long i = 0; i < l; i++)
955
+ rb_funcall(rb_ary_entry(value, i), id___dump, 4, output, output_big, parent, index);
956
+ } else
957
+ rb_funcall(value, id___dump, 4, output, output_big, parent, index);
958
+ return value;
959
+ }
960
+
961
+ static VALUE cStructure_singl_convert(int argc, VALUE *argv, VALUE self) {
962
+ VALUE input;
963
+ VALUE output;
964
+ VALUE input_big;
965
+ VALUE output_big;
966
+ VALUE parent;
967
+ VALUE index;
968
+ VALUE length;
969
+ rb_scan_args(argc, argv, "25", &input, &output, &input_big, &output_big, &parent, &index, &length);
970
+ if (NIL_P(input_big))
971
+ input_big = rb_funcall(mLibBin, rb_intern("default_big?"), 0);
972
+ if (NIL_P(output_big))
973
+ output_big = RTEST(input_big) ? Qfalse : Qtrue;
974
+ VALUE res;
975
+ if (!NIL_P(length)) {
976
+ long l = NUM2LONG(length);
977
+ res = rb_ary_new_capa(l);
978
+ for (long i = 0; i < l; i++) {
979
+ VALUE obj = rb_class_new_instance(0, NULL, self);
980
+ rb_funcall(obj, id___convert, 6, input, output, input_big, output_big, parent, index);
981
+ rb_ary_store(res, i, obj);
982
+ }
983
+ } else {
984
+ res = rb_class_new_instance(0, NULL, self);
985
+ rb_funcall(res, id___convert, 6, input, output, input_big, output_big, parent, index);
986
+ }
987
+ return res;
988
+ }
989
+
990
+ static VALUE cStructure_singl_shape(int argc, VALUE *argv, VALUE self) {
991
+ VALUE value;
992
+ VALUE previous_offset;
993
+ VALUE parent;
994
+ VALUE index;
995
+ VALUE kind;
996
+ VALUE length;
997
+ rb_scan_args(argc, argv, "15", &value, &previous_offset, &parent, &index, &kind, &length);
998
+ if (NIL_P(previous_offset))
999
+ previous_offset = INT2FIX(0);
1000
+ if (NIL_P(kind))
1001
+ kind = cDataShape;
1002
+ VALUE res;
1003
+ if (!NIL_P(length)) {
1004
+ long l = NUM2LONG(length);
1005
+ res = rb_ary_new_capa(l);
1006
+ for (long i = 0; i < l; i++)
1007
+ rb_ary_store(res, i, rb_funcall(rb_ary_entry(value, i), id___shape, 4, previous_offset, parent, index, kind));
1008
+ res = rb_class_new_instance(1, &res, kind);
1009
+ } else
1010
+ res = rb_funcall(value, id___shape, 4, previous_offset, parent, index, kind);
1011
+ return res;
1012
+ }
1013
+
1014
+ static void define_cStructure() {
1015
+ id_tell = rb_intern("tell");
1016
+ id_seek = rb_intern("seek");
1017
+ id_fields = rb_intern("@fields");
1018
+ id_instance_exec = rb_intern("instance_exec");
1019
+
1020
+ id___set_load_state = rb_intern("__set_load_state");
1021
+ id___unset_load_state = rb_intern("__unset_load_state");
1022
+ id___load_field = rb_intern("__load_field");
1023
+ id___load_fields = rb_intern("__load_fields");
1024
+ id_load = rb_intern("load");
1025
+ id___load = rb_intern("__load");
1026
+
1027
+ id___set_dump_state = rb_intern("__set_dump_state");
1028
+ id___unset_dump_state = rb_intern("__unset_dump_state");
1029
+ id___dump_field = rb_intern("__dump_field");
1030
+ id___dump_fields = rb_intern("__dump_fields");
1031
+ id_dump = rb_intern("dump");
1032
+ id___dump = rb_intern("__dump");
1033
+
1034
+ id___set_convert_state = rb_intern("__set_convert_state");
1035
+ id___unset_convert_state = rb_intern("__unset_convert_state");
1036
+ id___convert_field = rb_intern("__convert_field");
1037
+ id___convert_fields = rb_intern("__convert_fields");
1038
+ id_convert = rb_intern("convert");
1039
+ id___convert = rb_intern("__convert");
1040
+
1041
+ id___set_size_state = rb_intern("__set_size_state");
1042
+ id___unset_size_state = rb_intern("__unset_size_state");
1043
+ id___shape_field = rb_intern("__shape_field");
1044
+ id___shape_fields = rb_intern("__shape_fields");
1045
+ id_shape = rb_intern("shape");
1046
+ id___shape = rb_intern("__shape");
1047
+
1048
+ cStructure = rb_define_class_under(mLibBin, "Structure", rb_cObject);
1049
+ rb_define_alloc_func(cStructure, cStructure_alloc);
1050
+ /**
1051
+ * Create new Structure object.
1052
+ * @return [Structure] a new Structure instance with state set to nil.
1053
+ */
1054
+ rb_define_method(cStructure, "initialize", cStructure_initialize, 0);
1055
+
1056
+ DEFINE_STRUCT_STATE_ACCESSORS(parent);
1057
+ DEFINE_STRUCT_STATE_ACCESSORS(index);
1058
+ DEFINE_STRUCT_STATE_ACCESSORS(position);
1059
+ DEFINE_STRUCT_STATE_ACCESSORS(cur_position);
1060
+ DEFINE_STRUCT_STATE_ACCESSORS(input);
1061
+ DEFINE_STRUCT_STATE_ACCESSORS(output);
1062
+ DEFINE_STRUCT_STATE_ACCESSORS(input_big);
1063
+ DEFINE_STRUCT_STATE_ACCESSORS(output_big);
1064
+
1065
+ DEFINE_STRUCT_STATE_ACCESSORS(offset);
1066
+ DEFINE_STRUCT_STATE_ACCESSORS(condition);
1067
+ DEFINE_STRUCT_STATE_ACCESSORS(type);
1068
+ DEFINE_STRUCT_STATE_ACCESSORS(length);
1069
+ DEFINE_STRUCT_STATE_ACCESSORS(iterator);
1070
+ DEFINE_STRUCT_STATE_ACCESSORS(count);
1071
+ DEFINE_STRUCT_STATE_ACCESSORS(value);
1072
+
1073
+ /**
1074
+ * @overload __set_convert_state(input, output, input_big, output_big, parent, index)
1075
+ * Set attributes for conversion
1076
+ * @param input [IO] the stream to read data from
1077
+ * @param output [IO] the stream to write data to
1078
+ * @param input_big [Boolean] str endianness of +input+
1079
+ * @param output_big [Boolean] str endianness of +output+
1080
+ * @param parent [nil,Structure] the parent if it exists, nil otherwise
1081
+ * @param index [nil,Integer] the index if the structure is repeated, nil otherwise
1082
+ * @return [nil]
1083
+ * @example
1084
+ * # Orignal Ruby implementation
1085
+ * def __set_convert_state(input, output, input_big, output_big, parent, index)
1086
+ * __input_big = input_big
1087
+ * __output_big = output_big
1088
+ * __input = input
1089
+ * __output = output
1090
+ * __parent = parent
1091
+ * __index = index
1092
+ * __position = input.tell
1093
+ * __cur_position = __position
1094
+ * end
1095
+ */
1096
+ rb_define_method(cStructure, "__set_convert_state", cStructure_set_convert_state, 6);
1097
+ /**
1098
+ * Unset attributes after conversion.
1099
+ * @return [nil]
1100
+ * @example
1101
+ * # Orignal Ruby implementation
1102
+ * def __unset_convert_state
1103
+ * __input_big = nil
1104
+ * __output_big = nil
1105
+ * __input = nil
1106
+ * __output = nil
1107
+ * __parent = nil
1108
+ * __index = nil
1109
+ * __position = nil
1110
+ * __cur_position = nil
1111
+ * end
1112
+ */
1113
+ rb_define_method(cStructure, "__unset_convert_state", cStructure_unset_convert_state, 0);
1114
+ /**
1115
+ * @overload __set_size_state(position, parent, index)
1116
+ * Set attributes for computing size or shape
1117
+ * @param position [Integer] The position of the field
1118
+ * @param parent [nil,Structure] the parent if it exists, nil otherwise
1119
+ * @param index [nil,Integer] the index if the structure is repeated, nil otherwise
1120
+ * @return [nil]
1121
+ * @example
1122
+ * # Orignal Ruby implementation
1123
+ * def __set_size_state(position, parent, index)
1124
+ * __parent = parent
1125
+ * __index = index
1126
+ * __position = position
1127
+ * __cur_position = __position
1128
+ * end
1129
+ */
1130
+ rb_define_method(cStructure, "__set_size_state", cStructure_set_size_state, 3);
1131
+ /**
1132
+ * Unset attributes after size or shape computation
1133
+ * @return [nil]
1134
+ * @example
1135
+ * # Orignal Ruby implementation
1136
+ * def __unset_size_state
1137
+ * __parent = nil
1138
+ * __index = nil
1139
+ * __position = nil
1140
+ * __cur_position = nil
1141
+ * end
1142
+ */
1143
+ rb_define_method(cStructure, "__unset_size_state", cStructure_unset_size_state, 0);
1144
+ /**
1145
+ * @overload __set_load_state(input, input_big, parent, index)
1146
+ * Set attributes for loading
1147
+ * @param input [IO] the stream to read data from
1148
+ * @param input_big [Boolean] str endianness of +input+
1149
+ * @param parent [nil,Structure] the parent if it exists, nil otherwise
1150
+ * @param index [nil,Integer] the index if the structure is repeated, nil otherwise
1151
+ * @return [nil]
1152
+ * @example
1153
+ * # Orignal Ruby implementation
1154
+ * def __set_load_state(input, input_big, parent, index)
1155
+ * __input_big = input_big
1156
+ * __input = input
1157
+ * __parent = parent
1158
+ * __index = index
1159
+ * __position = input.tell
1160
+ * __cur_position = __position
1161
+ * end
1162
+ */
1163
+ rb_define_method(cStructure, "__set_load_state", cStructure_set_load_state, 4);
1164
+ /**
1165
+ * Unset attributes after loading
1166
+ * @return [nil]
1167
+ * @example
1168
+ * # Orignal Ruby implementation
1169
+ * def __unset_load_state
1170
+ * __input_big = nil
1171
+ * __input = nil
1172
+ * __parent = nil
1173
+ * __index = nil
1174
+ * __position = nil
1175
+ * __cur_position = nil
1176
+ * end
1177
+ */
1178
+ rb_define_method(cStructure, "__unset_load_state", cStructure_unset_load_state, 0);
1179
+ /**
1180
+ * @overload __set_dump_state(output, output_big, parent, index)
1181
+ * Set attributes for dumping
1182
+ * @param output [IO] the stream to write data to
1183
+ * @param output_big [Boolean] str endianness of +output+
1184
+ * @param parent [nil,Structure] the parent if it exists, nil otherwise
1185
+ * @param index [nil,Integer] the index if the structure is repeated, nil otherwise
1186
+ * @return [nil]
1187
+ * @example
1188
+ * # Orignal Ruby implementation
1189
+ * def __set_dump_state(output, output_big, parent, index)
1190
+ * __output_big = output_big
1191
+ * __output = output
1192
+ * __parent = parent
1193
+ * __index = index
1194
+ * __position = output.tell
1195
+ * __cur_position = __position
1196
+ * end
1197
+ */
1198
+ rb_define_method(cStructure, "__set_dump_state", cStructure_set_dump_state, 4);
1199
+ /**
1200
+ * Unset attributes after dumping
1201
+ * @return [nil]
1202
+ * @example
1203
+ * # Orignal Ruby implementation
1204
+ * def __unset_dump_state
1205
+ * __output_big = nil
1206
+ * __output = nil
1207
+ * __parent = nil
1208
+ * __index = nil
1209
+ * __position = nil
1210
+ * __cur_position = nil
1211
+ * end
1212
+ */
1213
+ rb_define_method(cStructure, "__unset_dump_state", cStructure_unset_dump_state, 0);
1214
+
1215
+ /**
1216
+ * @overload __decode_expression(expression)
1217
+ * Decode the given expression in the context of the receiver.
1218
+ * @param expression [Proc,Object] the expression to decode
1219
+ * @return [Object] the decoded value
1220
+ * @note Do not overload, this is not called through the usual ruby dispatch for performance reasons
1221
+ * @example
1222
+ * # Original Ruby implementation
1223
+ * def __decode_expression(expression)
1224
+ * if expression.is_a?(Proc)
1225
+ * instance_exec &expression
1226
+ * else
1227
+ * expression
1228
+ * end
1229
+ * end
1230
+ */
1231
+ rb_define_method(cStructure, "__decode_expression", cStructure_decode_expression, 1);
1232
+ /**
1233
+ * @overload __decode_expect(expect, value)
1234
+ * Decode the given expect expression, given the field value.
1235
+ * @param expect [Proc,Object,nil] the expression to decode
1236
+ * @param value [Object] the field value to validate
1237
+ * @return [Object] returns +value+ if validated. If expect is a Proc, the proc will be passed +value+
1238
+ * as an argument and be evaluated. If expect is a scalar, +expect+ and +value+ will be tested for equality.
1239
+ * If the result of the evaluation or the test is truthy, value is validate. Else an exception is raised.
1240
+ * @example
1241
+ * # Original Ruby implementation
1242
+ * def __decode_expect(expect, value)
1243
+ * return value if expect.nil?
1244
+ * if expect.is_a?(Proc)
1245
+ * raise "could not validate field value: #{value}" unless instance_exec(value, &expect)
1246
+ * else
1247
+ * raise "could not validate field value: #{value} expected: #{expect}" unless expect == value
1248
+ * end
1249
+ * return value
1250
+ * end
1251
+ */
1252
+ rb_define_method(cStructure, "__decode_expect", cStructure_decode_expect, 2);
1253
+ /**
1254
+ * @overload __decode_seek_offset(offset, relative_offset, align)
1255
+ * Decode the offset and seek to this position in the active streams.
1256
+ * @param offset [Proc,Integer,nil] the expression to decode
1257
+ * @param relative_offset [Boolean] the offset should be relative to the structure base (+__position+)
1258
+ * @param align [false,Integer] the required alignement of the field
1259
+ * @return [nil,false,Integer] return nil if no offset was specified, an Integer if the active streams
1260
+ * had to seek, or false if a zero offset was computed.
1261
+ * @note Do not overload, this is not called through the usual ruby dispatch for performance reasons
1262
+ * @example
1263
+ * # Original Ruby implementation
1264
+ * def __decode_seek_offset(offset, relative_offset, align)
1265
+ * cur_pos = nil
1266
+ * if !offset
1267
+ * return nil unless align
1268
+ * cur_pos =
1269
+ * if __input
1270
+ * __input.tell
1271
+ * elsif __output
1272
+ * __output.tell
1273
+ * else
1274
+ * __cur_position
1275
+ * end
1276
+ * pad = cur_pos % align
1277
+ * return nil if pad == 0
1278
+ * cur_pos += align - pad
1279
+ * else
1280
+ * cur_pos = __decode_expression(offset)
1281
+ * return false if cur_pos == 0x0
1282
+ * cur_pos += __position if relative_offset
1283
+ * cur_pos += align - (cur_pos % align) if align && cur_pos % align > 0
1284
+ * end
1285
+ * __cur_position = cur_pos
1286
+ * __input.seek(cur_pos) if __input
1287
+ * __output.seek(cur_pos) if __output
1288
+ * cur_pos
1289
+ * end
1290
+ */
1291
+ rb_define_method(cStructure, "__decode_seek_offset", cStructure_decode_seek_offset, 3);
1292
+ /**
1293
+ * @overload __decode_condition(condition)
1294
+ * Decode the condition expression
1295
+ * @param condition [Proc,Boolean,nil] the expression to decode
1296
+ * @return [Boolean] the field is active
1297
+ * @note Do not overload, this is not called through the usual ruby dispatch for performance reasons
1298
+ * @example
1299
+ * # Original Ruby implementation
1300
+ * def __decode_condition(condition)
1301
+ * return true unless condition
1302
+ * __decode_expression(condition)
1303
+ * end
1304
+ */
1305
+ rb_define_method(cStructure, "__decode_condition", cStructure_decode_condition, 1);
1306
+ /**
1307
+ * @overload __decode_count(count)
1308
+ * Decode the count expression.
1309
+ * @param count [Proc,Integer,nil] the expression to decode
1310
+ * @return [Integer] 1 if +count+ is nil, the decoded count otherwise
1311
+ * @note Do not overload, this is not called through the usual ruby dispatch for performance reasons
1312
+ * @example
1313
+ * # Original Ruby implementation
1314
+ * def __decode_count(count)
1315
+ * return 1 unless count
1316
+ * __decode_expression(count)
1317
+ * end
1318
+ */
1319
+ rb_define_method(cStructure, "__decode_count", cStructure_decode_count, 1);
1320
+ /**
1321
+ * @overload __decode_type(type)
1322
+ * Decode the type expression.
1323
+ * @param type [Proc,Class] the expression to decode
1324
+ * @return [Class] the decoded type
1325
+ * @note Do not overload, this is not called through the usual ruby dispatch for performance reasons
1326
+ * @example
1327
+ * # Original Ruby implementation
1328
+ * def __decode_type(type)
1329
+ * __decode_expression(type)
1330
+ * end
1331
+ */
1332
+ rb_define_method(cStructure, "__decode_type", cStructure_decode_type, 1);
1333
+ /**
1334
+ * @overload __decode_length(length)
1335
+ * Decode the length expression.
1336
+ * @param length [Proc,Integer,nil] the expression to decode
1337
+ * @return [Integer,nil] nil if the field is not a vector, or the
1338
+ * length of the vector
1339
+ * @note Do not overload, this is not called through the usual ruby dispatch for performance reasons
1340
+ * @example
1341
+ * # Original Ruby implementation
1342
+ * def __decode_length(length)
1343
+ * __decode_expression(length)
1344
+ * end
1345
+ */
1346
+ rb_define_method(cStructure, "__decode_length", cStructure_decode_length, 1);
1347
+ /**
1348
+ * @overload __decode_static_conditions(field)
1349
+ * Sets field specific context. Return nil if the field is inactive.
1350
+ * If the field is a sequence, only +__count+ is set, if not,
1351
+ * +__offset+, +__condition+, +__type+, and +__count+ are
1352
+ * also set.
1353
+ * @param field [Field] the field descriptor
1354
+ * @return [Integer,nil] nil if the field is inactive, the repetition count otherwise
1355
+ * @note Do not overload, this is not called through the usual ruby dispatch for performance reasons
1356
+ * @example
1357
+ * # Original Ruby implementation
1358
+ * def __decode_static_conditions(field)
1359
+ * __offset = nil
1360
+ * __condition = nil
1361
+ * __type = nil
1362
+ * __length = nil
1363
+ * __count = nil
1364
+ * unless field.sequence?
1365
+ * __offset = __decode_seek_offset(field.offset, field.relative_offset?, field.align)
1366
+ * return nil if __offset == false
1367
+ * __condition = __decode_condition(field.condition)
1368
+ * return nil unless __condition
1369
+ * __type = __decode_type(field.type)
1370
+ * __length = __decode_length(field.length)
1371
+ * end
1372
+ * __count = __decode_count(field.count)
1373
+ * end
1374
+ */
1375
+ rb_define_method(cStructure, "__decode_static_conditions", cStructure_decode_static_conditions, 1);
1376
+ /**
1377
+ * @overload __decode_dynamic_conditions(field)
1378
+ * Sets field repetition specific context.
1379
+ * Namely +__offset+, +__condition+, +__type+, and +__length+
1380
+ * should be set if the field repetition is active.
1381
+ * @param field [Field] the field descriptor
1382
+ * @return [Boolean] field repetition is active
1383
+ * @note Do not overload, this is not called through the usual ruby dispatch for performance reasons.
1384
+ * @example
1385
+ * # Original Ruby implementation
1386
+ * def __decode_dynamic_conditions(field)
1387
+ * return true unless field.sequence?
1388
+ * __offset = nil
1389
+ * __condition = nil
1390
+ * __type = nil
1391
+ * __length = nil
1392
+ * __offset = __decode_seek_offset(field.offset, field.relative_offset?, field.align)
1393
+ * return false if __offset == false
1394
+ * __condition = __decode_condition(field.condition)
1395
+ * return false unless __condition
1396
+ * __type = __decode_type(field.type)
1397
+ * __length = __decode_length(field.length)
1398
+ * return true
1399
+ * end
1400
+ */
1401
+ rb_define_method(cStructure, "__decode_dynamic_conditions", cStructure_decode_dynamic_conditions, 1);
1402
+
1403
+ /**
1404
+ * Restore the field specific context.
1405
+ * @return nil
1406
+ * @example
1407
+ * # Original Ruby implementation
1408
+ * def __restore_context
1409
+ * __iterator = nil
1410
+ * __type = nil
1411
+ * __length = nil
1412
+ * __count = nil
1413
+ * __offset = nil
1414
+ * __condition = nil
1415
+ * __value = nil
1416
+ * end
1417
+ */
1418
+ rb_define_method(cStructure, "__restore_context", cStructure_restore_context, 0);
1419
+
1420
+ /**
1421
+ * @overload __convert_field(field)
1422
+ * Load and dump the value of a structure field.
1423
+ * @param field [Field] the field descriptor
1424
+ * @return the field value or nil if the field was inactive
1425
+ * @example
1426
+ * # Original Ruby implementation
1427
+ * def __convert_field(field)
1428
+ * return nil if __decode_static_conditions(field).nil?
1429
+ * vs = __count.times.collect do |it|
1430
+ * __iterator = it
1431
+ * if __decode_dynamic_conditions(field)
1432
+ * __value = __type::convert(__input, __output, __input_big, __output_big, self, it, __length)
1433
+ * __decode_expect(field.expect, __value)
1434
+ * else
1435
+ * nil
1436
+ * end
1437
+ * end
1438
+ * __restore_context
1439
+ * vs = vs.first unless field.count
1440
+ * vs
1441
+ * end
1442
+ */
1443
+ rb_define_method(cStructure, "__convert_field", cStructure_convert_field, 1);
1444
+ /**
1445
+ * @overload __load_field(field)
1446
+ * Load the value of a structure field.
1447
+ * @param field [Field] the field descriptor
1448
+ * @return the field value or nil if the field was inactive
1449
+ * @example
1450
+ * # Original Ruby implementation
1451
+ * def __load_field(field)
1452
+ * return nil if __decode_static_conditions(field).nil?
1453
+ * vs = __count.times.collect do |it|
1454
+ * __iterator = it
1455
+ * if __decode_dynamic_conditions(field)
1456
+ * __value = __type::load(__input, __input_big, self, it, __length)
1457
+ * __decode_expect(field.expect, __value)
1458
+ * else
1459
+ * nil
1460
+ * end
1461
+ * end
1462
+ * __restore_context
1463
+ * vs = vs.first unless field.count
1464
+ * vs
1465
+ * end
1466
+ */
1467
+ rb_define_method(cStructure, "__load_field", cStructure_load_field, 1);
1468
+ /**
1469
+ * @overload __dump_field(value, field)
1470
+ * Dump the value of a structure field.
1471
+ * @param value the field value
1472
+ * @param field [Field] the field descriptor
1473
+ * @return nil
1474
+ * @example
1475
+ * # Original Ruby implementation
1476
+ * def __dump_field(vs, field)
1477
+ * return nil if __decode_static_conditions(field).nil?
1478
+ * vs = [vs] unless field.count
1479
+ * __count.times do |it|
1480
+ * __iterator = it
1481
+ * if __decode_dynamic_conditions(field)
1482
+ * __value = vs[it]
1483
+ * __decode_expect(field.expect, __value)
1484
+ * __type::dump(__value, __output, __output_big, self, it, __length)
1485
+ * end
1486
+ * end
1487
+ * __restore_context
1488
+ * end
1489
+ */
1490
+ rb_define_method(cStructure, "__dump_field", cStructure_dump_field, 2);
1491
+ /**
1492
+ * @overload __shape_field(value, kind, field)
1493
+ * Return the shape of the structure field.
1494
+ * @param value the field value
1495
+ * @param kind [Class] the class of the shape required
1496
+ * @param field [Field] the field descriptor
1497
+ * @return [nil,kind,Array<kind>] the field shape, or nil if the field was inactive
1498
+ * @example
1499
+ * # Original Ruby implementation
1500
+ * def __shape_field(vs, kind, field)
1501
+ * return nil if __decode_static_conditions(field).nil?
1502
+ * vs = [vs] unless field.count
1503
+ * vs = vs.each_with_index.collect do |v, it|
1504
+ * __iterator = it
1505
+ * if __decode_dynamic_conditions(field)
1506
+ * sh = __type::shape(v, __cur_position, self, it, kind, __length)
1507
+ * __cur_position = sh.last + 1 if sh.last && sh.last >= 0
1508
+ * sh
1509
+ * end
1510
+ * end
1511
+ * __restore_context
1512
+ * vs = field.count ? kind.new(vs) : vs.first
1513
+ * vs
1514
+ * end
1515
+ */
1516
+ rb_define_method(cStructure, "__shape_field", cStructure_shape_field, 3);
1517
+
1518
+ /**
1519
+ * Load the fields of the structure. The load state must
1520
+ * have been set beforehand.
1521
+ * @return [Structure] self
1522
+ * @example
1523
+ * # Original Ruby implementation
1524
+ * def __load_fields
1525
+ * field = nil
1526
+ * begin
1527
+ * __fields.each { |field|
1528
+ * send("#{field.name}=", __load_field(field))
1529
+ * }
1530
+ * rescue
1531
+ * STDERR.puts "#{self.class}: #{field.name}(#{field.type})"
1532
+ * raise
1533
+ * end
1534
+ * self
1535
+ * end
1536
+ */
1537
+ rb_define_method(cStructure, "__load_fields", cStructure_load_fields, 0);
1538
+ /**
1539
+ * Dump the fields of the structure. The dump state must
1540
+ * have been set beforehand.
1541
+ * @return [Structure] self
1542
+ * @example
1543
+ * # Original Ruby implementation
1544
+ * def __dump_fields
1545
+ * field = nil
1546
+ * begin
1547
+ * __fields.each { |field|
1548
+ * __dump_field(send(field.name), field)
1549
+ * }
1550
+ * rescue
1551
+ * STDERR.puts "#{self.class}: #{field.name}(#{field.type})"
1552
+ * raise
1553
+ * end
1554
+ * self
1555
+ * end
1556
+ */
1557
+ rb_define_method(cStructure, "__dump_fields", cStructure_dump_fields, 0);
1558
+ /**
1559
+ * Convert the fields of the structure. The conversion
1560
+ * state must have been set beforehand.
1561
+ * @return [Structure] self
1562
+ * @example
1563
+ * # Original Ruby implementation
1564
+ * def __convert_fields
1565
+ * field = nil
1566
+ * begin
1567
+ * __fields.each { |field|
1568
+ * send("#{field.name}=", __convert_field(field))
1569
+ * }
1570
+ * rescue
1571
+ * STDERR.puts "#{self.class}: #{field.name}(#{field.type})"
1572
+ * raise
1573
+ * end
1574
+ * self
1575
+ * end
1576
+ */
1577
+ rb_define_method(cStructure, "__convert_fields", cStructure_convert_fields, 0);
1578
+ /**
1579
+ * @overload __shape_fields(kind)
1580
+ * Return the shape of the structure fields in a Hash, indexed by the fields' names.
1581
+ * The size state must have been set beforehand.
1582
+ * @param kind [Class] the kind of structure to create
1583
+ * @return [Hash{Symbol=>kind}] the fields shape
1584
+ * @example
1585
+ * # Original Ruby implementation
1586
+ * def __shape_fields(kind)
1587
+ * members = {}
1588
+ * field = nil
1589
+ * begin
1590
+ * __fields.each { |field|
1591
+ * members[field.name] = __shape_field(send(field.name), kind, field)
1592
+ * }
1593
+ * rescue
1594
+ * LibBin.output.puts "#{self.class}: #{field.name}(#{field.type})" if LibBin.output
1595
+ * raise
1596
+ * end
1597
+ * return members
1598
+ * end
1599
+ */
1600
+ rb_define_method(cStructure, "__shape_fields", cStructure_shape_fields, 1);
1601
+
1602
+ /**
1603
+ * @overload __load(input, input_big, parent = nil, index = nil)
1604
+ * Fill in the structure by loading it from +input+.
1605
+ * @param input [IO] the stream to load the structure from
1606
+ * @param input_big [Boolean] the endianness of +input+
1607
+ * @param parent [Structure] if given, the parent of the structure
1608
+ * @param index [Integer] if given, the structure is repeated and +index+ is the rank this structure
1609
+ * @return [Structure] self
1610
+ * @example
1611
+ * # Original Ruby implementation
1612
+ * def __load(input, input_big, parent = nil, index = nil)
1613
+ * __set_load_state(input, input_big, parent, index)
1614
+ * __load_fields
1615
+ * __unset_load_state
1616
+ * self
1617
+ * end
1618
+ */
1619
+ rb_define_method(cStructure, "__load", cStructure_load, -1);
1620
+ /**
1621
+ * @overload __dump(output, output_big, parent = nil, index = nil)
1622
+ * Dump the structure to +output+.
1623
+ * @param output [IO] the stream to dump the structure to
1624
+ * @param output_big [Boolean] the endianness of +output+
1625
+ * @param parent [Structure] if given, the parent of the structure
1626
+ * @param index [Integer] if given, the structure is repeated and +index+ is the rank this structure
1627
+ * @return [Structure] self
1628
+ * @example
1629
+ * # Original Ruby implementation
1630
+ * def __dump(output, output_big, parent = nil, index = nil)
1631
+ * __set_dump_state(output, output_big, parent, index)
1632
+ * __dump_fields
1633
+ * __unset_dump_state
1634
+ * self
1635
+ * end
1636
+ */
1637
+ rb_define_method(cStructure, "__dump", cStructure_dump, -1);
1638
+ /**
1639
+ * @overload __convert(input, output, input_big, output_big, parent = nil, index = nil)
1640
+ * Fill in the structure by loading it from +input+ and
1641
+ * dumping it to +output+.
1642
+ * @param input [IO] the stream to load the structure from
1643
+ * @param output [IO] the stream to dump the structure to
1644
+ * @param input_big [Boolean] the endianness of +input+
1645
+ * @param output_big [Boolean] the endianness of +output+
1646
+ * @param parent [Structure] if given, the parent of the structure
1647
+ * @param index [Integer] if given, the structure is repeated and +index+ is the rank this structure
1648
+ * @return [Structure] self
1649
+ * @example
1650
+ * # Original Ruby implementation
1651
+ * def __convert(input, output, input_big, output_big, parent = nil, index = nil)
1652
+ * __set_convert_state(input, output, input_big, output_big, parent, index)
1653
+ * __convert_fields
1654
+ * __unset_convert_state
1655
+ * self
1656
+ * end
1657
+ */
1658
+ rb_define_method(cStructure, "__convert", cStructure_convert, -1);
1659
+ /**
1660
+ * @overload __shape(offset = 0, parent = nil, index = nil, kind = DataShape)
1661
+ * Return the shape of the structure.
1662
+ * @param offset [Integer] the base position of the field
1663
+ * @param parent [Structure] if given, the parent of the structure
1664
+ * @param index [Integer] if given, the structure is repeated and +index+ is the rank this structure
1665
+ * @param kind [Class] the kind of structure to create
1666
+ * @return [kind] the the shape of the structure
1667
+ * @example
1668
+ * # Original Ruby implementation
1669
+ * def __shape(previous_offset = 0, parent = nil, index = nil, kind = DataShape)
1670
+ * __set_size_state(previous_offset, parent, index)
1671
+ * members = __shape_fields(kind)
1672
+ * __unset_size_state
1673
+ * return nil if members.values.compact.size <= 0
1674
+ * kind::new(members)
1675
+ * end
1676
+ */
1677
+ rb_define_method(cStructure, "__shape", cStructure_shape, -1);
1678
+
1679
+ /**
1680
+ * @overload load(input, input_big = LibBin::default_big?, parent = nil, index = nil, length = nil)
1681
+ * Load a structure from +input+.
1682
+ * @param input [IO] the stream to load the structure from
1683
+ * @param input_big [Boolean] the endianness of +input+
1684
+ * @param parent [Structure] if given, the parent of the structure
1685
+ * @param index [Integer] if given, the structure is repeated and +index+ is the rank this structure
1686
+ * @param length [Integer] if given, the length of the vector of structure
1687
+ * @return [Structure,Array<Structure>] a new strcuture, or
1688
+ * an array of structures if length was specified
1689
+ * @example
1690
+ * # Original Ruby implementation
1691
+ * def self.load(input, input_big = LibBin::default_big?, parent = nil, index = nil, length = nil)
1692
+ * if length
1693
+ * length.times.collect {
1694
+ * self.new.__load(input, input_big, parent, index)
1695
+ * }
1696
+ * else
1697
+ * self.new.__load(input, input_big, parent, index)
1698
+ * end
1699
+ * end
1700
+ */
1701
+ rb_define_singleton_method(cStructure, "load", cStructure_singl_load, -1);
1702
+ /**
1703
+ * @overload dump(value, output, output_big = LibBin::default_big?, parent = nil, index = nil, length = nil)
1704
+ * Dump a structure to +output+.
1705
+ * @param value [Structure,Array<Structure>] the value of structure to dump
1706
+ * @param output [IO] the stream to dump the structure to
1707
+ * @param output_big [Boolean] the endianness of +output+
1708
+ * @param parent [Structure] if given, the parent of the structure
1709
+ * @param index [Integer] if given, the structure is repeated and +index+ is the rank this structure
1710
+ * @param length [Integer] if given, the length of the vector of structure
1711
+ * @return [Structure,Array<Structure>] +value+
1712
+ * @example
1713
+ * # Original Ruby implementation
1714
+ * def self.dump(value, output, output_big = LibBin::default_big?, parent = nil, index = nil, length = nil)
1715
+ * if length
1716
+ * length.times.each { |i|
1717
+ * value[i].__dump(output, output_big, parent, index)
1718
+ * }
1719
+ * value
1720
+ * else
1721
+ * value.__dump(output, output_big, parent, index)
1722
+ * end
1723
+ * end */
1724
+ rb_define_singleton_method(cStructure, "dump", cStructure_singl_dump, -1);
1725
+ /**
1726
+ * @overload convert(input, output, input_big = LibBin::default_big?, output_big = !input_big, parent = nil, index = nil, length = nil)
1727
+ * Convert a structure by loading it from +input+ and
1728
+ * dumping it to +output+. Returns the loaded structure.
1729
+ * @param input [IO] the stream to load the structure from
1730
+ * @param output [IO] the stream to dump the structure to
1731
+ * @param input_big [Boolean] the endianness of +input+
1732
+ * @param output_big [Boolean] the endianness of +output+
1733
+ * @param parent [Structure] if given, the parent of the structure
1734
+ * @param index [Integer] if given, the structure is repeated and +index+ is the rank this structure
1735
+ * @param length [Integer] if given, the length of the vector of structure
1736
+ * @return [Structure,Array<Structure>] a new strcuture, or
1737
+ * an array of structures if length was specified
1738
+ * @example
1739
+ * # Original Ruby implementation
1740
+ * def self.convert(input, output, input_big = LibBin::default_big?, output_big = !input_big, parent = nil, index = nil, length = nil)
1741
+ * if length
1742
+ * length.times.collect {
1743
+ * self.new.__convert(input, output, input_big, output_big, parent, index)
1744
+ * }
1745
+ * else
1746
+ * self.new.__convert(input, output, input_big, output_big, parent, index)
1747
+ * end
1748
+ * end
1749
+ */
1750
+ rb_define_singleton_method(cStructure, "convert", cStructure_singl_convert, -1);
1751
+ /**
1752
+ * @overload shape(value, offset = 0, parent = nil, index = nil, kind = DataShape, length = nil)
1753
+ * Return the shape of the value.
1754
+ * @param value [Structure,Array<Structure>] the value of structure to get the shape of
1755
+ * @param offset [Integer] the base position of the field
1756
+ * @param parent [Structure] if given, the parent of the structure
1757
+ * @param index [Integer] if given, the structure is repeated and +index+ is the rank this structure
1758
+ * @param kind [Class] the kind of structure to create
1759
+ * @param length [Integer] if given, the length of the vector of structure
1760
+ * @return [kind] the the shape of the structure
1761
+ * @example
1762
+ * # Original Ruby implementation
1763
+ * def self.shape(value, previous_offset = 0, parent = nil, index = nil, kind = DataShape, length = nil)
1764
+ * if length
1765
+ * kind.new(length.times.collect { |i|
1766
+ * value[i].__shape(previous_offset, parent, index, kind)
1767
+ * })
1768
+ * else
1769
+ * value.__shape(previous_offset, parent, index, kind)
1770
+ * end
1771
+ * end
1772
+ */
1773
+ rb_define_singleton_method(cStructure, "shape", cStructure_singl_shape, -1);
1774
+ }
1775
+
10
1776
  static VALUE pghalf_from_string_p(VALUE self, VALUE str, VALUE pack_str) {
11
- Check_Type(str, T_STRING);
12
- Check_Type(pack_str, T_STRING);
13
- VALUE arr = rb_funcall(str, rb_intern("unpack"), 1, pack_str);
14
- uint16_t val = NUM2USHORT(rb_funcall(arr, rb_intern("first"), 0));
15
- union float_u res;
1777
+ (void)self;
1778
+ Check_Type(str, T_STRING);
1779
+ Check_Type(pack_str, T_STRING);
1780
+ VALUE arr = rb_funcall(str, rb_intern("unpack"), 1, pack_str);
1781
+ uint16_t val = NUM2USHORT(rb_funcall(arr, rb_intern("first"), 0));
1782
+ union float_u res;
16
1783
 
17
- res.i = pghalf_to_float(val);
18
- return DBL2NUM(res.f);
1784
+ res.i = pghalf_to_float(val);
1785
+ return DBL2NUM(res.f);
19
1786
  }
20
1787
 
21
1788
  static VALUE half_from_string_p(VALUE self, VALUE str, VALUE pack_str) {
22
- Check_Type(str, T_STRING);
23
- Check_Type(pack_str, T_STRING);
24
- VALUE arr = rb_funcall(str, rb_intern("unpack"), 1, pack_str);
25
- uint16_t val = NUM2USHORT(rb_funcall(arr, rb_intern("first"), 0));
26
- union float_u res;
1789
+ (void)self;
1790
+ Check_Type(str, T_STRING);
1791
+ Check_Type(pack_str, T_STRING);
1792
+ VALUE arr = rb_funcall(str, rb_intern("unpack"), 1, pack_str);
1793
+ uint16_t val = NUM2USHORT(rb_funcall(arr, rb_intern("first"), 0));
1794
+ union float_u res;
27
1795
 
28
- res.i = half_to_float(val);
29
- return DBL2NUM(res.f);
1796
+ res.i = half_to_float(val);
1797
+ return DBL2NUM(res.f);
30
1798
  }
31
1799
 
32
1800
  static VALUE pghalf_to_string_p(VALUE self, VALUE number, VALUE pack_str) {
33
- Check_Type(number, T_FLOAT);
34
- union float_u val;
35
- uint16_t res;
1801
+ (void)self;
1802
+ Check_Type(number, T_FLOAT);
1803
+ union float_u val;
1804
+ uint16_t res;
36
1805
 
37
- val.f = NUM2DBL(number);
38
- res = pghalf_from_float(val.i);
39
- VALUE arr = rb_ary_new3(1, UINT2NUM(res) );
1806
+ val.f = NUM2DBL(number);
1807
+ res = pghalf_from_float(val.i);
1808
+ VALUE arr = rb_ary_new3(1, UINT2NUM(res) );
40
1809
 
41
- return rb_funcall(arr, rb_intern("pack"), 1, pack_str);
1810
+ return rb_funcall(arr, rb_intern("pack"), 1, pack_str);
42
1811
  }
43
1812
 
44
1813
  static VALUE half_to_string_p(VALUE self, VALUE number, VALUE pack_str) {
45
- Check_Type(number, T_FLOAT);
46
- union float_u val;
47
- uint16_t res;
1814
+ (void)self;
1815
+ Check_Type(number, T_FLOAT);
1816
+ union float_u val;
1817
+ uint16_t res;
1818
+
1819
+ val.f = NUM2DBL(number);
1820
+ res = half_from_float(val.i);
1821
+ VALUE arr = rb_ary_new3(1, UINT2NUM(res) );
1822
+
1823
+ return rb_funcall(arr, rb_intern("pack"), 1, pack_str);
1824
+ }
1825
+
1826
+ static void define_cField() {
1827
+ id_gsub = rb_intern("gsub");
48
1828
 
49
- val.f = NUM2DBL(number);
50
- res = half_from_float(val.i);
51
- VALUE arr = rb_ary_new3(1, UINT2NUM(res) );
1829
+ rb_str_dot_dot = rb_obj_freeze(rb_str_new_cstr(".."));
1830
+ rb_gc_register_mark_object(rb_str_dot_dot);
1831
+ rb_str___parent = rb_obj_freeze(rb_str_new_cstr("__parent"));
1832
+ rb_gc_register_mark_object(rb_str___parent);
1833
+ rb_str_backslash = rb_obj_freeze(rb_str_new_cstr("\\"));
1834
+ rb_gc_register_mark_object(rb_str_backslash);
1835
+ rb_str_dot = rb_obj_freeze(rb_str_new_cstr("."));
1836
+ rb_gc_register_mark_object(rb_str_dot);
52
1837
 
53
- return rb_funcall(arr, rb_intern("pack"), 1, pack_str);
1838
+ cField = rb_define_class_under(cStructure, "Field", rb_cObject);
1839
+ rb_define_alloc_func(cField, cField_alloc);
1840
+ /**
1841
+ * @overload initialize(name, type, length, count, offset, sequence, condition, relative_offset, align, expect)
1842
+ * @param name [Symbol, String] the name of the field.
1843
+ * @param type [Class, String, Proc] the type of the field, as a Class, or
1844
+ * as a String or Proc that will be evaluated in the context of the
1845
+ * {Structure} instance.
1846
+ * @param length [nil, Integer, String, Proc] if given, consider the field a
1847
+ * vector of the type. The length is either a constant Integer of a
1848
+ * String or Proc that will be evaluated in the context of the
1849
+ * {Structure} instance.
1850
+ * @param count [nil, Integer, String, Proc] if given, consider the field is
1851
+ * repeated count times. The count is either a constant Integer of a
1852
+ * String or Proc that will be evaluated in the context of the
1853
+ * {Structure} instance.
1854
+ * @param offset [nil, integer, String, Proc] if given, the absolute offset in
1855
+ * the file, or the offset from the parent position, where the field can
1856
+ * be found. See relative offset. The offset is either a constant
1857
+ * Integer of a String or Proc that will be evaluated in the context
1858
+ * of the {Structure} instance.
1859
+ * @param sequence [Boolean] if true, +type+, +length+, +offset+, and
1860
+ * +condition+ are evaluated for each repetition.
1861
+ * @param condition [nil, String, Proc] if given, the field, or repetition of the
1862
+ * field can be conditionally present. The condition will be evaluated in
1863
+ * the context of the {Structure} instance.
1864
+ * @param relative_offset [Boolean] consider the +offset+ relative to
1865
+ * the field +parent+.
1866
+ * @param align [nil, Integer] if given, align the field. If given as an
1867
+ * Integer it must be a power of 2. Else the field is aligned to the
1868
+ * field's type preferred alignment
1869
+ * @param expect [nil, Proc, Object] if given as a Proc the proc must
1870
+ * evaluate to a truthy value or an exception will be raised. Else, the
1871
+ * object will be tested for equality, and an exception will be raised if
1872
+ * objects were not equal. Proc is evaluated in the context of the {Structure}
1873
+ * instance and #__value will be set. Each repetition is validated.
1874
+ * @return [Field] new Field
1875
+ */
1876
+ rb_define_method(cField, "initialize", cField_initialize, 10);
1877
+ DEFINE_FIELD_STATE_GETTER(name);
1878
+ DEFINE_FIELD_STATE_GETTER(type);
1879
+ DEFINE_FIELD_STATE_GETTER(length);
1880
+ DEFINE_FIELD_STATE_GETTER(count);
1881
+ DEFINE_FIELD_STATE_GETTER(offset);
1882
+ DEFINE_FIELD_STATE_GETTER_BOOL(sequence);
1883
+ DEFINE_FIELD_STATE_GETTER(condition);
1884
+ DEFINE_FIELD_STATE_GETTER_BOOL(relative_offset);
1885
+ DEFINE_FIELD_STATE_GETTER(align);
1886
+ DEFINE_FIELD_STATE_GETTER(expect);
54
1887
  }
55
1888
 
56
1889
  void Init_libbin_c() {
57
- ID id;
58
- VALUE mod;
59
- id = rb_intern("LibBin");
60
- mod = rb_const_get(rb_cObject, id);
61
- rb_define_module_function(mod, "half_from_string", half_from_string_p, 2);
62
- rb_define_module_function(mod, "half_to_string", half_to_string_p, 2);
63
- rb_define_module_function(mod, "pghalf_from_string", pghalf_from_string_p, 2);
64
- rb_define_module_function(mod, "pghalf_to_string", pghalf_to_string_p, 2);
1890
+ mLibBin = rb_define_module("LibBin");
1891
+ /**
1892
+ * @overload half_from_string(str, unpack_str)
1893
+ * Load (unpacks) a half precision floating point.
1894
+ * @param str [String] the strin to read the number from
1895
+ * @param unpack_str [String] the unpack format of the underlying 16bit integer
1896
+ * @return [Float] the ruby representation of the value
1897
+ * @example
1898
+ * # Read a half precision floating point value stored in 'str' in little endian fashion
1899
+ * value = half_from_string(str, "S<")
1900
+ */
1901
+ rb_define_module_function(mLibBin, "half_from_string", half_from_string_p, 2);
1902
+ /**
1903
+ * @overload half_to_string(value, pack_str)
1904
+ * Convert a Numeric value to a half precision floating point and pack it into a string.
1905
+ * @param value [Numeric] the number to convert
1906
+ * @param pack_str [String] the pack format to store the underlying 16 bit integer representation of the value
1907
+ * @return [String] the packed half precision value
1908
+ * @example
1909
+ * # Stores a number as a half precision floating point value in a big endian fashion
1910
+ * str = half_to_string(value, "S>")
1911
+ */
1912
+ rb_define_module_function(mLibBin, "half_to_string", half_to_string_p, 2);
1913
+ /**
1914
+ * @overload pghalf_from_string(str, unpack_str)
1915
+ * Load (unpacks) a half precision floating point as used by PlatinumGames in some formats.
1916
+ * @param str [String] the strin to read the number from
1917
+ * @param unpack_str [String] the unpack format of the underlying 16bit integer
1918
+ * @return [Float] the ruby representation of the value
1919
+ * @example
1920
+ * # Read a half precision floating point value stored in 'str' in little endian fashion
1921
+ * half_from_string(str, "S<")
1922
+ */
1923
+ rb_define_module_function(mLibBin, "pghalf_from_string", pghalf_from_string_p, 2);
1924
+ /**
1925
+ * @overload pghalf_to_string(value, pack_str)
1926
+ * Convert a Numeric value to a half precision floating point as used by PlatinumGames in some formats, and pack it into a string.
1927
+ * @param value [Numeric] the number to convert
1928
+ * @param pack_str [String] the pack format to store the underlying 16 bit integer representation of the value
1929
+ * @return [String] the packed half precision value
1930
+ * @example
1931
+ * # Stores a number as a half precision floating point value in a big endian fashion
1932
+ * str = half_to_string(value, "S>")
1933
+ */
1934
+ rb_define_module_function(mLibBin, "pghalf_to_string", pghalf_to_string_p, 2);
1935
+ cDataRange = rb_define_class_under(mLibBin, "DataRange", rb_cObject);
1936
+ cDataShape = rb_define_class_under(mLibBin, "DataShape", cDataRange);
1937
+ define_cStructure();
1938
+ define_cField();
1939
+ define_cScalar();
65
1940
  }