ox-bundlecachetest 2.14.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +751 -0
  3. data/LICENSE +21 -0
  4. data/README.md +351 -0
  5. data/ext/ox/attr.h +78 -0
  6. data/ext/ox/base64.c +105 -0
  7. data/ext/ox/base64.h +18 -0
  8. data/ext/ox/buf.h +162 -0
  9. data/ext/ox/builder.c +948 -0
  10. data/ext/ox/cache.c +351 -0
  11. data/ext/ox/cache.h +21 -0
  12. data/ext/ox/cache8.c +106 -0
  13. data/ext/ox/cache8.h +23 -0
  14. data/ext/ox/dump.c +1260 -0
  15. data/ext/ox/err.c +46 -0
  16. data/ext/ox/err.h +36 -0
  17. data/ext/ox/extconf.rb +47 -0
  18. data/ext/ox/gen_load.c +342 -0
  19. data/ext/ox/hash_load.c +309 -0
  20. data/ext/ox/helper.h +84 -0
  21. data/ext/ox/intern.c +157 -0
  22. data/ext/ox/intern.h +25 -0
  23. data/ext/ox/obj_load.c +809 -0
  24. data/ext/ox/ox.c +1649 -0
  25. data/ext/ox/ox.h +245 -0
  26. data/ext/ox/parse.c +1197 -0
  27. data/ext/ox/sax.c +1570 -0
  28. data/ext/ox/sax.h +69 -0
  29. data/ext/ox/sax_as.c +270 -0
  30. data/ext/ox/sax_buf.c +209 -0
  31. data/ext/ox/sax_buf.h +204 -0
  32. data/ext/ox/sax_hint.c +207 -0
  33. data/ext/ox/sax_hint.h +40 -0
  34. data/ext/ox/sax_stack.h +113 -0
  35. data/ext/ox/slotcache.c +158 -0
  36. data/ext/ox/slotcache.h +19 -0
  37. data/ext/ox/special.c +390 -0
  38. data/ext/ox/special.h +14 -0
  39. data/ext/ox/type.h +39 -0
  40. data/lib/ox/bag.rb +103 -0
  41. data/lib/ox/cdata.rb +10 -0
  42. data/lib/ox/comment.rb +11 -0
  43. data/lib/ox/doctype.rb +11 -0
  44. data/lib/ox/document.rb +28 -0
  45. data/lib/ox/element.rb +464 -0
  46. data/lib/ox/error.rb +25 -0
  47. data/lib/ox/hasattrs.rb +54 -0
  48. data/lib/ox/instruct.rb +34 -0
  49. data/lib/ox/node.rb +23 -0
  50. data/lib/ox/raw.rb +12 -0
  51. data/lib/ox/sax.rb +97 -0
  52. data/lib/ox/version.rb +4 -0
  53. data/lib/ox/xmlrpc_adapter.rb +33 -0
  54. data/lib/ox.rb +79 -0
  55. metadata +128 -0
