ox 1.5.1 → 1.5.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ox might be problematic. Click here for more details.

data/README.md CHANGED
@@ -30,9 +30,11 @@ A fast XML parser and Object marshaller as a Ruby gem.
30
30
 
31
31
  ## <a name="release">Release Notes</a>
32
32
 
33
- ### Release 1.5.1
33
+ ### Release 1.5.2
34
34
 
35
- - Fixed XML dump character table. the '?' character was marked incorrectly.
35
+ - Added support for Date.
36
+
37
+ - Exception encoding and decoding support improved.
36
38
 
37
39
  ## <a name="description">Description</a>
38
40
 
@@ -46,9 +46,7 @@ static void slot_print(Cache cache, unsigned int depth);
46
46
 
47
47
  void
48
48
  ox_cache_new(Cache *cache) {
49
- if (0 == (*cache = (Cache)malloc(sizeof(struct _Cache)))) {
50
- rb_raise(rb_eNoMemError, "not enough memory\n");
51
- }
49
+ *cache = ALLOC(struct _Cache);
52
50
  (*cache)->key = 0;
53
51
  (*cache)->value = Qundef;
54
52
  bzero((*cache)->slots, sizeof((*cache)->slots));
@@ -87,7 +85,7 @@ ox_cache_get(Cache cache, const char *key, VALUE **slot) {
87
85
  cp2 = (*cp2)->slots + (*ck & 0x0F);
88
86
  ox_cache_new(cp2);
89
87
  if ('\0' == *(ck + 1)) {
90
- free(cache->key);
88
+ xfree(cache->key);
91
89
  } else {
92
90
  (*cp2)->key = cache->key;
93
91
  }
@@ -28,9 +28,7 @@ ox_cache8_new(Cache8 *cache) {
28
28
  Cache8 *cp;
29
29
  int i;
30
30
 
31
- if (0 == (*cache = (Cache8)malloc(sizeof(struct _Cache8)))) {
32
- rb_raise(rb_eNoMemError, "not enough memory\n");
33
- }
31
+ *cache = ALLOC(struct _Cache8);
34
32
  for (i = SLOT_CNT, cp = (*cache)->slots; 0 < i; i--, cp++) {
35
33
  *cp = 0;
36
34
  }
@@ -53,7 +51,7 @@ cache8_delete(Cache8 cache, int depth) {
53
51
  }
54
52
  }
55
53
  }
56
- free(cache);
54
+ xfree(cache);
57
55
  }
58
56
 
59
57
  slot_t
@@ -98,6 +98,7 @@ static void dump_value(Out out, const char *value, size_t size);
98
98
  static void dump_str_value(Out out, const char *value, size_t size);
99
99
  static int dump_var(ID key, VALUE value, Out out);
100
100
  static void dump_num(Out out, VALUE obj);
101
+ static void dump_date(Out out, VALUE obj);
101
102
  static void dump_time_thin(Out out, VALUE obj);
102
103
  static void dump_time_xsd(Out out, VALUE obj);
103
104
  static int dump_hash(VALUE key, VALUE value, Out out);
@@ -145,8 +146,10 @@ dump_hex(u_char c, Out out) {
145
146
  *out->cur++ = hex_chars[d];
146
147
  }
147
148
 
