libbin 1.0.5 → 2.0.0

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