data/ext/ox/obj_load.c ADDED
@@ -0,0 +1,809 @@
1
+ /* obj_load.c
2
+ * Copyright (c) 2011, Peter Ohler
3
+ * All rights reserved.
4
+ */
5
+
6
+ #include <errno.h>
7
+ #include <stdarg.h>
8
+ #include <stdio.h>
9
+ #include <stdlib.h>
10
+ #include <string.h>
11
+ #include <time.h>
12
+
13
+ #include "base64.h"
14
+ #include "intern.h"
15
+ #include "ox.h"
16
+ #include "ruby.h"
17
+ #include "ruby/encoding.h"
18
+
19
+ static void instruct(PInfo pi, const char *target, Attr attrs, const char *content);
20
+ static void add_text(PInfo pi, char *text, int closed);
21
+ static void add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren);
22
+ static void end_element(PInfo pi, const char *ename);
23
+
24
+ static VALUE parse_time(const char *text, VALUE clas);
25
+ static VALUE parse_xsd_time(const char *text, VALUE clas);
26
+ static VALUE parse_double_time(const char *text, VALUE clas);
27
+ static VALUE parse_regexp(const char *text);
28
+
29
+ static ID get_var_sym_from_attrs(Attr a, void *encoding);
30
+ static VALUE get_obj_from_attrs(Attr a, PInfo pi, VALUE base_class);
31
+ static VALUE get_class_from_attrs(Attr a, PInfo pi, VALUE base_class);
32
+ static VALUE classname2class(const char *name, PInfo pi, VALUE base_class);
33
+ static unsigned long get_id_from_attrs(PInfo pi, Attr a);
34
+ static CircArray circ_array_new(void);
35
+ static void circ_array_free(CircArray ca);
36
+ static void circ_array_set(CircArray ca, VALUE obj, unsigned long id);
37
+ static VALUE circ_array_get(CircArray ca, unsigned long id);
38
+
39
+ static void debug_stack(PInfo pi, const char *comment);
40
+ static void fill_indent(PInfo pi, char *buf, size_t size);
41
+
42
+ struct _parseCallbacks _ox_obj_callbacks = {
43
+ instruct, // instruct,
44
+ 0, // add_doctype,
45
+ 0, // add_comment,
46
+ 0, // add_cdata,
47
+ add_text,
48
+ add_element,
49
+ end_element,
50
+ NULL,
51
+ };
52
+
53
+ ParseCallbacks ox_obj_callbacks = &_ox_obj_callbacks;
54
+
55
+ extern ParseCallbacks ox_gen_callbacks;
56
+
57
+ inline static VALUE resolve_classname(VALUE mod, const char *class_name, Effort effort, VALUE base_class) {
58
+ VALUE clas;
59
+ ID ci = rb_intern(class_name);
60
+
61
+ switch (effort) {
62
+ case TolerantEffort:
63
+ if (rb_const_defined_at(mod, ci)) {
64
+ clas = rb_const_get_at(mod, ci);
65
+ } else {
66
+ clas = Qundef;
67
+ }
68
+ break;
69
+ case AutoEffort:
70
+ if (rb_const_defined_at(mod, ci)) {
71
+ clas = rb_const_get_at(mod, ci);
72
+ } else {
73
+ clas = rb_define_class_under(mod, class_name, base_class);
74
+ }
75
+ break;
76
+ case StrictEffort:
77
+ default:
78
+ // raise an error if name is not defined
79
+ clas = rb_const_get_at(mod, ci);
80
+ break;
81
+ }
82
+ return clas;
83
+ }
84
+
85
+ inline static VALUE classname2obj(const char *name, PInfo pi, VALUE base_class) {
86
+ VALUE clas = classname2class(name, pi, base_class);
87
+
88
+ if (Qundef == clas) {
89
+ return Qnil;
90
+ } else {
91
+ return rb_obj_alloc(clas);
92
+ }
93
+ }
94
+
95
+ inline static VALUE structname2obj(const char *name) {
96
+ VALUE ost;
97
+ const char *s = name;
98
+
99
+ for (; 1; s++) {
100
+ if ('\0' == *s) {
101
+ s = name;
102
+ break;
103
+ } else if (':' == *s) {
104
+ s += 2;
105
+ break;
106
+ }
107
+ }
108
+ ost = rb_const_get(ox_struct_class, rb_intern(s));
109
+ return rb_struct_alloc_noinit(ost);
110
+ }
111
+
112
+ inline static VALUE parse_ulong(const char *s, PInfo pi) {
113
+ unsigned long n = 0;
114
+
115
+ for (; '\0' != *s; s++) {
116
+ if ('0' <= *s && *s <= '9') {
117
+ n = n * 10 + (*s - '0');
118
+ } else {
119
+ set_error(&pi->err, "Invalid number for a julian day", pi->str, pi->s);
120
+ return Qundef;
121
+ }
122
+ }
123
+ return ULONG2NUM(n);
124
+ }
125
+
126
+ // 2010-07-09T10:47:45.895826162+09:00
127
+ inline static VALUE parse_time(const char *text, VALUE clas) {
128
+ VALUE t;
129
+
130
+ if (Qnil == (t = parse_double_time(text, clas)) && Qnil == (t = parse_xsd_time(text, clas))) {
131
+ VALUE args[1];
132
+
133
+ *args = rb_str_new2(text);
134
+ t = rb_funcall2(ox_time_class, ox_parse_id, 1, args);
135
+ }
136
+ return t;
137
+ }
138
+
139
+ static VALUE classname2class(const char *name, PInfo pi, VALUE base_class) {
140
+ VALUE *slot;
141
+ VALUE clas;
142
+
143
+ if (Qundef == (clas = slot_cache_get(ox_class_cache, name, &slot, 0))) {
144
+ char class_name[1024];
145
+ char *s;
146
+ const char *n = name;
147
+
148
+ clas = rb_cObject;
149
+ for (s = class_name; '\0' != *n; n++) {
150
+ if (':' == *n) {
151
+ *s = '\0';
152
+ n++;
153
+ if (':' != *n) {
154
+ set_error(&pi->err, "Invalid classname, expected another ':'", pi->str, pi->s);
155
+ return Qundef;
156
+ }
157
+ if (Qundef == (clas = resolve_classname(clas, class_name, pi->options->effort, base_class))) {
158
+ return Qundef;
159
+ }
160
+ s = class_name;
161
+ } else {
162
+ *s++ = *n;
163
+ }
164
+ }
165
+ *s = '\0';
166
+ if (Qundef != (clas = resolve_classname(clas, class_name, pi->options->effort, base_class))) {
167
+ *slot = clas;
168
+ rb_gc_register_address(slot);
169
+ }
170
+ }
171
+ return clas;
172
+ }
173
+
174
+ static ID get_var_sym_from_attrs(Attr a, void *encoding) {
175
+ for (; 0 != a->name; a++) {
176
+ if ('a' == *a->name && '\0' == *(a->name + 1)) {
177
+ const char *val = a->value;
178
+
179
+ if ('0' <= *val && *val <= '9') {
180
+ return INT2NUM(atoi(val));
181
+ }
182
+ return ox_id_intern(val, strlen(val));
183
+ }
184
+ }
185
+ return 0;
186
+ }
187
+
188
+ static VALUE get_obj_from_attrs(Attr a, PInfo pi, VALUE base_class) {
189
+ for (; 0 != a->name; a++) {
190
+ if ('c' == *a->name && '\0' == *(a->name + 1)) {
191
+ return classname2obj(a->value, pi, base_class);
192
+ }
193
+ }
194
+ return Qundef;
195
+ }
196
+
197
+ static VALUE get_struct_from_attrs(Attr a) {
198
+ for (; 0 != a->name; a++) {
199
+ if ('c' == *a->name && '\0' == *(a->name + 1)) {
200
+ return structname2obj(a->value);
201
+ }
202
+ }
203
+ return Qundef;
204
+ }
205
+
206
+ static VALUE get_class_from_attrs(Attr a, PInfo pi, VALUE base_class) {
207
+ for (; 0 != a->name; a++) {
208
+ if ('c' == *a->name && '\0' == *(a->name + 1)) {
209
+ return classname2class(a->value, pi, base_class);
210
+ }
211
+ }
212
+ return Qundef;
213
+ }
214
+
215
+ static unsigned long get_id_from_attrs(PInfo pi, Attr a) {
216
+ for (; 0 != a->name; a++) {
217
+ if ('i' == *a->name && '\0' == *(a->name + 1)) {
218
+ unsigned long id = 0;
219
+ const char *text = a->value;
220
+ char c;
221
+
222
+ for (; '\0' != *text; text++) {
223
+ c = *text;
224
+ if ('0' <= c && c <= '9') {
225
+ id = id * 10 + (c - '0');
226
+ } else {
227
+ set_error(&pi->err, "bad number format", pi->str, pi->s);
228
+ return 0;
229
+ }
230
+ }
231
+ return id;
232
+ }
233
+ }
234
+ return 0;
235
+ }
236
+
237
+ static CircArray circ_array_new(void) {
238
+ CircArray ca;
239
+
240
+ ca = ALLOC(struct _circArray);
241
+ ca->objs = ca->obj_array;
242
+ ca->size = sizeof(ca->obj_array) / sizeof(VALUE);
243
+ ca->cnt = 0;
244
+
245
+ return ca;
246
+ }
247
+
248
+ static void circ_array_free(CircArray ca) {
249
+ if (ca->objs != ca->obj_array) {
250
+ xfree(ca->objs);
251
+ }
252
+ xfree(ca);
253
+ }
254
+
255
+ static void circ_array_set(CircArray ca, VALUE obj, unsigned long id) {
256
+ if (0 < id) {
257
+ unsigned long i;
258
+
259
+ if (ca->size < id) {
260
+ unsigned long cnt = id + 512;
261
+
262
+ if (ca->objs == ca->obj_array) {
263
+ ca->objs = ALLOC_N(VALUE, cnt);
264
+ memcpy(ca->objs, ca->obj_array, sizeof(VALUE) * ca->cnt);
265
+ } else {
266
+ REALLOC_N(ca->objs, VALUE, cnt);
267
+ }
268
+ ca->size = cnt;
269
+ }
270
+ id--;
271
+ for (i = ca->cnt; i < id; i++) {
272
+ ca->objs[i] = Qundef;
273
+ }
274
+ ca->objs[id] = obj;
275
+ if (ca->cnt <= id) {
276
+ ca->cnt = id + 1;
277
+ }
278
+ }
279
+ }
280
+
281
+ static VALUE circ_array_get(CircArray ca, unsigned long id) {
282
+ VALUE obj = Qundef;
283
+
284
+ if (id <= ca->cnt) {
285
+ obj = ca->objs[id - 1];
286
+ }
287
+ return obj;
288
+ }
289
+
290
+ static VALUE parse_regexp(const char *text) {
291
+ const char *te;
292
+ int options = 0;
293
+
294
+ te = text + strlen(text) - 1;
295
+ #ifdef ONIG_OPTION_IGNORECASE
296
+ for (; text < te && '/' != *te; te--) {
297
+ switch (*te) {
298
+ case 'i': options |= ONIG_OPTION_IGNORECASE; break;
299
+ case 'm': options |= ONIG_OPTION_MULTILINE; break;
300
+ case 'x': options |= ONIG_OPTION_EXTEND; break;
301
+ default: break;
302
+ }
303
+ }
304
+ #endif
305
+ return rb_reg_new(text + 1, te - text - 1, options);
306
+ }
307
+
308
+ static void instruct(PInfo pi, const char *target, Attr attrs, const char *content) {
309
+ if (0 == strcmp("xml", target)) {
310
+ for (; 0 != attrs->name; attrs++) {
311
+ if (0 == strcmp("encoding", attrs->name)) {
312
+ pi->options->rb_enc = rb_enc_find(attrs->value);
313
+ }
314
+ }
315
+ }
316
+ }
317
+
318
+ static void add_text(PInfo pi, char *text, int closed) {
319
+ Helper h = helper_stack_peek(&pi->helpers);
320
+
321
+ if (!closed) {
322
+ set_error(&pi->err, "Text not closed", pi->str, pi->s);
323
+ return;
324
+ }
325
+ if (0 == h) {
326
+ set_error(&pi->err, "Unexpected text", pi->str, pi->s);
327
+ return;
328
+ }
329
+ if (DEBUG <= pi->options->trace) {
330
+ char indent[128];
331
+
332
+ fill_indent(pi, indent, sizeof(indent));
333
+ printf("%s '%s' to type %c\n", indent, text, h->type);
334
+ }
335
+ switch (h->type) {
336
+ case NoCode:
337
+ case StringCode:
338
+ h->obj = rb_str_new2(text);
339
+ if (0 != pi->options->rb_enc) {
340
+ rb_enc_associate(h->obj, pi->options->rb_enc);
341
+ }
342
+ if (0 != pi->circ_array) {
343
+ circ_array_set(pi->circ_array, h->obj, (unsigned long)pi->id);
344
+ }
345
+ break;
346
+ case FixnumCode: {
347
+ long n = 0;
348
+ char c;
349
+ int neg = 0;
350
+
351
+ if ('-' == *text) {
352
+ neg = 1;
353
+ text++;
354
+ }
355
+ for (; '\0' != *text; text++) {
356
+ c = *text;
357
+ if ('0' <= c && c <= '9') {
358
+ n = n * 10 + (c - '0');
359
+ } else {
360
+ set_error(&pi->err, "bad number format", pi->str, pi->s);
361
+ return;
362
+ }
363
+ }
364
+ if (neg) {
365
+ n = -n;
366
+ }
367
+ h->obj = LONG2NUM(n);
368
+ break;
369
+ }
370
+ case FloatCode: h->obj = rb_float_new(strtod(text, 0)); break;
371
+ case SymbolCode: h->obj = ox_sym_intern(text, strlen(text), NULL); break;
372
+ case DateCode: {
373
+ VALUE args[1];
374
+
375
+ if (Qundef == (*args = parse_ulong(text, pi))) {
376
+ return;
377
+ }
378
+ h->obj = rb_funcall2(ox_date_class, ox_jd_id, 1, args);
379
+ break;
380
+ }
381
+ case TimeCode: h->obj = parse_time(text, ox_time_class); break;
382
+ case String64Code: {
383
+ unsigned long str_size = b64_orig_size(text);
384
+ VALUE v;
385
+ char *str = ALLOCA_N(char, str_size + 1);
386
+
387
+ from_base64(text, (uchar *)str);
388
+ v = rb_str_new(str, str_size);
389
+ if (0 != pi->options->rb_enc) {
390
+ rb_enc_associate(v, pi->options->rb_enc);
391
+ }
392
+ if (0 != pi->circ_array) {
393
+ circ_array_set(pi->circ_array, v, (unsigned long)h->obj);
394
+ }
395
+ h->obj = v;
396
+ break;
397
+ }
398
+ case Symbol64Code: {
399
+ unsigned long str_size = b64_orig_size(text);
400
+ char *str = ALLOCA_N(char, str_size + 1);
401
+
402
+ from_base64(text, (uchar *)str);
403
+ h->obj = ox_sym_intern(str, strlen(str), NULL);
404
+ break;
405
+ }
406
+ case RegexpCode:
407
+ if ('/' == *text) {
408
+ h->obj = parse_regexp(text);
409
+ } else {
410
+ unsigned long str_size = b64_orig_size(text);
411
+ char *str = ALLOCA_N(char, str_size + 1);
412
+
413
+ from_base64(text, (uchar *)str);
414
+ h->obj = parse_regexp(str);
415
+ }
416
+ break;
417
+ case BignumCode: h->obj = rb_cstr_to_inum(text, 10, 1); break;
418
+ case BigDecimalCode: h->obj = rb_funcall(rb_cObject, ox_bigdecimal_id, 1, rb_str_new2(text)); break;
419
+ default: h->obj = Qnil; break;
420
+ }
421
+ }
422
+
423
+ static void add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren) {
424
+ Attr a;
425
+ Helper h;
426
+ unsigned long id;
427
+
428
+ if (TRACE <= pi->options->trace) {
429
+ char buf[1024];
430
+ char indent[128];
431
+ char *s = buf;
432
+ char *end = buf + sizeof(buf) - 2;
433
+
434
+ s += snprintf(s, end - s, " <%s%s", (hasChildren) ? "" : "/", ename);
435
+ for (a = attrs; 0 != a->name; a++) {
436
+ s += snprintf(s, end - s, " %s=%s", a->name, a->value);
437
+ }
438
+ *s++ = '>';
439
+ *s++ = '\0';
440
+ if (DEBUG <= pi->options->trace) {
441
+ printf("===== add element stack(%d) =====\n", helper_stack_depth(&pi->helpers));
442
+ debug_stack(pi, buf);
443
+ } else {
444
+ fill_indent(pi, indent, sizeof(indent));
445
+ printf("%s%s\n", indent, buf);
446
+ }
447
+ }
448
+ if (helper_stack_empty(&pi->helpers)) { // top level object
449
+ if (0 != (id = get_id_from_attrs(pi, attrs))) {
450
+ pi->circ_array = circ_array_new();
451
+ }
452
+ }
453
+ if ('\0' != ename[1]) {
454
+ set_error(&pi->err, "Invalid element name", pi->str, pi->s);
455
+ return;
456
+ }
457
+ h = helper_stack_push(&pi->helpers, get_var_sym_from_attrs(attrs, (void *)pi->options->rb_enc), Qundef, *ename);
458
+ switch (h->type) {
459
+ case NilClassCode: h->obj = Qnil; break;
460
+ case TrueClassCode: h->obj = Qtrue; break;
461
+ case FalseClassCode: h->obj = Qfalse; break;
462
+ case StringCode:
463
+ // h->obj will be replaced by add_text if it is called
464
+ h->obj = ox_empty_string;
465
+ if (0 != pi->circ_array) {
466
+ pi->id = get_id_from_attrs(pi, attrs);
467
+ circ_array_set(pi->circ_array, h->obj, pi->id);
468
+ }
469
+ break;
470
+ case FixnumCode:
471
+ case FloatCode:
472
+ case SymbolCode:
473
+ case Symbol64Code:
474
+ case RegexpCode:
475
+ case BignumCode:
476
+ case BigDecimalCode:
477
+ case ComplexCode:
478
+ case DateCode:
479
+ case TimeCode:
480
+ case RationalCode: // sub elements read next
481
+ // value will be read in the following add_text
482
+ h->obj = Qundef;
483
+ break;
484
+ case String64Code:
485
+ h->obj = Qundef;
486
+ if (0 != pi->circ_array) {
487
+ pi->id = get_id_from_attrs(pi, attrs);
488
+ }
489
+ break;
490
+ case ArrayCode:
491
+ h->obj = rb_ary_new();
492
+ if (0 != pi->circ_array) {
493
+ circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
494
+ }
495
+ break;
496
+ case HashCode:
497
+ h->obj = rb_hash_new();
498
+ if (0 != pi->circ_array) {
499
+ circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
500
+ }
501
+ break;
502
+ case RangeCode: h->obj = rb_ary_new_from_args(3, Qnil, Qnil, Qfalse); break;
503
+ case RawCode:
504
+ if (hasChildren) {
505
+ h->obj = ox_parse(pi->s, pi->end - pi->s, ox_gen_callbacks, &pi->s, pi->options, &pi->err);
506
+ if (0 != pi->circ_array) {
507
+ circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
508
+ }
509
+ } else {
510
+ h->obj = Qnil;
511
+ }
512
+ break;
513
+ case ExceptionCode:
514
+ if (Qundef == (h->obj = get_obj_from_attrs(attrs, pi, rb_eException))) {
515
+ return;
516
+ }
517
+ if (0 != pi->circ_array && Qnil != h->obj) {
518
+ circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
519
+ }
520
+ break;
521
+ case ObjectCode:
522
+ if (Qundef == (h->obj = get_obj_from_attrs(attrs, pi, ox_bag_clas))) {
523
+ return;
524
+ }
525
+ if (0 != pi->circ_array && Qnil != h->obj) {
526
+ circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
527
+ }
528
+ break;
529
+ case StructCode:
530
+ h->obj = get_struct_from_attrs(attrs);
531
+ if (0 != pi->circ_array) {
532
+ circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
533
+ }
534
+ break;
535
+ case ClassCode:
536
+ if (Qundef == (h->obj = get_class_from_attrs(attrs, pi, ox_bag_clas))) {
537
+ return;
538
+ }
539
+ break;
540
+ case RefCode:
541
+ h->obj = Qundef;
542
+ if (0 != pi->circ_array) {
543
+ h->obj = circ_array_get(pi->circ_array, get_id_from_attrs(pi, attrs));
544
+ }
545
+ if (Qundef == h->obj) {
546
+ set_error(&pi->err, "Invalid circular reference", pi->str, pi->s);
547
+ return;
548
+ }
549
+ break;
550
+ default:
551
+ set_error(&pi->err, "Invalid element name", pi->str, pi->s);
552
+ return;
553
+ break;
554
+ }
555
+ if (DEBUG <= pi->options->trace) {
556
+ debug_stack(pi, " -----------");
557
+ }
558
+ }
559
+
560
+ static void end_element(PInfo pi, const char *ename) {
561
+ if (TRACE <= pi->options->trace) {
562
+ char indent[128];
563
+
564
+ if (DEBUG <= pi->options->trace) {
565
+ char buf[1024];
566
+
567
+ printf("===== end element stack(%d) =====\n", helper_stack_depth(&pi->helpers));
568
+ snprintf(buf, sizeof(buf) - 1, "</%s>", ename);
569
+ debug_stack(pi, buf);
570
+ } else {
571
+ fill_indent(pi, indent, sizeof(indent));
572
+ printf("%s</%s>\n", indent, ename);
573
+ }
574
+ }
575
+ if (!helper_stack_empty(&pi->helpers)) {
576
+ Helper h = helper_stack_pop(&pi->helpers);
577
+ Helper ph = helper_stack_peek(&pi->helpers);
578
+
579
+ if (ox_empty_string == h->obj) {
580
+ // special catch for empty strings
581
+ h->obj = rb_str_new2("");
582
+ } else if (Qundef == h->obj) {
583
+ set_error(&pi->err, "Invalid element for object mode", pi->str, pi->s);
584
+ return;
585
+ } else if (RangeCode == h->type) { // Expect an array of 3 elements.
586
+ const VALUE *ap = RARRAY_PTR(h->obj);
587
+
588
+ h->obj = rb_range_new(*ap, *(ap + 1), Qtrue == *(ap + 2));
589
+ }
590
+ pi->obj = h->obj;
591
+ if (0 != ph) {
592
+ switch (ph->type) {
593
+ case ArrayCode: rb_ary_push(ph->obj, h->obj); break;
594
+ case ExceptionCode:
595
+ case ObjectCode:
596
+ if (Qnil != ph->obj) {
597
+ if (0 == h->var || NULL == rb_id2name(h->var)) {
598
+ set_error(&pi->err, "Invalid element for object mode", pi->str, pi->s);
599
+ return;
600
+ }
601
+ if (RUBY_T_OBJECT != rb_type(ph->obj)) {
602
+ set_error(&pi->err, "Corrupt object encoding", pi->str, pi->s);
603
+ return;
604
+ }
605
+ rb_ivar_set(ph->obj, h->var, h->obj);
606
+ }
607
+ break;
608
+ case StructCode:
609
+ if (0 == h->var) {
610
+ set_error(&pi->err, "Invalid element for object mode", pi->str, pi->s);
611
+ return;
612
+ }
613
+ rb_struct_aset(ph->obj, h->var, h->obj);
614
+ break;
615
+ case HashCode:
616
+ // put back h
617
+ helper_stack_push(&pi->helpers, h->var, h->obj, KeyCode);
618
+ break;
619
+ case RangeCode:
620
+ if (ox_beg_id == h->var) {
621
+ rb_ary_store(ph->obj, 0, h->obj);
622
+ } else if (ox_end_id == h->var) {
623
+ rb_ary_store(ph->obj, 1, h->obj);
624
+ } else if (ox_excl_id == h->var) {
625
+ rb_ary_store(ph->obj, 2, h->obj);
626
+ } else {
627
+ set_error(&pi->err, "Invalid range attribute", pi->str, pi->s);
628
+ return;
629
+ }
630
+ break;
631
+ case KeyCode: {
632
+ Helper gh;
633
+
634
+ helper_stack_pop(&pi->helpers);
635
+ if (NULL == (gh = helper_stack_peek(&pi->helpers)) || Qundef == ph->obj || Qundef == h->obj) {
636
+ set_error(&pi->err, "Corrupt parse stack, container is wrong type", pi->str, pi->s);
637
+ return;
638
+ }
639
+ rb_hash_aset(gh->obj, ph->obj, h->obj);
640
+ } break;
641
+ case ComplexCode:
642
+ if (Qundef == ph->obj) {
643
+ ph->obj = h->obj;
644
+ } else {
645
+ ph->obj = rb_complex_new(ph->obj, h->obj);
646
+ }
647
+ break;
648
+ case RationalCode: {
649
+ if (Qundef == h->obj || RUBY_T_FIXNUM != rb_type(h->obj)) {
650
+ set_error(&pi->err, "Invalid object format", pi->str, pi->s);
651
+ return;
652
+ }
653
+ if (Qundef == ph->obj) {
654
+ ph->obj = h->obj;
655
+ } else {
656
+ if (Qundef == ph->obj || RUBY_T_FIXNUM != rb_type(ph->obj)) {
657
+ set_error(&pi->err, "Corrupt parse stack, container is wrong type", pi->str, pi->s);
658
+ return;
659
+ }
660
+ #ifdef RUBINIUS_RUBY
661
+ ph->obj = rb_Rational(ph->obj, h->obj);
662
+ #else
663
+ ph->obj = rb_rational_new(ph->obj, h->obj);
664
+ #endif
665
+ }
666
+ break;
667
+ }
668
+ default:
669
+ set_error(&pi->err, "Corrupt parse stack, container is wrong type", pi->str, pi->s);
670
+ return;
671
+ break;
672
+ }
673
+ }
674
+ }
675
+ if (0 != pi->circ_array && helper_stack_empty(&pi->helpers)) {
676
+ circ_array_free(pi->circ_array);
677
+ pi->circ_array = 0;
678
+ }
679
+ if (DEBUG <= pi->options->trace) {
680
+ debug_stack(pi, " ----------");
681
+ }
682
+ }
683
+
684
+ static VALUE parse_double_time(const char *text, VALUE clas) {
685
+ long v = 0;
686
+ long v2 = 0;
687
+ const char *dot = 0;
688
+ char c;
689
+
690
+ for (; '.' != *text; text++) {
691
+ c = *text;
692
+ if (c < '0' || '9' < c) {
693
+ return Qnil;
694
+ }
695
+ v = 10 * v + (long)(c - '0');
696
+ }
697
+ dot = text++;
698
+ for (; '\0' != *text && text - dot <= 6; text++) {
699
+ c = *text;
700
+ if (c < '0' || '9' < c) {
701
+ return Qnil;
702
+ }
703
+ v2 = 10 * v2 + (long)(c - '0');
704
+ }
705
+ for (; text - dot <= 9; text++) {
706
+ v2 *= 10;
707
+ }
708
+ return rb_time_nano_new(v, v2);
709
+ }
710
+
711
+ typedef struct _tp {
712
+ int cnt;
713
+ char end;
714
+ char alt;
715
+ } *Tp;
716
+
717
+ static VALUE parse_xsd_time(const char *text, VALUE clas) {
718
+ long cargs[10];
719
+ long *cp = cargs;
720
+ long v;
721
+ int i;
722
+ char c;
723
+ struct _tp tpa[10] = {{4, '-', '-'},
724
+ {2, '-', '-'},
725
+ {2, 'T', 'T'},
726
+ {2, ':', ':'},
727
+ {2, ':', ':'},
728
+ {2, '.', '.'},
729
+ {9, '+', '-'},
730
+ {2, ':', ':'},
731
+ {2, '\0', '\0'},
732
+ {0, '\0', '\0'}};
733
+ Tp tp = tpa;
734
+ struct tm tm;
735
+
736
+ for (; 0 != tp->cnt; tp++) {
737
+ for (i = tp->cnt, v = 0; 0 < i; text++, i--) {
738
+ c = *text;
739
+ if (c < '0' || '9' < c) {
740
+ if (tp->end == c || tp->alt == c) {
741
+ break;
742
+ }
743
+ return Qnil;
744
+ }
745
+ v = 10 * v + (long)(c - '0');
746
+ }
747
+ c = *text++;
748
+ if (tp->end != c && tp->alt != c) {
749
+ return Qnil;
750
+ }
751
+ *cp++ = v;
752
+ }
753
+ tm.tm_year = (int)cargs[0] - 1900;
754
+ tm.tm_mon = (int)cargs[1] - 1;
755
+ tm.tm_mday = (int)cargs[2];
756
+ tm.tm_hour = (int)cargs[3];
757
+ tm.tm_min = (int)cargs[4];
758
+ tm.tm_sec = (int)cargs[5];
759
+ return rb_time_nano_new(mktime(&tm), cargs[6]);
760
+ }
761
+
762
+ // debug functions
763
+ static void fill_indent(PInfo pi, char *buf, size_t size) {
764
+ size_t cnt;
765
+
766
+ if (0 < (cnt = helper_stack_depth(&pi->helpers))) {
767
+ cnt *= 2;
768
+ if (size < cnt + 1) {
769
+ cnt = size - 1;
770
+ }
771
+ memset(buf, ' ', cnt);
772
+ buf += cnt;
773
+ }
774
+ *buf = '\0';
775
+ }
776
+
777
+ static void debug_stack(PInfo pi, const char *comment) {
778
+ char indent[128];
779
+ Helper h;
780
+
781
+ fill_indent(pi, indent, sizeof(indent));
782
+ printf("%s%s\n", indent, comment);
783
+ if (!helper_stack_empty(&pi->helpers)) {
784
+ for (h = pi->helpers.head; h < pi->helpers.tail; h++) {
785
+ const char *clas = "---";
786
+ const char *key = "---";
787
+
788
+ if (Qundef != h->obj) {
789
+ VALUE c = rb_obj_class(h->obj);
790
+
791
+ clas = rb_class2name(c);
792
+ }
793
+ if (0 != h->var) {
794
+ if (HashCode == h->type) {
795
+ VALUE v;
796
+
797
+ v = rb_String(h->var);
798
+ key = StringValuePtr(v);
799
+ } else if (ObjectCode == (h - 1)->type || ExceptionCode == (h - 1)->type ||
800
+ RangeCode == (h - 1)->type || StructCode == (h - 1)->type) {
801
+ key = rb_id2name(h->var);
802
+ } else {
803
+ printf("%s*** corrupt stack ***\n", indent);
804
+ }
805
+ }
806
+ printf("%s [%c] %s : %s\n", indent, h->type, clas, key);
807
+ }
808
+ }
809
+ }