148
- inline static Type
149
+ static Type
149
150
  obj_class_code(VALUE obj) {
151
+ VALUE clas = rb_obj_class(obj);
152
+
150
153
  switch (rb_type(obj)) {
151
154
  case T_NIL: return NilClassCode;
152
155
  case T_ARRAY: return ArrayCode;
@@ -162,9 +165,9 @@ obj_class_code(VALUE obj) {
162
165
 
163
166
  return (is_xml_friendly((u_char*)sym, (int)strlen(sym))) ? SymbolCode : Symbol64Code;
164
167
  }
165
- case T_DATA: return (rb_cTime == rb_obj_class(obj)) ? TimeCode : 0;
166
- case T_STRUCT: return (rb_cRange == rb_obj_class(obj)) ? RangeCode : StructCode;
167
- case T_OBJECT: return (ox_document_clas == rb_obj_class(obj) || ox_element_clas == rb_obj_class(obj)) ? RawCode : ObjectCode;
168
+ case T_DATA: return (rb_cTime == clas) ? TimeCode : ((ox_date_class == clas) ? DateCode : 0);
169
+ case T_STRUCT: return (rb_cRange == clas) ? RangeCode : StructCode;
170
+ case T_OBJECT: return (ox_document_clas == clas || ox_element_clas == clas) ? RawCode : ObjectCode;
168
171
  case T_REGEXP: return RegexpCode;
169
172
  case T_BIGNUM: return BignumCode;
170
173
  #ifdef T_COMPLEX
@@ -256,17 +259,13 @@ static void
256
259
  grow(Out out, size_t len) {
257
260
  size_t size = out->end - out->buf;
258
261
  long pos = out->cur - out->buf;
259
- char *buf;
260
262
 
261
263
  size *= 2;
262
264
  if (size <= len * 2 + pos) {
263
265
  size += len;
264
266
  }
265
- if (0 == (buf = (char*)realloc(out->buf, size + 10))) { // 1 extra for terminator character plus extra (paranoid)
266
- rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]\n", ENOSPC, strerror(ENOSPC));
267
- }
268
- out->buf = buf;
269
- out->end = buf + size;
267
+ REALLOC_N(out->buf, char, size + 10); // 10 extra for terminator character plus extra (paranoid)
268
+ out->end = out->buf + size;
270
269
  out->cur = out->buf + pos;
271
270
  }
272
271
 
@@ -294,7 +293,7 @@ dump_start(Out out, Element e) {
294
293
  if (0 < e->attr.len) {
295
294
  fill_attr(out, 'a', e->attr.str, e->attr.len);
296
295
  }
297
- if ((ObjectCode == e->type || StructCode == e->type || ClassCode == e->type) && 0 < e->clas.len) {
296
+ if ((ObjectCode == e->type || ExceptionCode == e->type || StructCode == e->type || ClassCode == e->type) && 0 < e->clas.len) {
298
297
  fill_attr(out, 'c', e->clas.str, e->clas.len);
299
298
  }
300
299
  if (0 < e->id) {
@@ -454,6 +453,30 @@ dump_time_thin(Out out, VALUE obj) {
454
453
  out->cur += size;
455
454
  }
456
455
 
456
+ static void
457
+ dump_date(Out out, VALUE obj) {
458
+ char buf[64];
459
+ char *b = buf + sizeof(buf) - 1;
460
+ long jd = NUM2LONG(rb_funcall2(obj, ox_jd_id, 0, 0));
461
+ long size;
462
+
463
+ *b-- = '\0';
464
+ for (; 0 < jd; b--, jd /= 10) {
465
+ *b = '0' + (jd % 10);
466
+ }
467
+ b++;
468
+ if ('\0' == *b) {
469
+ b--;
470
+ *b = '0';
471
+ }
472
+ size = sizeof(buf) - (b - buf) - 1;
473
+ if (out->end - out->cur <= size) {
474
+ grow(out, size);
475
+ }
476
+ memcpy(out->cur, b, size);
477
+ out->cur += size;
478
+ }
479
+
457
480
  static void
458
481
  dump_time_xsd(Out out, VALUE obj) {
459
482
  struct tm *tm;
@@ -621,24 +644,15 @@ dump_obj(ID aid, VALUE obj, unsigned int depth, Out out) {
621
644
  e.indent = -1;
622
645
  out->w_end(out, &e);
623
646
  } else {
624
- char buf64[4096];
625
- char *b64 = buf64;
626
647
  ulong size = b64_size(cnt);
648
+ char *b64 = ALLOCA_N(char, size + 1);
627
649
 
628
650
  e.type = String64Code;
629
- if (sizeof(buf64) < size) {
630
- if (0 == (b64 = (char*)malloc(size + 1))) {
631
- rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]\n", ENOSPC, strerror(ENOSPC));
632
- }
633
- }
634
651
  to_base64((u_char*)str, cnt, b64);
635
652
  out->w_start(out, &e);
636
653
  dump_value(out, b64, size);
637
654
  e.indent = -1;
638
655
  out->w_end(out, &e);
639
- if (buf64 != b64) {
640
- free(b64);
641
- }
642
656
  }
643
657
  #else
644
658
  e.type = StringCode;
@@ -662,24 +676,15 @@ dump_obj(ID aid, VALUE obj, unsigned int depth, Out out) {
662
676
  e.indent = -1;
663
677
  out->w_end(out, &e);
664
678
  } else {
665
- char buf64[4096];
666
- char *b64 = buf64;
667
679
  ulong size = b64_size(cnt);
680
+ char *b64 = ALLOCA_N(char, size + 1);
668
681
 
669
682
  e.type = Symbol64Code;
670
- if (sizeof(buf64) < size) {
671
- if (0 == (b64 = (char*)malloc(size + 1))) {
672
- rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]\n", ENOSPC, strerror(ENOSPC));
673
- }
674
- }
675
683
  to_base64((u_char*)sym, cnt, b64);
676
684
  out->w_start(out, &e);
677
685
  dump_value(out, b64, size);
678
686
  e.indent = -1;
679
687
  out->w_end(out, &e);
680
- if (buf64 != b64) {
681
- free(b64);
682
- }
683
688
  }
684
689
  #else
685
690
  e.type = SymbolCode;
@@ -701,14 +706,24 @@ dump_obj(ID aid, VALUE obj, unsigned int depth, Out out) {
701
706
  out->w_time(out, obj);
702
707
  e.indent = -1;
703
708
  out->w_end(out, &e);
704
- } else {
705
- if (StrictEffort == out->opts->effort) {
706
- rb_raise(rb_eNotImpError, "Failed to dump T_DATA %s\n", rb_class2name(clas));
707
- } else {
708
- e.type = NilClassCode;
709
- e.closed = 1;
710
- out->w_start(out, &e);
711
- }
709
+ } else {
710
+ const char *classname = rb_class2name(clas);
711
+
712
+ if (0 == strcmp("Date", classname)) {
713
+ e.type = DateCode;
714
+ out->w_start(out, &e);
715
+ dump_date(out, obj);
716
+ e.indent = -1;
717
+ out->w_end(out, &e);
718
+ } else {
719
+ if (StrictEffort == out->opts->effort) {
720
+ rb_raise(rb_eNotImpError, "Failed to dump T_DATA %s\n", classname);
721
+ } else {
722
+ e.type = NilClassCode;
723
+ e.closed = 1;
724
+ out->w_start(out, &e);
725
+ }
726
+ }
712
727
  }
713
728
  break;
714
729
  }
@@ -779,7 +794,7 @@ dump_obj(ID aid, VALUE obj, unsigned int depth, Out out) {
779
794
  } else { // Object
780
795
  // use encoding as the indicator for Ruby 1.8.7 or 1.9.x
781
796
  #ifdef HAVE_RUBY_ENCODING_H
782
- e.type = ObjectCode;
797
+ e.type = (Qtrue == rb_obj_is_kind_of(obj, rb_eException)) ? ExceptionCode : ObjectCode;
783
798
  cnt = (int)rb_ivar_count(obj);
784
799
  e.closed = (0 >= cnt);
785
800
  out->w_start(out, &e);
@@ -797,7 +812,7 @@ dump_obj(ID aid, VALUE obj, unsigned int depth, Out out) {
797
812
  #else
798
813
  VALUE vars = rb_obj_instance_variables(obj);
799
814
  #endif
800
- e.type = ObjectCode;
815
+ e.type = (Qtrue == rb_obj_is_kind_of(obj, rb_eException)) ? ExceptionCode : ObjectCode;
801
816
  cnt = (int)RARRAY_LEN(vars);
802
817
  e.closed = (0 >= cnt);
803
818
  out->w_start(out, &e);
@@ -839,20 +854,11 @@ dump_obj(ID aid, VALUE obj, unsigned int depth, Out out) {
839
854
  //dump_value(out, "/", 1);
840
855
  dump_str_value(out, s, cnt);
841
856
  } else {
842
- char buf64[4096];
843
- char *b64 = buf64;
844
857
  ulong size = b64_size(cnt);
858
+ char *b64 = ALLOCA_N(char, size + 1);
845
859
 
846
- if (sizeof(buf64) < size) {
847
- if (0 == (b64 = (char*)malloc(size + 1))) {
848
- rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]\n", ENOSPC, strerror(ENOSPC));
849
- }
850
- }
851
860
  to_base64((u_char*)s, cnt, b64);
852
861
  dump_value(out, b64, size);
853
- if (buf64 != b64) {
854
- free(b64);
855
- }
856
862
  }
857
863
  #else
858
864
  dump_str_value(out, s, cnt);
@@ -1119,8 +1125,8 @@ dump_obj_to_xml(VALUE obj, Options copts, Out out) {
1119
1125
  VALUE clas = rb_obj_class(obj);
1120
1126
 
1121
1127
  out->w_time = (Yes == copts->xsd_date) ? dump_time_xsd : dump_time_thin;
1122
- out->buf = (char*)malloc(65336);
1123
- out->end = out->buf + 65325; // 1 less than end plus extra for possible errors
1128
+ out->buf = ALLOC_N(char, 65336);
1129
+ out->end = out->buf + 65325; // 10 less than end plus extra for possible errors
1124
1130
  out->cur = out->buf;
1125
1131
  out->circ_cache = 0;
1126
1132
  out->circ_cnt = 0;
@@ -1168,6 +1174,6 @@ ox_write_obj_to_file(VALUE obj, const char *path, Options copts) {
1168
1174
  int err = ferror(f);
1169
1175
  rb_raise(rb_eIOError, "Write failed. [%d:%s]\n", err, strerror(err));
1170
1176
  }
1171
- free(out.buf);
1177
+ xfree(out.buf);
1172
1178
  fclose(f);
1173
1179
  }
@@ -50,9 +50,9 @@ static VALUE parse_double_time(const char *text, VALUE clas);
50
50
  static VALUE parse_regexp(const char *text);
51
51
 
52
52
  static VALUE get_var_sym_from_attrs(Attr a, void *encoding);
53
- static VALUE get_obj_from_attrs(Attr a, PInfo pi);
54
- static VALUE get_class_from_attrs(Attr a, PInfo pi);
55
- static VALUE classname2class(const char *name, PInfo pi);
53
+ static VALUE get_obj_from_attrs(Attr a, PInfo pi, VALUE base_class);
54
+ static VALUE get_class_from_attrs(Attr a, PInfo pi, VALUE base_class);
55
+ static VALUE classname2class(const char *name, PInfo pi, VALUE base_class);
56
56
  static unsigned long get_id_from_attrs(PInfo pi, Attr a);
57
57
  static CircArray circ_array_new(void);
58
58
  static void circ_array_free(CircArray ca);
@@ -125,7 +125,7 @@ name2var(const char *name, void *encoding) {
125
125
  }
126
126
 
127
127
  inline static VALUE
128
- resolve_classname(VALUE mod, const char *class_name, Effort effort) {
128
+ resolve_classname(VALUE mod, const char *class_name, Effort effort, VALUE base_class) {
129
129
  VALUE clas;
130
130
  ID ci = rb_intern(class_name);
131
131
 
@@ -141,7 +141,7 @@ resolve_classname(VALUE mod, const char *class_name, Effort effort) {
141
141
  if (rb_const_defined_at(mod, ci)) {
142
142
  clas = rb_const_get_at(mod, ci);
143
143
  } else {
144
- clas = rb_define_class_under(mod, class_name, ox_bag_clas);
144
+ clas = rb_define_class_under(mod, class_name, base_class);
145
145
  }
146
146
  break;
147
147
  case StrictEffort:
@@ -154,8 +154,8 @@ resolve_classname(VALUE mod, const char *class_name, Effort effort) {
154
154
  }
155
155
 
156
156
  inline static VALUE
157
- classname2obj(const char *name, PInfo pi) {
158
- VALUE clas = classname2class(name, pi);
157
+ classname2obj(const char *name, PInfo pi, VALUE base_class) {
158
+ VALUE clas = classname2class(name, pi, base_class);
159
159
 
160
160
  if (Qundef == clas) {
161
161
  return Qnil;
@@ -189,6 +189,20 @@ structname2obj(const char *name) {
189
189
  }
190
190
  #endif
191
191
 
192
+ inline static VALUE
193
+ parse_ulong(const char *s, PInfo pi) {
194
+ unsigned long n = 0;
195
+
196
+ for (; '\0' != *s; s++) {
197
+ if ('0' <= *s && *s <= '9') {
198
+ n = n * 10 + (*s - '0');
199
+ } else {
200
+ raise_error("Invalid number for a julian day", pi->str, pi->s);
201
+ }
202
+ }
203
+ return ULONG2NUM(n);
204
+ }
205
+
192
206
  // 2010-07-09T10:47:45.895826162+09:00
193
207
  inline static VALUE
194
208
  parse_time(const char *text, VALUE clas) {
@@ -206,7 +220,7 @@ parse_time(const char *text, VALUE clas) {
206
220
  }
207
221
 
208
222
  static VALUE
209
- classname2class(const char *name, PInfo pi) {
223
+ classname2class(const char *name, PInfo pi, VALUE base_class) {
210
224
  VALUE *slot;
211
225
  VALUE clas;
212
226
 
@@ -223,7 +237,7 @@ classname2class(const char *name, PInfo pi) {
223
237
  if (':' != *n) {
224
238
  raise_error("Invalid classname, expected another ':'", pi->str, pi->s);
225
239
  }
226
- if (Qundef == (clas = resolve_classname(clas, class_name, pi->effort))) {
240
+ if (Qundef == (clas = resolve_classname(clas, class_name, pi->effort, base_class))) {
227
241
  return Qundef;
228
242
  }
229
243
  s = class_name;
@@ -232,7 +246,7 @@ classname2class(const char *name, PInfo pi) {
232
246
  }
233
247
  }
234
248
  *s = '\0';
235
- if (Qundef != (clas = resolve_classname(clas, class_name, pi->effort))) {
249
+ if (Qundef != (clas = resolve_classname(clas, class_name, pi->effort, base_class))) {
236
250
  *slot = clas;
237
251
  }
238
252
  }
@@ -250,10 +264,10 @@ get_var_sym_from_attrs(Attr a, void *encoding) {
250
264
  }
251
265
 
252
266
  static VALUE
253
- get_obj_from_attrs(Attr a, PInfo pi) {
267
+ get_obj_from_attrs(Attr a, PInfo pi, VALUE base_class) {
254
268
  for (; 0 != a->name; a++) {
255
269
  if ('c' == *a->name && '\0' == *(a->name + 1)) {
256
- return classname2obj(a->value, pi);
270
+ return classname2obj(a->value, pi, base_class);
257
271
  }
258
272
  }
259
273
  return Qundef;
@@ -272,10 +286,10 @@ get_struct_from_attrs(Attr a) {
272
286
  #endif
273
287
 
274
288
  static VALUE
275
- get_class_from_attrs(Attr a, PInfo pi) {
289
+ get_class_from_attrs(Attr a, PInfo pi, VALUE base_class) {
276
290
  for (; 0 != a->name; a++) {
277
291
  if ('c' == *a->name && '\0' == *(a->name + 1)) {
278
- return classname2class(a->value, pi);
292
+ return classname2class(a->value, pi, base_class);
279
293
  }
280
294
  }
281
295
  return Qundef;
@@ -307,9 +321,7 @@ static CircArray
307
321
  circ_array_new() {
308
322
  CircArray ca;
309
323
 
310
- if (0 == (ca = (CircArray)malloc(sizeof(struct _CircArray)))) {
311
- rb_raise(rb_eNoMemError, "not enough memory\n");
312
- }
324
+ ca = ALLOC(struct _CircArray);
313
325
  ca->objs = ca->obj_array;
314
326
  ca->size = sizeof(ca->obj_array) / sizeof(VALUE);
315
327
  ca->cnt = 0;
@@ -320,9 +332,9 @@ circ_array_new() {
320
332
  static void
321
333
  circ_array_free(CircArray ca) {
322
334
  if (ca->objs != ca->obj_array) {
323
- free(ca->objs);
335
+ xfree(ca->objs);
324
336
  }
325
- free(ca);
337
+ xfree(ca);
326
338
  }
327
339
 
328
340
  static void
@@ -334,14 +346,10 @@ circ_array_set(CircArray ca, VALUE obj, unsigned long id) {
334
346
  unsigned long cnt = id + 512;
335
347
 
336
348
  if (ca->objs == ca->obj_array) {
337
- if (0 == (ca->objs = (VALUE*)malloc(sizeof(VALUE) * cnt))) {
338
- rb_raise(rb_eNoMemError, "not enough memory\n");
339
- }
349
+ ca->objs = ALLOC_N(VALUE, cnt);
340
350
  memcpy(ca->objs, ca->obj_array, sizeof(VALUE) * ca->cnt);
341
- } else {
342
- if (0 == (ca->objs = (VALUE*)realloc(ca->objs, sizeof(VALUE) * cnt))) {
343
- rb_raise(rb_eNoMemError, "not enough memory\n");
344
- }
351
+ } else {
352
+ REALLOC_N(ca->objs, VALUE, cnt);
345
353
  }
346
354
  ca->size = cnt;
347
355
  }
@@ -461,21 +469,23 @@ add_text(PInfo pi, char *text, int closed) {
461
469
  pi->h->obj = sym;
462
470
  break;
463
471
  }
472
+ case DateCode:
473
+ {
474
+ VALUE args[1];
475
+
476
+ *args = parse_ulong(text, pi);
477
+ pi->h->obj = rb_funcall2(ox_date_class, ox_jd_id, 1, args);
478
+ break;
479
+ }
464
480
  case TimeCode:
465
481
  pi->h->obj = parse_time(text, ox_time_class);
466
482
  break;
467
483
  case String64Code:
468
484
  {
469
- char buf[1024];
470
- char *str = buf;
471
485
  unsigned long str_size = b64_orig_size(text);
472
486
  VALUE v;
487
+ char *str = ALLOCA_N(char, str_size + 1);
473
488
 
474
- if (sizeof(buf) <= str_size) {
475
- if (0 == (str = (char*)malloc(str_size + 1))) {
476
- rb_raise(rb_eNoMemError, "not enough memory\n");
477
- }
478
- }
479
489
  from_base64(text, (u_char*)str);
480
490
  v = rb_str_new(str, str_size);
481
491
  #ifdef HAVE_RUBY_ENCODING_H
@@ -487,53 +497,32 @@ add_text(PInfo pi, char *text, int closed) {
487
497
  circ_array_set(pi->circ_array, v, (unsigned long)pi->h->obj);
488
498
  }
489
499
  pi->h->obj = v;
490
- if (buf != str) {
491
- free(str);
492
- }
493
500
  break;
494
501
  }
495
502
  case Symbol64Code:
496
503
  {
497
504
  VALUE sym;
498
505
  VALUE *slot;
499
- char buf[1024];
500
- char *str = buf;
501
506
  unsigned long str_size = b64_orig_size(text);
507
+ char *str = ALLOCA_N(char, str_size + 1);
502
508
 
503
- if (sizeof(buf) <= str_size) {
504
- if (0 == (str = (char*)malloc(str_size + 1))) {
505
- rb_raise(rb_eNoMemError, "not enough memory\n");
506
- }
507
- }
508
509
  from_base64(text, (u_char*)str);
509
510
  if (Qundef == (sym = ox_cache_get(ox_symbol_cache, str, &slot))) {
510
511
  sym = str2sym(str, pi->encoding);
511
512
  *slot = sym;
512
513
  }
513
514
  pi->h->obj = sym;
514
- if (buf != str) {
515
- free(str);
516
- }
517
515
  break;
518
516
  }
519
517
  case RegexpCode:
520
518
  if ('/' == *text) {
521
519
  pi->h->obj = parse_regexp(text);
522
520
  } else {
523
- char buf[1024];
524
- char *str = buf;
525
521
  unsigned long str_size = b64_orig_size(text);
522
+ char *str = ALLOCA_N(char, str_size + 1);
526
523
 
527
- if (sizeof(buf) <= str_size) {
528
- if (0 == (str = (char*)malloc(str_size + 1))) {
529
- rb_raise(rb_eNoMemError, "not enough memory\n");
530
- }
531
- }
532
524
  from_base64(text, (u_char*)str);
533
525
  pi->h->obj = parse_regexp(str);
534
- if (sizeof(buf) <= str_size) {
535
- free(str);
536
- }
537
526
  }
538
527
  break;
539
528
  case BignumCode:
@@ -609,6 +598,7 @@ add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren) {
609
598
  case RegexpCode:
610
599
  case BignumCode:
611
600
  case ComplexCode:
601
+ case DateCode:
612
602
  case TimeCode:
613
603
  case RationalCode: // sub elements read next
614
604
  // value will be read in the following add_text
@@ -645,8 +635,14 @@ add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren) {
645
635
  h->obj = Qnil;
646
636
  }
647
637
  break;
638
+ case ExceptionCode:
639
+ h->obj = get_obj_from_attrs(attrs, pi, rb_eException);
640
+ if (0 != pi->circ_array && Qnil != h->obj) {
641
+ circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
642
+ }
643
+ break;
648
644
  case ObjectCode:
649
- h->obj = get_obj_from_attrs(attrs, pi);
645
+ h->obj = get_obj_from_attrs(attrs, pi, ox_bag_clas);
650
646
  if (0 != pi->circ_array && Qnil != h->obj) {
651
647
  circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
652
648
  }
@@ -662,7 +658,7 @@ add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren) {
662
658
  #endif
663
659
  break;
664
660
  case ClassCode:
665
- h->obj = get_class_from_attrs(attrs, pi);
661
+ h->obj = get_class_from_attrs(attrs, pi, ox_bag_clas);
666
662
  break;
667
663
  case RefCode:
668
664
  h->obj = Qundef;
@@ -711,6 +707,7 @@ end_element(PInfo pi, const char *ename) {
711
707
  case ArrayCode:
712
708
  rb_ary_push(pi->h->obj, h->obj);
713
709
  break;
710
+ case ExceptionCode:
714
711
  case ObjectCode:
715
712
  if (Qnil != pi->h->obj) {
716
713
  rb_ivar_set(pi->h->obj, h->var, h->obj);
@@ -910,7 +907,7 @@ debug_stack(PInfo pi, const char *comment) {
910
907
 
911
908
  v = rb_funcall2(h->var, rb_intern("to_s"), 0, 0);
912
909
  key = StringValuePtr(v);
913
- } else if (ObjectCode == (h - 1)->type || RangeCode == (h - 1)->type || StructCode == (h - 1)->type) {
910
+ } else if (ObjectCode == (h - 1)->type || ExceptionCode == (h - 1)->type || RangeCode == (h - 1)->type || StructCode == (h - 1)->type) {
914
911
  key = rb_id2name(h->var);
915
912
  } else {
916
913
  printf("%s*** corrupt stack ***\n", indent);
@@ -60,6 +60,7 @@ ID ox_excl_id;
60
60
  ID ox_fileno_id;
61
61
  ID ox_inspect_id;
62
62
  ID ox_instruct_id;
63
+ ID ox_jd_id;
63
64
  ID ox_keys_id;
64
65
  ID ox_local_id;
65
66
  ID ox_mesg_id;
@@ -91,6 +92,7 @@ VALUE ox_element_clas;
91
92
  VALUE ox_bag_clas;
92
93
  VALUE ox_struct_class;
93
94
  VALUE ox_time_class;
95
+ VALUE ox_date_class;
94
96
 
95
97
  Cache ox_symbol_cache = 0;
96
98
  Cache ox_class_cache = 0;
@@ -285,15 +287,16 @@ set_def_opts(VALUE self, VALUE opts) {
285
287
  */
286
288
  static VALUE
287
289
  to_obj(VALUE self, VALUE ruby_xml) {
288
- VALUE obj;
289
290
  char *xml;
291
+ size_t len;
290
292
 
291
293
  Check_Type(ruby_xml, T_STRING);
292
294
  // the xml string gets modified so make a copy of it
293
- xml = strdup(StringValuePtr(ruby_xml));
294
- obj = ox_parse(xml, ox_obj_callbacks, 0, 0, StrictEffort);
295
- free(xml);
296
- return obj;
295
+ len = RSTRING_LEN(ruby_xml) + 1;
296
+ xml = ALLOCA_N(char, len);
297
+ strcpy(xml, StringValuePtr(ruby_xml));
298
+
299
+ return ox_parse(xml, ox_obj_callbacks, 0, 0, StrictEffort);
297
300
  }
298
301
 
299
302
  /* call-seq: parse(xml) => Ox::Document or Ox::Element
@@ -305,15 +308,16 @@ to_obj(VALUE self, VALUE ruby_xml) {
305
308
  */
306
309
  static VALUE
307
310
  to_gen(VALUE self, VALUE ruby_xml) {
308
- VALUE obj;
309
311
  char *xml;
312
+ size_t len;
310
313
 
311
314
  Check_Type(ruby_xml, T_STRING);
312
315
  // the xml string gets modified so make a copy of it
313
- xml = strdup(StringValuePtr(ruby_xml));
314
- obj = ox_parse(xml, ox_gen_callbacks, 0, 0, StrictEffort);
315
- free(xml);
316
- return obj;
316
+ len = RSTRING_LEN(ruby_xml) + 1;
317
+ xml = ALLOCA_N(char, len);
318
+ strcpy(xml, StringValuePtr(ruby_xml));
319
+
320
+ return ox_parse(xml, ox_gen_callbacks, 0, 0, StrictEffort);
317
321
  }
318
322
 
319
323
  static VALUE
@@ -371,8 +375,6 @@ load(char *xml, int argc, VALUE *argv, VALUE self) {
371
375
  obj = ox_parse(xml, ox_gen_callbacks, 0, options.trace, options.effort);
372
376
  break;
373
377
  }
374
- free(xml);
375
-
376
378
  return obj;
377
379
  }
378
380
 
@@ -396,10 +398,13 @@ load(char *xml, int argc, VALUE *argv, VALUE self) {
396
398
  static VALUE
397
399
  load_str(int argc, VALUE *argv, VALUE self) {
398
400
  char *xml;
401
+ size_t len;
399
402
 
400
403
  Check_Type(*argv, T_STRING);
401
404
  // the xml string gets modified so make a copy of it
402
- xml = strdup(StringValuePtr(*argv));
405
+ len = RSTRING_LEN(*argv) + 1;
406
+ xml = ALLOCA_N(char, len);
407
+ strcpy(xml, StringValuePtr(*argv));
403
408
 
404
409
  return load(xml, argc - 1, argv + 1, self);
405
410
  }
@@ -435,10 +440,7 @@ load_file(int argc, VALUE *argv, VALUE self) {
435
440
  }
436
441
  fseek(f, 0, SEEK_END);
437
442
  len = ftell(f);
438
- if (0 == (xml = malloc(len + 1))) {
439
- fclose(f);
440
- rb_raise(rb_eNoMemError, "Could not allocate memory for %ld byte file.\n", len);
441
- }
443
+ xml = ALLOCA_N(char, len + 1);
442
444
  fseek(f, 0, SEEK_SET);
443
445
  if (len != fread(xml, 1, len, f)) {
444
446
  fclose(f);
@@ -569,7 +571,7 @@ dump(int argc, VALUE *argv, VALUE self) {
569
571
  rb_enc_associate(rstr, rb_enc_find(copts.encoding));
570
572
  }
571
573
  #endif
572
- free(xml);
574
+ xfree(xml);
573
575
 
574
576
  return rstr;
575
577
  }
@@ -653,6 +655,7 @@ void Init_ox() {
653
655
  ox_fileno_id = rb_intern("fileno");
654
656
  ox_inspect_id = rb_intern("inspect");
655
657
  ox_instruct_id = rb_intern("instruct");
658
+ ox_jd_id = rb_intern("jd");
656
659
  ox_keys_id = rb_intern("keys");
657
660
  ox_local_id = rb_intern("local");
658
661
  ox_mesg_id = rb_intern("mesg");
@@ -672,6 +675,7 @@ void Init_ox() {
672
675
  ox_value_id = rb_intern("@value");
673
676
 
674
677
  ox_time_class = rb_const_get(rb_cObject, rb_intern("Time"));
678
+ ox_date_class = rb_const_get(rb_cObject, rb_intern("Date"));
675
679
  ox_struct_class = rb_const_get(rb_cObject, rb_intern("Struct"));
676
680
 
677
681
  ox_encoding_sym = ID2SYM(rb_intern("encoding")); rb_ary_push(keep, ox_encoding_sym);
@@ -121,6 +121,8 @@ typedef enum {
121
121
  String64Code = 'b', // base64 encoded String
122
122
  ClassCode = 'c',
123
123
  Symbol64Code = 'd', // base64 encoded Symbol
124
+ DateCode = 'D',
125
+ ExceptionCode = 'e',
124
126
  FloatCode = 'f',
125
127
  RegexpCode = 'g',
126
128
  HashCode = 'h',
@@ -231,6 +233,7 @@ extern ID ox_excl_id;
231
233
  extern ID ox_fileno_id;
232
234
  extern ID ox_inspect_id;
233
235
  extern ID ox_instruct_id;
236
+ extern ID ox_jd_id;
234
237
  extern ID ox_keys_id;
235
238
  extern ID ox_local_id;
236
239
  extern ID ox_mesg_id;
@@ -249,6 +252,7 @@ extern ID ox_tv_sec_id;
249
252
  extern ID ox_tv_usec_id;
250
253
  extern ID ox_value_id;
251
254
 
255
+ extern VALUE ox_date_class;
252
256
  extern VALUE ox_empty_string;
253
257
  extern VALUE ox_encoding_sym;
254
258
  extern VALUE ox_struct_class;
@@ -469,18 +469,14 @@ read_text(PInfo pi) {
469
469
 
470
470
  if (0 == alloc_buf) {
471
471
  size = sizeof(buf) * 2;
472
- if (0 == (alloc_buf = (char*)malloc(size))) {
473
- raise_error("text too long", pi->str, pi->s);
474
- }
472
+ alloc_buf = ALLOC_N(char, size);
475
473
  memcpy(alloc_buf, buf, b - buf);
476
474
  b = alloc_buf + (b - buf);
477
475
  } else {
478
476
  unsigned long pos = b - alloc_buf;
479
477
 
480
478
  size = (end - alloc_buf) * 2;
481
- if (0 == (alloc_buf = (char*)realloc(alloc_buf, size))) {
482
- raise_error("text too long", pi->str, pi->s);
483
- }
479
+ REALLOC_N(alloc_buf, char, size);
484
480
  b = alloc_buf + pos;
485
481
  }
486
482
  end = alloc_buf + size - 2;
@@ -492,7 +488,7 @@ read_text(PInfo pi) {
492
488
  *b = '\0';
493
489
  if (0 != alloc_buf) {
494
490
  pi->pcb->add_text(pi, alloc_buf, ('/' == *(pi->s + 1)));
495
- free(alloc_buf);
491
+ xfree(alloc_buf);
496
492
  } else {
497
493
  pi->pcb->add_text(pi, buf, ('/' == *(pi->s + 1)));
498
494
  }
@@ -534,18 +530,14 @@ read_reduced_text(PInfo pi) {
534
530
 
535
531
  if (0 == alloc_buf) {
536
532
  size = sizeof(buf) * 2;
537
- if (0 == (alloc_buf = (char*)malloc(size))) {
538
- raise_error("text too long", pi->str, pi->s);
539
- }
533
+ alloc_buf = ALLOC_N(char, size);
540
534
  memcpy(alloc_buf, buf, b - buf);
541
535
  b = alloc_buf + (b - buf);
542
536
  } else {
543
537
  unsigned long pos = b - alloc_buf;
544
538
 
545
539
  size = (end - alloc_buf) * 2;
546
- if (0 == (alloc_buf = (char*)realloc(alloc_buf, size))) {
547
- raise_error("text too long", pi->str, pi->s);
548
- }
540
+ REALLOC(alloc_buf, char, size);
549
541
  b = alloc_buf + pos;
550
542
  }
551
543
  end = alloc_buf + size - 2;
@@ -561,7 +553,7 @@ read_reduced_text(PInfo pi) {
561
553
  *b = '\0';
562
554
  if (0 != alloc_buf) {
563
555
  pi->pcb->add_text(pi, alloc_buf, ('/' == *(pi->s + 1)));
564
- free(alloc_buf);
556
+ xfree(alloc_buf);
565
557
  } else {
566
558
  pi->pcb->add_text(pi, buf, ('/' == *(pi->s + 1)));
567
559
  }
@@ -270,7 +270,7 @@ sax_drive_init(SaxDrive dr, VALUE handler, VALUE io, int convert) {
270
270
  static void
271
271
  sax_drive_cleanup(SaxDrive dr) {
272
272
  if (dr->base_buf != dr->buf) {
273
- free(dr->buf);
273
+ xfree(dr->buf);
274
274
  }
275
275
  }
276
276
 
@@ -291,14 +291,10 @@ sax_drive_read(SaxDrive dr) {
291
291
  size_t size = dr->buf_end - dr->buf;
292
292
 
293
293
  if (dr->buf == dr->base_buf) {
294
- if (0 == (dr->buf = (char*)malloc(size * 2))) {
295
- rb_raise(rb_eNoMemError, "Could not allocate memory for large element.\n");
296
- }
294
+ dr->buf = ALLOC_N(char, size * 2);
297
295
  memcpy(dr->buf, old, size);
298
296
  } else {
299
- if (0 == (dr->buf = (char*)realloc(dr->buf, size * 2))) {
300
- rb_raise(rb_eNoMemError, "Could not allocate memory for large element.\n");
301
- }
297
+ REALLOC_N(dr->buf, char, size * 2);
302
298
  }
303
299
  dr->buf_end = dr->buf + size * 2;
304
300
  dr->cur = dr->buf + (dr->cur - old);
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Ox
3
3
  # Current version of the module.
4
- VERSION = '1.5.1'
4
+ VERSION = '1.5.2'
5
5
  end
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby -wW1
2
+
3
+ $: << '../lib'
4
+ $: << '../ext'
5
+
6
+ require 'ox'
7
+
8
+ def name_it()
9
+ begin
10
+ "x".foo
11
+ rescue Exception => e
12
+ #puts e.message
13
+ xml = Ox.dump(e, effort: :tolerant)
14
+ puts xml
15
+ o = Ox.load(xml, mode: :object)
16
+ puts o.message
17
+ puts Ox.dump(e)
18
+ end
19
+ end
20
+
21
+ name_it()
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env ruby -wW1
2
+ # encoding: UTF-8
3
+
4
+ $: << File.join(File.dirname(__FILE__), "../lib")
5
+ $: << File.join(File.dirname(__FILE__), "../ext")
6
+
7
+ require 'stringio'
8
+ require 'ox'
9
+
10
+ x1 = %(<?xml version="1.0" encoding="ISO-8859-1" ?><tag key="value">Français</tag>).encode("ISO-8859-1")
11
+ # => "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?><tag key=\"value\">Fran\xE7ais</tag>"
12
+ x1.encoding
13
+ # => #<Encoding:ISO-8859-1>
14
+
15
+ x2 = %(<?xml version="1.0" encoding="UTF-8" ?><tag key="value">Français</tag>)
16
+ # => "<?xml version=\"1.0\" encoding=\"UTF-8\" ?><tag key=\"value\">Fran\xC3\xA7ais</tag>"
17
+ x2.encoding
18
+ # => #<Encoding:UTF-8>
19
+
20
+ class OH < ::Ox::Sax
21
+ def start_element(name)
22
+ puts "EL: #{name} (#{name.encoding})"
23
+ end
24
+
25
+ def end_element(name)
26
+ end
27
+
28
+ def attr(key, value)
29
+ puts "AT: #{key} => #{value} (#{key.encoding} => #{value.encoding})"
30
+ end
31
+
32
+ def text(value)
33
+ puts "TX: #{value} (#{value.encoding})"
34
+ end
35
+ end
36
+
37
+ ::Ox.sax_parse OH.new, StringIO.new(x1)
38
+ # => AT: version => 1.0 (US-ASCII => ASCII-8BIT)
39
+ # AT: encoding => ISO-8859-1 (US-ASCII => ISO-8859-1)
40
+ # EL: tag (US-ASCII)
41
+ # AT: key => value (US-ASCII => ISO-8859-1)
42
+ # TX: Fran�ais (ISO-8859-1)
43
+
44
+ puts
45
+
46
+ ::Ox.sax_parse OH.new, StringIO.new(x2)
47
+ # => AT: version => 1.0 (US-ASCII => ASCII-8BIT)
48
+ # AT: encoding => UTF-8 (US-ASCII => UTF-8)
49
+ # EL: tag (US-ASCII)
50
+ # AT: key => value (US-ASCII => UTF-8)
51
+ # TX: Français (UTF-8)
52
+
53
+ puts
54
+ x3 = %(<?xml version="1.0" encoding="ISO-8859-1" ?><tag Português="Español">Français</tag>).encode("ISO-8859-1")
55
+ ::Ox.sax_parse OH.new, StringIO.new(x3)
56
+
57
+ puts
58
+ x4 = %(<?xml version="1.0" encoding="UTF-8" ?><tag Português="Español">Français</tag>)
59
+ ::Ox.sax_parse OH.new, StringIO.new(x4)
60
+
@@ -6,6 +6,7 @@ $: << File.join(File.dirname(__FILE__), "../ext")
6
6
 
7
7
  require 'test/unit'
8
8
  require 'optparse'
9
+ require 'date'
9
10
  require 'ox'
10
11
 
11
12
  $indent = 2
@@ -107,6 +108,10 @@ class Func < ::Test::Unit::TestCase
107
108
  dump_and_load(Time.now, false)
108
109
  end
109
110
 
111
+ def test_date
112
+ dump_and_load(Date.new(2011, 1, 5), false)
113
+ end
114
+
110
115
  def test_array
111
116
  dump_and_load([], false)
112
117
  dump_and_load([1, 'a'], false)
@@ -262,10 +267,30 @@ class Func < ::Test::Unit::TestCase
262
267
  e = StandardError.new("Some Error")
263
268
  e.set_backtrace(["./func.rb:119: in test_exception",
264
269
  "./fake.rb:57: in fake_func"])
270
+ dump_and_load(e, false)
271
+ end
272
+ end
273
+
274
+ def test_exception_bag
275
+ if RUBY_VERSION.start_with?('1.8')
276
+ assert(true)
277
+ else
278
+ xml = %{
279
+ <e c="FakeError">
280
+ <s a="mesg">Some Error</s>
281
+ <a a="bt">
282
+ <s>./func.rb:119: in test_exception</s>
283
+ <s>./fake.rb:57: in fake_func</s>
284
+ </a>
285
+ </e>
286
+ }
287
+ x = Ox.load(xml, :mode => :object, :effort => :auto_define)
288
+ assert_equal('Some Error', x.message())
289
+ assert(x.is_a?(Exception))
265
290
  end
266
- dump_and_load(e, false)
267
291
  end
268
292
 
293
+
269
294
  def test_struct
270
295
  s = Struct.new('Box', :x, :y, :w, :h)
271
296
  dump_and_load(s.new(2, 4, 10, 20), false)
@@ -45,7 +45,7 @@ class Perf
45
45
  end
46
46
  end
47
47
  puts
48
- puts "Comparison Matrix\n(performance factor, 2.0 row is means twice as fast as column)"
48
+ puts "Comparison Matrix\n(performance factor, 2.0 means row is twice as fast as column)"
49
49
  puts ([' ' * width] + iva.map { |i| "%*s" % [width, i.title] }).join(' ')
50
50
  puts (['-' * width] + iva.map { |i| '-' * width }).join(' ')
51
51
  iva.each do |i|
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby -wW1
2
+
3
+ $: << '../lib'
4
+ $: << '../ext'
5
+
6
+ require 'stringio'
7
+ require 'ox'
8
+
9
+ class Sample < ::Ox::Sax
10
+ def start_element(name); puts "start: #{name}"; end
11
+ def end_element(name); puts "end: #{name}"; end
12
+ def attr(name, value); puts " #{name} => #{value}"; end
13
+ def text(value); puts "text #{value}"; end
14
+ end
15
+
16
+ io = StringIO.new(%{
17
+ <top name="sample">
18
+ <middle name="second">
19
+ <bottom name="third"/>
20
+ </middle>
21
+ </top>
22
+ })
23
+
24
+ handler = Sample.new()
25
+ Ox.sax_parse(handler, io)
26
+
27
+ # outputs
28
+ # start: top
29
+ # name => sample
30
+ # start: middle
31
+ # name => second
32
+ # start: bottom
33
+ # name => third
34
+ # end: bottom
35
+ # end: middle
36
+ # end: top
37
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ox
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1
4
+ version: 1.5.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-07 00:00:00.000000000 Z
12
+ date: 2012-03-15 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ! "A fast XML parser and object serializer that uses only standard C
15
15
  lib.\n \nOptimized XML (Ox), as the name implies was written to provide
@@ -53,6 +53,8 @@ files:
53
53
  - test/bench.rb
54
54
  - test/bug1.rb
55
55
  - test/bug2.rb
56
+ - test/bug3.rb
57
+ - test/bug4.rb
56
58
  - test/cache16_test.rb
57
59
  - test/cache8_test.rb
58
60
  - test/cache_test.rb
@@ -93,6 +95,7 @@ files:
93
95
  - test/sample/shape.rb
94
96
  - test/sample/text.rb
95
97
  - test/sample.rb
98
+ - test/sax_example.rb
96
99
  - test/sax_test.rb
97
100
  - test/test.rb
98
101
  - test/Sample.graffle
@@ -126,4 +129,3 @@ signing_key:
126
129
  specification_version: 3
127
130
  summary: A fast XML parser and object serializer.
128
131
  test_files: []
129
- has_rdoc: true