ext/ox/dump.c in ox-1.5.1 vs ext/ox/dump.c in ox-1.5.2

- old
+ new

@@ -96,10 +96,11 @@ static void dump_value(Out out, const char *value, size_t size); static void dump_str_value(Out out, const char *value, size_t size); static int dump_var(ID key, VALUE value, Out out); static void dump_num(Out out, VALUE obj); +static void dump_date(Out out, VALUE obj); static void dump_time_thin(Out out, VALUE obj); static void dump_time_xsd(Out out, VALUE obj); static int dump_hash(VALUE key, VALUE value, Out out); static int is_xml_friendly(const u_char *str, int len); @@ -143,12 +144,14 @@ *out->cur++ = hex_chars[d]; d = c & 0x0F; *out->cur++ = hex_chars[d]; } -inline static Type +static Type obj_class_code(VALUE obj) { + VALUE clas = rb_obj_class(obj); + switch (rb_type(obj)) { case T_NIL: return NilClassCode; case T_ARRAY: return ArrayCode; case T_HASH: return HashCode; case T_TRUE: return TrueClassCode; @@ -160,13 +163,13 @@ { const char *sym = rb_id2name(SYM2ID(obj)); return (is_xml_friendly((u_char*)sym, (int)strlen(sym))) ? SymbolCode : Symbol64Code; } - case T_DATA: return (rb_cTime == rb_obj_class(obj)) ? TimeCode : 0; - case T_STRUCT: return (rb_cRange == rb_obj_class(obj)) ? RangeCode : StructCode; - case T_OBJECT: return (ox_document_clas == rb_obj_class(obj) || ox_element_clas == rb_obj_class(obj)) ? RawCode : ObjectCode; + case T_DATA: return (rb_cTime == clas) ? TimeCode : ((ox_date_class == clas) ? DateCode : 0); + case T_STRUCT: return (rb_cRange == clas) ? RangeCode : StructCode; + case T_OBJECT: return (ox_document_clas == clas || ox_element_clas == clas) ? RawCode : ObjectCode; case T_REGEXP: return RegexpCode; case T_BIGNUM: return BignumCode; #ifdef T_COMPLEX case T_COMPLEX: return ComplexCode; #endif @@ -254,21 +257,17 @@ static void grow(Out out, size_t len) { size_t size = out->end - out->buf; long pos = out->cur - out->buf; - char *buf; size *= 2; if (size <= len * 2 + pos) { size += len; } - if (0 == (buf = (char*)realloc(out->buf, size + 10))) { // 1 extra for terminator character plus extra (paranoid) - rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]\n", ENOSPC, strerror(ENOSPC)); - } - out->buf = buf; - out->end = buf + size; + REALLOC_N(out->buf, char, size + 10); // 10 extra for terminator character plus extra (paranoid) + out->end = out->buf + size; out->cur = out->buf + pos; } static void dump_start(Out out, Element e) { @@ -292,11 +291,11 @@ *out->cur++ = '<'; *out->cur++ = e->type; if (0 < e->attr.len) { fill_attr(out, 'a', e->attr.str, e->attr.len); } - if ((ObjectCode == e->type || StructCode == e->type || ClassCode == e->type) && 0 < e->clas.len) { + if ((ObjectCode == e->type || ExceptionCode == e->type || StructCode == e->type || ClassCode == e->type) && 0 < e->clas.len) { fill_attr(out, 'c', e->clas.str, e->clas.len); } if (0 < e->id) { char buf[32]; char *end = buf + sizeof(buf); @@ -453,10 +452,34 @@ memcpy(out->cur, b, size); out->cur += size; } static void +dump_date(Out out, VALUE obj) { + char buf[64]; + char *b = buf + sizeof(buf) - 1; + long jd = NUM2LONG(rb_funcall2(obj, ox_jd_id, 0, 0)); + long size; + + *b-- = '\0'; + for (; 0 < jd; b--, jd /= 10) { + *b = '0' + (jd % 10); + } + b++; + if ('\0' == *b) { + b--; + *b = '0'; + } + size = sizeof(buf) - (b - buf) - 1; + if (out->end - out->cur <= size) { + grow(out, size); + } + memcpy(out->cur, b, size); + out->cur += size; +} + +static void dump_time_xsd(Out out, VALUE obj) { struct tm *tm; time_t sec = NUM2LONG(rb_funcall2(obj, ox_tv_sec_id, 0, 0)); long usec = NUM2LONG(rb_funcall2(obj, ox_tv_usec_id, 0, 0)); int tzhour, tzmin; @@ -619,28 +642,19 @@ out->w_start(out, &e); dump_str_value(out, str, cnt); e.indent = -1; out->w_end(out, &e); } else { - char buf64[4096]; - char *b64 = buf64; ulong size = b64_size(cnt); + char *b64 = ALLOCA_N(char, size + 1); e.type = String64Code; - if (sizeof(buf64) < size) { - if (0 == (b64 = (char*)malloc(size + 1))) { - rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]\n", ENOSPC, strerror(ENOSPC)); - } - } to_base64((u_char*)str, cnt, b64); out->w_start(out, &e); dump_value(out, b64, size); e.indent = -1; out->w_end(out, &e); - if (buf64 != b64) { - free(b64); - } } #else e.type = StringCode; out->w_start(out, &e); dump_str_value(out, str, cnt); @@ -660,28 +674,19 @@ out->w_start(out, &e); dump_str_value(out, sym, cnt); e.indent = -1; out->w_end(out, &e); } else { - char buf64[4096]; - char *b64 = buf64; ulong size = b64_size(cnt); + char *b64 = ALLOCA_N(char, size + 1); e.type = Symbol64Code; - if (sizeof(buf64) < size) { - if (0 == (b64 = (char*)malloc(size + 1))) { - rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]\n", ENOSPC, strerror(ENOSPC)); - } - } to_base64((u_char*)sym, cnt, b64); out->w_start(out, &e); dump_value(out, b64, size); e.indent = -1; out->w_end(out, &e); - if (buf64 != b64) { - free(b64); - } } #else e.type = SymbolCode; out->w_start(out, &e); dump_str_value(out, sym, cnt); @@ -699,18 +704,28 @@ e.type = TimeCode; out->w_start(out, &e); out->w_time(out, obj); e.indent = -1; out->w_end(out, &e); - } else { - if (StrictEffort == out->opts->effort) { - rb_raise(rb_eNotImpError, "Failed to dump T_DATA %s\n", rb_class2name(clas)); - } else { - e.type = NilClassCode; - e.closed = 1; - out->w_start(out, &e); - } + } else { + const char *classname = rb_class2name(clas); + + if (0 == strcmp("Date", classname)) { + e.type = DateCode; + out->w_start(out, &e); + dump_date(out, obj); + e.indent = -1; + out->w_end(out, &e); + } else { + if (StrictEffort == out->opts->effort) { + rb_raise(rb_eNotImpError, "Failed to dump T_DATA %s\n", classname); + } else { + e.type = NilClassCode; + e.closed = 1; + out->w_start(out, &e); + } + } } break; } case T_STRUCT: { @@ -777,11 +792,11 @@ dump_gen_element(obj, depth + 1, out); out->w_end(out, &e); } else { // Object // use encoding as the indicator for Ruby 1.8.7 or 1.9.x #ifdef HAVE_RUBY_ENCODING_H - e.type = ObjectCode; + e.type = (Qtrue == rb_obj_is_kind_of(obj, rb_eException)) ? ExceptionCode : ObjectCode; cnt = (int)rb_ivar_count(obj); e.closed = (0 >= cnt); out->w_start(out, &e); if (0 < cnt) { unsigned int od = out->depth; @@ -795,11 +810,11 @@ #if (defined JRUBY || defined RUBINIUS) VALUE vars = rb_funcall2(obj, rb_intern("instance_variables"), 0, 0); #else VALUE vars = rb_obj_instance_variables(obj); #endif - e.type = ObjectCode; + e.type = (Qtrue == rb_obj_is_kind_of(obj, rb_eException)) ? ExceptionCode : ObjectCode; cnt = (int)RARRAY_LEN(vars); e.closed = (0 >= cnt); out->w_start(out, &e); if (0 < cnt) { VALUE *np = RARRAY_PTR(vars); @@ -837,24 +852,15 @@ #if USE_B64 if (is_xml_friendly((u_char*)s, cnt)) { //dump_value(out, "/", 1); dump_str_value(out, s, cnt); } else { - char buf64[4096]; - char *b64 = buf64; ulong size = b64_size(cnt); + char *b64 = ALLOCA_N(char, size + 1); - if (sizeof(buf64) < size) { - if (0 == (b64 = (char*)malloc(size + 1))) { - rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]\n", ENOSPC, strerror(ENOSPC)); - } - } to_base64((u_char*)s, cnt, b64); dump_value(out, b64, size); - if (buf64 != b64) { - free(b64); - } } #else dump_str_value(out, s, cnt); #endif #if 0 @@ -1117,12 +1123,12 @@ static void dump_obj_to_xml(VALUE obj, Options copts, Out out) { VALUE clas = rb_obj_class(obj); out->w_time = (Yes == copts->xsd_date) ? dump_time_xsd : dump_time_thin; - out->buf = (char*)malloc(65336); - out->end = out->buf + 65325; // 1 less than end plus extra for possible errors + out->buf = ALLOC_N(char, 65336); + out->end = out->buf + 65325; // 10 less than end plus extra for possible errors out->cur = out->buf; out->circ_cache = 0; out->circ_cnt = 0; out->opts = copts; out->obj = obj; @@ -1166,8 +1172,8 @@ } if (size != fwrite(out.buf, 1, size, f)) { int err = ferror(f); rb_raise(rb_eIOError, "Write failed. [%d:%s]\n", err, strerror(err)); } - free(out.buf); + xfree(out.buf); fclose(f); }