From 668c09ae8352784883260ebae05eae7923ce3498 Mon Sep 17 00:00:00 2001 From: Peter Ohler Date: Thu, 8 Apr 2021 19:02:14 -0400 Subject: [PATCH] Revert "Make compaction available for `Oj::Doc` (#650)" This reverts commit 33c6dd346e70cb8e8c8fa63ba1a43fe2c24f3226. --- .clang-format | 7 - CHANGELOG.md | 4 - Rakefile | 1 + ext/oj/buf.h | 54 +- ext/oj/cache8.c | 92 +- ext/oj/cache8.h | 14 +- ext/oj/circarray.c | 52 +- ext/oj/circarray.h | 18 +- ext/oj/code.c | 330 ++++--- ext/oj/code.h | 40 +- ext/oj/compat.c | 228 ++--- ext/oj/custom.c | 1486 ++++++++++++++++--------------- ext/oj/dump.c | 1437 +++++++++++++++--------------- ext/oj/dump.h | 106 +-- ext/oj/dump_compat.c | 1092 +++++++++++------------ ext/oj/dump_leaf.c | 271 +++--- ext/oj/dump_object.c | 1168 ++++++++++++------------ ext/oj/dump_strict.c | 608 ++++++------- ext/oj/err.c | 32 +- ext/oj/err.h | 19 +- ext/oj/extconf.rb | 3 +- ext/oj/fast.c | 1910 +++++++++++++++++++--------------------- ext/oj/hash.c | 110 +-- ext/oj/hash.h | 12 +- ext/oj/hash_test.c | 79 +- ext/oj/mimic_json.c | 659 +++++++------- ext/oj/object.c | 964 ++++++++++---------- ext/oj/odd.c | 154 ++-- ext/oj/odd.h | 50 +- ext/oj/oj.c | 1655 ++++++++++++++++------------------ ext/oj/oj.h | 577 ++++++------ ext/oj/parse.c | 1646 +++++++++++++++++----------------- ext/oj/parse.h | 143 ++- ext/oj/rails.c | 1353 ++++++++++++++-------------- ext/oj/rails.h | 13 +- ext/oj/reader.c | 206 ++--- ext/oj/reader.h | 126 +-- ext/oj/resolve.c | 82 +- ext/oj/resolve.h | 4 +- ext/oj/rxclass.c | 112 +-- ext/oj/rxclass.h | 22 +- ext/oj/saj.c | 914 ++++++++++--------- ext/oj/scp.c | 86 +- ext/oj/sparse.c | 1344 ++++++++++++++-------------- ext/oj/stream_writer.c | 252 +++--- ext/oj/strict.c | 64 +- ext/oj/string_writer.c | 368 ++++---- ext/oj/trace.c | 42 +- ext/oj/trace.h | 22 +- ext/oj/util.c | 137 +-- ext/oj/util.h | 4 +- ext/oj/val_stack.c | 74 +- ext/oj/val_stack.h | 116 +-- ext/oj/wab.c | 432 ++++----- lib/oj/bag.rb | 1 - 55 files changed, 10211 insertions(+), 10584 deletions(-) delete mode 100644 .clang-format diff --git a/.clang-format b/.clang-format deleted file mode 100644 index 20f7f3fd..00000000 --- a/.clang-format +++ /dev/null @@ -1,7 +0,0 @@ -BasedOnStyle: Mozilla -IndentWidth: 4 -BreakBeforeBraces: Attach -ColumnLimit: 0 -AlwaysBreakAfterReturnType: AllDefinitions -DerivePointerAlignment: false -PointerAlignment: Right diff --git a/CHANGELOG.md b/CHANGELOG.md index 7da9bcc4..2d7c9fc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,5 @@ # CHANGELOG -## Ongoing - -- Added support for `GC.compact` on `Oj::Doc` - ## 3.11.3 - 2021-03-09 - Fixed `respond_to?` method on `Oj::EasyHash`. diff --git a/Rakefile b/Rakefile index 25b5d58f..1e27641f 100644 --- a/Rakefile +++ b/Rakefile @@ -92,3 +92,4 @@ begin rescue LoadError end + diff --git a/ext/oj/buf.h b/ext/oj/buf.h index 48ad657b..96350a6b 100644 --- a/ext/oj/buf.h +++ b/ext/oj/buf.h @@ -6,11 +6,11 @@ #include "ruby.h" typedef struct _buf { - char *head; - char *end; - char *tail; - char base[1024]; -} * Buf; + char *head; + char *end; + char *tail; + char base[1024]; +} *Buf; inline static void buf_init(Buf buf) { @@ -34,18 +34,18 @@ buf_len(Buf buf) { inline static void buf_append_string(Buf buf, const char *s, size_t slen) { if (buf->end <= buf->tail + slen) { - size_t len = buf->end - buf->head; - size_t toff = buf->tail - buf->head; - size_t new_len = len + slen + len / 2; + size_t len = buf->end - buf->head; + size_t toff = buf->tail - buf->head; + size_t new_len = len + slen + len / 2; - if (buf->base == buf->head) { - buf->head = ALLOC_N(char, new_len); - memcpy(buf->head, buf->base, len); - } else { - REALLOC_N(buf->head, char, new_len); - } - buf->tail = buf->head + toff; - buf->end = buf->head + new_len - 1; + if (buf->base == buf->head) { + buf->head = ALLOC_N(char, new_len); + memcpy(buf->head, buf->base, len); + } else { + REALLOC_N(buf->head, char, new_len); + } + buf->tail = buf->head + toff; + buf->end = buf->head + new_len - 1; } memcpy(buf->tail, s, slen); buf->tail += slen; @@ -54,18 +54,18 @@ buf_append_string(Buf buf, const char *s, size_t slen) { inline static void buf_append(Buf buf, char c) { if (buf->end <= buf->tail) { - size_t len = buf->end - buf->head; - size_t toff = buf->tail - buf->head; - size_t new_len = len + len / 2; + size_t len = buf->end - buf->head; + size_t toff = buf->tail - buf->head; + size_t new_len = len + len / 2; - if (buf->base == buf->head) { - buf->head = ALLOC_N(char, new_len); - memcpy(buf->head, buf->base, len); - } else { - REALLOC_N(buf->head, char, new_len); - } - buf->tail = buf->head + toff; - buf->end = buf->head + new_len - 1; + if (buf->base == buf->head) { + buf->head = ALLOC_N(char, new_len); + memcpy(buf->head, buf->base, len); + } else { + REALLOC_N(buf->head, char, new_len); + } + buf->tail = buf->head + toff; + buf->end = buf->head + new_len - 1; } *buf->tail = c; buf->tail++; diff --git a/ext/oj/cache8.c b/ext/oj/cache8.c index 011818eb..751a21dc 100644 --- a/ext/oj/cache8.c +++ b/ext/oj/cache8.c @@ -1,40 +1,40 @@ // Copyright (c) 2011 Peter Ohler. All rights reserved. // Licensed under the MIT License. See LICENSE file in the project root for license details. +#include #include -#include #include -#include #include +#include -#include "cache8.h" #include "ruby.h" +#include "cache8.h" -#define BITS 4 -#define MASK 0x000000000000000FULL -#define SLOT_CNT 16 -#define DEPTH 16 +#define BITS 4 +#define MASK 0x000000000000000FULL +#define SLOT_CNT 16 +#define DEPTH 16 typedef union { - struct _cache8 *child; - slot_t value; + struct _cache8 *child; + slot_t value; } Bucket; struct _cache8 { - Bucket buckets[SLOT_CNT]; + Bucket buckets[SLOT_CNT]; }; -static void cache8_delete(Cache8 cache, int depth); -static void slot_print(Cache8 cache, sid_t key, unsigned int depth); +static void cache8_delete(Cache8 cache, int depth); +static void slot_print(Cache8 cache, sid_t key, unsigned int depth); void oj_cache8_new(Cache8 *cache) { - Bucket *b; - int i; + Bucket *b; + int i; *cache = ALLOC(struct _cache8); for (i = SLOT_CNT, b = (*cache)->buckets; 0 < i; i--, b++) { - b->value = 0; + b->value = 0; } } @@ -45,33 +45,33 @@ oj_cache8_delete(Cache8 cache) { static void cache8_delete(Cache8 cache, int depth) { - Bucket *b; - unsigned int i; + Bucket *b; + unsigned int i; for (i = 0, b = cache->buckets; i < SLOT_CNT; i++, b++) { - if (0 != b->child) { - if (DEPTH - 1 != depth) { - cache8_delete(b->child, depth + 1); - } - } + if (0 != b->child) { + if (DEPTH - 1 != depth) { + cache8_delete(b->child, depth + 1); + } + } } xfree(cache); } slot_t oj_cache8_get(Cache8 cache, sid_t key, slot_t **slot) { - Bucket *b; - int i; - sid_t k8 = (sid_t)key; - sid_t k; + Bucket *b; + int i; + sid_t k8 = (sid_t)key; + sid_t k; for (i = 64 - BITS; 0 < i; i -= BITS) { - k = (k8 >> i) & MASK; - b = cache->buckets + k; - if (0 == b->child) { - oj_cache8_new(&b->child); - } - cache = b->child; + k = (k8 >> i) & MASK; + b = cache->buckets + k; + if (0 == b->child) { + oj_cache8_new(&b->child); + } + cache = b->child; } *slot = &(cache->buckets + (k8 & MASK))->value; @@ -86,24 +86,24 @@ oj_cache8_print(Cache8 cache) { static void slot_print(Cache8 c, sid_t key, unsigned int depth) { - Bucket *b; - unsigned int i; - sid_t k8 = (sid_t)key; - sid_t k; + Bucket *b; + unsigned int i; + sid_t k8 = (sid_t)key; + sid_t k; for (i = 0, b = c->buckets; i < SLOT_CNT; i++, b++) { - if (0 != b->child) { - k = (k8 << BITS) | i; - /*printf("*** key: 0x%016llx depth: %u i: %u\n", k, depth, i); */ - if (DEPTH - 1 == depth) { + if (0 != b->child) { + k = (k8 << BITS) | i; + /*printf("*** key: 0x%016llx depth: %u i: %u\n", k, depth, i); */ + if (DEPTH - 1 == depth) { #if IS_WINDOWS - printf("0x%016lx: %4lu\n", (long unsigned int)k, (long unsigned int)b->value); + printf("0x%016lx: %4lu\n", (long unsigned int)k, (long unsigned int)b->value); #else - printf("0x%016llx: %4llu\n", (long long unsigned int)k, (long long unsigned int)b->value); + printf("0x%016llx: %4llu\n", (long long unsigned int)k, (long long unsigned int)b->value); #endif - } else { - slot_print(b->child, k, depth + 1); - } - } + } else { + slot_print(b->child, k, depth + 1); + } + } } } diff --git a/ext/oj/cache8.h b/ext/oj/cache8.h index 3d30ee46..5517d315 100644 --- a/ext/oj/cache8.h +++ b/ext/oj/cache8.h @@ -7,15 +7,15 @@ #include "ruby.h" #include "stdint.h" -typedef struct _cache8 *Cache8; -typedef uint64_t slot_t; -typedef uint64_t sid_t; +typedef struct _cache8 *Cache8; +typedef uint64_t slot_t; +typedef uint64_t sid_t; -extern void oj_cache8_new(Cache8 *cache); -extern void oj_cache8_delete(Cache8 cache); +extern void oj_cache8_new(Cache8 *cache); +extern void oj_cache8_delete(Cache8 cache); -extern slot_t oj_cache8_get(Cache8 cache, sid_t key, slot_t **slot); +extern slot_t oj_cache8_get(Cache8 cache, sid_t key, slot_t **slot); -extern void oj_cache8_print(Cache8 cache); +extern void oj_cache8_print(Cache8 cache); #endif /* OJ_CACHE8_H */ diff --git a/ext/oj/circarray.c b/ext/oj/circarray.c index e8223739..ebc1471f 100644 --- a/ext/oj/circarray.c +++ b/ext/oj/circarray.c @@ -5,10 +5,10 @@ CircArray oj_circ_array_new() { - CircArray ca; + CircArray ca; if (0 == (ca = ALLOC(struct _circArray))) { - rb_raise(rb_eNoMemError, "not enough memory\n"); + rb_raise(rb_eNoMemError, "not enough memory\n"); } ca->objs = ca->obj_array; ca->size = sizeof(ca->obj_array) / sizeof(VALUE); @@ -20,7 +20,7 @@ oj_circ_array_new() { void oj_circ_array_free(CircArray ca) { if (ca->objs != ca->obj_array) { - xfree(ca->objs); + xfree(ca->objs); } xfree(ca); } @@ -28,38 +28,38 @@ oj_circ_array_free(CircArray ca) { void oj_circ_array_set(CircArray ca, VALUE obj, unsigned long id) { if (0 < id && 0 != ca) { - unsigned long i; + unsigned long i; - if (ca->size < id) { - unsigned long cnt = id + 512; + if (ca->size < id) { + unsigned long cnt = id + 512; - if (ca->objs == ca->obj_array) { - if (0 == (ca->objs = ALLOC_N(VALUE, cnt))) { - rb_raise(rb_eNoMemError, "not enough memory\n"); - } - memcpy(ca->objs, ca->obj_array, sizeof(VALUE) * ca->cnt); - } else { - REALLOC_N(ca->objs, VALUE, cnt); - } - ca->size = cnt; - } - id--; - for (i = ca->cnt; i < id; i++) { - ca->objs[i] = Qnil; - } - ca->objs[id] = obj; - if (ca->cnt <= id) { - ca->cnt = id + 1; - } + if (ca->objs == ca->obj_array) { + if (0 == (ca->objs = ALLOC_N(VALUE, cnt))) { + rb_raise(rb_eNoMemError, "not enough memory\n"); + } + memcpy(ca->objs, ca->obj_array, sizeof(VALUE) * ca->cnt); + } else { + REALLOC_N(ca->objs, VALUE, cnt); + } + ca->size = cnt; + } + id--; + for (i = ca->cnt; i < id; i++) { + ca->objs[i] = Qnil; + } + ca->objs[id] = obj; + if (ca->cnt <= id) { + ca->cnt = id + 1; + } } } VALUE oj_circ_array_get(CircArray ca, unsigned long id) { - VALUE obj = Qnil; + VALUE obj = Qnil; if (id <= ca->cnt && 0 != ca) { - obj = ca->objs[id - 1]; + obj = ca->objs[id - 1]; } return obj; } diff --git a/ext/oj/circarray.h b/ext/oj/circarray.h index 21dfb40e..6ab095d8 100644 --- a/ext/oj/circarray.h +++ b/ext/oj/circarray.h @@ -7,15 +7,15 @@ #include "ruby.h" typedef struct _circArray { - VALUE obj_array[1024]; - VALUE *objs; - unsigned long size; // allocated size or initial array size - unsigned long cnt; -} * CircArray; + VALUE obj_array[1024]; + VALUE *objs; + unsigned long size; // allocated size or initial array size + unsigned long cnt; +} *CircArray; -extern CircArray oj_circ_array_new(void); -extern void oj_circ_array_free(CircArray ca); -extern void oj_circ_array_set(CircArray ca, VALUE obj, unsigned long id); -extern VALUE oj_circ_array_get(CircArray ca, unsigned long id); +extern CircArray oj_circ_array_new(void); +extern void oj_circ_array_free(CircArray ca); +extern void oj_circ_array_set(CircArray ca, VALUE obj, unsigned long id); +extern VALUE oj_circ_array_get(CircArray ca, unsigned long id); #endif /* OJ_CIRCARRAY_H */ diff --git a/ext/oj/code.c b/ext/oj/code.c index 953fee53..b2179465 100644 --- a/ext/oj/code.c +++ b/ext/oj/code.c @@ -6,40 +6,40 @@ inline static VALUE resolve_classname(VALUE mod, const char *classname) { - VALUE clas = Qundef; - ID ci = rb_intern(classname); + VALUE clas = Qundef; + ID ci = rb_intern(classname); if (rb_const_defined_at(mod, ci)) { - clas = rb_const_get_at(mod, ci); + clas = rb_const_get_at(mod, ci); } return clas; } static VALUE path2class(const char *name) { - char class_name[1024]; - VALUE clas; - char *end = class_name + sizeof(class_name) - 1; - char *s; - const char *n = name; + char class_name[1024]; + VALUE clas; + char *end = class_name + sizeof(class_name) - 1; + char *s; + const char *n = name; clas = rb_cObject; for (s = class_name; '\0' != *n; n++) { - if (':' == *n) { - *s = '\0'; - n++; - if (':' != *n) { - return Qundef; - } - if (Qundef == (clas = resolve_classname(clas, class_name))) { - return Qundef; - } - s = class_name; - } else if (end <= s) { - return Qundef; - } else { - *s++ = *n; - } + if (':' == *n) { + *s = '\0'; + n++; + if (':' != *n) { + return Qundef; + } + if (Qundef == (clas = resolve_classname(clas, class_name))) { + return Qundef; + } + s = class_name; + } else if (end <= s) { + return Qundef; + } else { + *s++ = *n; + } } *s = '\0'; @@ -48,191 +48,183 @@ path2class(const char *name) { bool oj_code_dump(Code codes, VALUE obj, int depth, Out out) { - VALUE clas = rb_obj_class(obj); - Code c = codes; + VALUE clas = rb_obj_class(obj); + Code c = codes; for (; NULL != c->name; c++) { - if (Qundef == c->clas) { // indicates not defined - continue; - } - if (Qnil == c->clas) { - c->clas = path2class(c->name); - } - if (clas == c->clas && c->active) { - c->encode(obj, depth, out); - return true; - } + if (Qundef == c->clas) { // indicates not defined + continue; + } + if (Qnil == c->clas) { + c->clas = path2class(c->name); + } + if (clas == c->clas && c->active) { + c->encode(obj, depth, out); + return true; + } } return false; } VALUE oj_code_load(Code codes, VALUE clas, VALUE args) { - Code c = codes; + Code c = codes; for (; NULL != c->name; c++) { - if (Qundef == c->clas) { // indicates not defined - continue; - } - if (Qnil == c->clas) { - c->clas = path2class(c->name); - } - if (clas == c->clas) { - if (NULL == c->decode) { - break; - } - return c->decode(clas, args); - } + if (Qundef == c->clas) { // indicates not defined + continue; + } + if (Qnil == c->clas) { + c->clas = path2class(c->name); + } + if (clas == c->clas) { + if (NULL == c->decode) { + break; + } + return c->decode(clas, args); + } } return Qnil; } void oj_code_set_active(Code codes, VALUE clas, bool active) { - Code c = codes; + Code c = codes; for (; NULL != c->name; c++) { - if (Qundef == c->clas) { // indicates not defined - continue; - } - if (Qnil == c->clas) { - c->clas = path2class(c->name); - } - if (clas == c->clas || Qnil == clas) { - c->active = active; - if (Qnil != clas) { - break; - } - } + if (Qundef == c->clas) { // indicates not defined + continue; + } + if (Qnil == c->clas) { + c->clas = path2class(c->name); + } + if (clas == c->clas || Qnil == clas) { + c->active = active; + if (Qnil != clas) { + break; + } + } } } bool oj_code_has(Code codes, VALUE clas, bool encode) { - Code c = codes; + Code c = codes; for (; NULL != c->name; c++) { - if (Qundef == c->clas) { // indicates not defined - continue; - } - if (Qnil == c->clas) { - c->clas = path2class(c->name); - } - if (clas == c->clas) { - if (encode) { - return c->active && NULL != c->encode; - } else { - return c->active && NULL != c->decode; - } - } + if (Qundef == c->clas) { // indicates not defined + continue; + } + if (Qnil == c->clas) { + c->clas = path2class(c->name); + } + if (clas == c->clas) { + if (encode) { + return c->active && NULL != c->encode; + } else { + return c->active && NULL != c->decode; + } + } } return false; } void oj_code_attrs(VALUE obj, Attr attrs, int depth, Out out, bool with_class) { - int d2 = depth + 1; - int d3 = d2 + 1; - size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2; - const char *classname = rb_obj_classname(obj); - size_t len = strlen(classname); - size_t size = d2 * out->indent + 10 + len + out->opts->create_id_len + sep_len; - bool no_comma = true; + int d2 = depth + 1; + int d3 = d2 + 1; + size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2; + const char *classname = rb_obj_classname(obj); + size_t len = strlen(classname); + size_t size = d2 * out->indent + 10 + len + out->opts->create_id_len + sep_len; + bool no_comma = true; assure_size(out, size); *out->cur++ = '{'; if (with_class) { - fill_indent(out, d2); - *out->cur++ = '"'; - memcpy(out->cur, out->opts->create_id, out->opts->create_id_len); - out->cur += out->opts->create_id_len; - *out->cur++ = '"'; - if (0 < out->opts->dump_opts.before_size) { - strcpy(out->cur, out->opts->dump_opts.before_sep); - out->cur += out->opts->dump_opts.before_size; - } - *out->cur++ = ':'; - if (0 < out->opts->dump_opts.after_size) { - strcpy(out->cur, out->opts->dump_opts.after_sep); - out->cur += out->opts->dump_opts.after_size; - } - *out->cur++ = '"'; - memcpy(out->cur, classname, len); - out->cur += len; - *out->cur++ = '"'; - no_comma = false; + fill_indent(out, d2); + *out->cur++ = '"'; + memcpy(out->cur, out->opts->create_id, out->opts->create_id_len); + out->cur += out->opts->create_id_len; + *out->cur++ = '"'; + if (0 < out->opts->dump_opts.before_size) { + strcpy(out->cur, out->opts->dump_opts.before_sep); + out->cur += out->opts->dump_opts.before_size; + } + *out->cur++ = ':'; + if (0 < out->opts->dump_opts.after_size) { + strcpy(out->cur, out->opts->dump_opts.after_sep); + out->cur += out->opts->dump_opts.after_size; + } + *out->cur++ = '"'; + memcpy(out->cur, classname, len); + out->cur += len; + *out->cur++ = '"'; + no_comma = false; } size = d3 * out->indent + 2; for (; NULL != attrs->name; attrs++) { - assure_size(out, size + attrs->len + sep_len + 2); - if (no_comma) { - no_comma = false; - } else { - *out->cur++ = ','; - } - fill_indent(out, d2); - *out->cur++ = '"'; - memcpy(out->cur, attrs->name, attrs->len); - out->cur += attrs->len; - *out->cur++ = '"'; - if (0 < out->opts->dump_opts.before_size) { - strcpy(out->cur, out->opts->dump_opts.before_sep); - out->cur += out->opts->dump_opts.before_size; - } - *out->cur++ = ':'; - if (0 < out->opts->dump_opts.after_size) { - strcpy(out->cur, out->opts->dump_opts.after_sep); - out->cur += out->opts->dump_opts.after_size; - } - if (Qundef == attrs->value) { - if (Qundef != attrs->time) { - switch (out->opts->time_format) { - case RubyTime: - oj_dump_ruby_time(attrs->time, out); - break; - case XmlTime: - oj_dump_xml_time(attrs->time, out); - break; - case UnixZTime: - oj_dump_time(attrs->time, out, true); - break; - case UnixTime: - default: - oj_dump_time(attrs->time, out, false); - break; - } - } else { - char buf[32]; - char *b = buf + sizeof(buf) - 1; - int neg = 0; - long num = attrs->num; - - if (0 > num) { - neg = 1; - num = -num; - } - *b-- = '\0'; - if (0 < num) { - for (; 0 < num; num /= 10, b--) { - *b = (num % 10) + '0'; - } - if (neg) { - *b = '-'; - } else { - b++; - } - } else { - *b = '0'; - } - assure_size(out, (sizeof(buf) - (b - buf))); - for (; '\0' != *b; b++) { - *out->cur++ = *b; - } - } - } else { - oj_dump_compat_val(attrs->value, d3, out, true); - } + assure_size(out, size + attrs->len + sep_len + 2); + if (no_comma) { + no_comma = false; + } else { + *out->cur++ = ','; + } + fill_indent(out, d2); + *out->cur++ = '"'; + memcpy(out->cur, attrs->name, attrs->len); + out->cur += attrs->len; + *out->cur++ = '"'; + if (0 < out->opts->dump_opts.before_size) { + strcpy(out->cur, out->opts->dump_opts.before_sep); + out->cur += out->opts->dump_opts.before_size; + } + *out->cur++ = ':'; + if (0 < out->opts->dump_opts.after_size) { + strcpy(out->cur, out->opts->dump_opts.after_sep); + out->cur += out->opts->dump_opts.after_size; + } + if (Qundef == attrs->value) { + if (Qundef != attrs->time) { + switch (out->opts->time_format) { + case RubyTime: oj_dump_ruby_time(attrs->time, out); break; + case XmlTime: oj_dump_xml_time(attrs->time, out); break; + case UnixZTime: oj_dump_time(attrs->time, out, true); break; + case UnixTime: + default: oj_dump_time(attrs->time, out, false); break; + } + } else { + char buf[32]; + char *b = buf + sizeof(buf) - 1; + int neg = 0; + long num = attrs->num; + + if (0 > num) { + neg = 1; + num = -num; + } + *b-- = '\0'; + if (0 < num) { + for (; 0 < num; num /= 10, b--) { + *b = (num % 10) + '0'; + } + if (neg) { + *b = '-'; + } else { + b++; + } + } else { + *b = '0'; + } + assure_size(out, (sizeof(buf) - (b - buf))); + for (; '\0' != *b; b++) { + *out->cur++ = *b; + } + } + } else { + oj_dump_compat_val(attrs->value, d3, out, true); + } } assure_size(out, depth * out->indent + 2); fill_indent(out, depth); diff --git a/ext/oj/code.h b/ext/oj/code.h index 9912b7ac..8fd0a5f1 100644 --- a/ext/oj/code.h +++ b/ext/oj/code.h @@ -8,33 +8,33 @@ #include "oj.h" -typedef void (*EncodeFunc)(VALUE obj, int depth, Out out); -typedef VALUE (*DecodeFunc)(VALUE clas, VALUE args); +typedef void (*EncodeFunc)(VALUE obj, int depth, Out out); +typedef VALUE (*DecodeFunc)(VALUE clas, VALUE args); typedef struct _code { - const char *name; - VALUE clas; - EncodeFunc encode; - DecodeFunc decode; - bool active; // For compat mode. -} * Code; + const char *name; + VALUE clas; + EncodeFunc encode; + DecodeFunc decode; + bool active; // For compat mode. +} *Code; // Used by encode functions. typedef struct _attr { - const char *name; - int len; - VALUE value; - long num; - VALUE time; -} * Attr; + const char *name; + int len; + VALUE value; + long num; + VALUE time; +} *Attr; -extern bool oj_code_dump(Code codes, VALUE obj, int depth, Out out); -extern VALUE oj_code_load(Code codes, VALUE clas, VALUE args); -extern void oj_code_set_active(Code codes, VALUE clas, bool active); -extern bool oj_code_has(Code codes, VALUE clas, bool encode); +extern bool oj_code_dump(Code codes, VALUE obj, int depth, Out out); +extern VALUE oj_code_load(Code codes, VALUE clas, VALUE args); +extern void oj_code_set_active(Code codes, VALUE clas, bool active); +extern bool oj_code_has(Code codes, VALUE clas, bool encode); -extern void oj_code_attrs(VALUE obj, Attr attrs, int depth, Out out, bool with_class); +extern void oj_code_attrs(VALUE obj, Attr attrs, int depth, Out out, bool with_class); -extern struct _code oj_compat_codes[]; +extern struct _code oj_compat_codes[]; #endif /* OJ_CODE_H */ diff --git a/ext/oj/compat.c b/ext/oj/compat.c index 98cf21d0..af51a9ef 100644 --- a/ext/oj/compat.c +++ b/ext/oj/compat.c @@ -3,133 +3,133 @@ #include -#include "encode.h" -#include "err.h" -#include "hash.h" #include "oj.h" +#include "err.h" #include "parse.h" #include "resolve.h" +#include "hash.h" +#include "encode.h" #include "trace.h" static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) { - const char *key = kval->key; - int klen = kval->klen; - Val parent = stack_peek(&pi->stack); - volatile VALUE rkey = kval->key_val; + const char *key = kval->key; + int klen = kval->klen; + Val parent = stack_peek(&pi->stack); + volatile VALUE rkey = kval->key_val; if (Qundef == rkey && - Yes == pi->options.create_ok && - NULL != pi->options.create_id && - *pi->options.create_id == *key && - (int)pi->options.create_id_len == klen && - 0 == strncmp(pi->options.create_id, key, klen)) { - - parent->classname = oj_strndup(str, len); - parent->clen = len; + Yes == pi->options.create_ok && + NULL != pi->options.create_id && + *pi->options.create_id == *key && + (int)pi->options.create_id_len == klen && + 0 == strncmp(pi->options.create_id, key, klen)) { + + parent->classname = oj_strndup(str, len); + parent->clen = len; } else { - volatile VALUE rstr = rb_str_new(str, len); - - if (Qundef == rkey) { - rkey = rb_str_new(key, klen); - rstr = oj_encode(rstr); - rkey = oj_encode(rkey); - if (Yes == pi->options.sym_key) { - rkey = rb_str_intern(rkey); - } - } - if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) { - VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len); - - if (Qnil != clas) { - rstr = rb_funcall(clas, oj_json_create_id, 1, rstr); - } - } - if (rb_cHash != rb_obj_class(parent->val)) { - // The rb_hash_set would still work but the unit tests for the - // json gem require the less efficient []= method be called to set - // values. Even using the store method to set the values will fail - // the unit tests. - rb_funcall(parent->val, rb_intern("[]="), 2, rkey, rstr); - } else { - rb_hash_aset(parent->val, rkey, rstr); - } - if (Yes == pi->options.trace) { - oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr); - } + volatile VALUE rstr = rb_str_new(str, len); + + if (Qundef == rkey) { + rkey = rb_str_new(key, klen); + rstr = oj_encode(rstr); + rkey = oj_encode(rkey); + if (Yes == pi->options.sym_key) { + rkey = rb_str_intern(rkey); + } + } + if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) { + VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len); + + if (Qnil != clas) { + rstr = rb_funcall(clas, oj_json_create_id, 1, rstr); + } + } + if (rb_cHash != rb_obj_class(parent->val)) { + // The rb_hash_set would still work but the unit tests for the + // json gem require the less efficient []= method be called to set + // values. Even using the store method to set the values will fail + // the unit tests. + rb_funcall(parent->val, rb_intern("[]="), 2, rkey, rstr); + } else { + rb_hash_aset(parent->val, rkey, rstr); + } + if (Yes == pi->options.trace) { + oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr); + } } } static VALUE start_hash(ParseInfo pi) { - volatile VALUE h; + volatile VALUE h; if (Qnil != pi->options.hash_class) { - h = rb_class_new_instance(0, NULL, pi->options.hash_class); + h = rb_class_new_instance(0, NULL, pi->options.hash_class); } else { - h = rb_hash_new(); + h = rb_hash_new(); } if (Yes == pi->options.trace) { - oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__); + oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__); } return h; } static void end_hash(struct _parseInfo *pi) { - Val parent = stack_peek(&pi->stack); + Val parent = stack_peek(&pi->stack); if (0 != parent->classname) { - volatile VALUE clas; - - clas = oj_name2class(pi, parent->classname, parent->clen, 0, rb_eArgError); - if (Qundef != clas) { // else an error - ID creatable = rb_intern("json_creatable?"); - - if (!rb_respond_to(clas, creatable) || Qtrue == rb_funcall(clas, creatable, 0)) { - parent->val = rb_funcall(clas, oj_json_create_id, 1, parent->val); - } - } - if (0 != parent->classname) { - xfree((char *)parent->classname); - parent->classname = 0; - } + volatile VALUE clas; + + clas = oj_name2class(pi, parent->classname, parent->clen, 0, rb_eArgError); + if (Qundef != clas) { // else an error + ID creatable = rb_intern("json_creatable?"); + + if (!rb_respond_to(clas, creatable) || Qtrue == rb_funcall(clas, creatable, 0)) { + parent->val = rb_funcall(clas, oj_json_create_id, 1, parent->val); + } + } + if (0 != parent->classname) { + xfree((char*)parent->classname); + parent->classname = 0; + } } if (Yes == pi->options.trace) { - oj_trace_parse_hash_end(pi, __FILE__, __LINE__); + oj_trace_parse_hash_end(pi, __FILE__, __LINE__); } } static VALUE calc_hash_key(ParseInfo pi, Val parent) { - volatile VALUE rkey = parent->key_val; + volatile VALUE rkey = parent->key_val; if (Qundef == rkey) { - rkey = rb_str_new(parent->key, parent->klen); + rkey = rb_str_new(parent->key, parent->klen); } rkey = oj_encode(rkey); if (Yes == pi->options.sym_key) { - rkey = rb_str_intern(rkey); + rkey = rb_str_intern(rkey); } return rkey; } static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { - volatile VALUE rstr = rb_str_new(str, len); + volatile VALUE rstr = rb_str_new(str, len); rstr = oj_encode(rstr); if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) { - VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len); + VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len); - if (Qnil != clas) { - pi->stack.head->val = rb_funcall(clas, oj_json_create_id, 1, rstr); - return; - } + if (Qnil != clas) { + pi->stack.head->val = rb_funcall(clas, oj_json_create_id, 1, rstr); + return; + } } pi->stack.head->val = rstr; if (Yes == pi->options.trace) { - oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr); + oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr); } } @@ -137,89 +137,89 @@ static void add_num(ParseInfo pi, NumInfo ni) { pi->stack.head->val = oj_num_as_value(ni); if (Yes == pi->options.trace) { - oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val); + oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val); } } static void hash_set_num(struct _parseInfo *pi, Val parent, NumInfo ni) { - volatile VALUE rval = oj_num_as_value(ni); + volatile VALUE rval = oj_num_as_value(ni); if (!oj_use_hash_alt && rb_cHash != rb_obj_class(parent->val)) { - // The rb_hash_set would still work but the unit tests for the - // json gem require the less efficient []= method be called to set - // values. Even using the store method to set the values will fail - // the unit tests. - rb_funcall(stack_peek(&pi->stack)->val, rb_intern("[]="), 2, calc_hash_key(pi, parent), rval); + // The rb_hash_set would still work but the unit tests for the + // json gem require the less efficient []= method be called to set + // values. Even using the store method to set the values will fail + // the unit tests. + rb_funcall(stack_peek(&pi->stack)->val, rb_intern("[]="), 2, calc_hash_key(pi, parent), rval); } else { - rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval); + rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval); } if (Yes == pi->options.trace) { - oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval); + oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval); } } static void hash_set_value(ParseInfo pi, Val parent, VALUE value) { if (rb_cHash != rb_obj_class(parent->val)) { - // The rb_hash_set would still work but the unit tests for the - // json gem require the less efficient []= method be called to set - // values. Even using the store method to set the values will fail - // the unit tests. - rb_funcall(stack_peek(&pi->stack)->val, rb_intern("[]="), 2, calc_hash_key(pi, parent), value); + // The rb_hash_set would still work but the unit tests for the + // json gem require the less efficient []= method be called to set + // values. Even using the store method to set the values will fail + // the unit tests. + rb_funcall(stack_peek(&pi->stack)->val, rb_intern("[]="), 2, calc_hash_key(pi, parent), value); } else { - rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value); + rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value); } if (Yes == pi->options.trace) { - oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value); + oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value); } } static VALUE start_array(ParseInfo pi) { if (Qnil != pi->options.array_class) { - return rb_class_new_instance(0, NULL, pi->options.array_class); + return rb_class_new_instance(0, NULL, pi->options.array_class); } if (Yes == pi->options.trace) { - oj_trace_parse_in("start_array", pi, __FILE__, __LINE__); + oj_trace_parse_in("start_array", pi, __FILE__, __LINE__); } return rb_ary_new(); } static void array_append_num(ParseInfo pi, NumInfo ni) { - Val parent = stack_peek(&pi->stack); - volatile VALUE rval = oj_num_as_value(ni); + Val parent = stack_peek(&pi->stack); + volatile VALUE rval = oj_num_as_value(ni); if (!oj_use_array_alt && rb_cArray != rb_obj_class(parent->val)) { - // The rb_ary_push would still work but the unit tests for the json - // gem require the less efficient << method be called to push the - // values. - rb_funcall(parent->val, rb_intern("<<"), 1, rval); + // The rb_ary_push would still work but the unit tests for the json + // gem require the less efficient << method be called to push the + // values. + rb_funcall(parent->val, rb_intern("<<"), 1, rval); } else { - rb_ary_push(parent->val, rval); + rb_ary_push(parent->val, rval); } if (Yes == pi->options.trace) { - oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval); + oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval); } } static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { - volatile VALUE rstr = rb_str_new(str, len); + volatile VALUE rstr = rb_str_new(str, len); rstr = oj_encode(rstr); if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) { - VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len); + VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len); - if (Qnil != clas) { - rb_ary_push(stack_peek(&pi->stack)->val, rb_funcall(clas, oj_json_create_id, 1, rstr)); - return; - } + if (Qnil != clas) { + rb_ary_push(stack_peek(&pi->stack)->val, rb_funcall(clas, oj_json_create_id, 1, rstr)); + return; + } } rb_ary_push(stack_peek(&pi->stack)->val, rstr); if (Yes == pi->options.trace) { - oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr); + oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr); } } @@ -240,7 +240,7 @@ oj_set_compat_callbacks(ParseInfo pi) { VALUE oj_compat_parse(int argc, VALUE *argv, VALUE self) { - struct _parseInfo pi; + struct _parseInfo pi; parse_info_init(&pi); pi.options = oj_default_options; @@ -253,15 +253,15 @@ oj_compat_parse(int argc, VALUE *argv, VALUE self) { oj_set_compat_callbacks(&pi); if (T_STRING == rb_type(*argv)) { - return oj_pi_parse(argc, argv, &pi, 0, 0, false); + return oj_pi_parse(argc, argv, &pi, 0, 0, false); } else { - return oj_pi_sparse(argc, argv, &pi, 0); + return oj_pi_sparse(argc, argv, &pi, 0); } } VALUE oj_compat_load(int argc, VALUE *argv, VALUE self) { - struct _parseInfo pi; + struct _parseInfo pi; parse_info_init(&pi); pi.options = oj_default_options; @@ -274,15 +274,15 @@ oj_compat_load(int argc, VALUE *argv, VALUE self) { oj_set_compat_callbacks(&pi); if (T_STRING == rb_type(*argv)) { - return oj_pi_parse(argc, argv, &pi, 0, 0, false); + return oj_pi_parse(argc, argv, &pi, 0, 0, false); } else { - return oj_pi_sparse(argc, argv, &pi, 0); + return oj_pi_sparse(argc, argv, &pi, 0); } } VALUE oj_compat_parse_cstr(int argc, VALUE *argv, char *json, size_t len) { - struct _parseInfo pi; + struct _parseInfo pi; parse_info_init(&pi); pi.options = oj_default_options; diff --git a/ext/oj/custom.c b/ext/oj/custom.c index 5d38897a..84c02998 100644 --- a/ext/oj/custom.c +++ b/ext/oj/custom.c @@ -16,14 +16,14 @@ #include "trace.h" #include "util.h" -extern void oj_set_obj_ivar(Val parent, Val kval, VALUE value); -extern VALUE oj_parse_xml_time(const char *str, int len); // from object.c +extern void oj_set_obj_ivar(Val parent, Val kval, VALUE value); +extern VALUE oj_parse_xml_time(const char *str, int len); // from object.c static void dump_obj_str(VALUE obj, int depth, Out out) { - struct _attr attrs[] = { - { "s", 1, Qnil }, - { NULL, 0, Qnil }, + struct _attr attrs[] = { + { "s", 1, Qnil }, + { NULL, 0, Qnil }, }; attrs->value = rb_funcall(obj, oj_to_s_id, 0); @@ -32,60 +32,60 @@ dump_obj_str(VALUE obj, int depth, Out out) { static void dump_obj_as_str(VALUE obj, int depth, Out out) { - volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); - const char *str = rb_string_value_ptr((VALUE *)&rstr); + volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); + const char *str = rb_string_value_ptr((VALUE*)&rstr); oj_dump_cstr(str, RSTRING_LEN(rstr), 0, 0, out); } static void bigdecimal_dump(VALUE obj, int depth, Out out) { - volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); - const char *str = rb_string_value_ptr((VALUE *)&rstr); - int len = (int)RSTRING_LEN(rstr); + volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); + const char *str = rb_string_value_ptr((VALUE*)&rstr); + int len = (int)RSTRING_LEN(rstr); if (0 == strcasecmp("Infinity", str)) { - str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len); - oj_dump_raw(str, len, out); + str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len); + oj_dump_raw(str, len, out); } else if (0 == strcasecmp("-Infinity", str)) { - str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len); - oj_dump_raw(str, len, out); + str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len); + oj_dump_raw(str, len, out); } else if (No == out->opts->bigdec_as_num) { - oj_dump_cstr(str, len, 0, 0, out); + oj_dump_cstr(str, len, 0, 0, out); } else { - oj_dump_raw(str, len, out); + oj_dump_raw(str, len, out); } } -static ID real_id = 0; -static ID imag_id = 0; +static ID real_id = 0; +static ID imag_id = 0; static void complex_dump(VALUE obj, int depth, Out out) { if (NULL != out->opts->create_id) { - struct _attr attrs[] = { - { "real", 4, Qnil }, - { "imag", 4, Qnil }, - { NULL, 0, Qnil }, - }; - if (0 == real_id) { - real_id = rb_intern("real"); - imag_id = rb_intern("imag"); - } - attrs[0].value = rb_funcall(obj, real_id, 0); - attrs[1].value = rb_funcall(obj, imag_id, 0); - - oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok); + struct _attr attrs[] = { + { "real", 4, Qnil }, + { "imag", 4, Qnil }, + { NULL, 0, Qnil }, + }; + if (0 == real_id) { + real_id = rb_intern("real"); + imag_id = rb_intern("imag"); + } + attrs[0].value = rb_funcall(obj, real_id, 0); + attrs[1].value = rb_funcall(obj, imag_id, 0); + + oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok); } else { - dump_obj_as_str(obj, depth, out); + dump_obj_as_str(obj, depth, out); } } static VALUE complex_load(VALUE clas, VALUE args) { if (0 == real_id) { - real_id = rb_intern("real"); - imag_id = rb_intern("imag"); + real_id = rb_intern("real"); + imag_id = rb_intern("imag"); } return rb_complex_new(rb_hash_aref(args, rb_id2str(real_id)), rb_hash_aref(args, rb_id2str(imag_id))); } @@ -93,107 +93,99 @@ complex_load(VALUE clas, VALUE args) { static void time_dump(VALUE obj, int depth, Out out) { if (Yes == out->opts->create_ok) { - struct _attr attrs[] = { - { "time", 4, Qundef, 0, Qundef }, - { NULL, 0, Qnil }, - }; - attrs->time = obj; + struct _attr attrs[] = { + { "time", 4, Qundef, 0, Qundef }, + { NULL, 0, Qnil }, + }; + attrs->time = obj; - oj_code_attrs(obj, attrs, depth, out, true); + oj_code_attrs(obj, attrs, depth, out, true); } else { - switch (out->opts->time_format) { - case RubyTime: - oj_dump_ruby_time(obj, out); - break; - case XmlTime: - oj_dump_xml_time(obj, out); - break; - case UnixZTime: - oj_dump_time(obj, out, true); - break; - case UnixTime: - default: - oj_dump_time(obj, out, false); - break; - } + switch (out->opts->time_format) { + case RubyTime: oj_dump_ruby_time(obj, out); break; + case XmlTime: oj_dump_xml_time(obj, out); break; + case UnixZTime: oj_dump_time(obj, out, true); break; + case UnixTime: + default: oj_dump_time(obj, out, false); break; + } } } static void date_dump(VALUE obj, int depth, Out out) { if (Yes == out->opts->create_ok) { - struct _attr attrs[] = { - { "s", 1, Qnil }, - { NULL, 0, Qnil }, - }; - attrs->value = rb_funcall(obj, rb_intern("iso8601"), 0); + struct _attr attrs[] = { + { "s", 1, Qnil }, + { NULL, 0, Qnil }, + }; + attrs->value = rb_funcall(obj, rb_intern("iso8601"), 0); - oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok); + oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok); } else { - volatile VALUE v; - volatile VALUE ov; - - switch (out->opts->time_format) { - case RubyTime: - case XmlTime: - v = rb_funcall(obj, rb_intern("iso8601"), 0); - oj_dump_cstr(rb_string_value_ptr((VALUE *)&v), (int)RSTRING_LEN(v), 0, 0, out); - break; - case UnixZTime: - v = rb_funcall(obj, rb_intern("to_time"), 0); - if (oj_date_class == rb_obj_class(obj)) { - ov = rb_funcall(v, rb_intern("utc_offset"), 0); - v = rb_funcall(v, rb_intern("utc"), 0); - v = rb_funcall(v, rb_intern("+"), 1, ov); - oj_dump_time(v, out, false); - } else { - oj_dump_time(v, out, true); - } - break; - case UnixTime: - default: - v = rb_funcall(obj, rb_intern("to_time"), 0); - if (oj_date_class == rb_obj_class(obj)) { - ov = rb_funcall(v, rb_intern("utc_offset"), 0); - v = rb_funcall(v, rb_intern("utc"), 0); - v = rb_funcall(v, rb_intern("+"), 1, ov); - } - oj_dump_time(v, out, false); - break; - } + volatile VALUE v; + volatile VALUE ov; + + switch (out->opts->time_format) { + case RubyTime: + case XmlTime: + v = rb_funcall(obj, rb_intern("iso8601"), 0); + oj_dump_cstr(rb_string_value_ptr((VALUE*)&v), (int)RSTRING_LEN(v), 0, 0, out); + break; + case UnixZTime: + v = rb_funcall(obj, rb_intern("to_time"), 0); + if (oj_date_class == rb_obj_class(obj)) { + ov = rb_funcall(v, rb_intern("utc_offset"), 0); + v = rb_funcall(v, rb_intern("utc"), 0); + v = rb_funcall(v, rb_intern("+"), 1, ov); + oj_dump_time(v, out, false); + } else { + oj_dump_time(v, out, true); + } + break; + case UnixTime: + default: + v = rb_funcall(obj, rb_intern("to_time"), 0); + if (oj_date_class == rb_obj_class(obj)) { + ov = rb_funcall(v, rb_intern("utc_offset"), 0); + v = rb_funcall(v, rb_intern("utc"), 0); + v = rb_funcall(v, rb_intern("+"), 1, ov); + } + oj_dump_time(v, out, false); + break; + } } } static VALUE date_load(VALUE clas, VALUE args) { - volatile VALUE v; + volatile VALUE v; if (Qnil != (v = rb_hash_aref(args, rb_str_new2("s")))) { - return rb_funcall(oj_date_class, rb_intern("parse"), 1, v); + return rb_funcall(oj_date_class, rb_intern("parse"), 1, v); } return Qnil; } static VALUE datetime_load(VALUE clas, VALUE args) { - volatile VALUE v; + volatile VALUE v; if (Qnil != (v = rb_hash_aref(args, rb_str_new2("s")))) { - return rb_funcall(oj_datetime_class, rb_intern("parse"), 1, v); + return rb_funcall(oj_datetime_class, rb_intern("parse"), 1, v); } return Qnil; } -static ID table_id = 0; +static ID table_id = 0; static void openstruct_dump(VALUE obj, int depth, Out out) { - struct _attr attrs[] = { - { "table", 5, Qnil }, - { NULL, 0, Qnil }, + struct _attr attrs[] = { + { "table", 5, Qnil }, + { NULL, 0, Qnil }, }; if (0 == table_id) { - table_id = rb_intern("table"); + table_id = rb_intern("table"); } attrs->value = rb_funcall(obj, table_id, 0); @@ -203,7 +195,7 @@ openstruct_dump(VALUE obj, int depth, Out out) { static VALUE openstruct_load(VALUE clas, VALUE args) { if (0 == table_id) { - table_id = rb_intern("table"); + table_id = rb_intern("table"); } return rb_funcall(clas, oj_new_id, 1, rb_hash_aref(args, rb_id2str(table_id))); } @@ -211,25 +203,25 @@ openstruct_load(VALUE clas, VALUE args) { static void range_dump(VALUE obj, int depth, Out out) { if (NULL != out->opts->create_id) { - struct _attr attrs[] = { - { "begin", 5, Qnil }, - { "end", 3, Qnil }, - { "exclude", 7, Qnil }, - { NULL, 0, Qnil }, - }; - attrs[0].value = rb_funcall(obj, oj_begin_id, 0); - attrs[1].value = rb_funcall(obj, oj_end_id, 0); - attrs[2].value = rb_funcall(obj, oj_exclude_end_id, 0); - - oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok); + struct _attr attrs[] = { + { "begin", 5, Qnil }, + { "end", 3, Qnil }, + { "exclude", 7, Qnil }, + { NULL, 0, Qnil }, + }; + attrs[0].value = rb_funcall(obj, oj_begin_id, 0); + attrs[1].value = rb_funcall(obj, oj_end_id, 0); + attrs[2].value = rb_funcall(obj, oj_exclude_end_id, 0); + + oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok); } else { - dump_obj_as_str(obj, depth, out); + dump_obj_as_str(obj, depth, out); } } static VALUE range_load(VALUE clas, VALUE args) { - VALUE nargs[3]; + VALUE nargs[3]; nargs[0] = rb_hash_aref(args, rb_id2str(oj_begin_id)); nargs[1] = rb_hash_aref(args, rb_id2str(oj_end_id)); @@ -238,46 +230,46 @@ range_load(VALUE clas, VALUE args) { return rb_class_new_instance(3, nargs, rb_cRange); } -static ID numerator_id = 0; -static ID denominator_id = 0; +static ID numerator_id = 0; +static ID denominator_id = 0; static void rational_dump(VALUE obj, int depth, Out out) { if (NULL != out->opts->create_id) { - struct _attr attrs[] = { - { "numerator", 9, Qnil }, - { "denominator", 11, Qnil }, - { NULL, 0, Qnil }, - }; - if (0 == numerator_id) { - numerator_id = rb_intern("numerator"); - denominator_id = rb_intern("denominator"); - } - attrs[0].value = rb_funcall(obj, numerator_id, 0); - attrs[1].value = rb_funcall(obj, denominator_id, 0); - - oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok); + struct _attr attrs[] = { + { "numerator", 9, Qnil }, + { "denominator", 11, Qnil }, + { NULL, 0, Qnil }, + }; + if (0 == numerator_id) { + numerator_id = rb_intern("numerator"); + denominator_id = rb_intern("denominator"); + } + attrs[0].value = rb_funcall(obj, numerator_id, 0); + attrs[1].value = rb_funcall(obj, denominator_id, 0); + + oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok); } else { - dump_obj_as_str(obj, depth, out); + dump_obj_as_str(obj, depth, out); } } static VALUE rational_load(VALUE clas, VALUE args) { if (0 == numerator_id) { - numerator_id = rb_intern("numerator"); - denominator_id = rb_intern("denominator"); + numerator_id = rb_intern("numerator"); + denominator_id = rb_intern("denominator"); } return rb_rational_new(rb_hash_aref(args, rb_id2str(numerator_id)), - rb_hash_aref(args, rb_id2str(denominator_id))); + rb_hash_aref(args, rb_id2str(denominator_id))); } static VALUE regexp_load(VALUE clas, VALUE args) { - volatile VALUE v; + volatile VALUE v; if (Qnil != (v = rb_hash_aref(args, rb_str_new2("s")))) { - return rb_funcall(rb_cRegexp, oj_new_id, 1, v); + return rb_funcall(rb_cRegexp, oj_new_id, 1, v); } return Qnil; } @@ -289,7 +281,7 @@ time_load(VALUE clas, VALUE args) { return args; } -static struct _code codes[] = { +static struct _code codes[] = { { "BigDecimal", Qnil, bigdecimal_dump, NULL, true }, { "Complex", Qnil, complex_dump, complex_load, true }, { "Date", Qnil, date_dump, date_load, true }, @@ -304,57 +296,57 @@ static struct _code codes[] = { static int hash_cb(VALUE key, VALUE value, VALUE ov) { - Out out = (Out)ov; - int depth = out->depth; + Out out = (Out)ov; + int depth = out->depth; if (oj_dump_ignore(out->opts, value)) { - return ST_CONTINUE; + return ST_CONTINUE; } if (out->omit_nil && Qnil == value) { - return ST_CONTINUE; + return ST_CONTINUE; } if (!out->opts->dump_opts.use) { - assure_size(out, depth * out->indent + 1); - fill_indent(out, depth); + assure_size(out, depth * out->indent + 1); + fill_indent(out, depth); } else { - assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1); - if (0 < out->opts->dump_opts.hash_size) { - strcpy(out->cur, out->opts->dump_opts.hash_nl); - out->cur += out->opts->dump_opts.hash_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - - for (i = depth; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } + assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1); + if (0 < out->opts->dump_opts.hash_size) { + strcpy(out->cur, out->opts->dump_opts.hash_nl); + out->cur += out->opts->dump_opts.hash_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + + for (i = depth; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } } switch (rb_type(key)) { - case T_STRING: - oj_dump_str(key, 0, out, false); - break; - case T_SYMBOL: - oj_dump_sym(key, 0, out, false); - break; - default: - oj_dump_str(rb_funcall(key, oj_to_s_id, 0), 0, out, false); - break; + case T_STRING: + oj_dump_str(key, 0, out, false); + break; + case T_SYMBOL: + oj_dump_sym(key, 0, out, false); + break; + default: + oj_dump_str(rb_funcall(key, oj_to_s_id, 0), 0, out, false); + break; } if (!out->opts->dump_opts.use) { - *out->cur++ = ':'; + *out->cur++ = ':'; } else { - assure_size(out, out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2); - if (0 < out->opts->dump_opts.before_size) { - strcpy(out->cur, out->opts->dump_opts.before_sep); - out->cur += out->opts->dump_opts.before_size; - } - *out->cur++ = ':'; - if (0 < out->opts->dump_opts.after_size) { - strcpy(out->cur, out->opts->dump_opts.after_sep); - out->cur += out->opts->dump_opts.after_size; - } + assure_size(out, out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2); + if (0 < out->opts->dump_opts.before_size) { + strcpy(out->cur, out->opts->dump_opts.before_sep); + out->cur += out->opts->dump_opts.before_size; + } + *out->cur++ = ':'; + if (0 < out->opts->dump_opts.after_size) { + strcpy(out->cur, out->opts->dump_opts.after_sep); + out->cur += out->opts->dump_opts.after_size; + } } oj_dump_custom_val(value, depth, out, true); out->depth = depth; @@ -365,156 +357,156 @@ hash_cb(VALUE key, VALUE value, VALUE ov) { static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) { - int cnt; - long id = oj_check_circular(obj, out); + int cnt; + long id = oj_check_circular(obj, out); if (0 > id) { - oj_dump_nil(Qnil, depth, out, false); - return; + oj_dump_nil(Qnil, depth, out, false); + return; } cnt = (int)RHASH_SIZE(obj); assure_size(out, 2); if (0 == cnt) { - *out->cur++ = '{'; - *out->cur++ = '}'; + *out->cur++ = '{'; + *out->cur++ = '}'; } else { - *out->cur++ = '{'; - out->depth = depth + 1; - rb_hash_foreach(obj, hash_cb, (VALUE)out); - if (',' == *(out->cur - 1)) { - out->cur--; // backup to overwrite last comma - } - if (!out->opts->dump_opts.use) { - assure_size(out, depth * out->indent + 2); - fill_indent(out, depth); - } else { - assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1); - if (0 < out->opts->dump_opts.hash_size) { - strcpy(out->cur, out->opts->dump_opts.hash_nl); - out->cur += out->opts->dump_opts.hash_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - - for (i = depth; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - } - *out->cur++ = '}'; + *out->cur++ = '{'; + out->depth = depth + 1; + rb_hash_foreach(obj, hash_cb, (VALUE)out); + if (',' == *(out->cur - 1)) { + out->cur--; // backup to overwrite last comma + } + if (!out->opts->dump_opts.use) { + assure_size(out, depth * out->indent + 2); + fill_indent(out, depth); + } else { + assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1); + if (0 < out->opts->dump_opts.hash_size) { + strcpy(out->cur, out->opts->dump_opts.hash_nl); + out->cur += out->opts->dump_opts.hash_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + + for (i = depth; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + } + *out->cur++ = '}'; } *out->cur = '\0'; } static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) { - ID *idp; - AttrGetFunc *fp; - volatile VALUE v; - const char *name; - size_t size; - int d2 = depth + 1; + ID *idp; + AttrGetFunc *fp; + volatile VALUE v; + const char *name; + size_t size; + int d2 = depth + 1; assure_size(out, 2); *out->cur++ = '{'; if (NULL != out->opts->create_id && Yes == out->opts->create_ok) { - const char *classname = rb_class2name(clas); - int clen = (int)strlen(classname); - size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2; - - size = d2 * out->indent + 10 + clen + out->opts->create_id_len + sep_len; - assure_size(out, size); - fill_indent(out, d2); - *out->cur++ = '"'; - memcpy(out->cur, out->opts->create_id, out->opts->create_id_len); - out->cur += out->opts->create_id_len; - *out->cur++ = '"'; - if (0 < out->opts->dump_opts.before_size) { - strcpy(out->cur, out->opts->dump_opts.before_sep); - out->cur += out->opts->dump_opts.before_size; - } - *out->cur++ = ':'; - if (0 < out->opts->dump_opts.after_size) { - strcpy(out->cur, out->opts->dump_opts.after_sep); - out->cur += out->opts->dump_opts.after_size; - } - *out->cur++ = '"'; - memcpy(out->cur, classname, clen); - out->cur += clen; - *out->cur++ = '"'; - *out->cur++ = ','; + const char *classname = rb_class2name(clas); + int clen = (int)strlen(classname); + size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2; + + size = d2 * out->indent + 10 + clen + out->opts->create_id_len + sep_len; + assure_size(out, size); + fill_indent(out, d2); + *out->cur++ = '"'; + memcpy(out->cur, out->opts->create_id, out->opts->create_id_len); + out->cur += out->opts->create_id_len; + *out->cur++ = '"'; + if (0 < out->opts->dump_opts.before_size) { + strcpy(out->cur, out->opts->dump_opts.before_sep); + out->cur += out->opts->dump_opts.before_size; + } + *out->cur++ = ':'; + if (0 < out->opts->dump_opts.after_size) { + strcpy(out->cur, out->opts->dump_opts.after_sep); + out->cur += out->opts->dump_opts.after_size; + } + *out->cur++ = '"'; + memcpy(out->cur, classname, clen); + out->cur += clen; + *out->cur++ = '"'; + *out->cur++ = ','; } if (odd->raw) { - v = rb_funcall(obj, *odd->attrs, 0); - if (Qundef == v || T_STRING != rb_type(v)) { - rb_raise(rb_eEncodingError, "Invalid type for raw JSON.\n"); - } else { - const char *s = rb_string_value_ptr((VALUE *)&v); - int len = (int)RSTRING_LEN(v); - const char *name = rb_id2name(*odd->attrs); - size_t nlen = strlen(name); - - size = len + d2 * out->indent + nlen + 10; - assure_size(out, size); - fill_indent(out, d2); - *out->cur++ = '"'; - memcpy(out->cur, name, nlen); - out->cur += nlen; - *out->cur++ = '"'; - *out->cur++ = ':'; - memcpy(out->cur, s, len); - out->cur += len; - *out->cur = '\0'; - } + v = rb_funcall(obj, *odd->attrs, 0); + if (Qundef == v || T_STRING != rb_type(v)) { + rb_raise(rb_eEncodingError, "Invalid type for raw JSON.\n"); + } else { + const char *s = rb_string_value_ptr((VALUE*)&v); + int len = (int)RSTRING_LEN(v); + const char *name = rb_id2name(*odd->attrs); + size_t nlen = strlen(name); + + size = len + d2 * out->indent + nlen + 10; + assure_size(out, size); + fill_indent(out, d2); + *out->cur++ = '"'; + memcpy(out->cur, name, nlen); + out->cur += nlen; + *out->cur++ = '"'; + *out->cur++ = ':'; + memcpy(out->cur, s, len); + out->cur += len; + *out->cur = '\0'; + } } else { - size = d2 * out->indent + 1; - for (idp = odd->attrs, fp = odd->attrFuncs; 0 != *idp; idp++, fp++) { - size_t nlen; - - assure_size(out, size); - name = rb_id2name(*idp); - nlen = strlen(name); - if (0 != *fp) { - v = (*fp)(obj); - } else if (0 == strchr(name, '.')) { - v = rb_funcall(obj, *idp, 0); - } else { - char nbuf[256]; - char *n2 = nbuf; - char *n; - char *end; - ID i; - - if (sizeof(nbuf) <= nlen) { - if (NULL == (n2 = strdup(name))) { - rb_raise(rb_eNoMemError, "for attribute name."); - } - } else { - strcpy(n2, name); - } - n = n2; - v = obj; - while (0 != (end = strchr(n, '.'))) { - *end = '\0'; - i = rb_intern(n); - v = rb_funcall(v, i, 0); - n = end + 1; - } - i = rb_intern(n); - v = rb_funcall(v, i, 0); - if (nbuf != n2) { - free(n2); - } - } - fill_indent(out, d2); - oj_dump_cstr(name, nlen, 0, 0, out); - *out->cur++ = ':'; - oj_dump_custom_val(v, d2, out, true); - assure_size(out, 2); - *out->cur++ = ','; - } - out->cur--; + size = d2 * out->indent + 1; + for (idp = odd->attrs, fp = odd->attrFuncs; 0 != *idp; idp++, fp++) { + size_t nlen; + + assure_size(out, size); + name = rb_id2name(*idp); + nlen = strlen(name); + if (0 != *fp) { + v = (*fp)(obj); + } else if (0 == strchr(name, '.')) { + v = rb_funcall(obj, *idp, 0); + } else { + char nbuf[256]; + char *n2 = nbuf; + char *n; + char *end; + ID i; + + if (sizeof(nbuf) <= nlen) { + if (NULL == (n2 = strdup(name))) { + rb_raise(rb_eNoMemError, "for attribute name."); + } + } else { + strcpy(n2, name); + } + n = n2; + v = obj; + while (0 != (end = strchr(n, '.'))) { + *end = '\0'; + i = rb_intern(n); + v = rb_funcall(v, i, 0); + n = end + 1; + } + i = rb_intern(n); + v = rb_funcall(v, i, 0); + if (nbuf != n2) { + free(n2); + } + } + fill_indent(out, d2); + oj_dump_cstr(name, nlen, 0, 0, out); + *out->cur++ = ':'; + oj_dump_custom_val(v, d2, out, true); + assure_size(out, 2); + *out->cur++ = ','; + } + out->cur--; } *out->cur++ = '}'; *out->cur = '\0'; @@ -525,116 +517,116 @@ static VALUE dump_common(VALUE obj, int depth, Out out) { if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) { - oj_dump_raw_json(obj, depth, out); + oj_dump_raw_json(obj, depth, out); } else if (Yes == out->opts->to_json && rb_respond_to(obj, oj_to_json_id)) { - volatile VALUE rs; - const char *s; - int len; - - if (Yes == out->opts->trace) { - oj_trace("to_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn); - } - if (0 == rb_obj_method_arity(obj, oj_to_json_id)) { - rs = rb_funcall(obj, oj_to_json_id, 0); - } else { - rs = rb_funcall2(obj, oj_to_json_id, out->argc, out->argv); - } - if (Yes == out->opts->trace) { - oj_trace("to_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut); - } - s = rb_string_value_ptr((VALUE *)&rs); - len = (int)RSTRING_LEN(rs); - - assure_size(out, len + 1); - memcpy(out->cur, s, len); - out->cur += len; - *out->cur = '\0'; + volatile VALUE rs; + const char *s; + int len; + + if (Yes == out->opts->trace) { + oj_trace("to_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn); + } + if (0 == rb_obj_method_arity(obj, oj_to_json_id)) { + rs = rb_funcall(obj, oj_to_json_id, 0); + } else { + rs = rb_funcall2(obj, oj_to_json_id, out->argc, out->argv); + } + if (Yes == out->opts->trace) { + oj_trace("to_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut); + } + s = rb_string_value_ptr((VALUE*)&rs); + len = (int)RSTRING_LEN(rs); + + assure_size(out, len + 1); + memcpy(out->cur, s, len); + out->cur += len; + *out->cur = '\0'; } else if (Yes == out->opts->as_json && rb_respond_to(obj, oj_as_json_id)) { - volatile VALUE aj; - - if (Yes == out->opts->trace) { - oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn); - } - // Some classes elect to not take an options argument so check the arity - // of as_json. - if (0 == rb_obj_method_arity(obj, oj_as_json_id)) { - aj = rb_funcall(obj, oj_as_json_id, 0); - } else { - aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv); - } - if (Yes == out->opts->trace) { - oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut); - } - // Catch the obvious brain damaged recursive dumping. - if (aj == obj) { - volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); - - oj_dump_cstr(rb_string_value_ptr((VALUE *)&rstr), (int)RSTRING_LEN(rstr), false, false, out); - } else { - oj_dump_custom_val(aj, depth, out, true); - } + volatile VALUE aj; + + if (Yes == out->opts->trace) { + oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn); + } + // Some classes elect to not take an options argument so check the arity + // of as_json. + if (0 == rb_obj_method_arity(obj, oj_as_json_id)) { + aj = rb_funcall(obj, oj_as_json_id, 0); + } else { + aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv); + } + if (Yes == out->opts->trace) { + oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut); + } + // Catch the obvious brain damaged recursive dumping. + if (aj == obj) { + volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); + + oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), false, false, out); + } else { + oj_dump_custom_val(aj, depth, out, true); + } } else if (Yes == out->opts->to_hash && rb_respond_to(obj, oj_to_hash_id)) { - volatile VALUE h = rb_funcall(obj, oj_to_hash_id, 0); - - if (T_HASH != rb_type(h)) { - // It seems that ActiveRecord implemented to_hash so that it returns - // an Array and not a Hash. To get around that any value returned - // will be dumped. - - //rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n", rb_class2name(rb_obj_class(obj))); - oj_dump_custom_val(h, depth, out, false); - } else { - dump_hash(h, depth, out, true); - } + volatile VALUE h = rb_funcall(obj, oj_to_hash_id, 0); + + if (T_HASH != rb_type(h)) { + // It seems that ActiveRecord implemented to_hash so that it returns + // an Array and not a Hash. To get around that any value returned + // will be dumped. + + //rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n", rb_class2name(rb_obj_class(obj))); + oj_dump_custom_val(h, depth, out, false); + } else { + dump_hash(h, depth, out, true); + } } else if (!oj_code_dump(codes, obj, depth, out)) { - VALUE clas = rb_obj_class(obj); - Odd odd = oj_get_odd(clas); + VALUE clas = rb_obj_class(obj); + Odd odd = oj_get_odd(clas); - if (NULL == odd) { - return clas; - } - dump_odd(obj, odd, clas, depth + 1, out); + if (NULL == odd) { + return clas; + } + dump_odd(obj, odd, clas, depth + 1, out); } return Qnil; } static int dump_attr_cb(ID key, VALUE value, VALUE ov) { - Out out = (Out)ov; - int depth = out->depth; - size_t size; - const char *attr; + Out out = (Out)ov; + int depth = out->depth; + size_t size; + const char *attr; if (oj_dump_ignore(out->opts, value)) { - return ST_CONTINUE; + return ST_CONTINUE; } if (out->omit_nil && Qnil == value) { - return ST_CONTINUE; + return ST_CONTINUE; } size = depth * out->indent + 1; attr = rb_id2name(key); // Some exceptions such as NoMethodError have an invisible attribute where // the key name is NULL. Not an empty string but NULL. if (NULL == attr) { - attr = ""; + attr = ""; } else if (Yes == out->opts->ignore_under && '@' == *attr && '_' == attr[1]) { - return ST_CONTINUE; + return ST_CONTINUE; } if (0 == strcmp("bt", attr) || 0 == strcmp("mesg", attr)) { - return ST_CONTINUE; + return ST_CONTINUE; } assure_size(out, size); fill_indent(out, depth); if ('@' == *attr) { - attr++; - oj_dump_cstr(attr, strlen(attr), 0, 0, out); + attr++; + oj_dump_cstr(attr, strlen(attr), 0, 0, out); } else { - char buf[32]; + char buf[32]; - *buf = '~'; - strncpy(buf + 1, attr, sizeof(buf) - 2); - buf[sizeof(buf) - 1] = '\0'; - oj_dump_cstr(buf, strlen(buf), 0, 0, out); + *buf = '~'; + strncpy(buf + 1, attr, sizeof(buf) - 2); + buf[sizeof(buf) - 1] = '\0'; + oj_dump_cstr(buf, strlen(buf), 0, 0, out); } *out->cur++ = ':'; oj_dump_custom_val(value, depth, out, true); @@ -646,79 +638,79 @@ dump_attr_cb(ID key, VALUE value, VALUE ov) { static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out) { - size_t size = 0; - int d2 = depth + 1; - int cnt; - bool class_written = false; + size_t size = 0; + int d2 = depth + 1; + int cnt; + bool class_written = false; assure_size(out, 2); *out->cur++ = '{'; if (Qundef != clas && NULL != out->opts->create_id && Yes == out->opts->create_ok) { - size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2; - const char *classname = rb_obj_classname(obj); - size_t len = strlen(classname); - - size = d2 * out->indent + 10 + len + out->opts->create_id_len + sep_len; - assure_size(out, size); - fill_indent(out, d2); - *out->cur++ = '"'; - memcpy(out->cur, out->opts->create_id, out->opts->create_id_len); - out->cur += out->opts->create_id_len; - *out->cur++ = '"'; - if (0 < out->opts->dump_opts.before_size) { - strcpy(out->cur, out->opts->dump_opts.before_sep); - out->cur += out->opts->dump_opts.before_size; - } - *out->cur++ = ':'; - if (0 < out->opts->dump_opts.after_size) { - strcpy(out->cur, out->opts->dump_opts.after_sep); - out->cur += out->opts->dump_opts.after_size; - } - *out->cur++ = '"'; - memcpy(out->cur, classname, len); - out->cur += len; - *out->cur++ = '"'; - class_written = true; + size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2; + const char *classname = rb_obj_classname(obj); + size_t len = strlen(classname); + + size = d2 * out->indent + 10 + len + out->opts->create_id_len + sep_len; + assure_size(out, size); + fill_indent(out, d2); + *out->cur++ = '"'; + memcpy(out->cur, out->opts->create_id, out->opts->create_id_len); + out->cur += out->opts->create_id_len; + *out->cur++ = '"'; + if (0 < out->opts->dump_opts.before_size) { + strcpy(out->cur, out->opts->dump_opts.before_sep); + out->cur += out->opts->dump_opts.before_size; + } + *out->cur++ = ':'; + if (0 < out->opts->dump_opts.after_size) { + strcpy(out->cur, out->opts->dump_opts.after_sep); + out->cur += out->opts->dump_opts.after_size; + } + *out->cur++ = '"'; + memcpy(out->cur, classname, len); + out->cur += len; + *out->cur++ = '"'; + class_written = true; } cnt = (int)rb_ivar_count(obj); if (class_written) { - *out->cur++ = ','; + *out->cur++ = ','; } if (0 == cnt && Qundef == clas) { - // Might be something special like an Enumerable. - if (Qtrue == rb_obj_is_kind_of(obj, oj_enumerable_class)) { - out->cur--; - oj_dump_custom_val(rb_funcall(obj, rb_intern("entries"), 0), depth, out, false); - return; - } + // Might be something special like an Enumerable. + if (Qtrue == rb_obj_is_kind_of(obj, oj_enumerable_class)) { + out->cur--; + oj_dump_custom_val(rb_funcall(obj, rb_intern("entries"), 0), depth, out, false); + return; + } } out->depth = depth + 1; rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out); if (',' == *(out->cur - 1)) { - out->cur--; // backup to overwrite last comma + out->cur--; // backup to overwrite last comma } if (rb_obj_is_kind_of(obj, rb_eException)) { - volatile VALUE rv; - - if (',' != *(out->cur - 1)) { - *out->cur++ = ','; - } - // message - assure_size(out, 2); - fill_indent(out, d2); - oj_dump_cstr("~mesg", 5, 0, 0, out); - *out->cur++ = ':'; - rv = rb_funcall2(obj, rb_intern("message"), 0, 0); - oj_dump_custom_val(rv, d2, out, true); - assure_size(out, size + 2); - *out->cur++ = ','; - // backtrace - fill_indent(out, d2); - oj_dump_cstr("~bt", 3, 0, 0, out); - *out->cur++ = ':'; - rv = rb_funcall2(obj, rb_intern("backtrace"), 0, 0); - oj_dump_custom_val(rv, d2, out, true); - assure_size(out, 2); + volatile VALUE rv; + + if (',' != *(out->cur - 1)) { + *out->cur++ = ','; + } + // message + assure_size(out, 2); + fill_indent(out, d2); + oj_dump_cstr("~mesg", 5, 0, 0, out); + *out->cur++ = ':'; + rv = rb_funcall2(obj, rb_intern("message"), 0, 0); + oj_dump_custom_val(rv, d2, out, true); + assure_size(out, size + 2); + *out->cur++ = ','; + // backtrace + fill_indent(out, d2); + oj_dump_cstr("~bt", 3, 0, 0, out); + *out->cur++ = ':'; + rv = rb_funcall2(obj, rb_intern("backtrace"), 0, 0); + oj_dump_custom_val(rv, d2, out, true); + assure_size(out, 2); } out->depth = depth; @@ -729,184 +721,184 @@ dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out) { static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) { - long id = oj_check_circular(obj, out); - VALUE clas; + long id = oj_check_circular(obj, out); + VALUE clas; if (0 > id) { - oj_dump_nil(Qnil, depth, out, false); + oj_dump_nil(Qnil, depth, out, false); } else if (Qnil != (clas = dump_common(obj, depth, out))) { - dump_obj_attrs(obj, clas, 0, depth, out); + dump_obj_attrs(obj, clas, 0, depth, out); } *out->cur = '\0'; } static void dump_array(VALUE a, int depth, Out out, bool as_ok) { - size_t size; - int i, cnt; - int d2 = depth + 1; - long id = oj_check_circular(a, out); + size_t size; + int i, cnt; + int d2 = depth + 1; + long id = oj_check_circular(a, out); if (0 > id) { - oj_dump_nil(Qnil, depth, out, false); - return; + oj_dump_nil(Qnil, depth, out, false); + return; } cnt = (int)RARRAY_LEN(a); *out->cur++ = '['; assure_size(out, 2); if (0 == cnt) { - *out->cur++ = ']'; + *out->cur++ = ']'; } else { - if (out->opts->dump_opts.use) { - size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1; - } else { - size = d2 * out->indent + 2; - } - cnt--; - for (i = 0; i <= cnt; i++) { - assure_size(out, size); - if (out->opts->dump_opts.use) { - if (0 < out->opts->dump_opts.array_size) { - strcpy(out->cur, out->opts->dump_opts.array_nl); - out->cur += out->opts->dump_opts.array_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - for (i = d2; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - } else { - fill_indent(out, d2); - } - oj_dump_custom_val(rb_ary_entry(a, i), d2, out, true); - if (i < cnt) { - *out->cur++ = ','; - } - } - size = depth * out->indent + 1; - assure_size(out, size); - if (out->opts->dump_opts.use) { - if (0 < out->opts->dump_opts.array_size) { - strcpy(out->cur, out->opts->dump_opts.array_nl); - out->cur += out->opts->dump_opts.array_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - - for (i = depth; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - } else { - fill_indent(out, depth); - } - *out->cur++ = ']'; + if (out->opts->dump_opts.use) { + size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1; + } else { + size = d2 * out->indent + 2; + } + cnt--; + for (i = 0; i <= cnt; i++) { + assure_size(out, size); + if (out->opts->dump_opts.use) { + if (0 < out->opts->dump_opts.array_size) { + strcpy(out->cur, out->opts->dump_opts.array_nl); + out->cur += out->opts->dump_opts.array_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + for (i = d2; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + } else { + fill_indent(out, d2); + } + oj_dump_custom_val(rb_ary_entry(a, i), d2, out, true); + if (i < cnt) { + *out->cur++ = ','; + } + } + size = depth * out->indent + 1; + assure_size(out, size); + if (out->opts->dump_opts.use) { + if (0 < out->opts->dump_opts.array_size) { + strcpy(out->cur, out->opts->dump_opts.array_nl); + out->cur += out->opts->dump_opts.array_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + + for (i = depth; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + } else { + fill_indent(out, depth); + } + *out->cur++ = ']'; } *out->cur = '\0'; } static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) { - long id = oj_check_circular(obj, out); - VALUE clas; + long id = oj_check_circular(obj, out); + VALUE clas; if (0 > id) { - oj_dump_nil(Qnil, depth, out, false); + oj_dump_nil(Qnil, depth, out, false); } else if (Qnil != (clas = dump_common(obj, depth, out))) { - VALUE ma = Qnil; - VALUE v; - char num_id[32]; - int i; - int d2 = depth + 1; - int d3 = d2 + 1; - size_t size = d2 * out->indent + d3 * out->indent + 3; - const char *name; - int cnt; - size_t len; - - assure_size(out, size); - if (clas == rb_cRange) { - *out->cur++ = '"'; - oj_dump_custom_val(rb_funcall(obj, oj_begin_id, 0), d3, out, false); - assure_size(out, 3); - *out->cur++ = '.'; - *out->cur++ = '.'; - if (Qtrue == rb_funcall(obj, oj_exclude_end_id, 0)) { - *out->cur++ = '.'; - } - oj_dump_custom_val(rb_funcall(obj, oj_end_id, 0), d3, out, false); - *out->cur++ = '"'; - - return; - } - *out->cur++ = '{'; - fill_indent(out, d2); - size = d3 * out->indent + 2; - ma = rb_struct_s_members(clas); + VALUE ma = Qnil; + VALUE v; + char num_id[32]; + int i; + int d2 = depth + 1; + int d3 = d2 + 1; + size_t size = d2 * out->indent + d3 * out->indent + 3; + const char *name; + int cnt; + size_t len; + + assure_size(out, size); + if (clas == rb_cRange) { + *out->cur++ = '"'; + oj_dump_custom_val(rb_funcall(obj, oj_begin_id, 0), d3, out, false); + assure_size(out, 3); + *out->cur++ = '.'; + *out->cur++ = '.'; + if (Qtrue == rb_funcall(obj, oj_exclude_end_id, 0)) { + *out->cur++ = '.'; + } + oj_dump_custom_val(rb_funcall(obj, oj_end_id, 0), d3, out, false); + *out->cur++ = '"'; + + return; + } + *out->cur++ = '{'; + fill_indent(out, d2); + size = d3 * out->indent + 2; + ma = rb_struct_s_members(clas); #ifdef RSTRUCT_LEN #if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT - cnt = (int)NUM2LONG(RSTRUCT_LEN(obj)); -#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT - cnt = (int)RSTRUCT_LEN(obj); + cnt = (int)NUM2LONG(RSTRUCT_LEN(obj)); +#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT + cnt = (int)RSTRUCT_LEN(obj); #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT #else - // This is a bit risky as a struct in C ruby is not the same as a Struct - // class in interpreted Ruby so length() may not be defined. - cnt = FIX2INT(rb_funcall2(obj, oj_length_id, 0, 0)); + // This is a bit risky as a struct in C ruby is not the same as a Struct + // class in interpreted Ruby so length() may not be defined. + cnt = FIX2INT(rb_funcall2(obj, oj_length_id, 0, 0)); #endif - for (i = 0; i < cnt; i++) { + for (i = 0; i < cnt; i++) { #ifdef RSTRUCT_LEN - v = RSTRUCT_GET(obj, i); + v = RSTRUCT_GET(obj, i); #else - v = rb_struct_aref(obj, INT2FIX(i)); + v = rb_struct_aref(obj, INT2FIX(i)); #endif - if (ma != Qnil) { - volatile VALUE s = rb_sym_to_s(rb_ary_entry(ma, i)); - - name = rb_string_value_ptr((VALUE *)&s); - len = (int)RSTRING_LEN(s); - } else { - len = snprintf(num_id, sizeof(num_id), "%d", i); - name = num_id; - } - assure_size(out, size + len + 3); - fill_indent(out, d3); - *out->cur++ = '"'; - memcpy(out->cur, name, len); - out->cur += len; - *out->cur++ = '"'; - *out->cur++ = ':'; - oj_dump_custom_val(v, d3, out, true); - *out->cur++ = ','; - } - out->cur--; - *out->cur++ = '}'; - *out->cur = '\0'; + if (ma != Qnil) { + volatile VALUE s = rb_sym_to_s(rb_ary_entry(ma, i)); + + name = rb_string_value_ptr((VALUE*)&s); + len = (int)RSTRING_LEN(s); + } else { + len = snprintf(num_id, sizeof(num_id), "%d", i); + name = num_id; + } + assure_size(out, size + len + 3); + fill_indent(out, d3); + *out->cur++ = '"'; + memcpy(out->cur, name, len); + out->cur += len; + *out->cur++ = '"'; + *out->cur++ = ':'; + oj_dump_custom_val(v, d3, out, true); + *out->cur++ = ','; + } + out->cur--; + *out->cur++ = '}'; + *out->cur = '\0'; } } static void dump_data(VALUE obj, int depth, Out out, bool as_ok) { - long id = oj_check_circular(obj, out); - VALUE clas; + long id = oj_check_circular(obj, out); + VALUE clas; if (0 > id) { - oj_dump_nil(Qnil, depth, out, false); + oj_dump_nil(Qnil, depth, out, false); } else if (Qnil != (clas = dump_common(obj, depth, out))) { - dump_obj_attrs(obj, clas, id, depth, out); + dump_obj_attrs(obj, clas, id, depth, out); } } static void dump_regexp(VALUE obj, int depth, Out out, bool as_ok) { if (NULL != out->opts->create_id) { - dump_obj_str(obj, depth, out); + dump_obj_str(obj, depth, out); } else { - dump_obj_as_str(obj, depth, out); + dump_obj_as_str(obj, depth, out); } } @@ -920,55 +912,55 @@ dump_rational(VALUE obj, int depth, Out out, bool as_ok) { rational_dump(obj, depth, out); } -static DumpFunc custom_funcs[] = { - NULL, // RUBY_T_NONE = 0x00, - dump_obj, // RUBY_T_OBJECT = 0x01, - oj_dump_class, // RUBY_T_CLASS = 0x02, - oj_dump_class, // RUBY_T_MODULE = 0x03, - oj_dump_float, // RUBY_T_FLOAT = 0x04, - oj_dump_str, // RUBY_T_STRING = 0x05, - dump_regexp, // RUBY_T_REGEXP = 0x06, - dump_array, // RUBY_T_ARRAY = 0x07, - dump_hash, // RUBY_T_HASH = 0x08, - dump_struct, // RUBY_T_STRUCT = 0x09, - oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a, - NULL, // RUBY_T_FILE = 0x0b, - dump_data, // RUBY_T_DATA = 0x0c, - NULL, // RUBY_T_MATCH = 0x0d, - dump_complex, // RUBY_T_COMPLEX = 0x0e, - dump_rational, // RUBY_T_RATIONAL = 0x0f, - NULL, // 0x10 - oj_dump_nil, // RUBY_T_NIL = 0x11, - oj_dump_true, // RUBY_T_TRUE = 0x12, - oj_dump_false, // RUBY_T_FALSE = 0x13, - oj_dump_sym, // RUBY_T_SYMBOL = 0x14, - oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15, +static DumpFunc custom_funcs[] = { + NULL, // RUBY_T_NONE = 0x00, + dump_obj, // RUBY_T_OBJECT = 0x01, + oj_dump_class, // RUBY_T_CLASS = 0x02, + oj_dump_class, // RUBY_T_MODULE = 0x03, + oj_dump_float, // RUBY_T_FLOAT = 0x04, + oj_dump_str, // RUBY_T_STRING = 0x05, + dump_regexp, // RUBY_T_REGEXP = 0x06, + dump_array, // RUBY_T_ARRAY = 0x07, + dump_hash, // RUBY_T_HASH = 0x08, + dump_struct, // RUBY_T_STRUCT = 0x09, + oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a, + NULL, // RUBY_T_FILE = 0x0b, + dump_data, // RUBY_T_DATA = 0x0c, + NULL, // RUBY_T_MATCH = 0x0d, + dump_complex, // RUBY_T_COMPLEX = 0x0e, + dump_rational, // RUBY_T_RATIONAL = 0x0f, + NULL, // 0x10 + oj_dump_nil, // RUBY_T_NIL = 0x11, + oj_dump_true, // RUBY_T_TRUE = 0x12, + oj_dump_false, // RUBY_T_FALSE = 0x13, + oj_dump_sym, // RUBY_T_SYMBOL = 0x14, + oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15, }; void oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) { - int type = rb_type(obj); + int type = rb_type(obj); if (Yes == out->opts->trace) { - oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn); + oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn); } if (MAX_DEPTH < depth) { - rb_raise(rb_eNoMemError, "Too deeply nested.\n"); + rb_raise(rb_eNoMemError, "Too deeply nested.\n"); } if (0 < type && type <= RUBY_T_FIXNUM) { - DumpFunc f = custom_funcs[type]; - - if (NULL != f) { - f(obj, depth, out, true); - if (Yes == out->opts->trace) { - oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut); - } - return; - } + DumpFunc f = custom_funcs[type]; + + if (NULL != f) { + f(obj, depth, out, true); + if (Yes == out->opts->trace) { + oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut); + } + return; + } } oj_dump_nil(Qnil, depth, out, false); if (Yes == out->opts->trace) { - oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut); + oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut); } } @@ -976,202 +968,202 @@ oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) { static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) { - const char *key = kval->key; - int klen = kval->klen; - Val parent = stack_peek(&pi->stack); - volatile VALUE rkey = kval->key_val; + const char *key = kval->key; + int klen = kval->klen; + Val parent = stack_peek(&pi->stack); + volatile VALUE rkey = kval->key_val; if (Qundef == rkey && - Yes == pi->options.create_ok && - NULL != pi->options.create_id && - *pi->options.create_id == *key && - (int)pi->options.create_id_len == klen && - 0 == strncmp(pi->options.create_id, key, klen)) { - - parent->clas = oj_name2class(pi, str, len, false, rb_eArgError); - if (2 == klen && '^' == *key && 'o' == key[1]) { - if (Qundef != parent->clas) { - if (!oj_code_has(codes, parent->clas, false)) { - parent->val = rb_obj_alloc(parent->clas); - } - } - } + Yes == pi->options.create_ok && + NULL != pi->options.create_id && + *pi->options.create_id == *key && + (int)pi->options.create_id_len == klen && + 0 == strncmp(pi->options.create_id, key, klen)) { + + parent->clas = oj_name2class(pi, str, len, false, rb_eArgError); + if (2 == klen && '^' == *key && 'o' == key[1]) { + if (Qundef != parent->clas) { + if (!oj_code_has(codes, parent->clas, false)) { + parent->val = rb_obj_alloc(parent->clas); + } + } + } } else { - volatile VALUE rstr = rb_str_new(str, len); - - if (Qundef == rkey) { - rkey = rb_str_new(key, klen); - rstr = oj_encode(rstr); - rkey = oj_encode(rkey); - if (Yes == pi->options.sym_key) { - rkey = rb_str_intern(rkey); - } - } - if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) { - VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len); - - if (Qnil != clas) { - rstr = rb_funcall(clas, oj_json_create_id, 1, rstr); - } - } - switch (rb_type(parent->val)) { - case T_OBJECT: - oj_set_obj_ivar(parent, kval, rstr); - break; - case T_HASH: - if (4 == parent->klen && NULL != parent->key && rb_cTime == parent->clas && 0 == strncmp("time", parent->key, 4)) { - if (Qnil == (parent->val = oj_parse_xml_time(str, (int)len))) { - parent->val = rb_funcall(rb_cTime, rb_intern("parse"), 1, rb_str_new(str, len)); - } - } else { - rb_hash_aset(parent->val, rkey, rstr); - } - break; - default: - break; - } - if (Yes == pi->options.trace) { - oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr); - } + volatile VALUE rstr = rb_str_new(str, len); + + if (Qundef == rkey) { + rkey = rb_str_new(key, klen); + rstr = oj_encode(rstr); + rkey = oj_encode(rkey); + if (Yes == pi->options.sym_key) { + rkey = rb_str_intern(rkey); + } + } + if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) { + VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len); + + if (Qnil != clas) { + rstr = rb_funcall(clas, oj_json_create_id, 1, rstr); + } + } + switch (rb_type(parent->val)) { + case T_OBJECT: + oj_set_obj_ivar(parent, kval, rstr); + break; + case T_HASH: + if (4 == parent->klen && NULL != parent->key && rb_cTime == parent->clas && 0 == strncmp("time", parent->key, 4)) { + if (Qnil == (parent->val = oj_parse_xml_time(str, (int)len))) { + parent->val = rb_funcall(rb_cTime, rb_intern("parse"), 1, rb_str_new(str, len)); + } + } else { + rb_hash_aset(parent->val, rkey, rstr); + } + break; + default: + break; + } + if (Yes == pi->options.trace) { + oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr); + } } } static void end_hash(struct _parseInfo *pi) { - Val parent = stack_peek(&pi->stack); + Val parent = stack_peek(&pi->stack); if (Qundef != parent->clas && parent->clas != rb_obj_class(parent->val)) { - volatile VALUE obj = oj_code_load(codes, parent->clas, parent->val); - - if (Qnil != obj) { - parent->val = obj; - } else { - parent->val = rb_funcall(parent->clas, oj_json_create_id, 1, parent->val); - } - parent->clas = Qundef; + volatile VALUE obj = oj_code_load(codes, parent->clas, parent->val); + + if (Qnil != obj) { + parent->val = obj; + } else { + parent->val = rb_funcall(parent->clas, oj_json_create_id, 1, parent->val); + } + parent->clas = Qundef; } if (Yes == pi->options.trace) { - oj_trace_parse_hash_end(pi, __FILE__, __LINE__); + oj_trace_parse_hash_end(pi, __FILE__, __LINE__); } } static VALUE calc_hash_key(ParseInfo pi, Val parent) { - volatile VALUE rkey = parent->key_val; + volatile VALUE rkey = parent->key_val; if (Qundef == rkey) { - rkey = rb_str_new(parent->key, parent->klen); + rkey = rb_str_new(parent->key, parent->klen); } rkey = oj_encode(rkey); if (Yes == pi->options.sym_key) { - rkey = rb_str_intern(rkey); + rkey = rb_str_intern(rkey); } return rkey; } static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) { - Val parent = stack_peek(&pi->stack); - volatile VALUE rval = oj_num_as_value(ni); + Val parent = stack_peek(&pi->stack); + volatile VALUE rval = oj_num_as_value(ni); switch (rb_type(parent->val)) { - case T_OBJECT: - oj_set_obj_ivar(parent, kval, rval); - break; - case T_HASH: - if (4 == parent->klen && NULL != parent->key && rb_cTime == parent->clas && 0 != ni->div && 0 == strncmp("time", parent->key, 4)) { - int64_t nsec = ni->num * 1000000000LL / ni->div; - - if (ni->neg) { - ni->i = -ni->i; - if (0 < nsec) { - ni->i--; - nsec = 1000000000LL - nsec; - } - } - if (86400 == ni->exp) { // UTC time - parent->val = rb_time_nano_new(ni->i, (long)nsec); - // Since the ruby C routines alway create local time, the - // offset and then a conversion to UTC keeps makes the time - // match the expected value. - parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0); - } else if (ni->has_exp) { - int64_t t = (int64_t)(ni->i + ni->exp); - struct _timeInfo ti; - VALUE args[8]; - - sec_as_time(t, &ti); - - args[0] = LONG2NUM(ti.year); - args[1] = LONG2NUM(ti.mon); - args[2] = LONG2NUM(ti.day); - args[3] = LONG2NUM(ti.hour); - args[4] = LONG2NUM(ti.min); - args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0); - args[6] = LONG2NUM(ni->exp); - parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args); - } else { - parent->val = rb_time_nano_new(ni->i, (long)nsec); - } - rval = parent->val; - } else { - rb_hash_aset(parent->val, calc_hash_key(pi, kval), rval); - } - break; - default: - break; + case T_OBJECT: + oj_set_obj_ivar(parent, kval, rval); + break; + case T_HASH: + if (4 == parent->klen && NULL != parent->key && rb_cTime == parent->clas && 0 != ni->div && 0 == strncmp("time", parent->key, 4)) { + int64_t nsec = ni->num * 1000000000LL / ni->div; + + if (ni->neg) { + ni->i = -ni->i; + if (0 < nsec) { + ni->i--; + nsec = 1000000000LL - nsec; + } + } + if (86400 == ni->exp) { // UTC time + parent->val = rb_time_nano_new(ni->i, (long)nsec); + // Since the ruby C routines alway create local time, the + // offset and then a conversion to UTC keeps makes the time + // match the expected value. + parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0); + } else if (ni->has_exp) { + int64_t t = (int64_t)(ni->i + ni->exp); + struct _timeInfo ti; + VALUE args[8]; + + sec_as_time(t, &ti); + + args[0] = LONG2NUM(ti.year); + args[1] = LONG2NUM(ti.mon); + args[2] = LONG2NUM(ti.day); + args[3] = LONG2NUM(ti.hour); + args[4] = LONG2NUM(ti.min); + args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0); + args[6] = LONG2NUM(ni->exp); + parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args); + } else { + parent->val = rb_time_nano_new(ni->i, (long)nsec); + } + rval = parent->val; + } else { + rb_hash_aset(parent->val, calc_hash_key(pi, kval), rval); + } + break; + default: + break; } if (Yes == pi->options.trace) { - oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval); + oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval); } } static void hash_set_value(ParseInfo pi, Val kval, VALUE value) { - Val parent = stack_peek(&pi->stack); + Val parent = stack_peek(&pi->stack); switch (rb_type(parent->val)) { - case T_OBJECT: - oj_set_obj_ivar(parent, kval, value); - break; - case T_HASH: - rb_hash_aset(parent->val, calc_hash_key(pi, kval), value); - break; - default: - break; + case T_OBJECT: + oj_set_obj_ivar(parent, kval, value); + break; + case T_HASH: + rb_hash_aset(parent->val, calc_hash_key(pi, kval), value); + break; + default: + break; } if (Yes == pi->options.trace) { - oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value); + oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value); } } static void array_append_num(ParseInfo pi, NumInfo ni) { - Val parent = stack_peek(&pi->stack); - volatile VALUE rval = oj_num_as_value(ni); + Val parent = stack_peek(&pi->stack); + volatile VALUE rval = oj_num_as_value(ni); rb_ary_push(parent->val, rval); if (Yes == pi->options.trace) { - oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval); + oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval); } } static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { - volatile VALUE rstr = rb_str_new(str, len); + volatile VALUE rstr = rb_str_new(str, len); rstr = oj_encode(rstr); if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) { - VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len); + VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len); - if (Qnil != clas) { - rb_ary_push(stack_peek(&pi->stack)->val, rb_funcall(clas, oj_json_create_id, 1, rstr)); - return; - } + if (Qnil != clas) { + rb_ary_push(stack_peek(&pi->stack)->val, rb_funcall(clas, oj_json_create_id, 1, rstr)); + return; + } } rb_ary_push(stack_peek(&pi->stack)->val, rstr); if (Yes == pi->options.trace) { - oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr); + oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr); } } @@ -1188,7 +1180,7 @@ oj_set_custom_callbacks(ParseInfo pi) { VALUE oj_custom_parse(int argc, VALUE *argv, VALUE self) { - struct _parseInfo pi; + struct _parseInfo pi; parse_info_init(&pi); pi.options = oj_default_options; @@ -1200,15 +1192,15 @@ oj_custom_parse(int argc, VALUE *argv, VALUE self) { oj_set_custom_callbacks(&pi); if (T_STRING == rb_type(*argv)) { - return oj_pi_parse(argc, argv, &pi, 0, 0, false); + return oj_pi_parse(argc, argv, &pi, 0, 0, false); } else { - return oj_pi_sparse(argc, argv, &pi, 0); + return oj_pi_sparse(argc, argv, &pi, 0); } } VALUE oj_custom_parse_cstr(int argc, VALUE *argv, char *json, size_t len) { - struct _parseInfo pi; + struct _parseInfo pi; parse_info_init(&pi); pi.options = oj_default_options; diff --git a/ext/oj/dump.c b/ext/oj/dump.c index ebdc88a7..112a8ac6 100644 --- a/ext/oj/dump.c +++ b/ext/oj/dump.c @@ -9,32 +9,32 @@ #include #include +#include "oj.h" #include "cache8.h" #include "dump.h" #include "odd.h" -#include "oj.h" #include "trace.h" #include "util.h" // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS -#define OJ_INFINITY (1.0 / 0.0) +#define OJ_INFINITY (1.0/0.0) #define MAX_DEPTH 1000 -static const char inf_val[] = INF_VAL; -static const char ninf_val[] = NINF_VAL; -static const char nan_val[] = NAN_VAL; +static const char inf_val[] = INF_VAL; +static const char ninf_val[] = NINF_VAL; +static const char nan_val[] = NAN_VAL; -typedef unsigned long ulong; +typedef unsigned long ulong; -static size_t hibit_friendly_size(const uint8_t *str, size_t len); -static size_t xss_friendly_size(const uint8_t *str, size_t len); -static size_t ascii_friendly_size(const uint8_t *str, size_t len); +static size_t hibit_friendly_size(const uint8_t *str, size_t len); +static size_t xss_friendly_size(const uint8_t *str, size_t len); +static size_t ascii_friendly_size(const uint8_t *str, size_t len); -static const char hex_chars[17] = "0123456789abcdef"; +static const char hex_chars[17] = "0123456789abcdef"; // JSON standard except newlines are no escaped -static char newline_friendly_chars[256] = "\ +static char newline_friendly_chars[256] = "\ 66666666221622666666666666666666\ 11211111111111111111111111111111\ 11111111111111111111111111112111\ @@ -45,7 +45,7 @@ static char newline_friendly_chars[256] = "\ 11111111111111111111111111111111"; // JSON standard -static char hibit_friendly_chars[256] = "\ +static char hibit_friendly_chars[256] = "\ 66666666222622666666666666666666\ 11211111111111111111111111111111\ 11111111111111111111111111112111\ @@ -57,7 +57,7 @@ static char hibit_friendly_chars[256] = "\ // High bit set characters are always encoded as unicode. Worse case is 3 // bytes per character in the output. That makes this conservative. -static char ascii_friendly_chars[256] = "\ +static char ascii_friendly_chars[256] = "\ 66666666222622666666666666666666\ 11211111111111111111111111111111\ 11111111111111111111111111112111\ @@ -68,7 +68,7 @@ static char ascii_friendly_chars[256] = "\ 33333333333333333333333333333333"; // XSS safe mode -static char xss_friendly_chars[256] = "\ +static char xss_friendly_chars[256] = "\ 66666666222622666666666666666666\ 11211161111111121111111111116161\ 11111111111111111111111111112111\ @@ -79,7 +79,7 @@ static char xss_friendly_chars[256] = "\ 33333333333333333333333333333333"; // JSON XSS combo -static char hixss_friendly_chars[256] = "\ +static char hixss_friendly_chars[256] = "\ 66666666222622666666666666666666\ 11211111111111111111111111111111\ 11111111111111111111111111112111\ @@ -90,7 +90,7 @@ static char hixss_friendly_chars[256] = "\ 11611111111111111111111111111111"; // Rails XSS combo -static char rails_xss_friendly_chars[256] = "\ +static char rails_xss_friendly_chars[256] = "\ 66666666222622666666666666666666\ 11211161111111111111111111116161\ 11111111111111111111111111112111\ @@ -101,7 +101,7 @@ static char rails_xss_friendly_chars[256] = "\ 11611111111111111111111111111111"; // Rails HTML non-escape -static char rails_friendly_chars[256] = "\ +static char rails_friendly_chars[256] = "\ 66666666222622666666666666666666\ 11211111111111111111111111111111\ 11111111111111111111111111112111\ @@ -118,140 +118,135 @@ raise_strict(VALUE obj) { inline static size_t newline_friendly_size(const uint8_t *str, size_t len) { - size_t size = 0; - size_t i = len; + size_t size = 0; + size_t i = len; for (; 0 < i; str++, i--) { - size += newline_friendly_chars[*str]; + size += newline_friendly_chars[*str]; } return size - len * (size_t)'0'; } inline static size_t hibit_friendly_size(const uint8_t *str, size_t len) { - size_t size = 0; - size_t i = len; + size_t size = 0; + size_t i = len; for (; 0 < i; str++, i--) { - size += hibit_friendly_chars[*str]; + size += hibit_friendly_chars[*str]; } return size - len * (size_t)'0'; } inline static size_t ascii_friendly_size(const uint8_t *str, size_t len) { - size_t size = 0; - size_t i = len; + size_t size = 0; + size_t i = len; for (; 0 < i; str++, i--) { - size += ascii_friendly_chars[*str]; + size += ascii_friendly_chars[*str]; } return size - len * (size_t)'0'; } inline static size_t xss_friendly_size(const uint8_t *str, size_t len) { - size_t size = 0; - size_t i = len; + size_t size = 0; + size_t i = len; for (; 0 < i; str++, i--) { - size += xss_friendly_chars[*str]; + size += xss_friendly_chars[*str]; } return size - len * (size_t)'0'; } inline static size_t hixss_friendly_size(const uint8_t *str, size_t len) { - size_t size = 0; - size_t i = len; - bool check = false; + size_t size = 0; + size_t i = len; + bool check = false; for (; 0 < i; str++, i--) { - size += hixss_friendly_chars[*str]; - if (0 != (0x80 & *str)) { - check = true; - } + size += hixss_friendly_chars[*str]; + if (0 != (0x80 & *str)) { + check = true; + } } return size - len * (size_t)'0' + check; } inline static long rails_xss_friendly_size(const uint8_t *str, size_t len) { - long size = 0; - size_t i = len; - uint8_t hi = 0; + long size = 0; + size_t i = len; + uint8_t hi = 0; for (; 0 < i; str++, i--) { - size += rails_xss_friendly_chars[*str]; - hi |= *str & 0x80; + size += rails_xss_friendly_chars[*str]; + hi |= *str & 0x80; } if (0 == hi) { - return size - len * (size_t)'0'; + return size - len * (size_t)'0'; } return -(size - len * (size_t)'0'); } inline static size_t rails_friendly_size(const uint8_t *str, size_t len) { - size_t size = 0; - size_t i = len; + size_t size = 0; + size_t i = len; for (; 0 < i; str++, i--) { - size += rails_friendly_chars[*str]; + size += rails_friendly_chars[*str]; } return size - len * (size_t)'0'; } -const char * +const char* oj_nan_str(VALUE obj, int opt, int mode, bool plus, int *lenp) { - const char *str = NULL; + const char *str = NULL; if (AutoNan == opt) { - switch (mode) { - case CompatMode: - opt = WordNan; - break; - case StrictMode: - opt = RaiseNan; - break; - default: - break; - } + switch (mode) { + case CompatMode: opt = WordNan; break; + case StrictMode: opt = RaiseNan; break; + default: break; + } } switch (opt) { - case RaiseNan: - raise_strict(obj); - break; - case WordNan: - if (plus) { - str = "Infinity"; - *lenp = 8; - } else { - str = "-Infinity"; - *lenp = 9; - } - break; - case NullNan: - str = "null"; - *lenp = 4; - break; - case HugeNan: - default: - if (plus) { - str = inf_val; - *lenp = sizeof(inf_val) - 1; - } else { - str = ninf_val; - *lenp = sizeof(ninf_val) - 1; - } - break; + case RaiseNan: + raise_strict(obj); + break; + case WordNan: + if (plus) { + str = "Infinity"; + *lenp = 8; + } else { + str = "-Infinity"; + *lenp = 9; + } + break; + case NullNan: + str = "null"; + *lenp = 4; + break; + case HugeNan: + default: + if (plus) { + str = inf_val; + *lenp = sizeof(inf_val) - 1; + } else { + str = ninf_val; + *lenp = sizeof(ninf_val) - 1; + } + break; } return str; } inline static void dump_hex(uint8_t c, Out out) { - uint8_t d = (c >> 4) & 0x0F; + uint8_t d = (c >> 4) & 0x0F; *out->cur++ = hex_chars[d]; d = c & 0x0F; @@ -260,20 +255,20 @@ dump_hex(uint8_t c, Out out) { static void raise_invalid_unicode(const char *str, int len, int pos) { - char c; - char code[32]; - char *cp = code; - int i; - uint8_t d; + char c; + char code[32]; + char *cp = code; + int i; + uint8_t d; *cp++ = '['; for (i = pos; i < len && i - pos < 5; i++) { - c = str[i]; - d = (c >> 4) & 0x0F; - *cp++ = hex_chars[d]; - d = c & 0x0F; - *cp++ = hex_chars[d]; - *cp++ = ' '; + c = str[i]; + d = (c >> 4) & 0x0F; + *cp++ = hex_chars[d]; + d = c & 0x0F; + *cp++ = hex_chars[d]; + *cp++ = ' '; } cp--; *cp++ = ']'; @@ -281,83 +276,83 @@ raise_invalid_unicode(const char *str, int len, int pos) { rb_raise(oj_json_generator_error_class, "Invalid Unicode %s at %d", code, pos); } -static const char * +static const char* dump_unicode(const char *str, const char *end, Out out, const char *orig) { - uint32_t code = 0; - uint8_t b = *(uint8_t *)str; - int i, cnt; + uint32_t code = 0; + uint8_t b = *(uint8_t*)str; + int i, cnt; if (0xC0 == (0xE0 & b)) { - cnt = 1; - code = b & 0x0000001F; + cnt = 1; + code = b & 0x0000001F; } else if (0xE0 == (0xF0 & b)) { - cnt = 2; - code = b & 0x0000000F; + cnt = 2; + code = b & 0x0000000F; } else if (0xF0 == (0xF8 & b)) { - cnt = 3; - code = b & 0x00000007; + cnt = 3; + code = b & 0x00000007; } else if (0xF8 == (0xFC & b)) { - cnt = 4; - code = b & 0x00000003; + cnt = 4; + code = b & 0x00000003; } else if (0xFC == (0xFE & b)) { - cnt = 5; - code = b & 0x00000001; + cnt = 5; + code = b & 0x00000001; } else { - cnt = 0; - raise_invalid_unicode(orig, (int)(end - orig), (int)(str - orig)); + cnt = 0; + raise_invalid_unicode(orig, (int)(end - orig), (int)(str - orig)); } str++; for (; 0 < cnt; cnt--, str++) { - b = *(uint8_t *)str; - if (end <= str || 0x80 != (0xC0 & b)) { - raise_invalid_unicode(orig, (int)(end - orig), (int)(str - orig)); - } - code = (code << 6) | (b & 0x0000003F); + b = *(uint8_t*)str; + if (end <= str || 0x80 != (0xC0 & b)) { + raise_invalid_unicode(orig, (int)(end - orig), (int)(str - orig)); + } + code = (code << 6) | (b & 0x0000003F); } if (0x0000FFFF < code) { - uint32_t c1; - - code -= 0x00010000; - c1 = ((code >> 10) & 0x000003FF) + 0x0000D800; - code = (code & 0x000003FF) + 0x0000DC00; - *out->cur++ = '\\'; - *out->cur++ = 'u'; - for (i = 3; 0 <= i; i--) { - *out->cur++ = hex_chars[(uint8_t)(c1 >> (i * 4)) & 0x0F]; - } + uint32_t c1; + + code -= 0x00010000; + c1 = ((code >> 10) & 0x000003FF) + 0x0000D800; + code = (code & 0x000003FF) + 0x0000DC00; + *out->cur++ = '\\'; + *out->cur++ = 'u'; + for (i = 3; 0 <= i; i--) { + *out->cur++ = hex_chars[(uint8_t)(c1 >> (i * 4)) & 0x0F]; + } } *out->cur++ = '\\'; *out->cur++ = 'u'; for (i = 3; 0 <= i; i--) { - *out->cur++ = hex_chars[(uint8_t)(code >> (i * 4)) & 0x0F]; + *out->cur++ = hex_chars[(uint8_t)(code >> (i * 4)) & 0x0F]; } return str - 1; } -static const char * +static const char* check_unicode(const char *str, const char *end, const char *orig) { - uint8_t b = *(uint8_t *)str; - int cnt = 0; + uint8_t b = *(uint8_t*)str; + int cnt = 0; if (0xC0 == (0xE0 & b)) { - cnt = 1; + cnt = 1; } else if (0xE0 == (0xF0 & b)) { - cnt = 2; + cnt = 2; } else if (0xF0 == (0xF8 & b)) { - cnt = 3; + cnt = 3; } else if (0xF8 == (0xFC & b)) { - cnt = 4; + cnt = 4; } else if (0xFC == (0xFE & b)) { - cnt = 5; + cnt = 5; } else { - raise_invalid_unicode(orig, (int)(end - orig), (int)(str - orig)); + raise_invalid_unicode(orig, (int)(end - orig), (int)(str - orig)); } str++; for (; 0 < cnt; cnt--, str++) { - b = *(uint8_t *)str; - if (end <= str || 0x80 != (0xC0 & b)) { - raise_invalid_unicode(orig, (int)(end - orig), (int)(str - orig)); - } + b = *(uint8_t*)str; + if (end <= str || 0x80 != (0xC0 & b)) { + raise_invalid_unicode(orig, (int)(end - orig), (int)(str - orig)); + } } return str; } @@ -367,52 +362,52 @@ check_unicode(const char *str, const char *end, const char *orig) { // cache. long oj_check_circular(VALUE obj, Out out) { - slot_t id = 0; - slot_t *slot; + slot_t id = 0; + slot_t *slot; if (Yes == out->opts->circular) { - if (0 == (id = oj_cache8_get(out->circ_cache, obj, &slot))) { - out->circ_cnt++; - id = out->circ_cnt; - *slot = id; - } else { - if (ObjectMode == out->opts->mode) { - assure_size(out, 18); - *out->cur++ = '"'; - *out->cur++ = '^'; - *out->cur++ = 'r'; - dump_ulong(id, out); - *out->cur++ = '"'; - } - return -1; - } + if (0 == (id = oj_cache8_get(out->circ_cache, obj, &slot))) { + out->circ_cnt++; + id = out->circ_cnt; + *slot = id; + } else { + if (ObjectMode == out->opts->mode) { + assure_size(out, 18); + *out->cur++ = '"'; + *out->cur++ = '^'; + *out->cur++ = 'r'; + dump_ulong(id, out); + *out->cur++ = '"'; + } + return -1; + } } return (long)id; } void oj_dump_time(VALUE obj, Out out, int withZone) { - char buf[64]; - char *b = buf + sizeof(buf) - 1; - long size; - char *dot; - int neg = 0; - long one = 1000000000; - long long sec; - long long nsec; + char buf[64]; + char *b = buf + sizeof(buf) - 1; + long size; + char *dot; + int neg = 0; + long one = 1000000000; + long long sec; + long long nsec; #ifdef HAVE_RB_TIME_TIMESPEC // rb_time_timespec as well as rb_time_timeeval have a bug that causes an // exception to be raised if a time is before 1970 on 32 bit systems so // check the timespec size and use the ruby calls if a 32 bit system. if (16 <= sizeof(struct timespec)) { - struct timespec ts = rb_time_timespec(obj); + struct timespec ts = rb_time_timespec(obj); - sec = (long long)ts.tv_sec; - nsec = ts.tv_nsec; + sec = (long long)ts.tv_sec; + nsec = ts.tv_nsec; } else { - sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0)); - nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0)); + sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0)); + nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0)); } #else sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0)); @@ -421,64 +416,64 @@ oj_dump_time(VALUE obj, Out out, int withZone) { *b-- = '\0'; if (withZone) { - long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0)); - int zneg = (0 > tzsecs); - - if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) { - tzsecs = 86400; - } - if (zneg) { - tzsecs = -tzsecs; - } - if (0 == tzsecs) { - *b-- = '0'; - } else { - for (; 0 < tzsecs; b--, tzsecs /= 10) { - *b = '0' + (tzsecs % 10); - } - if (zneg) { - *b-- = '-'; - } - } - *b-- = 'e'; + long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0)); + int zneg = (0 > tzsecs); + + if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) { + tzsecs = 86400; + } + if (zneg) { + tzsecs = -tzsecs; + } + if (0 == tzsecs) { + *b-- = '0'; + } else { + for (; 0 < tzsecs; b--, tzsecs /= 10) { + *b = '0' + (tzsecs % 10); + } + if (zneg) { + *b-- = '-'; + } + } + *b-- = 'e'; } if (0 > sec) { - neg = 1; - sec = -sec; - if (0 < nsec) { - nsec = 1000000000 - nsec; - sec--; - } + neg = 1; + sec = -sec; + if (0 < nsec) { + nsec = 1000000000 - nsec; + sec--; + } } dot = b - 9; if (0 < out->opts->sec_prec) { - if (9 > out->opts->sec_prec) { - int i; - - for (i = 9 - out->opts->sec_prec; 0 < i; i--) { - dot++; - nsec = (nsec + 5) / 10; - one /= 10; - } - } - if (one <= nsec) { - nsec -= one; - sec++; - } - for (; dot < b; b--, nsec /= 10) { - *b = '0' + (nsec % 10); - } - *b-- = '.'; + if (9 > out->opts->sec_prec) { + int i; + + for (i = 9 - out->opts->sec_prec; 0 < i; i--) { + dot++; + nsec = (nsec + 5) / 10; + one /= 10; + } + } + if (one <= nsec) { + nsec -= one; + sec++; + } + for (; dot < b; b--, nsec /= 10) { + *b = '0' + (nsec % 10); + } + *b-- = '.'; } if (0 == sec) { - *b-- = '0'; + *b-- = '0'; } else { - for (; 0 < sec; b--, sec /= 10) { - *b = '0' + (sec % 10); - } + for (; 0 < sec; b--, sec /= 10) { + *b = '0' + (sec % 10); + } } if (neg) { - *b-- = '-'; + *b-- = '-'; } b++; size = sizeof(buf) - (b - buf) - 1; @@ -490,31 +485,31 @@ oj_dump_time(VALUE obj, Out out, int withZone) { void oj_dump_ruby_time(VALUE obj, Out out) { - volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); + volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); - oj_dump_cstr(rb_string_value_ptr((VALUE *)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out); + oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out); } void oj_dump_xml_time(VALUE obj, Out out) { - char buf[64]; - struct _timeInfo ti; - long one = 1000000000; - int64_t sec; - long long nsec; - long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0)); - int tzhour, tzmin; - char tzsign = '+'; + char buf[64]; + struct _timeInfo ti; + long one = 1000000000; + int64_t sec; + long long nsec; + long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0)); + int tzhour, tzmin; + char tzsign = '+'; #ifdef HAVE_RB_TIME_TIMESPEC if (16 <= sizeof(struct timespec)) { - struct timespec ts = rb_time_timespec(obj); + struct timespec ts = rb_time_timespec(obj); - sec = ts.tv_sec; - nsec = ts.tv_nsec; + sec = ts.tv_sec; + nsec = ts.tv_nsec; } else { - sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0)); - nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0)); + sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0)); + nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0)); } #else sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0)); @@ -523,24 +518,24 @@ oj_dump_xml_time(VALUE obj, Out out) { assure_size(out, 36); if (9 > out->opts->sec_prec) { - int i; - - // This is pretty lame but to be compatible with rails and active - // support rounding is not done but instead a floor is done when - // second precision is 3 just to be like rails. sigh. - if (3 == out->opts->sec_prec) { - nsec /= 1000000; - one = 1000; - } else { - for (i = 9 - out->opts->sec_prec; 0 < i; i--) { - nsec = (nsec + 5) / 10; - one /= 10; - } - if (one <= nsec) { - nsec -= one; - sec++; - } - } + int i; + + // This is pretty lame but to be compatible with rails and active + // support rounding is not done but instead a floor is done when + // second precision is 3 just to be like rails. sigh. + if (3 == out->opts->sec_prec) { + nsec /= 1000000; + one = 1000; + } else { + for (i = 9 - out->opts->sec_prec; 0 < i; i--) { + nsec = (nsec + 5) / 10; + one /= 10; + } + if (one <= nsec) { + nsec -= one; + sec++; + } + } } // 2012-01-05T23:58:07.123456000+09:00 //tm = localtime(&sec); @@ -555,33 +550,34 @@ oj_dump_xml_time(VALUE obj, Out out) { tzmin = (int)(tzsecs / 60) - (tzhour * 60); } if ((0 == nsec && !out->opts->sec_prec_set) || 0 == out->opts->sec_prec) { - if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) { - sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec); - oj_dump_cstr(buf, 20, 0, 0, out); - } else { - sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, tzsign, tzhour, tzmin); - oj_dump_cstr(buf, 25, 0, 0, out); - } + if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) { + sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec); + oj_dump_cstr(buf, 20, 0, 0, out); + } else { + sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, + tzsign, tzhour, tzmin); + oj_dump_cstr(buf, 25, 0, 0, out); + } } else if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) { - char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ"; - int len = 30; - - if (9 > out->opts->sec_prec) { - format[32] = '0' + out->opts->sec_prec; - len -= 9 - out->opts->sec_prec; - } - sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, (long)nsec); - oj_dump_cstr(buf, len, 0, 0, out); + char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ"; + int len = 30; + + if (9 > out->opts->sec_prec) { + format[32] = '0' + out->opts->sec_prec; + len -= 9 - out->opts->sec_prec; + } + sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, (long)nsec); + oj_dump_cstr(buf, len, 0, 0, out); } else { - char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d"; - int len = 35; - - if (9 > out->opts->sec_prec) { - format[32] = '0' + out->opts->sec_prec; - len -= 9 - out->opts->sec_prec; - } - sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, (long)nsec, tzsign, tzhour, tzmin); - oj_dump_cstr(buf, len, 0, 0, out); + char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d"; + int len = 35; + + if (9 > out->opts->sec_prec) { + format[32] = '0' + out->opts->sec_prec; + len -= 9 - out->opts->sec_prec; + } + sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, (long)nsec, tzsign, tzhour, tzmin); + oj_dump_cstr(buf, len, 0, 0, out); } } @@ -593,9 +589,9 @@ oj_dump_obj_to_json(VALUE obj, Options copts, Out out) { void oj_dump_obj_to_json_using_params(VALUE obj, Options copts, Out out, int argc, VALUE *argv) { if (0 == out->buf) { - out->buf = ALLOC_N(char, 4096); - out->end = out->buf + 4095 - BUFFER_EXTRA; // 1 less than end plus extra for possible errors - out->allocated = true; + out->buf = ALLOC_N(char, 4096); + out->end = out->buf + 4095 - BUFFER_EXTRA; // 1 less than end plus extra for possible errors + out->allocated = true; } out->cur = out->buf; out->circ_cnt = 0; @@ -606,57 +602,41 @@ oj_dump_obj_to_json_using_params(VALUE obj, Options copts, Out out, int argc, VA out->argv = argv; out->ropts = NULL; if (Yes == copts->circular) { - oj_cache8_new(&out->circ_cache); + oj_cache8_new(&out->circ_cache); } switch (copts->mode) { - case StrictMode: - oj_dump_strict_val(obj, 0, out); - break; - case NullMode: - oj_dump_null_val(obj, 0, out); - break; - case ObjectMode: - oj_dump_obj_val(obj, 0, out); - break; - case CompatMode: - oj_dump_compat_val(obj, 0, out, Yes == copts->to_json); - break; - case RailsMode: - oj_dump_rails_val(obj, 0, out); - break; - case CustomMode: - oj_dump_custom_val(obj, 0, out, true); - break; - case WabMode: - oj_dump_wab_val(obj, 0, out); - break; - default: - oj_dump_custom_val(obj, 0, out, true); - break; + case StrictMode: oj_dump_strict_val(obj, 0, out); break; + case NullMode: oj_dump_null_val(obj, 0, out); break; + case ObjectMode: oj_dump_obj_val(obj, 0, out); break; + case CompatMode: oj_dump_compat_val(obj, 0, out, Yes == copts->to_json); break; + case RailsMode: oj_dump_rails_val(obj, 0, out); break; + case CustomMode: oj_dump_custom_val(obj, 0, out, true); break; + case WabMode: oj_dump_wab_val(obj, 0, out); break; + default: oj_dump_custom_val(obj, 0, out, true); break; } if (0 < out->indent) { - switch (*(out->cur - 1)) { - case ']': - case '}': - assure_size(out, 1); - *out->cur++ = '\n'; - default: - break; - } + switch (*(out->cur - 1)) { + case ']': + case '}': + assure_size(out, 1); + *out->cur++ = '\n'; + default: + break; + } } *out->cur = '\0'; if (Yes == copts->circular) { - oj_cache8_delete(out->circ_cache); + oj_cache8_delete(out->circ_cache); } } void oj_write_obj_to_file(VALUE obj, const char *path, Options copts) { - char buf[4096]; + char buf[4096]; struct _out out; - size_t size; - FILE *f; - int ok; + size_t size; + FILE *f; + int ok; out.buf = buf; out.end = buf + sizeof(buf) - BUFFER_EXTRA; @@ -665,32 +645,32 @@ oj_write_obj_to_file(VALUE obj, const char *path, Options copts) { oj_dump_obj_to_json(obj, copts, &out); size = out.cur - out.buf; if (0 == (f = fopen(path, "w"))) { - if (out.allocated) { - xfree(out.buf); - } - rb_raise(rb_eIOError, "%s", strerror(errno)); + if (out.allocated) { + xfree(out.buf); + } + rb_raise(rb_eIOError, "%s", strerror(errno)); } ok = (size == fwrite(out.buf, 1, size, f)); if (out.allocated) { - xfree(out.buf); + xfree(out.buf); } fclose(f); if (!ok) { - int err = ferror(f); + int err = ferror(f); - rb_raise(rb_eIOError, "Write failed. [%d:%s]", err, strerror(err)); + rb_raise(rb_eIOError, "Write failed. [%d:%s]", err, strerror(err)); } } void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) { - char buf[4096]; + char buf[4096]; struct _out out; - ssize_t size; - VALUE clas = rb_obj_class(stream); + ssize_t size; + VALUE clas = rb_obj_class(stream); #if !IS_WINDOWS - int fd; - VALUE s; + int fd; + VALUE s; #endif out.buf = buf; @@ -700,39 +680,39 @@ oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) { oj_dump_obj_to_json(obj, copts, &out); size = out.cur - out.buf; if (oj_stringio_class == clas) { - rb_funcall(stream, oj_write_id, 1, rb_str_new(out.buf, size)); + rb_funcall(stream, oj_write_id, 1, rb_str_new(out.buf, size)); #if !IS_WINDOWS } else if (rb_respond_to(stream, oj_fileno_id) && - Qnil != (s = rb_funcall(stream, oj_fileno_id, 0)) && - 0 != (fd = FIX2INT(s))) { - if (size != write(fd, out.buf, size)) { - if (out.allocated) { - xfree(out.buf); - } - rb_raise(rb_eIOError, "Write failed. [%d:%s]", errno, strerror(errno)); - } + Qnil != (s = rb_funcall(stream, oj_fileno_id, 0)) && + 0 != (fd = FIX2INT(s))) { + if (size != write(fd, out.buf, size)) { + if (out.allocated) { + xfree(out.buf); + } + rb_raise(rb_eIOError, "Write failed. [%d:%s]", errno, strerror(errno)); + } #endif } else if (rb_respond_to(stream, oj_write_id)) { - rb_funcall(stream, oj_write_id, 1, rb_str_new(out.buf, size)); + rb_funcall(stream, oj_write_id, 1, rb_str_new(out.buf, size)); } else { - if (out.allocated) { - xfree(out.buf); - } - rb_raise(rb_eArgError, "to_stream() expected an IO Object."); + if (out.allocated) { + xfree(out.buf); + } + rb_raise(rb_eArgError, "to_stream() expected an IO Object."); } if (out.allocated) { - xfree(out.buf); + xfree(out.buf); } } void oj_dump_str(VALUE obj, int depth, Out out, bool as_ok) { - rb_encoding *enc = rb_to_encoding(rb_obj_encoding(obj)); + rb_encoding *enc = rb_to_encoding(rb_obj_encoding(obj)); if (rb_utf8_encoding() != enc) { - obj = rb_str_conv_enc(obj, enc, rb_utf8_encoding()); + obj = rb_str_conv_enc(obj, enc, rb_utf8_encoding()); } - oj_dump_cstr(rb_string_value_ptr((VALUE *)&obj), (int)RSTRING_LEN(obj), 0, 0, out); + oj_dump_cstr(rb_string_value_ptr((VALUE*)&obj), (int)RSTRING_LEN(obj), 0, 0, out); } void @@ -740,23 +720,23 @@ oj_dump_sym(VALUE obj, int depth, Out out, bool as_ok) { // This causes a memory leak in 2.5.1. Maybe in other versions as well. //const char *sym = rb_id2name(SYM2ID(obj)); - volatile VALUE s = rb_sym_to_s(obj); + volatile VALUE s = rb_sym_to_s(obj); - oj_dump_cstr(rb_string_value_ptr((VALUE *)&s), (int)RSTRING_LEN(s), 0, 0, out); + oj_dump_cstr(rb_string_value_ptr((VALUE*)&s), (int)RSTRING_LEN(s), 0, 0, out); } static void debug_raise(const char *orig, size_t cnt, int line) { - char buf[1024]; - char *b = buf; - const char *s = orig; - const char *s_end = s + cnt; + char buf[1024]; + char *b = buf; + const char *s = orig; + const char *s_end = s + cnt; if (32 < s_end - s) { - s_end = s + 32; + s_end = s + 32; } for (; s < s_end; s++) { - b += sprintf(b, " %02x", *s); + b += sprintf(b, " %02x", *s); } *b = '\0'; rb_raise(oj_json_generator_error_class, "Partial character in string. %s @ %d", buf, line); @@ -765,235 +745,221 @@ debug_raise(const char *orig, size_t cnt, int line) { void oj_dump_raw_json(VALUE obj, int depth, Out out) { if (oj_string_writer_class == rb_obj_class(obj)) { - StrWriter sw = (StrWriter)DATA_PTR(obj); - size_t len = sw->out.cur - sw->out.buf; + StrWriter sw = (StrWriter)DATA_PTR(obj); + size_t len = sw->out.cur - sw->out.buf; - if (0 < len) { - len--; - } - oj_dump_raw(sw->out.buf, len, out); + if (0 < len) { + len--; + } + oj_dump_raw(sw->out.buf, len, out); } else { - volatile VALUE jv; - - if (Yes == out->opts->trace) { - oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn); - } - jv = rb_funcall(obj, oj_raw_json_id, 2, RB_INT2NUM(depth), RB_INT2NUM(out->indent)); - if (Yes == out->opts->trace) { - oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut); - } - oj_dump_raw(rb_string_value_ptr((VALUE *)&jv), (size_t)RSTRING_LEN(jv), out); + volatile VALUE jv; + + if (Yes == out->opts->trace) { + oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn); + } + jv = rb_funcall(obj, oj_raw_json_id, 2, RB_INT2NUM(depth), RB_INT2NUM(out->indent)); + if (Yes == out->opts->trace) { + oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut); + } + oj_dump_raw(rb_string_value_ptr((VALUE*)&jv), (size_t)RSTRING_LEN(jv), out); } } void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out out) { - size_t size; - char *cmap; - const char *orig = str; - bool has_hi = false; + size_t size; + char *cmap; + const char *orig = str; + bool has_hi = false; switch (out->opts->escape_mode) { - case NLEsc: - cmap = newline_friendly_chars; - size = newline_friendly_size((uint8_t *)str, cnt); - break; - case ASCIIEsc: - cmap = ascii_friendly_chars; - size = ascii_friendly_size((uint8_t *)str, cnt); - break; - case XSSEsc: - cmap = xss_friendly_chars; - size = xss_friendly_size((uint8_t *)str, cnt); - break; - case JXEsc: - cmap = hixss_friendly_chars; - size = hixss_friendly_size((uint8_t *)str, cnt); - break; - case RailsXEsc: { - long sz; - - cmap = rails_xss_friendly_chars; - sz = rails_xss_friendly_size((uint8_t *)str, cnt); - if (sz < 0) { - has_hi = true; - size = (size_t)-sz; - } else { - size = (size_t)sz; - } - break; - } - case RailsEsc: - cmap = rails_friendly_chars; - size = rails_friendly_size((uint8_t *)str, cnt); - break; - case JSONEsc: - default: - cmap = hibit_friendly_chars; - size = hibit_friendly_size((uint8_t *)str, cnt); + case NLEsc: + cmap = newline_friendly_chars; + size = newline_friendly_size((uint8_t*)str, cnt); + break; + case ASCIIEsc: + cmap = ascii_friendly_chars; + size = ascii_friendly_size((uint8_t*)str, cnt); + break; + case XSSEsc: + cmap = xss_friendly_chars; + size = xss_friendly_size((uint8_t*)str, cnt); + break; + case JXEsc: + cmap = hixss_friendly_chars; + size = hixss_friendly_size((uint8_t*)str, cnt); + break; + case RailsXEsc: { + long sz; + + cmap = rails_xss_friendly_chars; + sz = rails_xss_friendly_size((uint8_t*)str, cnt); + if (sz < 0) { + has_hi = true; + size = (size_t)-sz; + } else { + size = (size_t)sz; + } + break; + } + case RailsEsc: + cmap = rails_friendly_chars; + size = rails_friendly_size((uint8_t*)str, cnt); + break; + case JSONEsc: + default: + cmap = hibit_friendly_chars; + size = hibit_friendly_size((uint8_t*)str, cnt); } assure_size(out, size + BUFFER_EXTRA); *out->cur++ = '"'; if (escape1) { - *out->cur++ = '\\'; - *out->cur++ = 'u'; - *out->cur++ = '0'; - *out->cur++ = '0'; - dump_hex((uint8_t)*str, out); - cnt--; - size--; - str++; - is_sym = 0; // just to make sure + *out->cur++ = '\\'; + *out->cur++ = 'u'; + *out->cur++ = '0'; + *out->cur++ = '0'; + dump_hex((uint8_t)*str, out); + cnt--; + size--; + str++; + is_sym = 0; // just to make sure } if (cnt == size && !has_hi) { - if (is_sym) { - *out->cur++ = ':'; - } - for (; '\0' != *str; str++) { - *out->cur++ = *str; - } - *out->cur++ = '"'; + if (is_sym) { + *out->cur++ = ':'; + } + for (; '\0' != *str; str++) { + *out->cur++ = *str; + } + *out->cur++ = '"'; } else { - const char *end = str + cnt; - const char *check_start = str; - - if (is_sym) { - *out->cur++ = ':'; - } - for (; str < end; str++) { - switch (cmap[(uint8_t)*str]) { - case '1': - if ((JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && check_start <= str) { - if (0 != (0x80 & (uint8_t)*str)) { - if (0xC0 == (0xC0 & (uint8_t)*str)) { - check_start = check_unicode(str, end, orig); - } else { - raise_invalid_unicode(orig, (int)(end - orig), (int)(str - orig)); - } - } - } - *out->cur++ = *str; - break; - case '2': - *out->cur++ = '\\'; - switch (*str) { - case '\\': - *out->cur++ = '\\'; - break; - case '\b': - *out->cur++ = 'b'; - break; - case '\t': - *out->cur++ = 't'; - break; - case '\n': - *out->cur++ = 'n'; - break; - case '\f': - *out->cur++ = 'f'; - break; - case '\r': - *out->cur++ = 'r'; - break; - default: - *out->cur++ = *str; - break; - } - break; - case '3': // Unicode - if (0xe2 == (uint8_t)*str && (JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && 2 <= end - str) { - if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) { - str = dump_unicode(str, end, out, orig); - } else { - check_start = check_unicode(str, end, orig); - *out->cur++ = *str; - } - break; - } - str = dump_unicode(str, end, out, orig); - break; - case '6': // control characters - if (*(uint8_t *)str < 0x80) { - *out->cur++ = '\\'; - *out->cur++ = 'u'; - *out->cur++ = '0'; - *out->cur++ = '0'; - dump_hex((uint8_t)*str, out); - } else { - if (0xe2 == (uint8_t)*str && (JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && 2 <= end - str) { - if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) { - str = dump_unicode(str, end, out, orig); - } else { - check_start = check_unicode(str, end, orig); - *out->cur++ = *str; - } - break; - } - str = dump_unicode(str, end, out, orig); - } - break; - default: - break; // ignore, should never happen if the table is correct - } - } - *out->cur++ = '"'; + const char *end = str + cnt; + const char *check_start = str; + + if (is_sym) { + *out->cur++ = ':'; + } + for (; str < end; str++) { + switch (cmap[(uint8_t)*str]) { + case '1': + if ((JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && check_start <= str) { + if (0 != (0x80 & (uint8_t)*str)) { + if (0xC0 == (0xC0 & (uint8_t)*str)) { + check_start = check_unicode(str, end, orig); + } else { + raise_invalid_unicode(orig, (int)(end - orig), (int)(str - orig)); + } + } + } + *out->cur++ = *str; + break; + case '2': + *out->cur++ = '\\'; + switch (*str) { + case '\\': *out->cur++ = '\\'; break; + case '\b': *out->cur++ = 'b'; break; + case '\t': *out->cur++ = 't'; break; + case '\n': *out->cur++ = 'n'; break; + case '\f': *out->cur++ = 'f'; break; + case '\r': *out->cur++ = 'r'; break; + default: *out->cur++ = *str; break; + } + break; + case '3': // Unicode + if (0xe2 == (uint8_t)*str && (JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && 2 <= end - str) { + if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) { + str = dump_unicode(str, end, out, orig); + } else { + check_start = check_unicode(str, end, orig); + *out->cur++ = *str; + } + break; + } + str = dump_unicode(str, end, out, orig); + break; + case '6': // control characters + if (*(uint8_t*)str < 0x80) { + *out->cur++ = '\\'; + *out->cur++ = 'u'; + *out->cur++ = '0'; + *out->cur++ = '0'; + dump_hex((uint8_t)*str, out); + } else { + if (0xe2 == (uint8_t)*str && (JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && 2 <= end - str) { + if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) { + str = dump_unicode(str, end, out, orig); + } else { + check_start = check_unicode(str, end, orig); + *out->cur++ = *str; + } + break; + } + str = dump_unicode(str, end, out, orig); + } + break; + default: + break; // ignore, should never happen if the table is correct + } + } + *out->cur++ = '"'; } if ((JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && 0 < str - orig && 0 != (0x80 & *(str - 1))) { - uint8_t c = (uint8_t) * (str - 1); - int i; - int scnt = (int)(str - orig); - - // Last utf-8 characters must be 0x10xxxxxx. The start must be - // 0x110xxxxx for 2 characters, 0x1110xxxx for 3, and 0x11110xxx for - // 4. - if (0 != (0x40 & c)) { - debug_raise(orig, cnt, __LINE__); - } - for (i = 1; i < (int)scnt && i < 4; i++) { - c = str[-1 - i]; - if (0x80 != (0xC0 & c)) { - switch (i) { - case 1: - if (0xC0 != (0xE0 & c)) { - debug_raise(orig, cnt, __LINE__); - } - break; - case 2: - if (0xE0 != (0xF0 & c)) { - debug_raise(orig, cnt, __LINE__); - } - break; - case 3: - if (0xF0 != (0xF8 & c)) { - debug_raise(orig, cnt, __LINE__); - } - break; - default: // can't get here - break; - } - break; - } - } - if (i == (int)scnt || 4 <= i) { - debug_raise(orig, cnt, __LINE__); - } + uint8_t c = (uint8_t)*(str - 1); + int i; + int scnt = (int)(str - orig); + + // Last utf-8 characters must be 0x10xxxxxx. The start must be + // 0x110xxxxx for 2 characters, 0x1110xxxx for 3, and 0x11110xxx for + // 4. + if (0 != (0x40 & c)) { + debug_raise(orig, cnt, __LINE__); + } + for (i = 1; i < (int)scnt && i < 4; i++) { + c = str[-1 - i]; + if (0x80 != (0xC0 & c)) { + switch (i) { + case 1: + if (0xC0 != (0xE0 & c)) { + debug_raise(orig, cnt, __LINE__); + } + break; + case 2: + if (0xE0 != (0xF0 & c)) { + debug_raise(orig, cnt, __LINE__); + } + break; + case 3: + if (0xF0 != (0xF8 & c)) { + debug_raise(orig, cnt, __LINE__); + } + break; + default: // can't get here + break; + } + break; + } + } + if (i == (int)scnt || 4 <= i) { + debug_raise(orig, cnt, __LINE__); + } } *out->cur = '\0'; } void oj_dump_class(VALUE obj, int depth, Out out, bool as_ok) { - const char *s = rb_class2name(obj); + const char *s = rb_class2name(obj); oj_dump_cstr(s, strlen(s), 0, 0, out); } void oj_dump_obj_to_s(VALUE obj, Out out) { - volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); + volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); - oj_dump_cstr(rb_string_value_ptr((VALUE *)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out); + oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out); } void @@ -1006,23 +972,23 @@ oj_dump_raw(const char *str, size_t cnt, Out out) { void oj_grow_out(Out out, size_t len) { - size_t size = out->end - out->buf; - long pos = out->cur - out->buf; - char *buf = out->buf; + size_t size = out->end - out->buf; + long pos = out->cur - out->buf; + char *buf = out->buf; size *= 2; if (size <= len * 2 + pos) { - size += len; + size += len; } if (out->allocated) { - REALLOC_N(buf, char, (size + BUFFER_EXTRA)); + REALLOC_N(buf, char, (size + BUFFER_EXTRA)); } else { - buf = ALLOC_N(char, (size + BUFFER_EXTRA)); - out->allocated = true; - memcpy(buf, out->buf, out->end - out->buf + BUFFER_EXTRA); + buf = ALLOC_N(char, (size + BUFFER_EXTRA)); + out->allocated = true; + memcpy(buf, out->buf, out->end - out->buf + BUFFER_EXTRA); } if (0 == buf) { - rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]", ENOSPC, strerror(ENOSPC)); + rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]", ENOSPC, strerror(ENOSPC)); } out->buf = buf; out->end = buf + size; @@ -1062,64 +1028,64 @@ oj_dump_false(VALUE obj, int depth, Out out, bool as_ok) { void oj_dump_fixnum(VALUE obj, int depth, Out out, bool as_ok) { - char buf[32]; - char *b = buf + sizeof(buf) - 1; - long long num = rb_num2ll(obj); - int neg = 0; - bool dump_as_string = false; + char buf[32]; + char *b = buf + sizeof(buf) - 1; + long long num = rb_num2ll(obj); + int neg = 0; + bool dump_as_string = false; if (out->opts->int_range_max != 0 && out->opts->int_range_min != 0 && - (out->opts->int_range_max < num || out->opts->int_range_min > num)) { - dump_as_string = true; + (out->opts->int_range_max < num || out->opts->int_range_min > num)) { + dump_as_string = true; } if (0 > num) { - neg = 1; - num = -num; + neg = 1; + num = -num; } *b-- = '\0'; if (dump_as_string) { - *b-- = '"'; + *b-- = '"'; } if (0 < num) { - for (; 0 < num; num /= 10, b--) { - *b = (num % 10) + '0'; - } - if (neg) { - *b = '-'; - } else { - b++; - } + for (; 0 < num; num /= 10, b--) { + *b = (num % 10) + '0'; + } + if (neg) { + *b = '-'; + } else { + b++; + } } else { - *b = '0'; + *b = '0'; } if (dump_as_string) { - *--b = '"'; + *--b = '"'; } assure_size(out, (sizeof(buf) - (b - buf))); for (; '\0' != *b; b++) { - *out->cur++ = *b; + *out->cur++ = *b; } *out->cur = '\0'; } void oj_dump_bignum(VALUE obj, int depth, Out out, bool as_ok) { - volatile VALUE rs = rb_big2str(obj, 10); - int cnt = (int)RSTRING_LEN(rs); - bool dump_as_string = false; + volatile VALUE rs = rb_big2str(obj, 10); + int cnt = (int)RSTRING_LEN(rs); + bool dump_as_string = false; if (out->opts->int_range_max != 0 || out->opts->int_range_min != 0) { // Bignum cannot be inside of Fixnum range - dump_as_string = true; - assure_size(out, cnt + 2); - *out->cur++ = '"'; + dump_as_string = true; + assure_size(out, cnt + 2); + *out->cur++ = '"'; } else { - assure_size(out, cnt); + assure_size(out, cnt); } - memcpy(out->cur, rb_string_value_ptr((VALUE *)&rs), cnt); + memcpy(out->cur, rb_string_value_ptr((VALUE*)&rs), cnt); out->cur += cnt; if (dump_as_string) { - *out->cur++ = '"'; + *out->cur++ = '"'; } *out->cur = '\0'; } @@ -1127,176 +1093,153 @@ oj_dump_bignum(VALUE obj, int depth, Out out, bool as_ok) { // Removed dependencies on math due to problems with CentOS 5.4. void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) { - char buf[64]; - char *b; - double d = rb_num2dbl(obj); - int cnt = 0; + char buf[64]; + char *b; + double d = rb_num2dbl(obj); + int cnt = 0; if (0.0 == d) { - b = buf; - *b++ = '0'; - *b++ = '.'; - *b++ = '0'; - *b++ = '\0'; - cnt = 3; + b = buf; + *b++ = '0'; + *b++ = '.'; + *b++ = '0'; + *b++ = '\0'; + cnt = 3; } else if (OJ_INFINITY == d) { - if (ObjectMode == out->opts->mode) { - strcpy(buf, inf_val); - cnt = sizeof(inf_val) - 1; - } else { - NanDump nd = out->opts->dump_opts.nan_dump; - - if (AutoNan == nd) { - switch (out->opts->mode) { - case CompatMode: - nd = WordNan; - break; - case StrictMode: - nd = RaiseNan; - break; - case NullMode: - nd = NullNan; - break; - case CustomMode: - nd = NullNan; - break; - default: - break; - } - } - switch (nd) { - case RaiseNan: - raise_strict(obj); - break; - case WordNan: - strcpy(buf, "Infinity"); - cnt = 8; - break; - case NullNan: - strcpy(buf, "null"); - cnt = 4; - break; - case HugeNan: - default: - strcpy(buf, inf_val); - cnt = sizeof(inf_val) - 1; - break; - } - } + if (ObjectMode == out->opts->mode) { + strcpy(buf, inf_val); + cnt = sizeof(inf_val) - 1; + } else { + NanDump nd = out->opts->dump_opts.nan_dump; + + if (AutoNan == nd) { + switch (out->opts->mode) { + case CompatMode: nd = WordNan; break; + case StrictMode: nd = RaiseNan; break; + case NullMode: nd = NullNan; break; + case CustomMode: nd = NullNan; break; + default: break; + } + } + switch (nd) { + case RaiseNan: + raise_strict(obj); + break; + case WordNan: + strcpy(buf, "Infinity"); + cnt = 8; + break; + case NullNan: + strcpy(buf, "null"); + cnt = 4; + break; + case HugeNan: + default: + strcpy(buf, inf_val); + cnt = sizeof(inf_val) - 1; + break; + } + } } else if (-OJ_INFINITY == d) { - if (ObjectMode == out->opts->mode) { - strcpy(buf, ninf_val); - cnt = sizeof(ninf_val) - 1; - } else { - NanDump nd = out->opts->dump_opts.nan_dump; - - if (AutoNan == nd) { - switch (out->opts->mode) { - case CompatMode: - nd = WordNan; - break; - case StrictMode: - nd = RaiseNan; - break; - case NullMode: - nd = NullNan; - break; - default: - break; - } - } - switch (nd) { - case RaiseNan: - raise_strict(obj); - break; - case WordNan: - strcpy(buf, "-Infinity"); - cnt = 9; - break; - case NullNan: - strcpy(buf, "null"); - cnt = 4; - break; - case HugeNan: - default: - strcpy(buf, ninf_val); - cnt = sizeof(ninf_val) - 1; - break; - } - } + if (ObjectMode == out->opts->mode) { + strcpy(buf, ninf_val); + cnt = sizeof(ninf_val) - 1; + } else { + NanDump nd = out->opts->dump_opts.nan_dump; + + if (AutoNan == nd) { + switch (out->opts->mode) { + case CompatMode: nd = WordNan; break; + case StrictMode: nd = RaiseNan; break; + case NullMode: nd = NullNan; break; + default: break; + } + } + switch (nd) { + case RaiseNan: + raise_strict(obj); + break; + case WordNan: + strcpy(buf, "-Infinity"); + cnt = 9; + break; + case NullNan: + strcpy(buf, "null"); + cnt = 4; + break; + case HugeNan: + default: + strcpy(buf, ninf_val); + cnt = sizeof(ninf_val) - 1; + break; + } + } } else if (isnan(d)) { - if (ObjectMode == out->opts->mode) { - strcpy(buf, nan_val); - cnt = sizeof(ninf_val) - 1; - } else { - NanDump nd = out->opts->dump_opts.nan_dump; - - if (AutoNan == nd) { - switch (out->opts->mode) { - case ObjectMode: - nd = HugeNan; - break; - case StrictMode: - nd = RaiseNan; - break; - case NullMode: - nd = NullNan; - break; - default: - break; - } - } - switch (nd) { - case RaiseNan: - raise_strict(obj); - break; - case WordNan: - strcpy(buf, "NaN"); - cnt = 3; - break; - case NullNan: - strcpy(buf, "null"); - cnt = 4; - break; - case HugeNan: - default: - strcpy(buf, nan_val); - cnt = sizeof(nan_val) - 1; - break; - } - } + if (ObjectMode == out->opts->mode) { + strcpy(buf, nan_val); + cnt = sizeof(ninf_val) - 1; + } else { + NanDump nd = out->opts->dump_opts.nan_dump; + + if (AutoNan == nd) { + switch (out->opts->mode) { + case ObjectMode: nd = HugeNan; break; + case StrictMode: nd = RaiseNan; break; + case NullMode: nd = NullNan; break; + default: break; + } + } + switch (nd) { + case RaiseNan: + raise_strict(obj); + break; + case WordNan: + strcpy(buf, "NaN"); + cnt = 3; + break; + case NullNan: + strcpy(buf, "null"); + cnt = 4; + break; + case HugeNan: + default: + strcpy(buf, nan_val); + cnt = sizeof(nan_val) - 1; + break; + } + } } else if (d == (double)(long long int)d) { - cnt = snprintf(buf, sizeof(buf), "%.1f", d); + cnt = snprintf(buf, sizeof(buf), "%.1f", d); } else if (0 == out->opts->float_prec) { - volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); - - cnt = (int)RSTRING_LEN(rstr); - if ((int)sizeof(buf) <= cnt) { - cnt = sizeof(buf) - 1; - } - strncpy(buf, rb_string_value_ptr((VALUE *)&rstr), cnt); - buf[cnt] = '\0'; + volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); + + cnt = (int)RSTRING_LEN(rstr); + if ((int)sizeof(buf) <= cnt) { + cnt = sizeof(buf) - 1; + } + strncpy(buf, rb_string_value_ptr((VALUE*)&rstr), cnt); + buf[cnt] = '\0'; } else { - cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, out->opts->float_fmt); + cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, out->opts->float_fmt); } assure_size(out, cnt); for (b = buf; '\0' != *b; b++) { - *out->cur++ = *b; + *out->cur++ = *b; } *out->cur = '\0'; } int oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char *format) { - int cnt = snprintf(buf, blen, format, d); + int cnt = snprintf(buf, blen, format, d); // Round off issues at 16 significant digits so check for obvious ones of // 0001 and 9999. if (17 <= cnt && (0 == strcmp("0001", buf + cnt - 4) || 0 == strcmp("9999", buf + cnt - 4))) { - volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); + volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); - strcpy(buf, rb_string_value_ptr((VALUE *)&rstr)); - cnt = (int)RSTRING_LEN(rstr); + strcpy(buf, rb_string_value_ptr((VALUE*)&rstr)); + cnt = (int)RSTRING_LEN(rstr); } return cnt; } @@ -1304,14 +1247,14 @@ oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char *fo bool oj_dump_ignore(Options opts, VALUE obj) { if (NULL != opts->ignore && (ObjectMode == opts->mode || CustomMode == opts->mode)) { - VALUE *vp = opts->ignore; - VALUE clas = rb_obj_class(obj); - - for (; Qnil != *vp; vp++) { - if (clas == *vp) { - return true; - } - } + VALUE *vp = opts->ignore; + VALUE clas = rb_obj_class(obj); + + for (; Qnil != *vp; vp++) { + if (clas == *vp) { + return true; + } + } } return false; } diff --git a/ext/oj/dump.h b/ext/oj/dump.h index 98113851..c3b6f985 100644 --- a/ext/oj/dump.h +++ b/ext/oj/dump.h @@ -13,80 +13,80 @@ // Extra padding at end of buffer. #define BUFFER_EXTRA 64 -extern void oj_dump_nil(VALUE obj, int depth, Out out, bool as_ok); -extern void oj_dump_true(VALUE obj, int depth, Out out, bool as_ok); -extern void oj_dump_false(VALUE obj, int depth, Out out, bool as_ok); -extern void oj_dump_fixnum(VALUE obj, int depth, Out out, bool as_ok); -extern void oj_dump_bignum(VALUE obj, int depth, Out out, bool as_ok); -extern void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok); -extern void oj_dump_str(VALUE obj, int depth, Out out, bool as_ok); -extern void oj_dump_sym(VALUE obj, int depth, Out out, bool as_ok); -extern void oj_dump_class(VALUE obj, int depth, Out out, bool as_ok); - -extern void oj_dump_raw(const char *str, size_t cnt, Out out); -extern void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out out); -extern void oj_dump_ruby_time(VALUE obj, Out out); -extern void oj_dump_xml_time(VALUE obj, Out out); -extern void oj_dump_time(VALUE obj, Out out, int withZone); -extern void oj_dump_obj_to_s(VALUE obj, Out out); - -extern const char *oj_nan_str(VALUE obj, int opt, int mode, bool plus, int *lenp); - -extern void oj_grow_out(Out out, size_t len); -extern long oj_check_circular(VALUE obj, Out out); - -extern void oj_dump_strict_val(VALUE obj, int depth, Out out); -extern void oj_dump_null_val(VALUE obj, int depth, Out out); -extern void oj_dump_obj_val(VALUE obj, int depth, Out out); -extern void oj_dump_compat_val(VALUE obj, int depth, Out out, bool as_ok); -extern void oj_dump_rails_val(VALUE obj, int depth, Out out); -extern void oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok); -extern void oj_dump_wab_val(VALUE obj, int depth, Out out); - -extern void oj_dump_raw_json(VALUE obj, int depth, Out out); - -extern VALUE oj_add_to_json(int argc, VALUE *argv, VALUE self); -extern VALUE oj_remove_to_json(int argc, VALUE *argv, VALUE self); - -extern int oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char *format); - -extern bool oj_dump_ignore(Options opts, VALUE obj); -extern time_t oj_sec_from_time_hard_way(VALUE obj); +extern void oj_dump_nil(VALUE obj, int depth, Out out, bool as_ok); +extern void oj_dump_true(VALUE obj, int depth, Out out, bool as_ok); +extern void oj_dump_false(VALUE obj, int depth, Out out, bool as_ok); +extern void oj_dump_fixnum(VALUE obj, int depth, Out out, bool as_ok); +extern void oj_dump_bignum(VALUE obj, int depth, Out out, bool as_ok); +extern void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok); +extern void oj_dump_str(VALUE obj, int depth, Out out, bool as_ok); +extern void oj_dump_sym(VALUE obj, int depth, Out out, bool as_ok); +extern void oj_dump_class(VALUE obj, int depth, Out out, bool as_ok); + +extern void oj_dump_raw(const char *str, size_t cnt, Out out); +extern void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out out); +extern void oj_dump_ruby_time(VALUE obj, Out out); +extern void oj_dump_xml_time(VALUE obj, Out out); +extern void oj_dump_time(VALUE obj, Out out, int withZone); +extern void oj_dump_obj_to_s(VALUE obj, Out out); + +extern const char* oj_nan_str(VALUE obj, int opt, int mode, bool plus, int *lenp); + +extern void oj_grow_out(Out out, size_t len); +extern long oj_check_circular(VALUE obj, Out out); + +extern void oj_dump_strict_val(VALUE obj, int depth, Out out); +extern void oj_dump_null_val(VALUE obj, int depth, Out out); +extern void oj_dump_obj_val(VALUE obj, int depth, Out out); +extern void oj_dump_compat_val(VALUE obj, int depth, Out out, bool as_ok); +extern void oj_dump_rails_val(VALUE obj, int depth, Out out); +extern void oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok); +extern void oj_dump_wab_val(VALUE obj, int depth, Out out); + +extern void oj_dump_raw_json(VALUE obj, int depth, Out out); + +extern VALUE oj_add_to_json(int argc, VALUE *argv, VALUE self); +extern VALUE oj_remove_to_json(int argc, VALUE *argv, VALUE self); + +extern int oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char *format); + +extern bool oj_dump_ignore(Options opts, VALUE obj); +extern time_t oj_sec_from_time_hard_way(VALUE obj); inline static void assure_size(Out out, size_t len) { if (out->end - out->cur <= (long)len) { - oj_grow_out(out, len); + oj_grow_out(out, len); } } inline static void fill_indent(Out out, int cnt) { if (0 < out->indent) { - cnt *= out->indent; - *out->cur++ = '\n'; - for (; 0 < cnt; cnt--) { - *out->cur++ = ' '; - } + cnt *= out->indent; + *out->cur++ = '\n'; + for (; 0 < cnt; cnt--) { + *out->cur++ = ' '; + } } } inline static void dump_ulong(unsigned long num, Out out) { - char buf[32]; - char *b = buf + sizeof(buf) - 1; + char buf[32]; + char *b = buf + sizeof(buf) - 1; *b-- = '\0'; if (0 < num) { - for (; 0 < num; num /= 10, b--) { - *b = (num % 10) + '0'; - } - b++; + for (; 0 < num; num /= 10, b--) { + *b = (num % 10) + '0'; + } + b++; } else { - *b = '0'; + *b = '0'; } for (; '\0' != *b; b++) { - *out->cur++ = *b; + *out->cur++ = *b; } *out->cur = '\0'; } diff --git a/ext/oj/dump_compat.c b/ext/oj/dump_compat.c index f3196aa3..a5fac992 100644 --- a/ext/oj/dump_compat.c +++ b/ext/oj/dump_compat.c @@ -7,14 +7,14 @@ #include "trace.h" // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS -#define OJ_INFINITY (1.0 / 0.0) +#define OJ_INFINITY (1.0/0.0) -bool oj_use_hash_alt = false; -bool oj_use_array_alt = false; +bool oj_use_hash_alt = false; +bool oj_use_array_alt = false; -static bool use_struct_alt = false; -static bool use_exception_alt = false; -static bool use_bignum_alt = false; +static bool use_struct_alt = false; +static bool use_exception_alt = false; +static bool use_bignum_alt = false; static void raise_json_err(const char *msg, const char *err_classname) { @@ -23,10 +23,10 @@ raise_json_err(const char *msg, const char *err_classname) { static void dump_obj_classname(const char *classname, int depth, Out out) { - int d2 = depth + 1; - size_t len = strlen(classname); - size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2; - size_t size = d2 * out->indent + 10 + len + out->opts->create_id_len + sep_len; + int d2 = depth + 1; + size_t len = strlen(classname); + size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2; + size_t size = d2 * out->indent + 10 + len + out->opts->create_id_len + sep_len; assure_size(out, size); *out->cur++ = '{'; @@ -36,13 +36,13 @@ dump_obj_classname(const char *classname, int depth, Out out) { out->cur += out->opts->create_id_len; *out->cur++ = '"'; if (0 < out->opts->dump_opts.before_size) { - strcpy(out->cur, out->opts->dump_opts.before_sep); - out->cur += out->opts->dump_opts.before_size; + strcpy(out->cur, out->opts->dump_opts.before_sep); + out->cur += out->opts->dump_opts.before_size; } *out->cur++ = ':'; if (0 < out->opts->dump_opts.after_size) { - strcpy(out->cur, out->opts->dump_opts.after_sep); - out->cur += out->opts->dump_opts.after_size; + strcpy(out->cur, out->opts->dump_opts.after_sep); + out->cur += out->opts->dump_opts.after_size; } *out->cur++ = '"'; memcpy(out->cur, classname, len); @@ -52,84 +52,84 @@ dump_obj_classname(const char *classname, int depth, Out out) { static void dump_values_array(VALUE *values, int depth, Out out) { - size_t size; - int d2 = depth + 1; + size_t size; + int d2 = depth + 1; assure_size(out, d2 * out->indent + 3); *out->cur++ = '['; if (Qundef == *values) { - *out->cur++ = ']'; + *out->cur++ = ']'; } else { - if (out->opts->dump_opts.use) { - size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 2; - size += out->opts->dump_opts.array_size; - size += out->opts->dump_opts.indent_size; - } else { - size = d2 * out->indent + 3; - } - for (; Qundef != *values; values++) { - assure_size(out, size); - if (out->opts->dump_opts.use) { - if (0 < out->opts->dump_opts.array_size) { - strcpy(out->cur, out->opts->dump_opts.array_nl); - out->cur += out->opts->dump_opts.array_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - - for (i = d2; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - } else { - fill_indent(out, d2); - } - oj_dump_compat_val(*values, d2, out, true); - if (Qundef != *(values + 1)) { - *out->cur++ = ','; - } - } - assure_size(out, size); - if (out->opts->dump_opts.use) { - if (0 < out->opts->dump_opts.array_size) { - strcpy(out->cur, out->opts->dump_opts.array_nl); - out->cur += out->opts->dump_opts.array_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - - for (i = depth; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - } else { - fill_indent(out, depth); - } - *out->cur++ = ']'; + if (out->opts->dump_opts.use) { + size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 2; + size += out->opts->dump_opts.array_size; + size += out->opts->dump_opts.indent_size; + } else { + size = d2 * out->indent + 3; + } + for (; Qundef != *values; values++) { + assure_size(out, size); + if (out->opts->dump_opts.use) { + if (0 < out->opts->dump_opts.array_size) { + strcpy(out->cur, out->opts->dump_opts.array_nl); + out->cur += out->opts->dump_opts.array_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + + for (i = d2; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + } else { + fill_indent(out, d2); + } + oj_dump_compat_val(*values, d2, out, true); + if (Qundef != *(values + 1)) { + *out->cur++ = ','; + } + } + assure_size(out, size); + if (out->opts->dump_opts.use) { + if (0 < out->opts->dump_opts.array_size) { + strcpy(out->cur, out->opts->dump_opts.array_nl); + out->cur += out->opts->dump_opts.array_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + + for (i = depth; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + } else { + fill_indent(out, depth); + } + *out->cur++ = ']'; } } static void dump_to_json(VALUE obj, Out out) { - volatile VALUE rs; - const char *s; - int len; + volatile VALUE rs; + const char *s; + int len; if (Yes == out->opts->trace) { - oj_trace("to_json", obj, __FILE__, __LINE__, 0, TraceRubyIn); + oj_trace("to_json", obj, __FILE__, __LINE__, 0, TraceRubyIn); } if (0 == rb_obj_method_arity(obj, oj_to_json_id)) { - rs = rb_funcall(obj, oj_to_json_id, 0); + rs = rb_funcall(obj, oj_to_json_id, 0); } else { - rs = rb_funcall2(obj, oj_to_json_id, out->argc, out->argv); + rs = rb_funcall2(obj, oj_to_json_id, out->argc, out->argv); } if (Yes == out->opts->trace) { - oj_trace("to_json", obj, __FILE__, __LINE__, 0, TraceRubyOut); + oj_trace("to_json", obj, __FILE__, __LINE__, 0, TraceRubyOut); } - s = rb_string_value_ptr((VALUE *)&rs); + s = rb_string_value_ptr((VALUE*)&rs); len = (int)RSTRING_LEN(rs); assure_size(out, len + 1); @@ -140,109 +140,109 @@ dump_to_json(VALUE obj, Out out) { static void dump_array(VALUE a, int depth, Out out, bool as_ok) { - size_t size; - int i, cnt; - int d2 = depth + 1; - long id = oj_check_circular(a, out); + size_t size; + int i, cnt; + int d2 = depth + 1; + long id = oj_check_circular(a, out); if (0 > id) { - raise_json_err("Too deeply nested", "NestingError"); - return; + raise_json_err("Too deeply nested", "NestingError"); + return; } if (as_ok && !oj_use_hash_alt && rb_obj_class(a) != rb_cArray && rb_respond_to(a, oj_to_json_id)) { - dump_to_json(a, out); - return; + dump_to_json(a, out); + return; } cnt = (int)RARRAY_LEN(a); *out->cur++ = '['; assure_size(out, 2); if (0 == cnt) { - *out->cur++ = ']'; + *out->cur++ = ']'; } else { - if (out->opts->dump_opts.use) { - size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1; - } else { - size = d2 * out->indent + 2; - } - cnt--; - for (i = 0; i <= cnt; i++) { - assure_size(out, size); - if (out->opts->dump_opts.use) { - if (0 < out->opts->dump_opts.array_size) { - strcpy(out->cur, out->opts->dump_opts.array_nl); - out->cur += out->opts->dump_opts.array_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - for (i = d2; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - } else { - fill_indent(out, d2); - } - oj_dump_compat_val(rb_ary_entry(a, i), d2, out, true); - if (i < cnt) { - *out->cur++ = ','; - } - } - if (out->opts->dump_opts.use) { - size = out->opts->dump_opts.array_size + out->opts->dump_opts.indent_size * depth + 1; - assure_size(out, size); - if (0 < out->opts->dump_opts.array_size) { - strcpy(out->cur, out->opts->dump_opts.array_nl); - out->cur += out->opts->dump_opts.array_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - - for (i = depth; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - } else { - size = depth * out->indent + 1; - assure_size(out, size); - fill_indent(out, depth); - } - *out->cur++ = ']'; + if (out->opts->dump_opts.use) { + size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1; + } else { + size = d2 * out->indent + 2; + } + cnt--; + for (i = 0; i <= cnt; i++) { + assure_size(out, size); + if (out->opts->dump_opts.use) { + if (0 < out->opts->dump_opts.array_size) { + strcpy(out->cur, out->opts->dump_opts.array_nl); + out->cur += out->opts->dump_opts.array_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + for (i = d2; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + } else { + fill_indent(out, d2); + } + oj_dump_compat_val(rb_ary_entry(a, i), d2, out, true); + if (i < cnt) { + *out->cur++ = ','; + } + } + if (out->opts->dump_opts.use) { + size = out->opts->dump_opts.array_size + out->opts->dump_opts.indent_size * depth + 1; + assure_size(out, size); + if (0 < out->opts->dump_opts.array_size) { + strcpy(out->cur, out->opts->dump_opts.array_nl); + out->cur += out->opts->dump_opts.array_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + + for (i = depth; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + } else { + size = depth * out->indent + 1; + assure_size(out, size); + fill_indent(out, depth); + } + *out->cur++ = ']'; } *out->cur = '\0'; } -static ID _dump_id = 0; +static ID _dump_id = 0; static void bigdecimal_alt(VALUE obj, int depth, Out out) { - struct _attr attrs[] = { - { "b", 1, Qnil }, - { NULL, 0, Qnil }, + struct _attr attrs[] = { + { "b", 1, Qnil }, + { NULL, 0, Qnil }, }; if (0 == _dump_id) { - _dump_id = rb_intern("_dump"); + _dump_id = rb_intern("_dump"); } attrs[0].value = rb_funcall(obj, _dump_id, 0); oj_code_attrs(obj, attrs, depth, out, true); } -static ID real_id = 0; -static ID imag_id = 0; +static ID real_id = 0; +static ID imag_id = 0; static void complex_alt(VALUE obj, int depth, Out out) { - struct _attr attrs[] = { - { "r", 1, Qnil }, - { "i", 1, Qnil }, - { NULL, 0, Qnil }, + struct _attr attrs[] = { + { "r", 1, Qnil }, + { "i", 1, Qnil }, + { NULL, 0, Qnil }, }; if (0 == real_id) { - real_id = rb_intern("real"); - imag_id = rb_intern("imag"); + real_id = rb_intern("real"); + imag_id = rb_intern("imag"); } attrs[0].value = rb_funcall(obj, real_id, 0); attrs[1].value = rb_funcall(obj, imag_id, 0); @@ -250,25 +250,25 @@ complex_alt(VALUE obj, int depth, Out out) { oj_code_attrs(obj, attrs, depth, out, true); } -static ID year_id = 0; -static ID month_id = 0; -static ID day_id = 0; -static ID start_id = 0; +static ID year_id = 0; +static ID month_id = 0; +static ID day_id = 0; +static ID start_id = 0; static void date_alt(VALUE obj, int depth, Out out) { - struct _attr attrs[] = { - { "y", 1, Qnil }, - { "m", 1, Qnil }, - { "d", 1, Qnil }, - { "sg", 2, Qnil }, - { NULL, 0, Qnil }, + struct _attr attrs[] = { + { "y", 1, Qnil }, + { "m", 1, Qnil }, + { "d", 1, Qnil }, + { "sg", 2, Qnil }, + { NULL, 0, Qnil }, }; if (0 == year_id) { - year_id = rb_intern("year"); - month_id = rb_intern("month"); - day_id = rb_intern("day"); - start_id = rb_intern("start"); + year_id = rb_intern("year"); + month_id = rb_intern("month"); + day_id = rb_intern("day"); + start_id = rb_intern("start"); } attrs[0].value = rb_funcall(obj, year_id, 0); attrs[1].value = rb_funcall(obj, month_id, 0); @@ -278,33 +278,33 @@ date_alt(VALUE obj, int depth, Out out) { oj_code_attrs(obj, attrs, depth, out, true); } -static ID hour_id = 0; -static ID min_id = 0; -static ID sec_id = 0; -static ID offset_id = 0; +static ID hour_id = 0; +static ID min_id = 0; +static ID sec_id = 0; +static ID offset_id = 0; static void datetime_alt(VALUE obj, int depth, Out out) { - struct _attr attrs[] = { - { "y", 1, Qnil }, - { "m", 1, Qnil }, - { "d", 1, Qnil }, - { "H", 1, Qnil }, - { "M", 1, Qnil }, - { "S", 1, Qnil }, - { "of", 2, Qnil }, - { "sg", 2, Qnil }, - { NULL, 0, Qnil }, + struct _attr attrs[] = { + { "y", 1, Qnil }, + { "m", 1, Qnil }, + { "d", 1, Qnil }, + { "H", 1, Qnil }, + { "M", 1, Qnil }, + { "S", 1, Qnil }, + { "of", 2, Qnil }, + { "sg", 2, Qnil }, + { NULL, 0, Qnil }, }; if (0 == hour_id) { - year_id = rb_intern("year"); - month_id = rb_intern("month"); - day_id = rb_intern("day"); - hour_id = rb_intern("hour"); - min_id = rb_intern("min"); - sec_id = rb_intern("sec"); - offset_id = rb_intern("offset"); - start_id = rb_intern("start"); + year_id = rb_intern("year"); + month_id = rb_intern("month"); + day_id = rb_intern("day"); + hour_id = rb_intern("hour"); + min_id = rb_intern("min"); + sec_id = rb_intern("sec"); + offset_id = rb_intern("offset"); + start_id = rb_intern("start"); } attrs[0].value = rb_funcall(obj, year_id, 0); attrs[1].value = rb_funcall(obj, month_id, 0); @@ -318,18 +318,18 @@ datetime_alt(VALUE obj, int depth, Out out) { oj_code_attrs(obj, attrs, depth, out, true); } -static ID message_id = 0; -static ID backtrace_id = 0; +static ID message_id = 0; +static ID backtrace_id = 0; static void exception_alt(VALUE obj, int depth, Out out) { - int d3 = depth + 2; - size_t size = d3 * out->indent + 2; - size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2; + int d3 = depth + 2; + size_t size = d3 * out->indent + 2; + size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2; if (0 == message_id) { - message_id = rb_intern("message"); - backtrace_id = rb_intern("backtrace"); + message_id = rb_intern("message"); + backtrace_id = rb_intern("backtrace"); } dump_obj_classname(rb_class2name(rb_obj_class(obj)), depth, out); @@ -340,13 +340,13 @@ exception_alt(VALUE obj, int depth, Out out) { *out->cur++ = 'm'; *out->cur++ = '"'; if (0 < out->opts->dump_opts.before_size) { - strcpy(out->cur, out->opts->dump_opts.before_sep); - out->cur += out->opts->dump_opts.before_size; + strcpy(out->cur, out->opts->dump_opts.before_sep); + out->cur += out->opts->dump_opts.before_size; } *out->cur++ = ':'; if (0 < out->opts->dump_opts.after_size) { - strcpy(out->cur, out->opts->dump_opts.after_sep); - out->cur += out->opts->dump_opts.after_size; + strcpy(out->cur, out->opts->dump_opts.after_sep); + out->cur += out->opts->dump_opts.after_size; } oj_dump_str(rb_funcall(obj, message_id, 0), 0, out, false); assure_size(out, size + sep_len + 6); @@ -356,13 +356,13 @@ exception_alt(VALUE obj, int depth, Out out) { *out->cur++ = 'b'; *out->cur++ = '"'; if (0 < out->opts->dump_opts.before_size) { - strcpy(out->cur, out->opts->dump_opts.before_sep); - out->cur += out->opts->dump_opts.before_size; + strcpy(out->cur, out->opts->dump_opts.before_sep); + out->cur += out->opts->dump_opts.before_size; } *out->cur++ = ':'; if (0 < out->opts->dump_opts.after_size) { - strcpy(out->cur, out->opts->dump_opts.after_sep); - out->cur += out->opts->dump_opts.after_size; + strcpy(out->cur, out->opts->dump_opts.after_sep); + out->cur += out->opts->dump_opts.after_size; } dump_array(rb_funcall(obj, backtrace_id, 0), depth, out, false); fill_indent(out, depth); @@ -370,16 +370,16 @@ exception_alt(VALUE obj, int depth, Out out) { *out->cur = '\0'; } -static ID table_id = 0; +static ID table_id = 0; static void openstruct_alt(VALUE obj, int depth, Out out) { - struct _attr attrs[] = { - { "t", 1, Qnil }, - { NULL, 0, Qnil }, + struct _attr attrs[] = { + { "t", 1, Qnil }, + { NULL, 0, Qnil }, }; if (0 == table_id) { - table_id = rb_intern("table"); + table_id = rb_intern("table"); } attrs[0].value = rb_funcall(obj, table_id, 0); @@ -388,10 +388,10 @@ openstruct_alt(VALUE obj, int depth, Out out) { static void range_alt(VALUE obj, int depth, Out out) { - int d3 = depth + 2; - size_t size = d3 * out->indent + 2; - size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2; - VALUE args[] = { Qundef, Qundef, Qundef, Qundef }; + int d3 = depth + 2; + size_t size = d3 * out->indent + 2; + size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2; + VALUE args[] = { Qundef, Qundef, Qundef, Qundef }; dump_obj_classname(rb_class2name(rb_obj_class(obj)), depth, out); @@ -402,13 +402,13 @@ range_alt(VALUE obj, int depth, Out out) { *out->cur++ = 'a'; *out->cur++ = '"'; if (0 < out->opts->dump_opts.before_size) { - strcpy(out->cur, out->opts->dump_opts.before_sep); - out->cur += out->opts->dump_opts.before_size; + strcpy(out->cur, out->opts->dump_opts.before_sep); + out->cur += out->opts->dump_opts.before_size; } *out->cur++ = ':'; if (0 < out->opts->dump_opts.after_size) { - strcpy(out->cur, out->opts->dump_opts.after_sep); - out->cur += out->opts->dump_opts.after_size; + strcpy(out->cur, out->opts->dump_opts.after_sep); + out->cur += out->opts->dump_opts.after_size; } args[0] = rb_funcall(obj, oj_begin_id, 0); args[1] = rb_funcall(obj, oj_end_id, 0); @@ -419,19 +419,19 @@ range_alt(VALUE obj, int depth, Out out) { *out->cur = '\0'; } -static ID numerator_id = 0; -static ID denominator_id = 0; +static ID numerator_id = 0; +static ID denominator_id = 0; static void rational_alt(VALUE obj, int depth, Out out) { - struct _attr attrs[] = { - { "n", 1, Qnil }, - { "d", 1, Qnil }, - { NULL, 0, Qnil }, + struct _attr attrs[] = { + { "n", 1, Qnil }, + { "d", 1, Qnil }, + { NULL, 0, Qnil }, }; if (0 == numerator_id) { - numerator_id = rb_intern("numerator"); - denominator_id = rb_intern("denominator"); + numerator_id = rb_intern("numerator"); + denominator_id = rb_intern("denominator"); } attrs[0].value = rb_funcall(obj, numerator_id, 0); attrs[1].value = rb_funcall(obj, denominator_id, 0); @@ -439,19 +439,19 @@ rational_alt(VALUE obj, int depth, Out out) { oj_code_attrs(obj, attrs, depth, out, true); } -static ID options_id = 0; -static ID source_id = 0; +static ID options_id = 0; +static ID source_id = 0; static void regexp_alt(VALUE obj, int depth, Out out) { - struct _attr attrs[] = { - { "o", 1, Qnil }, - { "s", 1, Qnil }, - { NULL, 0, Qnil }, + struct _attr attrs[] = { + { "o", 1, Qnil }, + { "s", 1, Qnil }, + { NULL, 0, Qnil }, }; if (0 == options_id) { - options_id = rb_intern("options"); - source_id = rb_intern("source"); + options_id = rb_intern("options"); + source_id = rb_intern("source"); } attrs[0].value = rb_funcall(obj, options_id, 0); attrs[1].value = rb_funcall(obj, source_id, 0); @@ -461,23 +461,23 @@ regexp_alt(VALUE obj, int depth, Out out) { static void time_alt(VALUE obj, int depth, Out out) { - struct _attr attrs[] = { - { "s", 1, Qundef, 0, Qundef }, - { "n", 1, Qundef, 0, Qundef }, - { NULL, 0, Qnil }, + struct _attr attrs[] = { + { "s", 1, Qundef, 0, Qundef }, + { "n", 1, Qundef, 0, Qundef }, + { NULL, 0, Qnil }, }; - time_t sec; - long long nsec; + time_t sec; + long long nsec; #ifdef HAVE_RB_TIME_TIMESPEC if (16 <= sizeof(struct timespec)) { - struct timespec ts = rb_time_timespec(obj); + struct timespec ts = rb_time_timespec(obj); - sec = (long long)ts.tv_sec; - nsec = ts.tv_nsec; + sec = (long long)ts.tv_sec; + nsec = ts.tv_nsec; } else { - sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0)); - nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0)); + sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0)); + nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0)); } #else sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0)); @@ -490,7 +490,7 @@ time_alt(VALUE obj, int depth, Out out) { oj_code_attrs(obj, attrs, depth, out, true); } -struct _code oj_compat_codes[] = { +struct _code oj_compat_codes[] = { { "BigDecimal", Qnil, bigdecimal_alt, NULL, false }, { "Complex", Qnil, complex_alt, NULL, false }, { "Date", Qnil, date_alt, false }, @@ -506,52 +506,52 @@ struct _code oj_compat_codes[] = { VALUE oj_add_to_json(int argc, VALUE *argv, VALUE self) { - Code a; + Code a; if (0 == argc) { - for (a = oj_compat_codes; NULL != a->name; a++) { - if (Qnil == a->clas || Qundef == a->clas) { - a->clas = rb_const_get_at(rb_cObject, rb_intern(a->name)); - } - a->active = true; - } - use_struct_alt = true; - use_exception_alt = true; - use_bignum_alt = true; - oj_use_hash_alt = true; - oj_use_array_alt = true; + for (a = oj_compat_codes; NULL != a->name; a++) { + if (Qnil == a->clas || Qundef == a->clas) { + a->clas = rb_const_get_at(rb_cObject, rb_intern(a->name)); + } + a->active = true; + } + use_struct_alt = true; + use_exception_alt = true; + use_bignum_alt = true; + oj_use_hash_alt = true; + oj_use_array_alt = true; } else { - for (; 0 < argc; argc--, argv++) { - if (rb_cStruct == *argv) { - use_struct_alt = true; - continue; - } - if (rb_eException == *argv) { - use_exception_alt = true; - continue; - } - if (rb_cInteger == *argv) { - use_bignum_alt = true; - continue; - } - if (rb_cHash == *argv) { - oj_use_hash_alt = true; - continue; - } - if (rb_cArray == *argv) { - oj_use_array_alt = true; - continue; - } - for (a = oj_compat_codes; NULL != a->name; a++) { - if (Qnil == a->clas || Qundef == a->clas) { - a->clas = rb_const_get_at(rb_cObject, rb_intern(a->name)); - } - if (*argv == a->clas) { - a->active = true; - break; - } - } - } + for (; 0 < argc; argc--, argv++) { + if (rb_cStruct == *argv) { + use_struct_alt = true; + continue; + } + if (rb_eException == *argv) { + use_exception_alt = true; + continue; + } + if (rb_cInteger == *argv) { + use_bignum_alt = true; + continue; + } + if (rb_cHash == *argv) { + oj_use_hash_alt = true; + continue; + } + if (rb_cArray == *argv) { + oj_use_array_alt = true; + continue; + } + for (a = oj_compat_codes; NULL != a->name; a++) { + if (Qnil == a->clas || Qundef == a->clas) { + a->clas = rb_const_get_at(rb_cObject, rb_intern(a->name)); + } + if (*argv == a->clas) { + a->active = true; + break; + } + } + } } return Qnil; } @@ -559,36 +559,36 @@ oj_add_to_json(int argc, VALUE *argv, VALUE self) { VALUE oj_remove_to_json(int argc, VALUE *argv, VALUE self) { if (0 == argc) { - oj_code_set_active(oj_compat_codes, Qnil, false); - use_struct_alt = false; - use_exception_alt = false; - use_bignum_alt = false; - oj_use_hash_alt = false; - oj_use_array_alt = false; + oj_code_set_active(oj_compat_codes, Qnil, false); + use_struct_alt = false; + use_exception_alt = false; + use_bignum_alt = false; + oj_use_hash_alt = false; + oj_use_array_alt = false; } else { - for (; 0 < argc; argc--, argv++) { - if (rb_cStruct == *argv) { - use_struct_alt = false; - continue; - } - if (rb_eException == *argv) { - use_exception_alt = false; - continue; - } - if (rb_cInteger == *argv) { - use_bignum_alt = false; - continue; - } - if (rb_cHash == *argv) { - oj_use_hash_alt = false; - continue; - } - if (rb_cArray == *argv) { - oj_use_array_alt = false; - continue; - } - oj_code_set_active(oj_compat_codes, *argv, false); - } + for (; 0 < argc; argc--, argv++) { + if (rb_cStruct == *argv) { + use_struct_alt = false; + continue; + } + if (rb_eException == *argv) { + use_exception_alt = false; + continue; + } + if (rb_cInteger == *argv) { + use_bignum_alt = false; + continue; + } + if (rb_cHash == *argv) { + oj_use_hash_alt = false; + continue; + } + if (rb_cArray == *argv) { + oj_use_array_alt = false; + continue; + } + oj_code_set_active(oj_compat_codes, *argv, false); + } } return Qnil; } @@ -598,103 +598,103 @@ oj_remove_to_json(int argc, VALUE *argv, VALUE self) { // exception. Worse, for BigDecimals a quoted "Infinity" is returned. static void dump_float(VALUE obj, int depth, Out out, bool as_ok) { - char buf[64]; - char *b; - double d = rb_num2dbl(obj); - int cnt = 0; + char buf[64]; + char *b; + double d = rb_num2dbl(obj); + int cnt = 0; if (0.0 == d) { - b = buf; - *b++ = '0'; - *b++ = '.'; - *b++ = '0'; - *b++ = '\0'; - cnt = 3; + b = buf; + *b++ = '0'; + *b++ = '.'; + *b++ = '0'; + *b++ = '\0'; + cnt = 3; } else if (OJ_INFINITY == d) { - if (WordNan == out->opts->dump_opts.nan_dump) { - strcpy(buf, "Infinity"); - } else { - raise_json_err("Infinity not allowed in JSON.", "GeneratorError"); - } + if (WordNan == out->opts->dump_opts.nan_dump) { + strcpy(buf, "Infinity"); + } else { + raise_json_err("Infinity not allowed in JSON.", "GeneratorError"); + } } else if (-OJ_INFINITY == d) { - if (WordNan == out->opts->dump_opts.nan_dump) { - strcpy(buf, "-Infinity"); - } else { - raise_json_err("-Infinity not allowed in JSON.", "GeneratorError"); - } + if (WordNan == out->opts->dump_opts.nan_dump) { + strcpy(buf, "-Infinity"); + } else { + raise_json_err("-Infinity not allowed in JSON.", "GeneratorError"); + } } else if (isnan(d)) { - if (WordNan == out->opts->dump_opts.nan_dump) { - strcpy(buf, "NaN"); - } else { - raise_json_err("NaN not allowed in JSON.", "GeneratorError"); - } + if (WordNan == out->opts->dump_opts.nan_dump) { + strcpy(buf, "NaN"); + } else { + raise_json_err("NaN not allowed in JSON.", "GeneratorError"); + } } else if (d == (double)(long long int)d) { - cnt = snprintf(buf, sizeof(buf), "%.1f", d); + cnt = snprintf(buf, sizeof(buf), "%.1f", d); } else if (oj_rails_float_opt) { - cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, "%0.16g"); + cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, "%0.16g"); } else { - volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); + volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); - strcpy(buf, rb_string_value_ptr((VALUE *)&rstr)); - cnt = (int)RSTRING_LEN(rstr); + strcpy(buf, rb_string_value_ptr((VALUE*)&rstr)); + cnt = (int)RSTRING_LEN(rstr); } assure_size(out, cnt); for (b = buf; '\0' != *b; b++) { - *out->cur++ = *b; + *out->cur++ = *b; } *out->cur = '\0'; } static int hash_cb(VALUE key, VALUE value, VALUE ov) { - Out out = (Out)ov; - int depth = out->depth; + Out out = (Out)ov; + int depth = out->depth; if (out->omit_nil && Qnil == value) { - return ST_CONTINUE; + return ST_CONTINUE; } if (!out->opts->dump_opts.use) { - assure_size(out, depth * out->indent + 1); - fill_indent(out, depth); + assure_size(out, depth * out->indent + 1); + fill_indent(out, depth); } else { - assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1); - if (0 < out->opts->dump_opts.hash_size) { - strcpy(out->cur, out->opts->dump_opts.hash_nl); - out->cur += out->opts->dump_opts.hash_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - for (i = depth; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } + assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1); + if (0 < out->opts->dump_opts.hash_size) { + strcpy(out->cur, out->opts->dump_opts.hash_nl); + out->cur += out->opts->dump_opts.hash_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + for (i = depth; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } } switch (rb_type(key)) { - case T_STRING: - oj_dump_str(key, 0, out, false); - break; - case T_SYMBOL: - oj_dump_sym(key, 0, out, false); - break; - default: - /*rb_raise(rb_eTypeError, "In :compat mode all Hash keys must be Strings or Symbols, not %s.\n", rb_class2name(rb_obj_class(key)));*/ - oj_dump_str(rb_funcall(key, oj_to_s_id, 0), 0, out, false); - break; + case T_STRING: + oj_dump_str(key, 0, out, false); + break; + case T_SYMBOL: + oj_dump_sym(key, 0, out, false); + break; + default: + /*rb_raise(rb_eTypeError, "In :compat mode all Hash keys must be Strings or Symbols, not %s.\n", rb_class2name(rb_obj_class(key)));*/ + oj_dump_str(rb_funcall(key, oj_to_s_id, 0), 0, out, false); + break; } if (!out->opts->dump_opts.use) { - *out->cur++ = ':'; + *out->cur++ = ':'; } else { - assure_size(out, out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2); - if (0 < out->opts->dump_opts.before_size) { - strcpy(out->cur, out->opts->dump_opts.before_sep); - out->cur += out->opts->dump_opts.before_size; - } - *out->cur++ = ':'; - if (0 < out->opts->dump_opts.after_size) { - strcpy(out->cur, out->opts->dump_opts.after_sep); - out->cur += out->opts->dump_opts.after_size; - } + assure_size(out, out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2); + if (0 < out->opts->dump_opts.before_size) { + strcpy(out->cur, out->opts->dump_opts.before_sep); + out->cur += out->opts->dump_opts.before_size; + } + *out->cur++ = ':'; + if (0 < out->opts->dump_opts.after_size) { + strcpy(out->cur, out->opts->dump_opts.after_sep); + out->cur += out->opts->dump_opts.after_size; + } } oj_dump_compat_val(value, depth, out, true); out->depth = depth; @@ -705,48 +705,48 @@ hash_cb(VALUE key, VALUE value, VALUE ov) { static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) { - int cnt; - long id = oj_check_circular(obj, out); + int cnt; + long id = oj_check_circular(obj, out); if (0 > id) { - raise_json_err("Too deeply nested", "NestingError"); - return; + raise_json_err("Too deeply nested", "NestingError"); + return; } if (as_ok && !oj_use_hash_alt && rb_obj_class(obj) != rb_cHash && rb_respond_to(obj, oj_to_json_id)) { - dump_to_json(obj, out); - return; + dump_to_json(obj, out); + return; } cnt = (int)RHASH_SIZE(obj); assure_size(out, 2); if (0 == cnt) { - *out->cur++ = '{'; - *out->cur++ = '}'; + *out->cur++ = '{'; + *out->cur++ = '}'; } else { - *out->cur++ = '{'; - out->depth = depth + 1; - rb_hash_foreach(obj, hash_cb, (VALUE)out); - if (',' == *(out->cur - 1)) { - out->cur--; // backup to overwrite last comma - } - if (!out->opts->dump_opts.use) { - assure_size(out, depth * out->indent + 2); - fill_indent(out, depth); - } else { - assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1); - if (0 < out->opts->dump_opts.hash_size) { - strcpy(out->cur, out->opts->dump_opts.hash_nl); - out->cur += out->opts->dump_opts.hash_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - - for (i = depth; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - } - *out->cur++ = '}'; + *out->cur++ = '{'; + out->depth = depth + 1; + rb_hash_foreach(obj, hash_cb, (VALUE)out); + if (',' == *(out->cur - 1)) { + out->cur--; // backup to overwrite last comma + } + if (!out->opts->dump_opts.use) { + assure_size(out, depth * out->indent + 2); + fill_indent(out, depth); + } else { + assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1); + if (0 < out->opts->dump_opts.hash_size) { + strcpy(out->cur, out->opts->dump_opts.hash_nl); + out->cur += out->opts->dump_opts.hash_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + + for (i = depth; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + } + *out->cur++ = '}'; } *out->cur = '\0'; } @@ -756,19 +756,19 @@ dump_hash(VALUE obj, int depth, Out out, bool as_ok) { static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) { if (oj_code_dump(oj_compat_codes, obj, depth, out)) { - return; + return; } if (use_exception_alt && rb_obj_is_kind_of(obj, rb_eException)) { - exception_alt(obj, depth, out); - return; + exception_alt(obj, depth, out); + return; } if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) { - oj_dump_raw_json(obj, depth, out); - return; + oj_dump_raw_json(obj, depth, out); + return; } if (as_ok && rb_respond_to(obj, oj_to_json_id)) { - dump_to_json(obj, out); - return; + dump_to_json(obj, out); + return; } // Nothing else matched so encode as a JSON object with Ruby obj members // as JSON object members. @@ -777,88 +777,88 @@ dump_obj(VALUE obj, int depth, Out out, bool as_ok) { static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) { - VALUE clas = rb_obj_class(obj); + VALUE clas = rb_obj_class(obj); if (oj_code_dump(oj_compat_codes, obj, depth, out)) { - return; + return; } if (rb_cRange == clas) { - *out->cur++ = '"'; - oj_dump_compat_val(rb_funcall(obj, oj_begin_id, 0), 0, out, false); - assure_size(out, 3); - *out->cur++ = '.'; - *out->cur++ = '.'; - if (Qtrue == rb_funcall(obj, oj_exclude_end_id, 0)) { - *out->cur++ = '.'; - } - oj_dump_compat_val(rb_funcall(obj, oj_end_id, 0), 0, out, false); - *out->cur++ = '"'; - - return; + *out->cur++ = '"'; + oj_dump_compat_val(rb_funcall(obj, oj_begin_id, 0), 0, out, false); + assure_size(out, 3); + *out->cur++ = '.'; + *out->cur++ = '.'; + if (Qtrue == rb_funcall(obj, oj_exclude_end_id, 0)) { + *out->cur++ = '.'; + } + oj_dump_compat_val(rb_funcall(obj, oj_end_id, 0), 0, out, false); + *out->cur++ = '"'; + + return; } if (as_ok && rb_respond_to(obj, oj_to_json_id)) { - dump_to_json(obj, out); + dump_to_json(obj, out); - return; + return; } if (use_struct_alt) { - int d3 = depth + 2; - size_t size = d3 * out->indent + 2; - size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2; - const char *classname = rb_class2name(rb_obj_class(obj)); - VALUE args[100]; - int cnt; - int i; - - if (NULL == classname || '#' == *classname) { - raise_json_err("Only named structs are supported.", "JSONError"); - } + int d3 = depth + 2; + size_t size = d3 * out->indent + 2; + size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2; + const char *classname = rb_class2name(rb_obj_class(obj)); + VALUE args[100]; + int cnt; + int i; + + if (NULL == classname || '#' == *classname) { + raise_json_err("Only named structs are supported.", "JSONError"); + } #ifdef RSTRUCT_LEN #if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT - cnt = (int)NUM2LONG(RSTRUCT_LEN(obj)); -#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT - cnt = (int)RSTRUCT_LEN(obj); + cnt = (int)NUM2LONG(RSTRUCT_LEN(obj)); +#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT + cnt = (int)RSTRUCT_LEN(obj); #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT #else - // This is a bit risky as a struct in C ruby is not the same as a Struct - // class in interpreted Ruby so length() may not be defined. - cnt = FIX2INT(rb_funcall2(obj, oj_length_id, 0, 0)); + // This is a bit risky as a struct in C ruby is not the same as a Struct + // class in interpreted Ruby so length() may not be defined. + cnt = FIX2INT(rb_funcall2(obj, oj_length_id, 0, 0)); #endif - if (sizeof(args) / sizeof(*args) <= (size_t)cnt) { - // TBD allocate and try again - cnt = 99; - } - dump_obj_classname(rb_class2name(rb_obj_class(obj)), depth, out); - - assure_size(out, size + sep_len + 6); - *out->cur++ = ','; - fill_indent(out, d3); - *out->cur++ = '"'; - *out->cur++ = 'v'; - *out->cur++ = '"'; - if (0 < out->opts->dump_opts.before_size) { - strcpy(out->cur, out->opts->dump_opts.before_sep); - out->cur += out->opts->dump_opts.before_size; - } - *out->cur++ = ':'; - if (0 < out->opts->dump_opts.after_size) { - strcpy(out->cur, out->opts->dump_opts.after_sep); - out->cur += out->opts->dump_opts.after_size; - } - for (i = 0; i < cnt; i++) { + if (sizeof(args) / sizeof(*args) <= (size_t)cnt) { + // TBD allocate and try again + cnt = 99; + } + dump_obj_classname(rb_class2name(rb_obj_class(obj)), depth, out); + + assure_size(out, size + sep_len + 6); + *out->cur++ = ','; + fill_indent(out, d3); + *out->cur++ = '"'; + *out->cur++ = 'v'; + *out->cur++ = '"'; + if (0 < out->opts->dump_opts.before_size) { + strcpy(out->cur, out->opts->dump_opts.before_sep); + out->cur += out->opts->dump_opts.before_size; + } + *out->cur++ = ':'; + if (0 < out->opts->dump_opts.after_size) { + strcpy(out->cur, out->opts->dump_opts.after_sep); + out->cur += out->opts->dump_opts.after_size; + } + for (i = 0; i < cnt; i++) { #ifdef RSTRUCT_LEN - args[i] = RSTRUCT_GET(obj, i); + args[i] = RSTRUCT_GET(obj, i); #else - args[i] = rb_struct_aref(obj, INT2FIX(i)); + args[i] = rb_struct_aref(obj, INT2FIX(i)); #endif - } - args[cnt] = Qundef; - dump_values_array(args, depth, out); - fill_indent(out, depth); - *out->cur++ = '}'; - *out->cur = '\0'; + } + args[cnt] = Qundef; + dump_values_array(args, depth, out); + fill_indent(out, depth); + *out->cur++ = '}'; + *out->cur = '\0'; } else { - oj_dump_obj_to_s(obj, out); + oj_dump_obj_to_s(obj, out); } } @@ -867,107 +867,107 @@ dump_bignum(VALUE obj, int depth, Out out, bool as_ok) { // The json gem uses to_s explicitly. to_s can be overridden while // rb_big2str can not so unless overridden by using add_to_json(Integer) // this must use to_s to pass the json gem unit tests. - volatile VALUE rs; - int cnt; - bool dump_as_string = false; + volatile VALUE rs; + int cnt; + bool dump_as_string = false; if (use_bignum_alt) { - rs = rb_big2str(obj, 10); + rs = rb_big2str(obj, 10); } else { - rs = rb_funcall(obj, oj_to_s_id, 0); + rs = rb_funcall(obj, oj_to_s_id, 0); } rb_check_type(rs, T_STRING); cnt = (int)RSTRING_LEN(rs); if (out->opts->int_range_min != 0 || out->opts->int_range_max != 0) { - dump_as_string = true; // Bignum cannot be inside of Fixnum range - assure_size(out, cnt + 2); - *out->cur++ = '"'; + dump_as_string = true; // Bignum cannot be inside of Fixnum range + assure_size(out, cnt + 2); + *out->cur++ = '"'; } else { - assure_size(out, cnt); + assure_size(out, cnt); } - memcpy(out->cur, rb_string_value_ptr((VALUE *)&rs), cnt); + memcpy(out->cur, rb_string_value_ptr((VALUE*)&rs), cnt); out->cur += cnt; if (dump_as_string) { - *out->cur++ = '"'; + *out->cur++ = '"'; } *out->cur = '\0'; } -static DumpFunc compat_funcs[] = { - NULL, // RUBY_T_NONE = 0x00, - dump_obj, // RUBY_T_OBJECT = 0x01, - oj_dump_class, // RUBY_T_CLASS = 0x02, - oj_dump_class, // RUBY_T_MODULE = 0x03, - dump_float, // RUBY_T_FLOAT = 0x04, - oj_dump_str, // RUBY_T_STRING = 0x05, - dump_obj, // RUBY_T_REGEXP = 0x06, - dump_array, // RUBY_T_ARRAY = 0x07, - dump_hash, // RUBY_T_HASH = 0x08, - dump_struct, // RUBY_T_STRUCT = 0x09, - dump_bignum, // RUBY_T_BIGNUM = 0x0a, - NULL, // RUBY_T_FILE = 0x0b, - dump_obj, // RUBY_T_DATA = 0x0c, - NULL, // RUBY_T_MATCH = 0x0d, - dump_obj, // RUBY_T_COMPLEX = 0x0e, - dump_obj, // RUBY_T_RATIONAL = 0x0f, - NULL, // 0x10 - oj_dump_nil, // RUBY_T_NIL = 0x11, - oj_dump_true, // RUBY_T_TRUE = 0x12, - oj_dump_false, // RUBY_T_FALSE = 0x13, - oj_dump_sym, // RUBY_T_SYMBOL = 0x14, - oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15, +static DumpFunc compat_funcs[] = { + NULL, // RUBY_T_NONE = 0x00, + dump_obj, // RUBY_T_OBJECT = 0x01, + oj_dump_class, // RUBY_T_CLASS = 0x02, + oj_dump_class, // RUBY_T_MODULE = 0x03, + dump_float, // RUBY_T_FLOAT = 0x04, + oj_dump_str, // RUBY_T_STRING = 0x05, + dump_obj, // RUBY_T_REGEXP = 0x06, + dump_array, // RUBY_T_ARRAY = 0x07, + dump_hash, // RUBY_T_HASH = 0x08, + dump_struct, // RUBY_T_STRUCT = 0x09, + dump_bignum, // RUBY_T_BIGNUM = 0x0a, + NULL, // RUBY_T_FILE = 0x0b, + dump_obj, // RUBY_T_DATA = 0x0c, + NULL, // RUBY_T_MATCH = 0x0d, + dump_obj, // RUBY_T_COMPLEX = 0x0e, + dump_obj, // RUBY_T_RATIONAL = 0x0f, + NULL, // 0x10 + oj_dump_nil, // RUBY_T_NIL = 0x11, + oj_dump_true, // RUBY_T_TRUE = 0x12, + oj_dump_false, // RUBY_T_FALSE = 0x13, + oj_dump_sym, // RUBY_T_SYMBOL = 0x14, + oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15, }; static void set_state_depth(VALUE state, int depth) { - VALUE json_module = rb_const_get_at(rb_cObject, rb_intern("JSON")); - VALUE ext = rb_const_get(json_module, rb_intern("Ext")); - VALUE generator = rb_const_get(ext, rb_intern("Generator")); - VALUE state_class = rb_const_get(generator, rb_intern("State")); + VALUE json_module = rb_const_get_at(rb_cObject, rb_intern("JSON")); + VALUE ext = rb_const_get(json_module, rb_intern("Ext")); + VALUE generator = rb_const_get(ext, rb_intern("Generator")); + VALUE state_class = rb_const_get(generator, rb_intern("State")); if (state_class == rb_obj_class(state)) { - rb_funcall(state, rb_intern("depth="), 1, INT2NUM(depth)); + rb_funcall(state, rb_intern("depth="), 1, INT2NUM(depth)); } } void oj_dump_compat_val(VALUE obj, int depth, Out out, bool as_ok) { - int type = rb_type(obj); + int type = rb_type(obj); if (Yes == out->opts->trace) { - oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn); + oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn); } if (out->opts->dump_opts.max_depth <= depth) { - // When JSON.dump is called then an ArgumentError is expected and the - // limit is the depth inclusive. If JSON.generate is called then a - // NestingError is expected and the limit is inclusive. Worse than - // that there are unit tests for both. - if (CALLER_DUMP == out->caller) { - if (0 < out->argc) { - set_state_depth(*out->argv, depth); - } - rb_raise(rb_eArgError, "Too deeply nested."); - } else if (out->opts->dump_opts.max_depth < depth) { - if (0 < out->argc) { - set_state_depth(*out->argv, depth - 1); - } - raise_json_err("Too deeply nested", "NestingError"); - } + // When JSON.dump is called then an ArgumentError is expected and the + // limit is the depth inclusive. If JSON.generate is called then a + // NestingError is expected and the limit is inclusive. Worse than + // that there are unit tests for both. + if (CALLER_DUMP == out->caller) { + if (0 < out->argc) { + set_state_depth(*out->argv, depth); + } + rb_raise(rb_eArgError, "Too deeply nested."); + } else if (out->opts->dump_opts.max_depth < depth) { + if (0 < out->argc) { + set_state_depth(*out->argv, depth - 1); + } + raise_json_err("Too deeply nested", "NestingError"); + } } if (0 < type && type <= RUBY_T_FIXNUM) { - DumpFunc f = compat_funcs[type]; + DumpFunc f = compat_funcs[type]; - if (NULL != f) { - f(obj, depth, out, as_ok); - if (Yes == out->opts->trace) { - oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut); - } - return; - } + if (NULL != f) { + f(obj, depth, out, as_ok); + if (Yes == out->opts->trace) { + oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut); + } + return; + } } oj_dump_nil(Qnil, depth, out, false); if (Yes == out->opts->trace) { - oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut); + oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut); } } diff --git a/ext/oj/dump_leaf.c b/ext/oj/dump_leaf.c index 5353cb4c..932b9366 100644 --- a/ext/oj/dump_leaf.c +++ b/ext/oj/dump_leaf.c @@ -3,40 +3,41 @@ #include -#include "dump.h" #include "oj.h" +#include "dump.h" -static void dump_leaf(Leaf leaf, int depth, Out out); +static void dump_leaf(Leaf leaf, int depth, Out out); static void grow(Out out, size_t len) { - size_t size = out->end - out->buf; - long pos = out->cur - out->buf; - char *buf; + size_t size = out->end - out->buf; + long pos = out->cur - out->buf; + char *buf; size *= 2; if (size <= len * 2 + pos) { - size += len; + size += len; } if (out->allocated) { - buf = REALLOC_N(out->buf, char, (size + BUFFER_EXTRA)); + buf = REALLOC_N(out->buf, char, (size + BUFFER_EXTRA)); } else { - buf = ALLOC_N(char, (size + BUFFER_EXTRA)); - out->allocated = true; - memcpy(buf, out->buf, out->end - out->buf + BUFFER_EXTRA); + buf = ALLOC_N(char, (size + BUFFER_EXTRA)); + out->allocated = true; + memcpy(buf, out->buf, out->end - out->buf + BUFFER_EXTRA); } if (0 == buf) { - rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]\n", ENOSPC, strerror(ENOSPC)); + rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]\n", ENOSPC, strerror(ENOSPC)); } out->buf = buf; out->end = buf + size; out->cur = out->buf + pos; } + inline static void dump_chars(const char *s, size_t size, Out out) { if (out->end - out->cur <= (long)size) { - grow(out, size); + grow(out, size); } memcpy(out->cur, s, size); out->cur += size; @@ -46,129 +47,129 @@ dump_chars(const char *s, size_t size, Out out) { static void dump_leaf_str(Leaf leaf, Out out) { switch (leaf->value_type) { - case STR_VAL: - oj_dump_cstr(leaf->str, strlen(leaf->str), 0, 0, out); - break; - case RUBY_VAL: - oj_dump_cstr(rb_string_value_cstr(&leaf->value), (int)RSTRING_LEN(leaf->value), 0, 0, out); - break; - case COL_VAL: - default: - rb_raise(rb_eTypeError, "Unexpected value type %02x.\n", leaf->value_type); - break; + case STR_VAL: + oj_dump_cstr(leaf->str, strlen(leaf->str), 0, 0, out); + break; + case RUBY_VAL: + oj_dump_cstr(rb_string_value_cstr(&leaf->value), (int)RSTRING_LEN(leaf->value), 0, 0, out); + break; + case COL_VAL: + default: + rb_raise(rb_eTypeError, "Unexpected value type %02x.\n", leaf->value_type); + break; } } static void dump_leaf_fixnum(Leaf leaf, Out out) { switch (leaf->value_type) { - case STR_VAL: - dump_chars(leaf->str, strlen(leaf->str), out); - break; - case RUBY_VAL: - if (T_BIGNUM == rb_type(leaf->value)) { - oj_dump_bignum(leaf->value, 0, out, false); - } else { - oj_dump_fixnum(leaf->value, 0, out, false); - } - break; - case COL_VAL: - default: - rb_raise(rb_eTypeError, "Unexpected value type %02x.\n", leaf->value_type); - break; + case STR_VAL: + dump_chars(leaf->str, strlen(leaf->str), out); + break; + case RUBY_VAL: + if (T_BIGNUM == rb_type(leaf->value)) { + oj_dump_bignum(leaf->value, 0, out, false); + } else { + oj_dump_fixnum(leaf->value, 0, out, false); + } + break; + case COL_VAL: + default: + rb_raise(rb_eTypeError, "Unexpected value type %02x.\n", leaf->value_type); + break; } } static void dump_leaf_float(Leaf leaf, Out out) { switch (leaf->value_type) { - case STR_VAL: - dump_chars(leaf->str, strlen(leaf->str), out); - break; - case RUBY_VAL: - oj_dump_float(leaf->value, 0, out, false); - break; - case COL_VAL: - default: - rb_raise(rb_eTypeError, "Unexpected value type %02x.\n", leaf->value_type); - break; + case STR_VAL: + dump_chars(leaf->str, strlen(leaf->str), out); + break; + case RUBY_VAL: + oj_dump_float(leaf->value, 0, out, false); + break; + case COL_VAL: + default: + rb_raise(rb_eTypeError, "Unexpected value type %02x.\n", leaf->value_type); + break; } } static void dump_leaf_array(Leaf leaf, int depth, Out out) { - size_t size; - int d2 = depth + 1; + size_t size; + int d2 = depth + 1; size = 2; if (out->end - out->cur <= (long)size) { - grow(out, size); + grow(out, size); } *out->cur++ = '['; if (0 == leaf->elements) { - *out->cur++ = ']'; + *out->cur++ = ']'; } else { - Leaf first = leaf->elements->next; - Leaf e = first; - - size = d2 * out->indent + 2; - do { - if (out->end - out->cur <= (long)size) { - grow(out, size); - } - fill_indent(out, d2); - dump_leaf(e, d2, out); - if (e->next != first) { - *out->cur++ = ','; - } - e = e->next; - } while (e != first); - size = depth * out->indent + 1; - if (out->end - out->cur <= (long)size) { - grow(out, size); - } - fill_indent(out, depth); - *out->cur++ = ']'; + Leaf first = leaf->elements->next; + Leaf e = first; + + size = d2 * out->indent + 2; + do { + if (out->end - out->cur <= (long)size) { + grow(out, size); + } + fill_indent(out, d2); + dump_leaf(e, d2, out); + if (e->next != first) { + *out->cur++ = ','; + } + e = e->next; + } while (e != first); + size = depth * out->indent + 1; + if (out->end - out->cur <= (long)size) { + grow(out, size); + } + fill_indent(out, depth); + *out->cur++ = ']'; } *out->cur = '\0'; } static void dump_leaf_hash(Leaf leaf, int depth, Out out) { - size_t size; - int d2 = depth + 1; + size_t size; + int d2 = depth + 1; size = 2; if (out->end - out->cur <= (long)size) { - grow(out, size); + grow(out, size); } *out->cur++ = '{'; if (0 == leaf->elements) { - *out->cur++ = '}'; + *out->cur++ = '}'; } else { - Leaf first = leaf->elements->next; - Leaf e = first; - - size = d2 * out->indent + 2; - do { - if (out->end - out->cur <= (long)size) { - grow(out, size); - } - fill_indent(out, d2); - oj_dump_cstr(e->key, strlen(e->key), 0, 0, out); - *out->cur++ = ':'; - dump_leaf(e, d2, out); - if (e->next != first) { - *out->cur++ = ','; - } - e = e->next; - } while (e != first); - size = depth * out->indent + 1; - if (out->end - out->cur <= (long)size) { - grow(out, size); - } - fill_indent(out, depth); - *out->cur++ = '}'; + Leaf first = leaf->elements->next; + Leaf e = first; + + size = d2 * out->indent + 2; + do { + if (out->end - out->cur <= (long)size) { + grow(out, size); + } + fill_indent(out, d2); + oj_dump_cstr(e->key, strlen(e->key), 0, 0, out); + *out->cur++ = ':'; + dump_leaf(e, d2, out); + if (e->next != first) { + *out->cur++ = ','; + } + e = e->next; + } while (e != first); + size = depth * out->indent + 1; + if (out->end - out->cur <= (long)size) { + grow(out, size); + } + fill_indent(out, depth); + *out->cur++ = '}'; } *out->cur = '\0'; } @@ -176,42 +177,42 @@ dump_leaf_hash(Leaf leaf, int depth, Out out) { static void dump_leaf(Leaf leaf, int depth, Out out) { switch (leaf->rtype) { - case T_NIL: - oj_dump_nil(Qnil, 0, out, false); - break; - case T_TRUE: - oj_dump_true(Qtrue, 0, out, false); - break; - case T_FALSE: - oj_dump_false(Qfalse, 0, out, false); - break; - case T_STRING: - dump_leaf_str(leaf, out); - break; - case T_FIXNUM: - dump_leaf_fixnum(leaf, out); - break; - case T_FLOAT: - dump_leaf_float(leaf, out); - break; - case T_ARRAY: - dump_leaf_array(leaf, depth, out); - break; - case T_HASH: - dump_leaf_hash(leaf, depth, out); - break; - default: - rb_raise(rb_eTypeError, "Unexpected type %02x.\n", leaf->rtype); - break; + case T_NIL: + oj_dump_nil(Qnil, 0, out, false); + break; + case T_TRUE: + oj_dump_true(Qtrue, 0, out, false); + break; + case T_FALSE: + oj_dump_false(Qfalse, 0, out, false); + break; + case T_STRING: + dump_leaf_str(leaf, out); + break; + case T_FIXNUM: + dump_leaf_fixnum(leaf, out); + break; + case T_FLOAT: + dump_leaf_float(leaf, out); + break; + case T_ARRAY: + dump_leaf_array(leaf, depth, out); + break; + case T_HASH: + dump_leaf_hash(leaf, depth, out); + break; + default: + rb_raise(rb_eTypeError, "Unexpected type %02x.\n", leaf->rtype); + break; } } void oj_dump_leaf_to_json(Leaf leaf, Options copts, Out out) { if (0 == out->buf) { - out->buf = ALLOC_N(char, 4096); - out->end = out->buf + 4095 - BUFFER_EXTRA; // 1 less than end plus extra for possible errors - out->allocated = true; + out->buf = ALLOC_N(char, 4096); + out->end = out->buf + 4095 - BUFFER_EXTRA; // 1 less than end plus extra for possible errors + out->allocated = true; } out->cur = out->buf; out->circ_cnt = 0; @@ -223,10 +224,10 @@ oj_dump_leaf_to_json(Leaf leaf, Options copts, Out out) { void oj_write_leaf_to_file(Leaf leaf, const char *path, Options copts) { - char buf[4096]; + char buf[4096]; struct _out out; - size_t size; - FILE *f; + size_t size; + FILE *f; out.buf = buf; out.end = buf + sizeof(buf) - BUFFER_EXTRA; @@ -235,15 +236,15 @@ oj_write_leaf_to_file(Leaf leaf, const char *path, Options copts) { oj_dump_leaf_to_json(leaf, copts, &out); size = out.cur - out.buf; if (0 == (f = fopen(path, "w"))) { - rb_raise(rb_eIOError, "%s\n", strerror(errno)); + rb_raise(rb_eIOError, "%s\n", strerror(errno)); } if (size != fwrite(out.buf, 1, size, f)) { - int err = ferror(f); + int err = ferror(f); - rb_raise(rb_eIOError, "Write failed. [%d:%s]\n", err, strerror(err)); + rb_raise(rb_eIOError, "Write failed. [%d:%s]\n", err, strerror(err)); } if (out.allocated) { - xfree(out.buf); + xfree(out.buf); } fclose(f); } diff --git a/ext/oj/dump_object.c b/ext/oj/dump_object.c index 47d9f7dc..96780b3c 100644 --- a/ext/oj/dump_object.c +++ b/ext/oj/dump_object.c @@ -5,100 +5,94 @@ #include "odd.h" #include "trace.h" -static const char hex_chars[17] = "0123456789abcdef"; +static const char hex_chars[17] = "0123456789abcdef"; -static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out); +static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out); static void dump_time(VALUE obj, Out out) { switch (out->opts->time_format) { - case RubyTime: - case XmlTime: - oj_dump_xml_time(obj, out); - break; - case UnixZTime: - oj_dump_time(obj, out, 1); - break; - case UnixTime: - default: - oj_dump_time(obj, out, 0); - break; + case RubyTime: + case XmlTime: oj_dump_xml_time(obj, out); break; + case UnixZTime: oj_dump_time(obj, out, 1); break; + case UnixTime: + default: oj_dump_time(obj, out, 0); break; } } static void dump_data(VALUE obj, int depth, Out out, bool as_ok) { - VALUE clas = rb_obj_class(obj); + VALUE clas = rb_obj_class(obj); if (rb_cTime == clas) { - assure_size(out, 6); - *out->cur++ = '{'; - *out->cur++ = '"'; - *out->cur++ = '^'; - *out->cur++ = 't'; - *out->cur++ = '"'; - *out->cur++ = ':'; - dump_time(obj, out); - *out->cur++ = '}'; - *out->cur = '\0'; + assure_size(out, 6); + *out->cur++ = '{'; + *out->cur++ = '"'; + *out->cur++ = '^'; + *out->cur++ = 't'; + *out->cur++ = '"'; + *out->cur++ = ':'; + dump_time(obj, out); + *out->cur++ = '}'; + *out->cur = '\0'; } else { - if (oj_bigdecimal_class == clas) { - volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); - const char *str = rb_string_value_ptr((VALUE *)&rstr); - int len = (int)RSTRING_LEN(rstr); - - if (No != out->opts->bigdec_as_num) { - oj_dump_raw(str, len, out); - } else if (0 == strcasecmp("Infinity", str)) { - str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len); - oj_dump_raw(str, len, out); - } else if (0 == strcasecmp("-Infinity", str)) { - str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len); - oj_dump_raw(str, len, out); - } else { - oj_dump_cstr(str, len, 0, 0, out); - } - } else { - long id = oj_check_circular(obj, out); - - if (0 <= id) { - dump_obj_attrs(obj, clas, id, depth, out); - } - } + if (oj_bigdecimal_class == clas) { + volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); + const char *str = rb_string_value_ptr((VALUE*)&rstr); + int len = (int)RSTRING_LEN(rstr); + + if (No != out->opts->bigdec_as_num) { + oj_dump_raw(str, len, out); + } else if (0 == strcasecmp("Infinity", str)) { + str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len); + oj_dump_raw(str, len, out); + } else if (0 == strcasecmp("-Infinity", str)) { + str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len); + oj_dump_raw(str, len, out); + } else { + oj_dump_cstr(str, len, 0, 0, out); + } + } else { + long id = oj_check_circular(obj, out); + + if (0 <= id) { + dump_obj_attrs(obj, clas, id, depth, out); + } + } } } static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) { - VALUE clas = rb_obj_class(obj); + VALUE clas = rb_obj_class(obj); if (oj_bigdecimal_class == clas) { - volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); - const char *str = rb_string_value_ptr((VALUE *)&rstr); - int len = (int)RSTRING_LEN(rstr); - - if (0 == strcasecmp("Infinity", str)) { - str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len); - oj_dump_raw(str, len, out); - } else if (0 == strcasecmp("-Infinity", str)) { - str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len); - oj_dump_raw(str, len, out); - } else { - oj_dump_raw(str, len, out); - } + volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); + const char *str = rb_string_value_ptr((VALUE*)&rstr); + int len = (int)RSTRING_LEN(rstr); + + if (0 == strcasecmp("Infinity", str)) { + str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len); + oj_dump_raw(str, len, out); + } else if (0 == strcasecmp("-Infinity", str)) { + str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len); + oj_dump_raw(str, len, out); + } else { + oj_dump_raw(str, len, out); + } } else { - long id = oj_check_circular(obj, out); + long id = oj_check_circular(obj, out); - if (0 <= id) { - dump_obj_attrs(obj, clas, id, depth, out); - } + if (0 <= id) { + dump_obj_attrs(obj, clas, id, depth, out); + } } } static void dump_class(VALUE obj, int depth, Out out, bool as_ok) { - const char *s = rb_class2name(obj); - size_t len = strlen(s); + const char *s = rb_class2name(obj); + size_t len = strlen(s); assure_size(out, 6); *out->cur++ = '{'; @@ -114,85 +108,85 @@ dump_class(VALUE obj, int depth, Out out, bool as_ok) { static void dump_array_class(VALUE a, VALUE clas, int depth, Out out) { - size_t size; - int i, cnt; - int d2 = depth + 1; - long id = oj_check_circular(a, out); + size_t size; + int i, cnt; + int d2 = depth + 1; + long id = oj_check_circular(a, out); if (id < 0) { - return; + return; } if (Qundef != clas && rb_cArray != clas && ObjectMode == out->opts->mode) { - dump_obj_attrs(a, clas, 0, depth, out); - return; + dump_obj_attrs(a, clas, 0, depth, out); + return; } cnt = (int)RARRAY_LEN(a); *out->cur++ = '['; if (0 < id) { - assure_size(out, d2 * out->indent + 16); - fill_indent(out, d2); - *out->cur++ = '"'; - *out->cur++ = '^'; - *out->cur++ = 'i'; - dump_ulong(id, out); - *out->cur++ = '"'; + assure_size(out, d2 * out->indent + 16); + fill_indent(out, d2); + *out->cur++ = '"'; + *out->cur++ = '^'; + *out->cur++ = 'i'; + dump_ulong(id, out); + *out->cur++ = '"'; } size = 2; assure_size(out, 2); if (0 == cnt) { - *out->cur++ = ']'; + *out->cur++ = ']'; } else { - if (0 < id) { - *out->cur++ = ','; - } - if (out->opts->dump_opts.use) { - size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1; - } else { - size = d2 * out->indent + 2; - } - cnt--; - for (i = 0; i <= cnt; i++) { - assure_size(out, size); - if (out->opts->dump_opts.use) { - if (0 < out->opts->dump_opts.array_size) { - strcpy(out->cur, out->opts->dump_opts.array_nl); - out->cur += out->opts->dump_opts.array_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - for (i = d2; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - } else { - fill_indent(out, d2); - } - oj_dump_obj_val(rb_ary_entry(a, i), d2, out); - if (i < cnt) { - *out->cur++ = ','; - } - } - size = depth * out->indent + 1; - assure_size(out, size); - if (out->opts->dump_opts.use) { - //printf("*** d2: %u indent: %u '%s'\n", d2, out->opts->dump_opts->indent_size, out->opts->dump_opts->indent); - if (0 < out->opts->dump_opts.array_size) { - strcpy(out->cur, out->opts->dump_opts.array_nl); - out->cur += out->opts->dump_opts.array_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - - for (i = depth; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - } else { - fill_indent(out, depth); - } - *out->cur++ = ']'; + if (0 < id) { + *out->cur++ = ','; + } + if (out->opts->dump_opts.use) { + size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1; + } else { + size = d2 * out->indent + 2; + } + cnt--; + for (i = 0; i <= cnt; i++) { + assure_size(out, size); + if (out->opts->dump_opts.use) { + if (0 < out->opts->dump_opts.array_size) { + strcpy(out->cur, out->opts->dump_opts.array_nl); + out->cur += out->opts->dump_opts.array_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + for (i = d2; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + } else { + fill_indent(out, d2); + } + oj_dump_obj_val(rb_ary_entry(a, i), d2, out); + if (i < cnt) { + *out->cur++ = ','; + } + } + size = depth * out->indent + 1; + assure_size(out, size); + if (out->opts->dump_opts.use) { + //printf("*** d2: %u indent: %u '%s'\n", d2, out->opts->dump_opts->indent_size, out->opts->dump_opts->indent); + if (0 < out->opts->dump_opts.array_size) { + strcpy(out->cur, out->opts->dump_opts.array_nl); + out->cur += out->opts->dump_opts.array_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + + for (i = depth; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + } else { + fill_indent(out, depth); + } + *out->cur++ = ']'; } *out->cur = '\0'; } @@ -205,13 +199,13 @@ dump_array(VALUE obj, int depth, Out out, bool as_ok) { static void dump_str_class(VALUE obj, VALUE clas, int depth, Out out) { if (Qundef != clas && rb_cString != clas) { - dump_obj_attrs(obj, clas, 0, depth, out); + dump_obj_attrs(obj, clas, 0, depth, out); } else { - const char *s = rb_string_value_ptr((VALUE *)&obj); - size_t len = (int)RSTRING_LEN(obj); - char s1 = s[1]; + const char *s = rb_string_value_ptr((VALUE*)&obj); + size_t len = (int)RSTRING_LEN(obj); + char s1 = s[1]; - oj_dump_cstr(s, len, 0, (':' == *s || ('^' == *s && ('r' == s1 || 'i' == s1))), out); + oj_dump_cstr(s, len, 0, (':' == *s || ('^' == *s && ('r' == s1 || 'i' == s1))), out); } } @@ -222,66 +216,66 @@ dump_str(VALUE obj, int depth, Out out, bool as_ok) { static void dump_sym(VALUE obj, int depth, Out out, bool as_ok) { - volatile VALUE s = rb_sym_to_s(obj); + volatile VALUE s = rb_sym_to_s(obj); - oj_dump_cstr(rb_string_value_ptr((VALUE *)&s), (int)RSTRING_LEN(s), 1, 0, out); + oj_dump_cstr(rb_string_value_ptr((VALUE*)&s), (int)RSTRING_LEN(s), 1, 0, out); } static int hash_cb(VALUE key, VALUE value, VALUE ov) { - Out out = (Out)ov; - int depth = out->depth; - long size = depth * out->indent + 1; + Out out = (Out)ov; + int depth = out->depth; + long size = depth * out->indent + 1; if (oj_dump_ignore(out->opts, value)) { - return ST_CONTINUE; + return ST_CONTINUE; } if (out->omit_nil && Qnil == value) { - return ST_CONTINUE; + return ST_CONTINUE; } assure_size(out, size); fill_indent(out, depth); if (rb_type(key) == T_STRING) { - dump_str_class(key, Qundef, depth, out); - *out->cur++ = ':'; - oj_dump_obj_val(value, depth, out); + dump_str_class(key, Qundef, depth, out); + *out->cur++ = ':'; + oj_dump_obj_val(value, depth, out); } else if (rb_type(key) == T_SYMBOL) { - dump_sym(key, 0, out, false); - *out->cur++ = ':'; - oj_dump_obj_val(value, depth, out); + dump_sym(key, 0, out, false); + *out->cur++ = ':'; + oj_dump_obj_val(value, depth, out); } else { - int d2 = depth + 1; - long s2 = size + out->indent + 1; - int i; - int started = 0; - uint8_t b; - - assure_size(out, s2 + 15); - *out->cur++ = '"'; - *out->cur++ = '^'; - *out->cur++ = '#'; - out->hash_cnt++; - for (i = 28; 0 <= i; i -= 4) { - b = (uint8_t)((out->hash_cnt >> i) & 0x0000000F); - if ('\0' != b) { - started = 1; - } - if (started) { - *out->cur++ = hex_chars[b]; - } - } - *out->cur++ = '"'; - *out->cur++ = ':'; - *out->cur++ = '['; - fill_indent(out, d2); - oj_dump_obj_val(key, d2, out); - assure_size(out, s2); - *out->cur++ = ','; - fill_indent(out, d2); - oj_dump_obj_val(value, d2, out); - assure_size(out, size); - fill_indent(out, depth); - *out->cur++ = ']'; + int d2 = depth + 1; + long s2 = size + out->indent + 1; + int i; + int started = 0; + uint8_t b; + + assure_size(out, s2 + 15); + *out->cur++ = '"'; + *out->cur++ = '^'; + *out->cur++ = '#'; + out->hash_cnt++; + for (i = 28; 0 <= i; i -= 4) { + b = (uint8_t)((out->hash_cnt >> i) & 0x0000000F); + if ('\0' != b) { + started = 1; + } + if (started) { + *out->cur++ = hex_chars[b]; + } + } + *out->cur++ = '"'; + *out->cur++ = ':'; + *out->cur++ = '['; + fill_indent(out, d2); + oj_dump_obj_val(key, d2, out); + assure_size(out, s2); + *out->cur++ = ','; + fill_indent(out, d2); + oj_dump_obj_val(value, d2, out); + assure_size(out, size); + fill_indent(out, depth); + *out->cur++ = ']'; } out->depth = depth; *out->cur++ = ','; @@ -291,62 +285,62 @@ hash_cb(VALUE key, VALUE value, VALUE ov) { static void dump_hash_class(VALUE obj, VALUE clas, int depth, Out out) { - int cnt; - size_t size; + int cnt; + size_t size; if (Qundef != clas && rb_cHash != clas) { - dump_obj_attrs(obj, clas, 0, depth, out); - return; + dump_obj_attrs(obj, clas, 0, depth, out); + return; } cnt = (int)RHASH_SIZE(obj); size = depth * out->indent + 2; assure_size(out, 2); if (0 == cnt) { - *out->cur++ = '{'; - *out->cur++ = '}'; + *out->cur++ = '{'; + *out->cur++ = '}'; } else { - long id = oj_check_circular(obj, out); - - if (0 > id) { - return; - } - *out->cur++ = '{'; - if (0 < id) { - assure_size(out, size + 16); - fill_indent(out, depth + 1); - *out->cur++ = '"'; - *out->cur++ = '^'; - *out->cur++ = 'i'; - *out->cur++ = '"'; - *out->cur++ = ':'; - dump_ulong(id, out); - *out->cur++ = ','; - } - out->depth = depth + 1; - rb_hash_foreach(obj, hash_cb, (VALUE)out); - if (',' == *(out->cur - 1)) { - out->cur--; // backup to overwrite last comma - } - if (!out->opts->dump_opts.use) { - assure_size(out, size); - fill_indent(out, depth); - } else { - size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1; - assure_size(out, size); - if (0 < out->opts->dump_opts.hash_size) { - strcpy(out->cur, out->opts->dump_opts.hash_nl); - out->cur += out->opts->dump_opts.hash_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - - for (i = depth; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - } - *out->cur++ = '}'; + long id = oj_check_circular(obj, out); + + if (0 > id) { + return; + } + *out->cur++ = '{'; + if (0 < id) { + assure_size(out, size + 16); + fill_indent(out, depth + 1); + *out->cur++ = '"'; + *out->cur++ = '^'; + *out->cur++ = 'i'; + *out->cur++ = '"'; + *out->cur++ = ':'; + dump_ulong(id, out); + *out->cur++ = ','; + } + out->depth = depth + 1; + rb_hash_foreach(obj, hash_cb, (VALUE)out); + if (',' == *(out->cur - 1)) { + out->cur--; // backup to overwrite last comma + } + if (!out->opts->dump_opts.use) { + assure_size(out, size); + fill_indent(out, depth); + } else { + size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1; + assure_size(out, size); + if (0 < out->opts->dump_opts.hash_size) { + strcpy(out->cur, out->opts->dump_opts.hash_nl); + out->cur += out->opts->dump_opts.hash_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + + for (i = depth; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + } + *out->cur++ = '}'; } *out->cur = '\0'; } @@ -354,39 +348,39 @@ dump_hash_class(VALUE obj, VALUE clas, int depth, Out out) { #ifdef HAVE_RB_IVAR_FOREACH static int dump_attr_cb(ID key, VALUE value, VALUE ov) { - Out out = (Out)ov; - int depth = out->depth; - size_t size = depth * out->indent + 1; - const char *attr = rb_id2name(key); + Out out = (Out)ov; + int depth = out->depth; + size_t size = depth * out->indent + 1; + const char *attr = rb_id2name(key); if (oj_dump_ignore(out->opts, value)) { - return ST_CONTINUE; + return ST_CONTINUE; } if (out->omit_nil && Qnil == value) { - return ST_CONTINUE; + return ST_CONTINUE; } // Some exceptions such as NoMethodError have an invisible attribute where // the key name is NULL. Not an empty string but NULL. if (NULL == attr) { - attr = ""; + attr = ""; } else if (Yes == out->opts->ignore_under && '@' == *attr && '_' == attr[1]) { - return ST_CONTINUE; + return ST_CONTINUE; } if (0 == strcmp("bt", attr) || 0 == strcmp("mesg", attr)) { - return ST_CONTINUE; + return ST_CONTINUE; } assure_size(out, size); fill_indent(out, depth); if ('@' == *attr) { - attr++; - oj_dump_cstr(attr, strlen(attr), 0, 0, out); + attr++; + oj_dump_cstr(attr, strlen(attr), 0, 0, out); } else { - char buf[32]; + char buf[32]; - *buf = '~'; - strncpy(buf + 1, attr, sizeof(buf) - 2); - buf[sizeof(buf) - 1] = '\0'; - oj_dump_cstr(buf, strlen(buf), 0, 0, out); + *buf = '~'; + strncpy(buf + 1, attr, sizeof(buf) - 2); + buf[sizeof(buf) - 1] = '\0'; + oj_dump_cstr(buf, strlen(buf), 0, 0, out); } *out->cur++ = ':'; oj_dump_obj_val(value, depth, out); @@ -404,100 +398,100 @@ dump_hash(VALUE obj, int depth, Out out, bool as_ok) { static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) { - ID *idp; - AttrGetFunc *fp; - volatile VALUE v; - const char *name; - size_t size; - int d2 = depth + 1; + ID *idp; + AttrGetFunc *fp; + volatile VALUE v; + const char *name; + size_t size; + int d2 = depth + 1; assure_size(out, 2); *out->cur++ = '{'; if (Qundef != clas) { - const char *class_name = rb_class2name(clas); - int clen = (int)strlen(class_name); - - size = d2 * out->indent + clen + 10; - assure_size(out, size); - fill_indent(out, d2); - *out->cur++ = '"'; - *out->cur++ = '^'; - *out->cur++ = 'O'; - *out->cur++ = '"'; - *out->cur++ = ':'; - oj_dump_cstr(class_name, clen, 0, 0, out); - *out->cur++ = ','; + const char *class_name = rb_class2name(clas); + int clen = (int)strlen(class_name); + + size = d2 * out->indent + clen + 10; + assure_size(out, size); + fill_indent(out, d2); + *out->cur++ = '"'; + *out->cur++ = '^'; + *out->cur++ = 'O'; + *out->cur++ = '"'; + *out->cur++ = ':'; + oj_dump_cstr(class_name, clen, 0, 0, out); + *out->cur++ = ','; } if (odd->raw) { - v = rb_funcall(obj, *odd->attrs, 0); - if (Qundef == v || T_STRING != rb_type(v)) { - rb_raise(rb_eEncodingError, "Invalid type for raw JSON."); - } else { - const char *s = rb_string_value_ptr((VALUE *)&v); - int len = (int)RSTRING_LEN(v); - const char *name = rb_id2name(*odd->attrs); - size_t nlen = strlen(name); - - size = len + d2 * out->indent + nlen + 10; - assure_size(out, size); - fill_indent(out, d2); - *out->cur++ = '"'; - memcpy(out->cur, name, nlen); - out->cur += nlen; - *out->cur++ = '"'; - *out->cur++ = ':'; - memcpy(out->cur, s, len); - out->cur += len; - *out->cur = '\0'; - } + v = rb_funcall(obj, *odd->attrs, 0); + if (Qundef == v || T_STRING != rb_type(v)) { + rb_raise(rb_eEncodingError, "Invalid type for raw JSON."); + } else { + const char *s = rb_string_value_ptr((VALUE*)&v); + int len = (int)RSTRING_LEN(v); + const char *name = rb_id2name(*odd->attrs); + size_t nlen = strlen(name); + + size = len + d2 * out->indent + nlen + 10; + assure_size(out, size); + fill_indent(out, d2); + *out->cur++ = '"'; + memcpy(out->cur, name, nlen); + out->cur += nlen; + *out->cur++ = '"'; + *out->cur++ = ':'; + memcpy(out->cur, s, len); + out->cur += len; + *out->cur = '\0'; + } } else { - size = d2 * out->indent + 1; - for (idp = odd->attrs, fp = odd->attrFuncs; 0 != *idp; idp++, fp++) { - size_t nlen; - - assure_size(out, size); - name = rb_id2name(*idp); - nlen = strlen(name); - if (0 != *fp) { - v = (*fp)(obj); - } else if (0 == strchr(name, '.')) { - v = rb_funcall(obj, *idp, 0); - } else { - char nbuf[256]; - char *n2 = nbuf; - char *n; - char *end; - ID i; - - if (sizeof(nbuf) <= nlen) { - if (NULL == (n2 = strdup(name))) { - rb_raise(rb_eNoMemError, "for attribute name."); - } - } else { - strcpy(n2, name); - } - n = n2; - v = obj; - while (0 != (end = strchr(n, '.'))) { - *end = '\0'; - i = rb_intern(n); - v = rb_funcall(v, i, 0); - n = end + 1; - } - i = rb_intern(n); - v = rb_funcall(v, i, 0); - if (nbuf != n2) { - free(n2); - } - } - fill_indent(out, d2); - oj_dump_cstr(name, nlen, 0, 0, out); - *out->cur++ = ':'; - oj_dump_obj_val(v, d2, out); - assure_size(out, 2); - *out->cur++ = ','; - } - out->cur--; + size = d2 * out->indent + 1; + for (idp = odd->attrs, fp = odd->attrFuncs; 0 != *idp; idp++, fp++) { + size_t nlen; + + assure_size(out, size); + name = rb_id2name(*idp); + nlen = strlen(name); + if (0 != *fp) { + v = (*fp)(obj); + } else if (0 == strchr(name, '.')) { + v = rb_funcall(obj, *idp, 0); + } else { + char nbuf[256]; + char *n2 = nbuf; + char *n; + char *end; + ID i; + + if (sizeof(nbuf) <= nlen) { + if (NULL == (n2 = strdup(name))) { + rb_raise(rb_eNoMemError, "for attribute name."); + } + } else { + strcpy(n2, name); + } + n = n2; + v = obj; + while (0 != (end = strchr(n, '.'))) { + *end = '\0'; + i = rb_intern(n); + v = rb_funcall(v, i, 0); + n = end + 1; + } + i = rb_intern(n); + v = rb_funcall(v, i, 0); + if (nbuf != n2) { + free(n2); + } + } + fill_indent(out, d2); + oj_dump_cstr(name, nlen, 0, 0, out); + *out->cur++ = ':'; + oj_dump_obj_val(v, d2, out); + assure_size(out, 2); + *out->cur++ = ','; + } + out->cur--; } *out->cur++ = '}'; *out->cur = '\0'; @@ -505,181 +499,181 @@ dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) { static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out) { - size_t size = 0; - int d2 = depth + 1; - int type = rb_type(obj); - Odd odd; + size_t size = 0; + int d2 = depth + 1; + int type = rb_type(obj); + Odd odd; if (0 != (odd = oj_get_odd(clas))) { - dump_odd(obj, odd, clas, depth + 1, out); - return; + dump_odd(obj, odd, clas, depth + 1, out); + return; } assure_size(out, 2); *out->cur++ = '{'; if (Qundef != clas) { - const char *class_name = rb_class2name(clas); - int clen = (int)strlen(class_name); - - assure_size(out, d2 * out->indent + clen + 10); - fill_indent(out, d2); - *out->cur++ = '"'; - *out->cur++ = '^'; - *out->cur++ = 'o'; - *out->cur++ = '"'; - *out->cur++ = ':'; - oj_dump_cstr(class_name, clen, 0, 0, out); + const char *class_name = rb_class2name(clas); + int clen = (int)strlen(class_name); + + assure_size(out, d2 * out->indent + clen + 10); + fill_indent(out, d2); + *out->cur++ = '"'; + *out->cur++ = '^'; + *out->cur++ = 'o'; + *out->cur++ = '"'; + *out->cur++ = ':'; + oj_dump_cstr(class_name, clen, 0, 0, out); } if (0 < id) { - assure_size(out, d2 * out->indent + 16); - *out->cur++ = ','; - fill_indent(out, d2); - *out->cur++ = '"'; - *out->cur++ = '^'; - *out->cur++ = 'i'; - *out->cur++ = '"'; - *out->cur++ = ':'; - dump_ulong(id, out); + assure_size(out, d2 * out->indent + 16); + *out->cur++ = ','; + fill_indent(out, d2); + *out->cur++ = '"'; + *out->cur++ = '^'; + *out->cur++ = 'i'; + *out->cur++ = '"'; + *out->cur++ = ':'; + dump_ulong(id, out); } switch (type) { - case T_STRING: - assure_size(out, d2 * out->indent + 14); - *out->cur++ = ','; - fill_indent(out, d2); - *out->cur++ = '"'; - *out->cur++ = 's'; - *out->cur++ = 'e'; - *out->cur++ = 'l'; - *out->cur++ = 'f'; - *out->cur++ = '"'; - *out->cur++ = ':'; - oj_dump_cstr(rb_string_value_ptr((VALUE *)&obj), (int)RSTRING_LEN(obj), 0, 0, out); - break; - case T_ARRAY: - assure_size(out, d2 * out->indent + 14); - *out->cur++ = ','; - fill_indent(out, d2); - *out->cur++ = '"'; - *out->cur++ = 's'; - *out->cur++ = 'e'; - *out->cur++ = 'l'; - *out->cur++ = 'f'; - *out->cur++ = '"'; - *out->cur++ = ':'; - dump_array_class(obj, Qundef, depth + 1, out); - break; - case T_HASH: - assure_size(out, d2 * out->indent + 14); - *out->cur++ = ','; - fill_indent(out, d2); - *out->cur++ = '"'; - *out->cur++ = 's'; - *out->cur++ = 'e'; - *out->cur++ = 'l'; - *out->cur++ = 'f'; - *out->cur++ = '"'; - *out->cur++ = ':'; - dump_hash_class(obj, Qundef, depth + 1, out); - break; - default: - break; + case T_STRING: + assure_size(out, d2 * out->indent + 14); + *out->cur++ = ','; + fill_indent(out, d2); + *out->cur++ = '"'; + *out->cur++ = 's'; + *out->cur++ = 'e'; + *out->cur++ = 'l'; + *out->cur++ = 'f'; + *out->cur++ = '"'; + *out->cur++ = ':'; + oj_dump_cstr(rb_string_value_ptr((VALUE*)&obj), (int)RSTRING_LEN(obj), 0, 0, out); + break; + case T_ARRAY: + assure_size(out, d2 * out->indent + 14); + *out->cur++ = ','; + fill_indent(out, d2); + *out->cur++ = '"'; + *out->cur++ = 's'; + *out->cur++ = 'e'; + *out->cur++ = 'l'; + *out->cur++ = 'f'; + *out->cur++ = '"'; + *out->cur++ = ':'; + dump_array_class(obj, Qundef, depth + 1, out); + break; + case T_HASH: + assure_size(out, d2 * out->indent + 14); + *out->cur++ = ','; + fill_indent(out, d2); + *out->cur++ = '"'; + *out->cur++ = 's'; + *out->cur++ = 'e'; + *out->cur++ = 'l'; + *out->cur++ = 'f'; + *out->cur++ = '"'; + *out->cur++ = ':'; + dump_hash_class(obj, Qundef, depth + 1, out); + break; + default: + break; } { - int cnt; + int cnt; #ifdef HAVE_RB_IVAR_COUNT - cnt = (int)rb_ivar_count(obj); + cnt = (int)rb_ivar_count(obj); #else - volatile VALUE vars = rb_funcall2(obj, oj_instance_variables_id, 0, 0); - VALUE *np = RARRAY_PTR(vars); - ID vid; - const char *attr; - int i; - int first = 1; - - cnt = (int)RARRAY_LEN(vars); + volatile VALUE vars = rb_funcall2(obj, oj_instance_variables_id, 0, 0); + VALUE *np = RARRAY_PTR(vars); + ID vid; + const char *attr; + int i; + int first = 1; + + cnt = (int)RARRAY_LEN(vars); #endif - if (Qundef != clas && 0 < cnt) { - *out->cur++ = ','; - } - if (0 == cnt && Qundef == clas) { - // Might be something special like an Enumerable. - if (Qtrue == rb_obj_is_kind_of(obj, oj_enumerable_class)) { - out->cur--; - oj_dump_obj_val(rb_funcall(obj, rb_intern("entries"), 0), depth, out); - return; - } - } - out->depth = depth + 1; + if (Qundef != clas && 0 < cnt) { + *out->cur++ = ','; + } + if (0 == cnt && Qundef == clas) { + // Might be something special like an Enumerable. + if (Qtrue == rb_obj_is_kind_of(obj, oj_enumerable_class)) { + out->cur--; + oj_dump_obj_val(rb_funcall(obj, rb_intern("entries"), 0), depth, out); + return; + } + } + out->depth = depth + 1; #ifdef HAVE_RB_IVAR_FOREACH - rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out); - if (',' == *(out->cur - 1)) { - out->cur--; // backup to overwrite last comma - } + rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out); + if (',' == *(out->cur - 1)) { + out->cur--; // backup to overwrite last comma + } #else - size = d2 * out->indent + 1; - for (i = cnt; 0 < i; i--, np++) { - VALUE value; - - vid = rb_to_id(*np); - attr = rb_id2name(vid); - if (Yes == out->opts->ignore_under && '@' == *attr && '_' == attr[1]) { - continue; - } - value = rb_ivar_get(obj, vid); - - if (oj_dump_ignore(out->opts, value)) { - continue; - } - if (out->omit_nil && Qnil == value) { - continue; - } - if (first) { - first = 0; - } else { - *out->cur++ = ','; - } - assure_size(out, size); - fill_indent(out, d2); - if ('@' == *attr) { - attr++; - oj_dump_cstr(attr, strlen(attr), 0, 0, out); - } else { - char buf[32]; - - *buf = '~'; - strncpy(buf + 1, attr, sizeof(buf) - 2); - buf[sizeof(buf) - 1] = '\0'; - oj_dump_cstr(buf, strlen(attr) + 1, 0, 0, out); - } - *out->cur++ = ':'; - oj_dump_obj_val(value, d2, out); - assure_size(out, 2); - } + size = d2 * out->indent + 1; + for (i = cnt; 0 < i; i--, np++) { + VALUE value; + + vid = rb_to_id(*np); + attr = rb_id2name(vid); + if (Yes == out->opts->ignore_under && '@' == *attr && '_' == attr[1]) { + continue; + } + value = rb_ivar_get(obj, vid); + + if (oj_dump_ignore(out->opts, value)) { + continue; + } + if (out->omit_nil && Qnil == value) { + continue; + } + if (first) { + first = 0; + } else { + *out->cur++ = ','; + } + assure_size(out, size); + fill_indent(out, d2); + if ('@' == *attr) { + attr++; + oj_dump_cstr(attr, strlen(attr), 0, 0, out); + } else { + char buf[32]; + + *buf = '~'; + strncpy(buf + 1, attr, sizeof(buf) - 2); + buf[sizeof(buf) - 1] = '\0'; + oj_dump_cstr(buf, strlen(attr) + 1, 0, 0, out); + } + *out->cur++ = ':'; + oj_dump_obj_val(value, d2, out); + assure_size(out, 2); + } #endif - if (rb_obj_is_kind_of(obj, rb_eException)) { - volatile VALUE rv; - - if (',' != *(out->cur - 1)) { - *out->cur++ = ','; - } - // message - assure_size(out, size); - fill_indent(out, d2); - oj_dump_cstr("~mesg", 5, 0, 0, out); - *out->cur++ = ':'; - rv = rb_funcall2(obj, rb_intern("message"), 0, 0); - oj_dump_obj_val(rv, d2, out); - assure_size(out, 2); - *out->cur++ = ','; - // backtrace - assure_size(out, size); - fill_indent(out, d2); - oj_dump_cstr("~bt", 3, 0, 0, out); - *out->cur++ = ':'; - rv = rb_funcall2(obj, rb_intern("backtrace"), 0, 0); - oj_dump_obj_val(rv, d2, out); - assure_size(out, 2); - } - out->depth = depth; + if (rb_obj_is_kind_of(obj, rb_eException)) { + volatile VALUE rv; + + if (',' != *(out->cur - 1)) { + *out->cur++ = ','; + } + // message + assure_size(out, size); + fill_indent(out, d2); + oj_dump_cstr("~mesg", 5, 0, 0, out); + *out->cur++ = ':'; + rv = rb_funcall2(obj, rb_intern("message"), 0, 0); + oj_dump_obj_val(rv, d2, out); + assure_size(out, 2); + *out->cur++ = ','; + // backtrace + assure_size(out, size); + fill_indent(out, d2); + oj_dump_cstr("~bt", 3, 0, 0, out); + *out->cur++ = ':'; + rv = rb_funcall2(obj, rb_intern("backtrace"), 0, 0); + oj_dump_obj_val(rv, d2, out); + assure_size(out, 2); + } + out->depth = depth; } fill_indent(out, depth); *out->cur++ = '}'; @@ -693,13 +687,13 @@ dump_regexp(VALUE obj, int depth, Out out, bool as_ok) { static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) { - VALUE clas = rb_obj_class(obj); - const char *class_name = rb_class2name(clas); - int i; - int d2 = depth + 1; - int d3 = d2 + 1; - size_t len = strlen(class_name); - size_t size = d2 * out->indent + d3 * out->indent + 10 + len; + VALUE clas = rb_obj_class(obj); + const char *class_name = rb_class2name(clas); + int i; + int d2 = depth + 1; + int d3 = d2 + 1; + size_t len = strlen(class_name); + size_t size = d2 * out->indent + d3 * out->indent + 10 + len; assure_size(out, size); *out->cur++ = '{'; @@ -711,72 +705,72 @@ dump_struct(VALUE obj, int depth, Out out, bool as_ok) { *out->cur++ = ':'; *out->cur++ = '['; if ('#' == *class_name) { - VALUE ma = rb_struct_s_members(clas); - const char *name; - int cnt = (int)RARRAY_LEN(ma); - - *out->cur++ = '['; - for (i = 0; i < cnt; i++) { - volatile VALUE s = rb_sym_to_s(rb_ary_entry(ma, i)); - - name = rb_string_value_ptr((VALUE *)&s); - len = (int)RSTRING_LEN(s); - size = len + 3; - assure_size(out, size); - if (0 < i) { - *out->cur++ = ','; - } - *out->cur++ = '"'; - memcpy(out->cur, name, len); - out->cur += len; - *out->cur++ = '"'; - } - *out->cur++ = ']'; + VALUE ma = rb_struct_s_members(clas); + const char *name; + int cnt = (int)RARRAY_LEN(ma); + + *out->cur++ = '['; + for (i = 0; i < cnt; i++) { + volatile VALUE s = rb_sym_to_s(rb_ary_entry(ma, i)); + + name = rb_string_value_ptr((VALUE*)&s); + len = (int)RSTRING_LEN(s); + size = len + 3; + assure_size(out, size); + if (0 < i) { + *out->cur++ = ','; + } + *out->cur++ = '"'; + memcpy(out->cur, name, len); + out->cur += len; + *out->cur++ = '"'; + } + *out->cur++ = ']'; } else { - fill_indent(out, d3); - *out->cur++ = '"'; - memcpy(out->cur, class_name, len); - out->cur += len; - *out->cur++ = '"'; + fill_indent(out, d3); + *out->cur++ = '"'; + memcpy(out->cur, class_name, len); + out->cur += len; + *out->cur++ = '"'; } *out->cur++ = ','; size = d3 * out->indent + 2; #ifdef RSTRUCT_LEN { - VALUE v; - int cnt; + VALUE v; + int cnt; #if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT - cnt = (int)NUM2LONG(RSTRUCT_LEN(obj)); -#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT - cnt = (int)RSTRUCT_LEN(obj); + cnt = (int)NUM2LONG(RSTRUCT_LEN(obj)); +#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT + cnt = (int)RSTRUCT_LEN(obj); #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT - for (i = 0; i < cnt; i++) { - v = RSTRUCT_GET(obj, i); - if (oj_dump_ignore(out->opts, v)) { - v = Qnil; - } - assure_size(out, size); - fill_indent(out, d3); - oj_dump_obj_val(v, d3, out); - *out->cur++ = ','; - } + for (i = 0; i < cnt; i++) { + v = RSTRUCT_GET(obj, i); + if (oj_dump_ignore(out->opts, v)) { + v = Qnil; + } + assure_size(out, size); + fill_indent(out, d3); + oj_dump_obj_val(v, d3, out); + *out->cur++ = ','; + } } #else { - // This is a bit risky as a struct in C ruby is not the same as a Struct - // class in interpreted Ruby so length() may not be defined. - int slen = FIX2INT(rb_funcall2(obj, oj_length_id, 0, 0)); - - for (i = 0; i < slen; i++) { - assure_size(out, size); - fill_indent(out, d3); - if (oj_dump_ignore(out->opts, v)) { - v = Qnil; - } - oj_dump_obj_val(rb_struct_aref(obj, INT2FIX(i)), d3, out, 0, 0, true); - *out->cur++ = ','; - } + // This is a bit risky as a struct in C ruby is not the same as a Struct + // class in interpreted Ruby so length() may not be defined. + int slen = FIX2INT(rb_funcall2(obj, oj_length_id, 0, 0)); + + for (i = 0; i < slen; i++) { + assure_size(out, size); + fill_indent(out, d3); + if (oj_dump_ignore(out->opts, v)) { + v = Qnil; + } + oj_dump_obj_val(rb_struct_aref(obj, INT2FIX(i)), d3, out, 0, 0, true); + *out->cur++ = ','; + } } #endif out->cur--; @@ -795,54 +789,54 @@ dump_rational(VALUE obj, int depth, Out out, bool as_ok) { dump_obj_attrs(obj, rb_obj_class(obj), 0, depth, out); } -static DumpFunc obj_funcs[] = { - NULL, // RUBY_T_NONE = 0x00, - dump_obj, // RUBY_T_OBJECT = 0x01, - dump_class, // RUBY_T_CLASS = 0x02, - dump_class, // RUBY_T_MODULE = 0x03, - oj_dump_float, // RUBY_T_FLOAT = 0x04, - dump_str, // RUBY_T_STRING = 0x05, - dump_regexp, // RUBY_T_REGEXP = 0x06, - dump_array, // RUBY_T_ARRAY = 0x07, - dump_hash, // RUBY_T_HASH = 0x08, - dump_struct, // RUBY_T_STRUCT = 0x09, - oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a, - NULL, // RUBY_T_FILE = 0x0b, - dump_data, // RUBY_T_DATA = 0x0c, - NULL, // RUBY_T_MATCH = 0x0d, - dump_complex, // RUBY_T_COMPLEX = 0x0e, - dump_rational, // RUBY_T_RATIONAL = 0x0f, - NULL, // 0x10 - oj_dump_nil, // RUBY_T_NIL = 0x11, - oj_dump_true, // RUBY_T_TRUE = 0x12, - oj_dump_false, // RUBY_T_FALSE = 0x13, - dump_sym, // RUBY_T_SYMBOL = 0x14, - oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15, +static DumpFunc obj_funcs[] = { + NULL, // RUBY_T_NONE = 0x00, + dump_obj, // RUBY_T_OBJECT = 0x01, + dump_class, // RUBY_T_CLASS = 0x02, + dump_class, // RUBY_T_MODULE = 0x03, + oj_dump_float, // RUBY_T_FLOAT = 0x04, + dump_str, // RUBY_T_STRING = 0x05, + dump_regexp, // RUBY_T_REGEXP = 0x06, + dump_array, // RUBY_T_ARRAY = 0x07, + dump_hash, // RUBY_T_HASH = 0x08, + dump_struct, // RUBY_T_STRUCT = 0x09, + oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a, + NULL, // RUBY_T_FILE = 0x0b, + dump_data, // RUBY_T_DATA = 0x0c, + NULL, // RUBY_T_MATCH = 0x0d, + dump_complex, // RUBY_T_COMPLEX = 0x0e, + dump_rational, // RUBY_T_RATIONAL = 0x0f, + NULL, // 0x10 + oj_dump_nil, // RUBY_T_NIL = 0x11, + oj_dump_true, // RUBY_T_TRUE = 0x12, + oj_dump_false, // RUBY_T_FALSE = 0x13, + dump_sym, // RUBY_T_SYMBOL = 0x14, + oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15, }; void oj_dump_obj_val(VALUE obj, int depth, Out out) { - int type = rb_type(obj); + int type = rb_type(obj); if (Yes == out->opts->trace) { - oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn); + oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn); } if (MAX_DEPTH < depth) { - rb_raise(rb_eNoMemError, "Too deeply nested.\n"); + rb_raise(rb_eNoMemError, "Too deeply nested.\n"); } if (0 < type && type <= RUBY_T_FIXNUM) { - DumpFunc f = obj_funcs[type]; + DumpFunc f = obj_funcs[type]; - if (NULL != f) { - f(obj, depth, out, false); - if (Yes == out->opts->trace) { - oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut); - } - return; - } + if (NULL != f) { + f(obj, depth, out, false); + if (Yes == out->opts->trace) { + oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut); + } + return; + } } oj_dump_nil(Qnil, depth, out, false); if (Yes == out->opts->trace) { - oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut); + oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut); } } diff --git a/ext/oj/dump_strict.c b/ext/oj/dump_strict.c index 068fe1db..580e0b93 100644 --- a/ext/oj/dump_strict.c +++ b/ext/oj/dump_strict.c @@ -1,25 +1,25 @@ // Copyright (c) 2012, 2017 Peter Ohler. All rights reserved. // Licensed under the MIT License. See LICENSE file in the project root for license details. -#include -#include -#include #include -#include #include +#include +#include +#include #include +#include #include "dump.h" #include "trace.h" // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS -#define OJ_INFINITY (1.0 / 0.0) +#define OJ_INFINITY (1.0/0.0) -typedef unsigned long ulong; +typedef unsigned long ulong; -static const char inf_val[] = INF_VAL; -static const char ninf_val[] = NINF_VAL; -static const char nan_val[] = NAN_VAL; +static const char inf_val[] = INF_VAL; +static const char ninf_val[] = NINF_VAL; +static const char nan_val[] = NAN_VAL; static void raise_strict(VALUE obj) { @@ -29,227 +29,227 @@ raise_strict(VALUE obj) { // Removed dependencies on math due to problems with CentOS 5.4. static void dump_float(VALUE obj, int depth, Out out, bool as_ok) { - char buf[64]; - char *b; - double d = rb_num2dbl(obj); - int cnt = 0; + char buf[64]; + char *b; + double d = rb_num2dbl(obj); + int cnt = 0; if (0.0 == d) { - b = buf; - *b++ = '0'; - *b++ = '.'; - *b++ = '0'; - *b++ = '\0'; - cnt = 3; + b = buf; + *b++ = '0'; + *b++ = '.'; + *b++ = '0'; + *b++ = '\0'; + cnt = 3; } else { - NanDump nd = out->opts->dump_opts.nan_dump; - - if (AutoNan == nd) { - nd = RaiseNan; - } - if (OJ_INFINITY == d) { - switch (nd) { - case RaiseNan: - case WordNan: - raise_strict(obj); - break; - case NullNan: - strcpy(buf, "null"); - cnt = 4; - break; - case HugeNan: - default: - strcpy(buf, inf_val); - cnt = sizeof(inf_val) - 1; - break; - } - } else if (-OJ_INFINITY == d) { - switch (nd) { - case RaiseNan: - case WordNan: - raise_strict(obj); - break; - case NullNan: - strcpy(buf, "null"); - cnt = 4; - break; - case HugeNan: - default: - strcpy(buf, ninf_val); - cnt = sizeof(ninf_val) - 1; - break; - } - } else if (isnan(d)) { - switch (nd) { - case RaiseNan: - case WordNan: - raise_strict(obj); - break; - case NullNan: - strcpy(buf, "null"); - cnt = 4; - break; - case HugeNan: - default: - strcpy(buf, nan_val); - cnt = sizeof(nan_val) - 1; - break; - } - } else if (d == (double)(long long int)d) { - cnt = snprintf(buf, sizeof(buf), "%.1f", d); - } else if (0 == out->opts->float_prec) { - volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); - - cnt = (int)RSTRING_LEN(rstr); - if ((int)sizeof(buf) <= cnt) { - cnt = sizeof(buf) - 1; - } - strncpy(buf, rb_string_value_ptr((VALUE *)&rstr), cnt); - buf[cnt] = '\0'; - } else { - cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, out->opts->float_fmt); - } + NanDump nd = out->opts->dump_opts.nan_dump; + + if (AutoNan == nd) { + nd = RaiseNan; + } + if (OJ_INFINITY == d) { + switch (nd) { + case RaiseNan: + case WordNan: + raise_strict(obj); + break; + case NullNan: + strcpy(buf, "null"); + cnt = 4; + break; + case HugeNan: + default: + strcpy(buf, inf_val); + cnt = sizeof(inf_val) - 1; + break; + } + } else if (-OJ_INFINITY == d) { + switch (nd) { + case RaiseNan: + case WordNan: + raise_strict(obj); + break; + case NullNan: + strcpy(buf, "null"); + cnt = 4; + break; + case HugeNan: + default: + strcpy(buf, ninf_val); + cnt = sizeof(ninf_val) - 1; + break; + } + } else if (isnan(d)) { + switch (nd) { + case RaiseNan: + case WordNan: + raise_strict(obj); + break; + case NullNan: + strcpy(buf, "null"); + cnt = 4; + break; + case HugeNan: + default: + strcpy(buf, nan_val); + cnt = sizeof(nan_val) - 1; + break; + } + } else if (d == (double)(long long int)d) { + cnt = snprintf(buf, sizeof(buf), "%.1f", d); + } else if (0 == out->opts->float_prec) { + volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); + + cnt = (int)RSTRING_LEN(rstr); + if ((int)sizeof(buf) <= cnt) { + cnt = sizeof(buf) - 1; + } + strncpy(buf, rb_string_value_ptr((VALUE*)&rstr), cnt); + buf[cnt] = '\0'; + } else { + cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, out->opts->float_fmt); + } } assure_size(out, cnt); for (b = buf; '\0' != *b; b++) { - *out->cur++ = *b; + *out->cur++ = *b; } *out->cur = '\0'; } static void dump_array(VALUE a, int depth, Out out, bool as_ok) { - size_t size; - int i, cnt; - int d2 = depth + 1; + size_t size; + int i, cnt; + int d2 = depth + 1; if (Yes == out->opts->circular) { - if (0 > oj_check_circular(a, out)) { - oj_dump_nil(Qnil, 0, out, false); - return; - } + if (0 > oj_check_circular(a, out)) { + oj_dump_nil(Qnil, 0, out, false); + return; + } } cnt = (int)RARRAY_LEN(a); *out->cur++ = '['; size = 2; assure_size(out, size); if (0 == cnt) { - *out->cur++ = ']'; + *out->cur++ = ']'; } else { - if (out->opts->dump_opts.use) { - size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1; - } else { - size = d2 * out->indent + 2; - } - cnt--; - for (i = 0; i <= cnt; i++) { - assure_size(out, size); - if (out->opts->dump_opts.use) { - if (0 < out->opts->dump_opts.array_size) { - strcpy(out->cur, out->opts->dump_opts.array_nl); - out->cur += out->opts->dump_opts.array_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - for (i = d2; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - } else { - fill_indent(out, d2); - } - if (NullMode == out->opts->mode) { - oj_dump_null_val(rb_ary_entry(a, i), d2, out); - } else { - oj_dump_strict_val(rb_ary_entry(a, i), d2, out); - } - if (i < cnt) { - *out->cur++ = ','; - } - } - size = depth * out->indent + 1; - assure_size(out, size); - if (out->opts->dump_opts.use) { - //printf("*** d2: %u indent: %u '%s'\n", d2, out->opts->dump_opts->indent_size, out->opts->dump_opts->indent); - if (0 < out->opts->dump_opts.array_size) { - strcpy(out->cur, out->opts->dump_opts.array_nl); - out->cur += out->opts->dump_opts.array_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - - for (i = depth; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - } else { - fill_indent(out, depth); - } - *out->cur++ = ']'; + if (out->opts->dump_opts.use) { + size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1; + } else { + size = d2 * out->indent + 2; + } + cnt--; + for (i = 0; i <= cnt; i++) { + assure_size(out, size); + if (out->opts->dump_opts.use) { + if (0 < out->opts->dump_opts.array_size) { + strcpy(out->cur, out->opts->dump_opts.array_nl); + out->cur += out->opts->dump_opts.array_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + for (i = d2; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + } else { + fill_indent(out, d2); + } + if (NullMode == out->opts->mode) { + oj_dump_null_val(rb_ary_entry(a, i), d2, out); + } else { + oj_dump_strict_val(rb_ary_entry(a, i), d2, out); + } + if (i < cnt) { + *out->cur++ = ','; + } + } + size = depth * out->indent + 1; + assure_size(out, size); + if (out->opts->dump_opts.use) { + //printf("*** d2: %u indent: %u '%s'\n", d2, out->opts->dump_opts->indent_size, out->opts->dump_opts->indent); + if (0 < out->opts->dump_opts.array_size) { + strcpy(out->cur, out->opts->dump_opts.array_nl); + out->cur += out->opts->dump_opts.array_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + + for (i = depth; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + } else { + fill_indent(out, depth); + } + *out->cur++ = ']'; } *out->cur = '\0'; } static int hash_cb(VALUE key, VALUE value, VALUE ov) { - Out out = (Out)ov; - int depth = out->depth; - long size; - int rtype = rb_type(key); + Out out = (Out)ov; + int depth = out->depth; + long size; + int rtype = rb_type(key); if (rtype != T_STRING && rtype != T_SYMBOL) { - rb_raise(rb_eTypeError, "In :strict and :null mode all Hash keys must be Strings or Symbols, not %s.\n", rb_class2name(rb_obj_class(key))); + rb_raise(rb_eTypeError, "In :strict and :null mode all Hash keys must be Strings or Symbols, not %s.\n", rb_class2name(rb_obj_class(key))); } if (out->omit_nil && Qnil == value) { - return ST_CONTINUE; + return ST_CONTINUE; } if (!out->opts->dump_opts.use) { - size = depth * out->indent + 1; - assure_size(out, size); - fill_indent(out, depth); - if (rtype == T_STRING) { - oj_dump_str(key, 0, out, false); - } else { - oj_dump_sym(key, 0, out, false); - } - *out->cur++ = ':'; + size = depth * out->indent + 1; + assure_size(out, size); + fill_indent(out, depth); + if (rtype == T_STRING) { + oj_dump_str(key, 0, out, false); + } else { + oj_dump_sym(key, 0, out, false); + } + *out->cur++ = ':'; } else { - size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1; - assure_size(out, size); - if (0 < out->opts->dump_opts.hash_size) { - strcpy(out->cur, out->opts->dump_opts.hash_nl); - out->cur += out->opts->dump_opts.hash_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - for (i = depth; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - if (rtype == T_STRING) { - oj_dump_str(key, 0, out, false); - } else { - oj_dump_sym(key, 0, out, false); - } - size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2; - assure_size(out, size); - if (0 < out->opts->dump_opts.before_size) { - strcpy(out->cur, out->opts->dump_opts.before_sep); - out->cur += out->opts->dump_opts.before_size; - } - *out->cur++ = ':'; - if (0 < out->opts->dump_opts.after_size) { - strcpy(out->cur, out->opts->dump_opts.after_sep); - out->cur += out->opts->dump_opts.after_size; - } + size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1; + assure_size(out, size); + if (0 < out->opts->dump_opts.hash_size) { + strcpy(out->cur, out->opts->dump_opts.hash_nl); + out->cur += out->opts->dump_opts.hash_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + for (i = depth; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + if (rtype == T_STRING) { + oj_dump_str(key, 0, out, false); + } else { + oj_dump_sym(key, 0, out, false); + } + size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2; + assure_size(out, size); + if (0 < out->opts->dump_opts.before_size) { + strcpy(out->cur, out->opts->dump_opts.before_sep); + out->cur += out->opts->dump_opts.before_size; + } + *out->cur++ = ':'; + if (0 < out->opts->dump_opts.after_size) { + strcpy(out->cur, out->opts->dump_opts.after_sep); + out->cur += out->opts->dump_opts.after_size; + } } if (NullMode == out->opts->mode) { - oj_dump_null_val(value, depth, out); + oj_dump_null_val(value, depth, out); } else { - oj_dump_strict_val(value, depth, out); + oj_dump_strict_val(value, depth, out); } out->depth = depth; *out->cur++ = ','; @@ -259,174 +259,174 @@ hash_cb(VALUE key, VALUE value, VALUE ov) { static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) { - int cnt; - size_t size; + int cnt; + size_t size; if (Yes == out->opts->circular) { - if (0 > oj_check_circular(obj, out)) { - oj_dump_nil(Qnil, 0, out, false); - return; - } + if (0 > oj_check_circular(obj, out)) { + oj_dump_nil(Qnil, 0, out, false); + return; + } } cnt = (int)RHASH_SIZE(obj); size = depth * out->indent + 2; assure_size(out, 2); *out->cur++ = '{'; if (0 == cnt) { - *out->cur++ = '}'; + *out->cur++ = '}'; } else { - out->depth = depth + 1; - rb_hash_foreach(obj, hash_cb, (VALUE)out); - if (',' == *(out->cur - 1)) { - out->cur--; // backup to overwrite last comma - } - if (!out->opts->dump_opts.use) { - assure_size(out, size); - fill_indent(out, depth); - } else { - size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1; - assure_size(out, size); - if (0 < out->opts->dump_opts.hash_size) { - strcpy(out->cur, out->opts->dump_opts.hash_nl); - out->cur += out->opts->dump_opts.hash_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - - for (i = depth; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - } - *out->cur++ = '}'; + out->depth = depth + 1; + rb_hash_foreach(obj, hash_cb, (VALUE)out); + if (',' == *(out->cur - 1)) { + out->cur--; // backup to overwrite last comma + } + if (!out->opts->dump_opts.use) { + assure_size(out, size); + fill_indent(out, depth); + } else { + size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1; + assure_size(out, size); + if (0 < out->opts->dump_opts.hash_size) { + strcpy(out->cur, out->opts->dump_opts.hash_nl); + out->cur += out->opts->dump_opts.hash_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + + for (i = depth; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + } + *out->cur++ = '}'; } *out->cur = '\0'; } static void dump_data_strict(VALUE obj, int depth, Out out, bool as_ok) { - VALUE clas = rb_obj_class(obj); + VALUE clas = rb_obj_class(obj); if (oj_bigdecimal_class == clas) { - volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); + volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); - oj_dump_raw(rb_string_value_ptr((VALUE *)&rstr), (int)RSTRING_LEN(rstr), out); + oj_dump_raw(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), out); } else { - raise_strict(obj); + raise_strict(obj); } } static void dump_data_null(VALUE obj, int depth, Out out, bool as_ok) { - VALUE clas = rb_obj_class(obj); + VALUE clas = rb_obj_class(obj); if (oj_bigdecimal_class == clas) { - volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); + volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); - oj_dump_raw(rb_string_value_ptr((VALUE *)&rstr), (int)RSTRING_LEN(rstr), out); + oj_dump_raw(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), out); } else { - oj_dump_nil(Qnil, depth, out, false); + oj_dump_nil(Qnil, depth, out, false); } } -static DumpFunc strict_funcs[] = { - NULL, // RUBY_T_NONE = 0x00, - dump_data_strict, // RUBY_T_OBJECT = 0x01, - NULL, // RUBY_T_CLASS = 0x02, - NULL, // RUBY_T_MODULE = 0x03, - dump_float, // RUBY_T_FLOAT = 0x04, - oj_dump_str, // RUBY_T_STRING = 0x05, - NULL, // RUBY_T_REGEXP = 0x06, - dump_array, // RUBY_T_ARRAY = 0x07, - dump_hash, // RUBY_T_HASH = 0x08, - NULL, // RUBY_T_STRUCT = 0x09, - oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a, - NULL, // RUBY_T_FILE = 0x0b, - dump_data_strict, // RUBY_T_DATA = 0x0c, - NULL, // RUBY_T_MATCH = 0x0d, - NULL, // RUBY_T_COMPLEX = 0x0e, - NULL, // RUBY_T_RATIONAL = 0x0f, - NULL, // 0x10 - oj_dump_nil, // RUBY_T_NIL = 0x11, - oj_dump_true, // RUBY_T_TRUE = 0x12, - oj_dump_false, // RUBY_T_FALSE = 0x13, - oj_dump_sym, // RUBY_T_SYMBOL = 0x14, - oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15, +static DumpFunc strict_funcs[] = { + NULL, // RUBY_T_NONE = 0x00, + dump_data_strict, // RUBY_T_OBJECT = 0x01, + NULL, // RUBY_T_CLASS = 0x02, + NULL, // RUBY_T_MODULE = 0x03, + dump_float, // RUBY_T_FLOAT = 0x04, + oj_dump_str, // RUBY_T_STRING = 0x05, + NULL, // RUBY_T_REGEXP = 0x06, + dump_array, // RUBY_T_ARRAY = 0x07, + dump_hash, // RUBY_T_HASH = 0x08, + NULL, // RUBY_T_STRUCT = 0x09, + oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a, + NULL, // RUBY_T_FILE = 0x0b, + dump_data_strict, // RUBY_T_DATA = 0x0c, + NULL, // RUBY_T_MATCH = 0x0d, + NULL, // RUBY_T_COMPLEX = 0x0e, + NULL, // RUBY_T_RATIONAL = 0x0f, + NULL, // 0x10 + oj_dump_nil, // RUBY_T_NIL = 0x11, + oj_dump_true, // RUBY_T_TRUE = 0x12, + oj_dump_false, // RUBY_T_FALSE = 0x13, + oj_dump_sym, // RUBY_T_SYMBOL = 0x14, + oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15, }; void oj_dump_strict_val(VALUE obj, int depth, Out out) { - int type = rb_type(obj); + int type = rb_type(obj); if (Yes == out->opts->trace) { - oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn); + oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn); } if (MAX_DEPTH < depth) { - rb_raise(rb_eNoMemError, "Too deeply nested.\n"); + rb_raise(rb_eNoMemError, "Too deeply nested.\n"); } if (0 < type && type <= RUBY_T_FIXNUM) { - DumpFunc f = strict_funcs[type]; - - if (NULL != f) { - f(obj, depth, out, false); - if (Yes == out->opts->trace) { - oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut); - } - return; - } + DumpFunc f = strict_funcs[type]; + + if (NULL != f) { + f(obj, depth, out, false); + if (Yes == out->opts->trace) { + oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut); + } + return; + } } raise_strict(obj); } -static DumpFunc null_funcs[] = { - NULL, // RUBY_T_NONE = 0x00, - dump_data_null, // RUBY_T_OBJECT = 0x01, - NULL, // RUBY_T_CLASS = 0x02, - NULL, // RUBY_T_MODULE = 0x03, - dump_float, // RUBY_T_FLOAT = 0x04, - oj_dump_str, // RUBY_T_STRING = 0x05, - NULL, // RUBY_T_REGEXP = 0x06, - dump_array, // RUBY_T_ARRAY = 0x07, - dump_hash, // RUBY_T_HASH = 0x08, - NULL, // RUBY_T_STRUCT = 0x09, - oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a, - NULL, // RUBY_T_FILE = 0x0b, - dump_data_null, // RUBY_T_DATA = 0x0c, - NULL, // RUBY_T_MATCH = 0x0d, - NULL, // RUBY_T_COMPLEX = 0x0e, - NULL, // RUBY_T_RATIONAL = 0x0f, - NULL, // 0x10 - oj_dump_nil, // RUBY_T_NIL = 0x11, - oj_dump_true, // RUBY_T_TRUE = 0x12, - oj_dump_false, // RUBY_T_FALSE = 0x13, - oj_dump_sym, // RUBY_T_SYMBOL = 0x14, - oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15, +static DumpFunc null_funcs[] = { + NULL, // RUBY_T_NONE = 0x00, + dump_data_null, // RUBY_T_OBJECT = 0x01, + NULL, // RUBY_T_CLASS = 0x02, + NULL, // RUBY_T_MODULE = 0x03, + dump_float, // RUBY_T_FLOAT = 0x04, + oj_dump_str, // RUBY_T_STRING = 0x05, + NULL, // RUBY_T_REGEXP = 0x06, + dump_array, // RUBY_T_ARRAY = 0x07, + dump_hash, // RUBY_T_HASH = 0x08, + NULL, // RUBY_T_STRUCT = 0x09, + oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a, + NULL, // RUBY_T_FILE = 0x0b, + dump_data_null, // RUBY_T_DATA = 0x0c, + NULL, // RUBY_T_MATCH = 0x0d, + NULL, // RUBY_T_COMPLEX = 0x0e, + NULL, // RUBY_T_RATIONAL = 0x0f, + NULL, // 0x10 + oj_dump_nil, // RUBY_T_NIL = 0x11, + oj_dump_true, // RUBY_T_TRUE = 0x12, + oj_dump_false, // RUBY_T_FALSE = 0x13, + oj_dump_sym, // RUBY_T_SYMBOL = 0x14, + oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15, }; void oj_dump_null_val(VALUE obj, int depth, Out out) { - int type = rb_type(obj); + int type = rb_type(obj); if (Yes == out->opts->trace) { - oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut); + oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut); } if (MAX_DEPTH < depth) { - rb_raise(rb_eNoMemError, "Too deeply nested.\n"); + rb_raise(rb_eNoMemError, "Too deeply nested.\n"); } if (0 < type && type <= RUBY_T_FIXNUM) { - DumpFunc f = null_funcs[type]; - - if (NULL != f) { - f(obj, depth, out, false); - if (Yes == out->opts->trace) { - oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut); - } - return; - } + DumpFunc f = null_funcs[type]; + + if (NULL != f) { + f(obj, depth, out, false); + if (Yes == out->opts->trace) { + oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut); + } + return; + } } oj_dump_nil(Qnil, depth, out, false); if (Yes == out->opts->trace) { - oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut); + oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut); } } diff --git a/ext/oj/err.c b/ext/oj/err.c index 2490c30a..375f7dab 100644 --- a/ext/oj/err.c +++ b/ext/oj/err.c @@ -7,7 +7,7 @@ void oj_err_set(Err e, VALUE clas, const char *format, ...) { - va_list ap; + va_list ap; va_start(ap, format); e->clas = clas; @@ -21,34 +21,34 @@ oj_err_raise(Err e) { } void -_oj_err_set_with_location(Err err, VALUE eclas, const char *msg, const char *json, const char *current, const char *file, int line) { - int n = 1; - int col = 1; +_oj_err_set_with_location(Err err, VALUE eclas, const char *msg, const char *json, const char *current, const char* file, int line) { + int n = 1; + int col = 1; for (; json < current && '\n' != *current; current--) { - col++; + col++; } for (; json < current; current--) { - if ('\n' == *current) { - n++; - } + if ('\n' == *current) { + n++; + } } oj_err_set(err, eclas, "%s at line %d, column %d [%s:%d]", msg, n, col, file, line); } void -_oj_raise_error(const char *msg, const char *json, const char *current, const char *file, int line) { - struct _err err; - int n = 1; - int col = 1; +_oj_raise_error(const char *msg, const char *json, const char *current, const char* file, int line) { + struct _err err; + int n = 1; + int col = 1; for (; json < current && '\n' != *current; current--) { - col++; + col++; } for (; json < current; current--) { - if ('\n' == *current) { - n++; - } + if ('\n' == *current) { + n++; + } } oj_err_set(&err, oj_parse_error_class, "%s at line %d, column %d [%s:%d]", msg, n, col, file, line); rb_raise(err.clas, "%s", err.msg); diff --git a/ext/oj/err.h b/ext/oj/err.h index d48cccf2..6caa08fe 100644 --- a/ext/oj/err.h +++ b/ext/oj/err.h @@ -7,26 +7,27 @@ #include "ruby.h" // Needed to silence 2.4.0 warnings. #ifndef NORETURN -#define NORETURN(x) x +# define NORETURN(x) x #endif #define set_error(err, eclas, msg, json, current) _oj_err_set_with_location(err, eclas, msg, json, current, FILE, LINE) typedef struct _err { - VALUE clas; - char msg[128]; -} * Err; + VALUE clas; + char msg[128]; +} *Err; -extern VALUE oj_parse_error_class; +extern VALUE oj_parse_error_class; -extern void oj_err_set(Err e, VALUE clas, const char *format, ...); -extern void _oj_err_set_with_location(Err err, VALUE eclas, const char *msg, const char *json, const char *current, const char *file, int line); +extern void oj_err_set(Err e, VALUE clas, const char *format, ...); +extern void _oj_err_set_with_location(Err err, VALUE eclas, const char *msg, const char *json, const char *current, const char* file, int line); -NORETURN(extern void oj_err_raise(Err e)); +NORETURN(extern void oj_err_raise(Err e)); #define raise_error(msg, json, current) _oj_raise_error(msg, json, current, __FILE__, __LINE__) -NORETURN(extern void _oj_raise_error(const char *msg, const char *json, const char *current, const char *file, int line)); +NORETURN(extern void _oj_raise_error(const char *msg, const char *json, const char *current, const char* file, int line)); + inline static void err_init(Err e) { diff --git a/ext/oj/extconf.rb b/ext/oj/extconf.rb index eadb4a16..e48ff165 100644 --- a/ext/oj/extconf.rb +++ b/ext/oj/extconf.rb @@ -26,9 +26,8 @@ have_func('rb_time_timespec') have_func('rb_ivar_count') have_func('rb_ivar_foreach') -# Support for compaction. -have_func('rb_gc_mark_movable') have_func('stpcpy') +have_func('rb_data_object_wrap') have_func('pthread_mutex_init') dflags['OJ_DEBUG'] = true unless ENV['OJ_DEBUG'].nil? diff --git a/ext/oj/fast.c b/ext/oj/fast.c index 528c6179..cc559f3e 100644 --- a/ext/oj/fast.c +++ b/ext/oj/fast.c @@ -2,105 +2,98 @@ // Licensed under the MIT License. See LICENSE file in the project root for license details. #if !IS_WINDOWS -#include // for getrlimit() on linux +#include // for getrlimit() on linux #endif -#include -#include -#include #include +#include #include +#include +#include -#include "encode.h" #include "oj.h" +#include "encode.h" // maximum to allocate on the stack, arbitrary limit -#define SMALL_XML 65536 -#define MAX_STACK 100 +#define SMALL_XML 65536 +#define MAX_STACK 100 //#define BATCH_SIZE (4096 / sizeof(struct _leaf) - 1) -#define BATCH_SIZE 100 - -// Support for compaction -#ifdef HAVE_RB_GC_MARK_MOVABLE -#define mark rb_gc_mark_movable -#else -#define mark rb_gc_mark -#endif +#define BATCH_SIZE 100 typedef struct _batch { - struct _batch *next; - int next_avail; - struct _leaf leaves[BATCH_SIZE]; -} * Batch; + struct _batch *next; + int next_avail; + struct _leaf leaves[BATCH_SIZE]; +} *Batch; typedef struct _doc { - Leaf data; - Leaf *where; // points to current location - Leaf where_path[MAX_STACK]; // points to head of path - char *json; - unsigned long size; // number of leaves/branches in the doc - VALUE self; - Batch batches; - struct _batch batch0; -} * Doc; + Leaf data; + Leaf *where; // points to current location + Leaf where_path[MAX_STACK]; // points to head of path + char *json; + unsigned long size; // number of leaves/branches in the doc + VALUE self; + Batch batches; + struct _batch batch0; +} *Doc; typedef struct _parseInfo { - char *str; /* buffer being read from */ - char *s; /* current position in buffer */ - Doc doc; - void *stack_min; -} * ParseInfo; - -static void leaf_init(Leaf leaf, int type); -static Leaf leaf_new(Doc doc, int type); -static void leaf_append_element(Leaf parent, Leaf element); -static VALUE leaf_value(Doc doc, Leaf leaf); -static void leaf_fixnum_value(Leaf leaf); -static void leaf_float_value(Leaf leaf); -static VALUE leaf_array_value(Doc doc, Leaf leaf); -static VALUE leaf_hash_value(Doc doc, Leaf leaf); -static Leaf read_next(ParseInfo pi); -static Leaf read_obj(ParseInfo pi); -static Leaf read_array(ParseInfo pi); -static Leaf read_str(ParseInfo pi); -static Leaf read_num(ParseInfo pi); -static Leaf read_true(ParseInfo pi); -static Leaf read_false(ParseInfo pi); -static Leaf read_nil(ParseInfo pi); -static void next_non_white(ParseInfo pi); -static char *read_quoted_value(ParseInfo pi); -static void skip_comment(ParseInfo pi); - -static VALUE protect_open_proc(VALUE x); -static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated); -static void each_leaf(Doc doc, VALUE self); -static int move_step(Doc doc, const char *path, int loc); -static Leaf get_doc_leaf(Doc doc, const char *path); -static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path); -static void each_value(Doc doc, Leaf leaf); - -static void doc_init(Doc doc); -static void doc_free(Doc doc); -static VALUE doc_open(VALUE clas, VALUE str); -static VALUE doc_open_file(VALUE clas, VALUE filename); -static VALUE doc_where(VALUE self); -static VALUE doc_local_key(VALUE self); -static VALUE doc_home(VALUE self); -static VALUE doc_type(int argc, VALUE *argv, VALUE self); -static VALUE doc_fetch(int argc, VALUE *argv, VALUE self); -static VALUE doc_each_leaf(int argc, VALUE *argv, VALUE self); -static VALUE doc_move(VALUE self, VALUE str); -static VALUE doc_each_child(int argc, VALUE *argv, VALUE self); -static VALUE doc_each_value(int argc, VALUE *argv, VALUE self); -static VALUE doc_dump(int argc, VALUE *argv, VALUE self); -static VALUE doc_size(VALUE self); - -VALUE oj_doc_class = Qundef; + char *str; /* buffer being read from */ + char *s; /* current position in buffer */ + Doc doc; + void *stack_min; +} *ParseInfo; + +static void leaf_init(Leaf leaf, int type); +static Leaf leaf_new(Doc doc, int type); +static void leaf_append_element(Leaf parent, Leaf element); +static VALUE leaf_value(Doc doc, Leaf leaf); +static void leaf_fixnum_value(Leaf leaf); +static void leaf_float_value(Leaf leaf); +static VALUE leaf_array_value(Doc doc, Leaf leaf); +static VALUE leaf_hash_value(Doc doc, Leaf leaf); + +static Leaf read_next(ParseInfo pi); +static Leaf read_obj(ParseInfo pi); +static Leaf read_array(ParseInfo pi); +static Leaf read_str(ParseInfo pi); +static Leaf read_num(ParseInfo pi); +static Leaf read_true(ParseInfo pi); +static Leaf read_false(ParseInfo pi); +static Leaf read_nil(ParseInfo pi); +static void next_non_white(ParseInfo pi); +static char* read_quoted_value(ParseInfo pi); +static void skip_comment(ParseInfo pi); + +static VALUE protect_open_proc(VALUE x); +static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated); +static void each_leaf(Doc doc, VALUE self); +static int move_step(Doc doc, const char *path, int loc); +static Leaf get_doc_leaf(Doc doc, const char *path); +static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path); +static void each_value(Doc doc, Leaf leaf); + +static void doc_init(Doc doc); +static void doc_free(Doc doc); +static VALUE doc_open(VALUE clas, VALUE str); +static VALUE doc_open_file(VALUE clas, VALUE filename); +static VALUE doc_where(VALUE self); +static VALUE doc_local_key(VALUE self); +static VALUE doc_home(VALUE self); +static VALUE doc_type(int argc, VALUE *argv, VALUE self); +static VALUE doc_fetch(int argc, VALUE *argv, VALUE self); +static VALUE doc_each_leaf(int argc, VALUE *argv, VALUE self); +static VALUE doc_move(VALUE self, VALUE str); +static VALUE doc_each_child(int argc, VALUE *argv, VALUE self); +static VALUE doc_each_value(int argc, VALUE *argv, VALUE self); +static VALUE doc_dump(int argc, VALUE *argv, VALUE self); +static VALUE doc_size(VALUE self); + +VALUE oj_doc_class = Qundef; // This is only for CentOS 5.4 with Ruby 1.9.3-p0. #ifndef HAVE_STPCPY -char * -stpcpy(char *dest, const char *src) { - size_t cnt = strlen(src); +char *stpcpy(char *dest, const char *src) { + size_t cnt = strlen(src); strcpy(dest, src); @@ -111,38 +104,38 @@ stpcpy(char *dest, const char *src) { inline static void next_non_white(ParseInfo pi) { for (; 1; pi->s++) { - switch (*pi->s) { - case ' ': - case '\t': - case '\f': - case '\n': - case '\r': - break; - case '/': - skip_comment(pi); - break; - default: - return; - } + switch(*pi->s) { + case ' ': + case '\t': + case '\f': + case '\n': + case '\r': + break; + case '/': + skip_comment(pi); + break; + default: + return; + } } } -inline static char * +inline static char* ulong_fill(char *s, size_t num) { - char buf[32]; - char *b = buf + sizeof(buf) - 1; + char buf[32]; + char *b = buf + sizeof(buf) - 1; *b-- = '\0'; for (; 0 < num; num /= 10, b--) { - *b = (num % 10) + '0'; + *b = (num % 10) + '0'; } b++; if ('\0' == *b) { - b--; - *b = '0'; + b--; + *b = '0'; } for (; '\0' != *b; b++, s++) { - *s = *b; + *s = *b; } return s; } @@ -153,44 +146,44 @@ leaf_init(Leaf leaf, int type) { leaf->rtype = type; leaf->parent_type = T_NONE; switch (type) { - case T_ARRAY: - case T_HASH: - leaf->elements = 0; - leaf->value_type = COL_VAL; - break; - case T_NIL: - leaf->value = Qnil; - leaf->value_type = RUBY_VAL; - break; - case T_TRUE: - leaf->value = Qtrue; - leaf->value_type = RUBY_VAL; - break; - case T_FALSE: - leaf->value = Qfalse; - leaf->value_type = RUBY_VAL; - break; - case T_FIXNUM: - case T_FLOAT: - case T_STRING: - default: - leaf->value_type = STR_VAL; - break; + case T_ARRAY: + case T_HASH: + leaf->elements = 0; + leaf->value_type = COL_VAL; + break; + case T_NIL: + leaf->value = Qnil; + leaf->value_type = RUBY_VAL; + break; + case T_TRUE: + leaf->value = Qtrue; + leaf->value_type = RUBY_VAL; + break; + case T_FALSE: + leaf->value = Qfalse; + leaf->value_type = RUBY_VAL; + break; + case T_FIXNUM: + case T_FLOAT: + case T_STRING: + default: + leaf->value_type = STR_VAL; + break; } } inline static Leaf leaf_new(Doc doc, int type) { - Leaf leaf; + Leaf leaf; if (0 == doc->batches || BATCH_SIZE == doc->batches->next_avail) { - Batch b = ALLOC(struct _batch); + Batch b = ALLOC(struct _batch); - // Initializes all leaves with a NO_VAL value_type - memset(b, 0, sizeof(struct _batch)); - b->next = doc->batches; - doc->batches = b; - b->next_avail = 0; + // Initializes all leaves with a NO_VAL value_type + memset(b, 0, sizeof(struct _batch)); + b->next = doc->batches; + doc->batches = b; + b->next_avail = 0; } leaf = &doc->batches->leaves[doc->batches->next_avail]; doc->batches->next_avail++; @@ -202,59 +195,59 @@ leaf_new(Doc doc, int type) { inline static void leaf_append_element(Leaf parent, Leaf element) { if (0 == parent->elements) { - parent->elements = element; - element->next = element; + parent->elements = element; + element->next = element; } else { - element->next = parent->elements->next; - parent->elements->next = element; - parent->elements = element; + element->next = parent->elements->next; + parent->elements->next = element; + parent->elements = element; } } static VALUE leaf_value(Doc doc, Leaf leaf) { if (RUBY_VAL != leaf->value_type) { - switch (leaf->rtype) { - case T_NIL: - leaf->value = Qnil; - break; - case T_TRUE: - leaf->value = Qtrue; - break; - case T_FALSE: - leaf->value = Qfalse; - break; - case T_FIXNUM: - leaf_fixnum_value(leaf); - break; - case T_FLOAT: - leaf_float_value(leaf); - break; - case T_STRING: - leaf->value = rb_str_new2(leaf->str); - leaf->value = oj_encode(leaf->value); - leaf->value_type = RUBY_VAL; - break; - case T_ARRAY: - return leaf_array_value(doc, leaf); - break; - case T_HASH: - return leaf_hash_value(doc, leaf); - break; - default: - rb_raise(rb_const_get_at(Oj, rb_intern("Error")), "Unexpected type %02x.", leaf->rtype); - break; - } + switch (leaf->rtype) { + case T_NIL: + leaf->value = Qnil; + break; + case T_TRUE: + leaf->value = Qtrue; + break; + case T_FALSE: + leaf->value = Qfalse; + break; + case T_FIXNUM: + leaf_fixnum_value(leaf); + break; + case T_FLOAT: + leaf_float_value(leaf); + break; + case T_STRING: + leaf->value = rb_str_new2(leaf->str); + leaf->value = oj_encode(leaf->value); + leaf->value_type = RUBY_VAL; + break; + case T_ARRAY: + return leaf_array_value(doc, leaf); + break; + case T_HASH: + return leaf_hash_value(doc, leaf); + break; + default: + rb_raise(rb_const_get_at(Oj, rb_intern("Error")), "Unexpected type %02x.", leaf->rtype); + break; + } } return leaf->value; } inline static Doc self_doc(VALUE self) { - Doc doc = DATA_PTR(self); + Doc doc = DATA_PTR(self); if (0 == doc) { - rb_raise(rb_eIOError, "Document already closed or not open."); + rb_raise(rb_eIOError, "Document already closed or not open."); } return doc; } @@ -263,29 +256,29 @@ static void skip_comment(ParseInfo pi) { pi->s++; // skip first / if ('*' == *pi->s) { - pi->s++; - for (; '\0' != *pi->s; pi->s++) { - if ('*' == *pi->s && '/' == *(pi->s + 1)) { - pi->s++; - return; - } else if ('\0' == *pi->s) { - raise_error("comment not terminated", pi->str, pi->s); - } - } + pi->s++; + for (; '\0' != *pi->s; pi->s++) { + if ('*' == *pi->s && '/' == *(pi->s + 1)) { + pi->s++; + return; + } else if ('\0' == *pi->s) { + raise_error("comment not terminated", pi->str, pi->s); + } + } } else if ('/' == *pi->s) { - for (; 1; pi->s++) { - switch (*pi->s) { - case '\n': - case '\r': - case '\f': - case '\0': - return; - default: - break; - } - } + for (; 1; pi->s++) { + switch (*pi->s) { + case '\n': + case '\r': + case '\f': + case '\0': + return; + default: + break; + } + } } else { - raise_error("invalid comment", pi->str, pi->s); + raise_error("invalid comment", pi->str, pi->s); } } @@ -295,36 +288,37 @@ skip_comment(ParseInfo pi) { #define NUM_MAX (FIXNUM_MAX >> 8) #endif + static void leaf_fixnum_value(Leaf leaf) { - char *s = leaf->str; - int64_t n = 0; - int neg = 0; - int big = 0; + char *s = leaf->str; + int64_t n = 0; + int neg = 0; + int big = 0; if ('-' == *s) { - s++; - neg = 1; + s++; + neg = 1; } else if ('+' == *s) { - s++; + s++; } for (; '0' <= *s && *s <= '9'; s++) { - n = n * 10 + (*s - '0'); - if (NUM_MAX <= n) { - big = 1; - } + n = n * 10 + (*s - '0'); + if (NUM_MAX <= n) { + big = 1; + } } if (big) { - char c = *s; + char c = *s; - *s = '\0'; - leaf->value = rb_cstr_to_inum(leaf->str, 10, 0); - *s = c; + *s = '\0'; + leaf->value = rb_cstr_to_inum(leaf->str, 10, 0); + *s = c; } else { - if (neg) { - n = -n; - } - leaf->value = rb_ll2inum(n); + if (neg) { + n = -n; + } + leaf->value = rb_ll2inum(n); } leaf->value_type = RUBY_VAL; } @@ -337,83 +331,83 @@ leaf_float_value(Leaf leaf) { static VALUE leaf_array_value(Doc doc, Leaf leaf) { - volatile VALUE a = rb_ary_new(); + volatile VALUE a = rb_ary_new(); if (0 != leaf->elements) { - Leaf first = leaf->elements->next; - Leaf e = first; + Leaf first = leaf->elements->next; + Leaf e = first; - do { - rb_ary_push(a, leaf_value(doc, e)); - e = e->next; - } while (e != first); + do { + rb_ary_push(a, leaf_value(doc, e)); + e = e->next; + } while (e != first); } return a; } static VALUE leaf_hash_value(Doc doc, Leaf leaf) { - volatile VALUE h = rb_hash_new(); + volatile VALUE h = rb_hash_new(); if (0 != leaf->elements) { - Leaf first = leaf->elements->next; - Leaf e = first; - volatile VALUE key; + Leaf first = leaf->elements->next; + Leaf e = first; + volatile VALUE key; - do { - key = rb_str_new2(e->key); - key = oj_encode(key); - rb_hash_aset(h, key, leaf_value(doc, e)); - e = e->next; - } while (e != first); + do { + key = rb_str_new2(e->key); + key = oj_encode(key); + rb_hash_aset(h, key, leaf_value(doc, e)); + e = e->next; + } while (e != first); } return h; } static Leaf read_next(ParseInfo pi) { - Leaf leaf = 0; + Leaf leaf = 0; - if ((void *)&leaf < pi->stack_min) { - rb_raise(rb_eSysStackError, "JSON is too deeply nested"); + if ((void*)&leaf < pi->stack_min) { + rb_raise(rb_eSysStackError, "JSON is too deeply nested"); } - next_non_white(pi); // skip white space + next_non_white(pi); // skip white space switch (*pi->s) { - case '{': - leaf = read_obj(pi); - break; - case '[': - leaf = read_array(pi); - break; - case '"': - leaf = read_str(pi); - break; - case '+': - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - leaf = read_num(pi); - break; - case 't': - leaf = read_true(pi); - break; - case 'f': - leaf = read_false(pi); - break; - case 'n': - leaf = read_nil(pi); - break; - case '\0': - default: - break; // returns 0 + case '{': + leaf = read_obj(pi); + break; + case '[': + leaf = read_array(pi); + break; + case '"': + leaf = read_str(pi); + break; + case '+': + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + leaf = read_num(pi); + break; + case 't': + leaf = read_true(pi); + break; + case 'f': + leaf = read_false(pi); + break; + case 'n': + leaf = read_nil(pi); + break; + case '\0': + default: + break; // returns 0 } pi->doc->size++; @@ -422,95 +416,95 @@ read_next(ParseInfo pi) { static Leaf read_obj(ParseInfo pi) { - Leaf h = leaf_new(pi->doc, T_HASH); - char *end; - const char *key = 0; - Leaf val = 0; + Leaf h = leaf_new(pi->doc, T_HASH); + char *end; + const char *key = 0; + Leaf val = 0; pi->s++; next_non_white(pi); if ('}' == *pi->s) { - pi->s++; - return h; + pi->s++; + return h; } while (1) { - next_non_white(pi); - key = 0; - val = 0; - if ('"' != *pi->s || 0 == (key = read_quoted_value(pi))) { - raise_error("unexpected character", pi->str, pi->s); - } - next_non_white(pi); - if (':' == *pi->s) { - pi->s++; - } else { - raise_error("invalid format, expected :", pi->str, pi->s); - } - if (0 == (val = read_next(pi))) { - //printf("*** '%s'\n", pi->s); - raise_error("unexpected character", pi->str, pi->s); - } - end = pi->s; - val->key = key; - val->parent_type = T_HASH; - leaf_append_element(h, val); - next_non_white(pi); - if ('}' == *pi->s) { - pi->s++; - *end = '\0'; - break; - } else if (',' == *pi->s) { - pi->s++; - } else { - //printf("*** '%s'\n", pi->s); - raise_error("invalid format, expected , or } while in an object", pi->str, pi->s); - } - *end = '\0'; + next_non_white(pi); + key = 0; + val = 0; + if ('"' != *pi->s || 0 == (key = read_quoted_value(pi))) { + raise_error("unexpected character", pi->str, pi->s); + } + next_non_white(pi); + if (':' == *pi->s) { + pi->s++; + } else { + raise_error("invalid format, expected :", pi->str, pi->s); + } + if (0 == (val = read_next(pi))) { + //printf("*** '%s'\n", pi->s); + raise_error("unexpected character", pi->str, pi->s); + } + end = pi->s; + val->key = key; + val->parent_type = T_HASH; + leaf_append_element(h, val); + next_non_white(pi); + if ('}' == *pi->s) { + pi->s++; + *end = '\0'; + break; + } else if (',' == *pi->s) { + pi->s++; + } else { + //printf("*** '%s'\n", pi->s); + raise_error("invalid format, expected , or } while in an object", pi->str, pi->s); + } + *end = '\0'; } return h; } static Leaf read_array(ParseInfo pi) { - Leaf a = leaf_new(pi->doc, T_ARRAY); - Leaf e; - char *end; - int cnt = 0; + Leaf a = leaf_new(pi->doc, T_ARRAY); + Leaf e; + char *end; + int cnt = 0; pi->s++; next_non_white(pi); if (']' == *pi->s) { - pi->s++; - return a; + pi->s++; + return a; } while (1) { - next_non_white(pi); - if (0 == (e = read_next(pi))) { - raise_error("unexpected character", pi->str, pi->s); - } - cnt++; - e->index = cnt; - e->parent_type = T_ARRAY; - leaf_append_element(a, e); - end = pi->s; - next_non_white(pi); - if (',' == *pi->s) { - pi->s++; - } else if (']' == *pi->s) { - pi->s++; - *end = '\0'; - break; - } else { - raise_error("invalid format, expected , or ] while in an array", pi->str, pi->s); - } - *end = '\0'; + next_non_white(pi); + if (0 == (e = read_next(pi))) { + raise_error("unexpected character", pi->str, pi->s); + } + cnt++; + e->index = cnt; + e->parent_type = T_ARRAY; + leaf_append_element(a, e); + end = pi->s; + next_non_white(pi); + if (',' == *pi->s) { + pi->s++; + } else if (']' == *pi->s) { + pi->s++; + *end = '\0'; + break; + } else { + raise_error("invalid format, expected , or ] while in an array", pi->str, pi->s); + } + *end = '\0'; } return a; } static Leaf read_str(ParseInfo pi) { - Leaf leaf = leaf_new(pi->doc, T_STRING); + Leaf leaf = leaf_new(pi->doc, T_STRING); leaf->str = read_quoted_value(pi); @@ -519,29 +513,29 @@ read_str(ParseInfo pi) { static Leaf read_num(ParseInfo pi) { - char *start = pi->s; - int type = T_FIXNUM; - Leaf leaf; + char *start = pi->s; + int type = T_FIXNUM; + Leaf leaf; if ('-' == *pi->s) { - pi->s++; + pi->s++; } // digits for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) { } if ('.' == *pi->s) { - type = T_FLOAT; - pi->s++; - for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) { - } + type = T_FLOAT; + pi->s++; + for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) { + } } if ('e' == *pi->s || 'E' == *pi->s) { - pi->s++; - if ('-' == *pi->s || '+' == *pi->s) { - pi->s++; - } - for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) { - } + pi->s++; + if ('-' == *pi->s || '+' == *pi->s) { + pi->s++; + } + for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) { + } } leaf = leaf_new(pi->doc, type); leaf->str = start; @@ -551,11 +545,11 @@ read_num(ParseInfo pi) { static Leaf read_true(ParseInfo pi) { - Leaf leaf = leaf_new(pi->doc, T_TRUE); + Leaf leaf = leaf_new(pi->doc, T_TRUE); pi->s++; if ('r' != *pi->s || 'u' != *(pi->s + 1) || 'e' != *(pi->s + 2)) { - raise_error("invalid format, expected 'true'", pi->str, pi->s); + raise_error("invalid format, expected 'true'", pi->str, pi->s); } pi->s += 3; @@ -564,11 +558,11 @@ read_true(ParseInfo pi) { static Leaf read_false(ParseInfo pi) { - Leaf leaf = leaf_new(pi->doc, T_FALSE); + Leaf leaf = leaf_new(pi->doc, T_FALSE); pi->s++; if ('a' != *pi->s || 'l' != *(pi->s + 1) || 's' != *(pi->s + 2) || 'e' != *(pi->s + 3)) { - raise_error("invalid format, expected 'false'", pi->str, pi->s); + raise_error("invalid format, expected 'false'", pi->str, pi->s); } pi->s += 4; @@ -577,11 +571,11 @@ read_false(ParseInfo pi) { static Leaf read_nil(ParseInfo pi) { - Leaf leaf = leaf_new(pi->doc, T_NIL); + Leaf leaf = leaf_new(pi->doc, T_NIL); pi->s++; if ('u' != *pi->s || 'l' != *(pi->s + 1) || 'l' != *(pi->s + 2)) { - raise_error("invalid format, expected 'nil'", pi->str, pi->s); + raise_error("invalid format, expected 'nil'", pi->str, pi->s); } pi->s += 3; @@ -590,55 +584,55 @@ read_nil(ParseInfo pi) { static uint32_t read_4hex(ParseInfo pi, const char *h) { - uint32_t b = 0; - int i; + uint32_t b = 0; + int i; for (i = 0; i < 4; i++, h++) { - b = b << 4; - if ('0' <= *h && *h <= '9') { - b += *h - '0'; - } else if ('A' <= *h && *h <= 'F') { - b += *h - 'A' + 10; - } else if ('a' <= *h && *h <= 'f') { - b += *h - 'a' + 10; - } else { - raise_error("invalid hex character", pi->str, pi->s); - } + b = b << 4; + if ('0' <= *h && *h <= '9') { + b += *h - '0'; + } else if ('A' <= *h && *h <= 'F') { + b += *h - 'A' + 10; + } else if ('a' <= *h && *h <= 'f') { + b += *h - 'a' + 10; + } else { + raise_error("invalid hex character", pi->str, pi->s); + } } return b; } -static char * +static char* unicode_to_chars(ParseInfo pi, char *t, uint32_t code) { if (0x0000007F >= code) { - *t++ = (char)code; + *t++ = (char)code; } else if (0x000007FF >= code) { - *t++ = 0xC0 | (code >> 6); - *t++ = 0x80 | (0x3F & code); + *t++ = 0xC0 | (code >> 6); + *t++ = 0x80 | (0x3F & code); } else if (0x0000FFFF >= code) { - *t++ = 0xE0 | (code >> 12); - *t++ = 0x80 | ((code >> 6) & 0x3F); - *t++ = 0x80 | (0x3F & code); + *t++ = 0xE0 | (code >> 12); + *t++ = 0x80 | ((code >> 6) & 0x3F); + *t++ = 0x80 | (0x3F & code); } else if (0x001FFFFF >= code) { - *t++ = 0xF0 | (code >> 18); - *t++ = 0x80 | ((code >> 12) & 0x3F); - *t++ = 0x80 | ((code >> 6) & 0x3F); - *t++ = 0x80 | (0x3F & code); + *t++ = 0xF0 | (code >> 18); + *t++ = 0x80 | ((code >> 12) & 0x3F); + *t++ = 0x80 | ((code >> 6) & 0x3F); + *t++ = 0x80 | (0x3F & code); } else if (0x03FFFFFF >= code) { - *t++ = 0xF8 | (code >> 24); - *t++ = 0x80 | ((code >> 18) & 0x3F); - *t++ = 0x80 | ((code >> 12) & 0x3F); - *t++ = 0x80 | ((code >> 6) & 0x3F); - *t++ = 0x80 | (0x3F & code); + *t++ = 0xF8 | (code >> 24); + *t++ = 0x80 | ((code >> 18) & 0x3F); + *t++ = 0x80 | ((code >> 12) & 0x3F); + *t++ = 0x80 | ((code >> 6) & 0x3F); + *t++ = 0x80 | (0x3F & code); } else if (0x7FFFFFFF >= code) { - *t++ = 0xFC | (code >> 30); - *t++ = 0x80 | ((code >> 24) & 0x3F); - *t++ = 0x80 | ((code >> 18) & 0x3F); - *t++ = 0x80 | ((code >> 12) & 0x3F); - *t++ = 0x80 | ((code >> 6) & 0x3F); - *t++ = 0x80 | (0x3F & code); + *t++ = 0xFC | (code >> 30); + *t++ = 0x80 | ((code >> 24) & 0x3F); + *t++ = 0x80 | ((code >> 18) & 0x3F); + *t++ = 0x80 | ((code >> 12) & 0x3F); + *t++ = 0x80 | ((code >> 6) & 0x3F); + *t++ = 0x80 | (0x3F & code); } else { - raise_error("invalid Unicode character", pi->str, pi->s); + raise_error("invalid Unicode character", pi->str, pi->s); } return t; } @@ -646,79 +640,63 @@ unicode_to_chars(ParseInfo pi, char *t, uint32_t code) { /* Assume the value starts immediately and goes until the quote character is * reached again. Do not read the character after the terminating quote. */ -static char * +static char* read_quoted_value(ParseInfo pi) { - char *value = 0; - char *h = pi->s; // head - char *t = h; // tail + char *value = 0; + char *h = pi->s; // head + char *t = h; // tail - h++; // skip quote character + h++; // skip quote character t++; value = h; for (; '"' != *h; h++, t++) { - if ('\0' == *h) { - pi->s = h; - raise_error("quoted string not terminated", pi->str, pi->s); - } else if ('\\' == *h) { - h++; - switch (*h) { - case 'n': - *t = '\n'; - break; - case 'r': - *t = '\r'; - break; - case 't': - *t = '\t'; - break; - case 'f': - *t = '\f'; - break; - case 'b': - *t = '\b'; - break; - case '"': - *t = '"'; - break; - case '/': - *t = '/'; - break; - case '\\': - *t = '\\'; - break; - case 'u': { - uint32_t code; - - h++; - code = read_4hex(pi, h); - h += 3; - if (0x0000D800 <= code && code <= 0x0000DFFF) { - uint32_t c1 = (code - 0x0000D800) & 0x000003FF; - uint32_t c2; - - h++; - if ('\\' != *h || 'u' != *(h + 1)) { - pi->s = h; - raise_error("invalid escaped character", pi->str, pi->s); - } - h += 2; - c2 = read_4hex(pi, h); - h += 3; - c2 = (c2 - 0x0000DC00) & 0x000003FF; - code = ((c1 << 10) | c2) + 0x00010000; - } - t = unicode_to_chars(pi, t, code); - t--; - break; - } - default: - pi->s = h; - raise_error("invalid escaped character", pi->str, pi->s); - break; - } - } else if (t != h) { - *t = *h; - } + if ('\0' == *h) { + pi->s = h; + raise_error("quoted string not terminated", pi->str, pi->s); + } else if ('\\' == *h) { + h++; + switch (*h) { + case 'n': *t = '\n'; break; + case 'r': *t = '\r'; break; + case 't': *t = '\t'; break; + case 'f': *t = '\f'; break; + case 'b': *t = '\b'; break; + case '"': *t = '"'; break; + case '/': *t = '/'; break; + case '\\': *t = '\\'; break; + case 'u': { + uint32_t code; + + h++; + code = read_4hex(pi, h); + h += 3; + if (0x0000D800 <= code && code <= 0x0000DFFF) { + uint32_t c1 = (code - 0x0000D800) & 0x000003FF; + uint32_t c2; + + h++; + if ('\\' != *h || 'u' != *(h + 1)) { + pi->s = h; + raise_error("invalid escaped character", pi->str, pi->s); + } + h += 2; + c2 = read_4hex(pi, h); + h += 3; + c2 = (c2 - 0x0000DC00) & 0x000003FF; + code = ((c1 << 10) | c2) + 0x00010000; + } + t = unicode_to_chars(pi, t, code); + t--; + break; + } + default: + pi->s = h; + raise_error("invalid escaped character", pi->str, pi->s); + break; + } + } else if (t != h) { + *t = *h; + } } *t = '\0'; // terminate value pi->s = h + 1; @@ -738,220 +716,177 @@ doc_init(Doc doc) { static void doc_free(Doc doc) { if (0 != doc) { - Batch b; + Batch b; - while (0 != (b = doc->batches)) { - doc->batches = doc->batches->next; - if (&doc->batch0 != b) { - xfree(b); - } - } - //xfree(f); + while (0 != (b = doc->batches)) { + doc->batches = doc->batches->next; + if (&doc->batch0 != b) { + xfree(b); + } + } + //xfree(f); } } static VALUE protect_open_proc(VALUE x) { - ParseInfo pi = (ParseInfo)x; + ParseInfo pi = (ParseInfo)x; pi->doc->data = read_next(pi); // parse *pi->doc->where = pi->doc->data; pi->doc->where = pi->doc->where_path; if (rb_block_given_p()) { - return rb_yield(pi->doc->self); // caller processing + return rb_yield(pi->doc->self); // caller processing } return Qnil; } static void free_doc_cb(void *x) { - Doc doc = (Doc)x; + Doc doc = (Doc)x; if (0 != doc) { - xfree(doc->json); - doc_free(doc); + xfree(doc->json); + doc_free(doc); } } static void mark_leaf(Leaf leaf) { switch (leaf->value_type) { - case COL_VAL: - if (NULL != leaf->elements) { - Leaf first = leaf->elements->next; - Leaf e = first; - - do { - mark_leaf(e); - e = e->next; - } while (e != first); - } - break; - case RUBY_VAL: - mark(leaf->value); - break; - - default: - break; + case COL_VAL: + if (NULL != leaf->elements) { + Leaf first = leaf->elements->next; + Leaf e = first; + + do { + mark_leaf(e); + e = e->next; + } while (e != first); + } + break; + case RUBY_VAL: + rb_gc_mark(leaf->value); + break; + + default: + break; } } static void mark_doc(void *ptr) { if (NULL != ptr) { - Doc doc = (Doc)ptr; + Doc doc = (Doc)ptr; - mark(doc->self); - mark_leaf(doc->data); + rb_gc_mark(doc->self); + mark_leaf(doc->data); } } -#ifdef HAVE_RB_GC_MARK_MOVABLE -static void -compact_leaf(Leaf leaf) { - switch (leaf->value_type) { - case COL_VAL: - if (NULL != leaf->elements) { - Leaf first = leaf->elements->next; - Leaf e = first; - - do { - compact_leaf(e); - e = e->next; - } while (e != first); - } - break; - case RUBY_VAL: - leaf->value = rb_gc_location(leaf->value); - break; - - default: - break; - } -} - -static void -compact_doc(void *ptr) { - Doc doc = (Doc)ptr; - - if (doc) { - doc->self = rb_gc_location(doc->self); - compact_leaf(doc->data); - } -} -#endif - -static const rb_data_type_t oj_doc_type = { - "Oj/doc", - { - mark_doc, - free_doc_cb, - NULL, -#ifdef HAVE_RB_GC_MARK_MOVABLE - compact_doc, -#endif - }, - 0, - 0, -}; static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) { - struct _parseInfo pi; - volatile VALUE result = Qnil; - Doc doc; - int ex = 0; - volatile VALUE self; + struct _parseInfo pi; + volatile VALUE result = Qnil; + Doc doc; + int ex = 0; + volatile VALUE self; // TBD are both needed? is stack allocation ever needed? if (given) { - doc = ALLOCA_N(struct _doc, 1); + doc = ALLOCA_N(struct _doc, 1); } else { - doc = ALLOC(struct _doc); + doc = ALLOC(struct _doc); } /* skip UTF-8 BOM if present */ if (0xEF == (uint8_t)*json && 0xBB == (uint8_t)json[1] && 0xBF == (uint8_t)json[2]) { - pi.str = json + 3; + pi.str = json + 3; } else { - pi.str = json; + pi.str = json; } pi.s = pi.str; doc_init(doc); pi.doc = doc; #if IS_WINDOWS - pi.stack_min = (void *)((char *)&pi - (512 * 1024)); // assume a 1M stack and give half to ruby + pi.stack_min = (void*)((char*)&pi - (512 * 1024)); // assume a 1M stack and give half to ruby #else { - struct rlimit lim; + struct rlimit lim; - if (0 == getrlimit(RLIMIT_STACK, &lim) && RLIM_INFINITY != lim.rlim_cur) { - pi.stack_min = (void *)((char *)&lim - (lim.rlim_cur / 4 * 3)); // let 3/4ths of the stack be used only - } else { - pi.stack_min = 0; // indicates not to check stack limit - } + if (0 == getrlimit(RLIMIT_STACK, &lim) && RLIM_INFINITY != lim.rlim_cur) { + pi.stack_min = (void*)((char*)&lim - (lim.rlim_cur / 4 * 3)); // let 3/4ths of the stack be used only + } else { + pi.stack_min = 0; // indicates not to check stack limit + } } #endif - self = TypedData_Wrap_Struct(clas, &oj_doc_type, doc); + // last arg is free func void* func(void*) +#ifdef HAVE_RB_DATA_OBJECT_WRAP + self = rb_data_object_wrap(clas, doc, mark_doc, free_doc_cb); +#else + self = rb_data_object_alloc(clas, doc, mark_doc, free_doc_cb); +#endif doc->self = self; doc->json = json; DATA_PTR(doc->self) = doc; result = rb_protect(protect_open_proc, (VALUE)&pi, &ex); if (given || 0 != ex) { - DATA_PTR(doc->self) = NULL; - doc_free(pi.doc); - if (allocated && 0 != ex) { // will jump so caller will not free - xfree(json); - } - rb_gc_enable(); + DATA_PTR(doc->self) = NULL; + doc_free(pi.doc); + if (allocated && 0 != ex) { // will jump so caller will not free + xfree(json); + } + rb_gc_enable(); } else { - result = doc->self; + result = doc->self; } if (0 != ex) { - rb_jump_tag(ex); + rb_jump_tag(ex); } return result; } static Leaf get_doc_leaf(Doc doc, const char *path) { - Leaf leaf = *doc->where; + Leaf leaf = *doc->where; if (0 != doc->data && 0 != path) { - Leaf stack[MAX_STACK]; - Leaf *lp; - - if ('/' == *path) { - path++; - *stack = doc->data; - lp = stack; - } else if (doc->where == doc->where_path) { - *stack = doc->data; - lp = stack; - } else { - size_t cnt = doc->where - doc->where_path; - - if (MAX_STACK <= cnt) { - rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK); - } - memcpy(stack, doc->where_path, sizeof(Leaf) * (cnt + 1)); - lp = stack + cnt; - } - return get_leaf(stack, lp, path); + Leaf stack[MAX_STACK]; + Leaf *lp; + + if ('/' == *path) { + path++; + *stack = doc->data; + lp = stack; + } else if (doc->where == doc->where_path) { + *stack = doc->data; + lp = stack; + } else { + size_t cnt = doc->where - doc->where_path; + + if (MAX_STACK <= cnt) { + rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK); + } + memcpy(stack, doc->where_path, sizeof(Leaf) * (cnt + 1)); + lp = stack + cnt; + } + return get_leaf(stack, lp, path); } return leaf; } -static const char * +static const char* next_slash(const char *s) { for (; '\0' != *s; s++) { - if ('\\' == *s) { - s++; - if ('\0' == *s) { - break; - } - } else if ('/' == *s) { - return s; - } + if ('\\' == *s) { + s++; + if ('\0' == *s) { + break; + } + } else if ('/' == *s) { + return s; + } } return NULL; } @@ -959,83 +894,83 @@ next_slash(const char *s) { static bool key_match(const char *pat, const char *key, int plen) { for (; 0 < plen; plen--, pat++, key++) { - if ('\\' == *pat) { - plen--; - pat++; - } - if (*pat != *key) { - return false; - } + if ('\\' == *pat) { + plen--; + pat++; + } + if (*pat != *key) { + return false; + } } return '\0' == *key; } static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path) { - Leaf leaf = *lp; + Leaf leaf = *lp; if (MAX_STACK <= lp - stack) { - rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK); + rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK); } if ('\0' != *path) { - if ('.' == *path && '.' == *(path + 1)) { - path += 2; - if ('/' == *path) { - path++; - } - if (stack < lp) { - leaf = get_leaf(stack, lp - 1, path); - } else { - return 0; - } - } else if (COL_VAL == leaf->value_type && 0 != leaf->elements) { - Leaf first = leaf->elements->next; - Leaf e = first; - int type = leaf->rtype; - - leaf = 0; - if (T_ARRAY == type) { - int cnt = 0; - - for (; '0' <= *path && *path <= '9'; path++) { - cnt = cnt * 10 + (*path - '0'); - } - if ('/' == *path) { - path++; - } - do { - if (1 >= cnt) { - lp++; - *lp = e; - leaf = get_leaf(stack, lp, path); - break; - } - cnt--; - e = e->next; - } while (e != first); - } else if (T_HASH == type) { - const char *key = path; - const char *slash = next_slash(path); - int klen; - - if (0 == slash) { - klen = (int)strlen(key); - path += klen; - } else { - klen = (int)(slash - key); - path += klen + 1; - } - do { - if (key_match(key, e->key, klen)) { - lp++; - *lp = e; - leaf = get_leaf(stack, lp, path); - break; - } - e = e->next; - } while (e != first); - } - } + if ('.' == *path && '.' == *(path + 1)) { + path += 2; + if ('/' == *path) { + path++; + } + if (stack < lp) { + leaf = get_leaf(stack, lp - 1, path); + } else { + return 0; + } + } else if (COL_VAL == leaf->value_type && 0 != leaf->elements) { + Leaf first = leaf->elements->next; + Leaf e = first; + int type = leaf->rtype; + + leaf = 0; + if (T_ARRAY == type) { + int cnt = 0; + + for (; '0' <= *path && *path <= '9'; path++) { + cnt = cnt * 10 + (*path - '0'); + } + if ('/' == *path) { + path++; + } + do { + if (1 >= cnt) { + lp++; + *lp = e; + leaf = get_leaf(stack, lp, path); + break; + } + cnt--; + e = e->next; + } while (e != first); + } else if (T_HASH == type) { + const char *key = path; + const char *slash = next_slash(path); + int klen; + + if (0 == slash) { + klen = (int)strlen(key); + path += klen; + } else { + klen = (int)(slash - key); + path += klen + 1; + } + do { + if (key_match(key, e->key, klen)) { + lp++; + *lp = e; + leaf = get_leaf(stack, lp, path); + break; + } + e = e->next; + } while (e != first); + } + } } return leaf; } @@ -1043,113 +978,113 @@ get_leaf(Leaf *stack, Leaf *lp, const char *path) { static void each_leaf(Doc doc, VALUE self) { if (COL_VAL == (*doc->where)->value_type) { - if (0 != (*doc->where)->elements) { - Leaf first = (*doc->where)->elements->next; - Leaf e = first; - - doc->where++; - if (MAX_STACK <= doc->where - doc->where_path) { - rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK); - } - do { - *doc->where = e; - each_leaf(doc, self); - e = e->next; - } while (e != first); - doc->where--; - } + if (0 != (*doc->where)->elements) { + Leaf first = (*doc->where)->elements->next; + Leaf e = first; + + doc->where++; + if (MAX_STACK <= doc->where - doc->where_path) { + rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK); + } + do { + *doc->where = e; + each_leaf(doc, self); + e = e->next; + } while (e != first); + doc->where--; + } } else { - rb_yield(self); + rb_yield(self); } } static int move_step(Doc doc, const char *path, int loc) { if (MAX_STACK <= doc->where - doc->where_path) { - rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK); + rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK); } if ('\0' == *path) { - loc = 0; + loc = 0; } else { - Leaf leaf; - - if (0 == doc->where || 0 == (leaf = *doc->where)) { - printf("*** Internal error at %s\n", path); - return loc; - } - if ('.' == *path && '.' == *(path + 1)) { - Leaf init = *doc->where; - - path += 2; - if (doc->where == doc->where_path) { - return loc; - } - if ('/' == *path) { - path++; - } - *doc->where = 0; - doc->where--; - loc = move_step(doc, path, loc + 1); - if (0 != loc) { - *doc->where = init; - doc->where++; - } - } else if (COL_VAL == leaf->value_type && 0 != leaf->elements) { - Leaf first = leaf->elements->next; - Leaf e = first; - - if (T_ARRAY == leaf->rtype) { - int cnt = 0; - - for (; '0' <= *path && *path <= '9'; path++) { - cnt = cnt * 10 + (*path - '0'); - } - if ('/' == *path) { - path++; - } else if ('\0' != *path) { - return loc; - } - do { - if (1 >= cnt) { - doc->where++; - *doc->where = e; - loc = move_step(doc, path, loc + 1); - if (0 != loc) { - *doc->where = 0; - doc->where--; - } - break; - } - cnt--; - e = e->next; - } while (e != first); - } else if (T_HASH == leaf->rtype) { - const char *key = path; - const char *slash = next_slash(path); - int klen; - - if (0 == slash) { - klen = (int)strlen(key); - path += klen; - } else { - klen = (int)(slash - key); - path += klen + 1; - } - do { - if (key_match(key, e->key, klen)) { - doc->where++; - *doc->where = e; - loc = move_step(doc, path, loc + 1); - if (0 != loc) { - *doc->where = 0; - doc->where--; - } - break; - } - e = e->next; - } while (e != first); - } - } + Leaf leaf; + + if (0 == doc->where || 0 == (leaf = *doc->where)) { + printf("*** Internal error at %s\n", path); + return loc; + } + if ('.' == *path && '.' == *(path + 1)) { + Leaf init = *doc->where; + + path += 2; + if (doc->where == doc->where_path) { + return loc; + } + if ('/' == *path) { + path++; + } + *doc->where = 0; + doc->where--; + loc = move_step(doc, path, loc + 1); + if (0 != loc) { + *doc->where = init; + doc->where++; + } + } else if (COL_VAL == leaf->value_type && 0 != leaf->elements) { + Leaf first = leaf->elements->next; + Leaf e = first; + + if (T_ARRAY == leaf->rtype) { + int cnt = 0; + + for (; '0' <= *path && *path <= '9'; path++) { + cnt = cnt * 10 + (*path - '0'); + } + if ('/' == *path) { + path++; + } else if ('\0' != *path) { + return loc; + } + do { + if (1 >= cnt) { + doc->where++; + *doc->where = e; + loc = move_step(doc, path, loc + 1); + if (0 != loc) { + *doc->where = 0; + doc->where--; + } + break; + } + cnt--; + e = e->next; + } while (e != first); + } else if (T_HASH == leaf->rtype) { + const char *key = path; + const char *slash = next_slash(path); + int klen; + + if (0 == slash) { + klen = (int)strlen(key); + path += klen; + } else { + klen = (int)(slash - key); + path += klen + 1; + } + do { + if (key_match(key, e->key, klen)) { + doc->where++; + *doc->where = e; + loc = move_step(doc, path, loc + 1); + if (0 != loc) { + *doc->where = 0; + doc->where--; + } + break; + } + e = e->next; + } while (e != first); + } + } } return loc; } @@ -1157,17 +1092,17 @@ move_step(Doc doc, const char *path, int loc) { static void each_value(Doc doc, Leaf leaf) { if (COL_VAL == leaf->value_type) { - if (0 != leaf->elements) { - Leaf first = leaf->elements->next; - Leaf e = first; - - do { - each_value(doc, e); - e = e->next; - } while (e != first); - } + if (0 != leaf->elements) { + Leaf first = leaf->elements->next; + Leaf e = first; + + do { + each_value(doc, e); + e = e->next; + } while (e != first); + } } else { - rb_yield(leaf_value(doc, leaf)); + rb_yield(leaf_value(doc, leaf)); } } @@ -1192,19 +1127,19 @@ each_value(Doc doc, Leaf leaf) { */ static VALUE doc_open(VALUE clas, VALUE str) { - char *json; - size_t len; - volatile VALUE obj; - int given = rb_block_given_p(); - int allocate; + char *json; + size_t len; + volatile VALUE obj; + int given = rb_block_given_p(); + int allocate; Check_Type(str, T_STRING); len = (int)RSTRING_LEN(str) + 1; allocate = (SMALL_XML < len || !given); if (allocate) { - json = ALLOC_N(char, len); + json = ALLOC_N(char, len); } else { - json = ALLOCA_N(char, len); + json = ALLOCA_N(char, len); } // It should not be necessaary to stop GC but if it is not stopped and a // large string is parsed that string is corrupted or freed during @@ -1215,7 +1150,7 @@ doc_open(VALUE clas, VALUE str) { obj = parse_json(clas, json, given, allocate); rb_gc_enable(); if (given && allocate) { - xfree(json); + xfree(json); } return obj; } @@ -1240,34 +1175,32 @@ doc_open(VALUE clas, VALUE str) { */ static VALUE doc_open_file(VALUE clas, VALUE filename) { - char *path; - char *json; - FILE *f; - size_t len; - volatile VALUE obj; - int given = rb_block_given_p(); - int allocate; + char *path; + char *json; + FILE *f; + size_t len; + volatile VALUE obj; + int given = rb_block_given_p(); + int allocate; Check_Type(filename, T_STRING); path = StringValuePtr(filename); if (0 == (f = fopen(path, "r"))) { - rb_raise(rb_eIOError, "%s", strerror(errno)); + rb_raise(rb_eIOError, "%s", strerror(errno)); } fseek(f, 0, SEEK_END); len = ftell(f); allocate = (SMALL_XML < len || !given); if (allocate) { - json = ALLOC_N(char, len + 1); + json = ALLOC_N(char, len + 1); } else { - json = ALLOCA_N(char, len + 1); + json = ALLOCA_N(char, len + 1); } fseek(f, 0, SEEK_SET); if (len != fread(json, 1, len, f)) { - fclose(f); - rb_raise(rb_const_get_at(Oj, rb_intern("LoadError")), - "Failed to read %lu bytes from %s.", - (unsigned long)len, - path); + fclose(f); + rb_raise(rb_const_get_at(Oj, rb_intern("LoadError")), + "Failed to read %lu bytes from %s.", (unsigned long)len, path); } fclose(f); json[len] = '\0'; @@ -1275,30 +1208,30 @@ doc_open_file(VALUE clas, VALUE filename) { obj = parse_json(clas, json, given, allocate); rb_gc_enable(); if (given && allocate) { - xfree(json); + xfree(json); } return obj; } static int esc_strlen(const char *s) { - int cnt = 0; + int cnt = 0; for (; '\0' != *s; s++, cnt++) { - if ('/' == *s) { - cnt++; - } + if ('/' == *s) { + cnt++; + } } return cnt; } -static char * +static char* append_key(char *p, const char *key) { for (; '\0' != *key; p++, key++) { - if ('/' == *key) { - *p++ = '\\'; - } - *p = *key; + if ('/' == *key) { + *p++ = '\\'; + } + *p = *key; } return p; } @@ -1314,39 +1247,39 @@ append_key(char *p, const char *key) { */ static VALUE doc_where(VALUE self) { - Doc doc = self_doc(self); + Doc doc = self_doc(self); if (0 == *doc->where_path || doc->where == doc->where_path) { - return oj_slash_string; + return oj_slash_string; } else { - Leaf *lp; - Leaf leaf; - size_t size = 3; // leading / and terminating \0 - char *path; - char *p; - - for (lp = doc->where_path; lp <= doc->where; lp++) { - leaf = *lp; - if (T_HASH == leaf->parent_type) { - size += esc_strlen((*lp)->key) + 1; - } else if (T_ARRAY == leaf->parent_type) { - size += ((*lp)->index < 100) ? 3 : 11; - } - } - path = ALLOCA_N(char, size); - p = path; - for (lp = doc->where_path; lp <= doc->where; lp++) { - leaf = *lp; - if (T_HASH == leaf->parent_type) { - p = append_key(p, (*lp)->key); - } else if (T_ARRAY == leaf->parent_type) { - p = ulong_fill(p, (*lp)->index); - } - *p++ = '/'; - } - *--p = '\0'; - - return rb_str_new(path, p - path); + Leaf *lp; + Leaf leaf; + size_t size = 3; // leading / and terminating \0 + char *path; + char *p; + + for (lp = doc->where_path; lp <= doc->where; lp++) { + leaf = *lp; + if (T_HASH == leaf->parent_type) { + size += esc_strlen((*lp)->key) + 1; + } else if (T_ARRAY == leaf->parent_type) { + size += ((*lp)->index < 100) ? 3 : 11; + } + } + path = ALLOCA_N(char, size); + p = path; + for (lp = doc->where_path; lp <= doc->where; lp++) { + leaf = *lp; + if (T_HASH == leaf->parent_type) { + p = append_key(p, (*lp)->key); + } else if (T_ARRAY == leaf->parent_type) { + p = ulong_fill(p, (*lp)->index); + } + *p++ = '/'; + } + *--p = '\0'; + + return rb_str_new(path, p - path); } } @@ -1360,15 +1293,15 @@ doc_where(VALUE self) { */ static VALUE doc_local_key(VALUE self) { - Doc doc = self_doc(self); - Leaf leaf = *doc->where; - volatile VALUE key = Qnil; + Doc doc = self_doc(self); + Leaf leaf = *doc->where; + volatile VALUE key = Qnil; if (T_HASH == leaf->parent_type) { - key = rb_str_new2(leaf->key); - key = oj_encode(key); + key = rb_str_new2(leaf->key); + key = oj_encode(key); } else if (T_ARRAY == leaf->parent_type) { - key = LONG2NUM(leaf->index); + key = LONG2NUM(leaf->index); } return key; } @@ -1382,7 +1315,7 @@ doc_local_key(VALUE self) { */ static VALUE doc_home(VALUE self) { - Doc doc = self_doc(self); + Doc doc = self_doc(self); *doc->where_path = doc->data; doc->where = doc->where_path; @@ -1403,50 +1336,31 @@ doc_home(VALUE self) { */ static VALUE doc_type(int argc, VALUE *argv, VALUE self) { - Doc doc = self_doc(self); - Leaf leaf; - const char *path = 0; - VALUE type = Qnil; + Doc doc = self_doc(self); + Leaf leaf; + const char *path = 0; + VALUE type = Qnil; if (1 <= argc) { - Check_Type(*argv, T_STRING); - path = StringValuePtr(*argv); + Check_Type(*argv, T_STRING); + path = StringValuePtr(*argv); } if (0 != (leaf = get_doc_leaf(doc, path))) { - switch (leaf->rtype) { - case T_NIL: - type = rb_cNilClass; - break; - case T_TRUE: - type = rb_cTrueClass; - break; - case T_FALSE: - type = rb_cFalseClass; - break; - case T_STRING: - type = rb_cString; - break; + switch (leaf->rtype) { + case T_NIL: type = rb_cNilClass; break; + case T_TRUE: type = rb_cTrueClass; break; + case T_FALSE: type = rb_cFalseClass; break; + case T_STRING: type = rb_cString; break; #ifdef RUBY_INTEGER_UNIFICATION - case T_FIXNUM: - type = rb_cInteger; - break; + case T_FIXNUM: type = rb_cInteger; break; #else - case T_FIXNUM: - type = rb_cFixnum; - break; + case T_FIXNUM: type = rb_cFixnum; break; #endif - case T_FLOAT: - type = rb_cFloat; - break; - case T_ARRAY: - type = rb_cArray; - break; - case T_HASH: - type = rb_cHash; - break; - default: - break; - } + case T_FLOAT: type = rb_cFloat; break; + case T_ARRAY: type = rb_cArray; break; + case T_HASH: type = rb_cHash; break; + default: break; + } } return type; } @@ -1465,21 +1379,21 @@ doc_type(int argc, VALUE *argv, VALUE self) { */ static VALUE doc_fetch(int argc, VALUE *argv, VALUE self) { - Doc doc; - Leaf leaf; - volatile VALUE val = Qnil; - const char *path = 0; + Doc doc; + Leaf leaf; + volatile VALUE val = Qnil; + const char *path = 0; doc = self_doc(self); if (1 <= argc) { - Check_Type(*argv, T_STRING); - path = StringValuePtr(*argv); - if (2 == argc) { - val = argv[1]; - } + Check_Type(*argv, T_STRING); + path = StringValuePtr(*argv); + if (2 == argc) { + val = argv[1]; + } } if (0 != (leaf = get_doc_leaf(doc, path))) { - val = leaf_value(doc, leaf); + val = leaf_value(doc, leaf); } return val; } @@ -1502,33 +1416,33 @@ doc_fetch(int argc, VALUE *argv, VALUE self) { static VALUE doc_each_leaf(int argc, VALUE *argv, VALUE self) { if (rb_block_given_p()) { - Leaf save_path[MAX_STACK]; - Doc doc = self_doc(self); - const char *path = 0; - size_t wlen; - - wlen = doc->where - doc->where_path; - if (0 < wlen) { - memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1)); - } - if (1 <= argc) { - Check_Type(*argv, T_STRING); - path = StringValuePtr(*argv); - if ('/' == *path) { - doc->where = doc->where_path; - path++; - } - if (0 != move_step(doc, path, 1)) { - if (0 < wlen) { - memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1)); - } - return Qnil; - } - } - each_leaf(doc, self); - if (0 < wlen) { - memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1)); - } + Leaf save_path[MAX_STACK]; + Doc doc = self_doc(self); + const char *path = 0; + size_t wlen; + + wlen = doc->where - doc->where_path; + if (0 < wlen) { + memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1)); + } + if (1 <= argc) { + Check_Type(*argv, T_STRING); + path = StringValuePtr(*argv); + if ('/' == *path) { + doc->where = doc->where_path; + path++; + } + if (0 != move_step(doc, path, 1)) { + if (0 < wlen) { + memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1)); + } + return Qnil; + } + } + each_leaf(doc, self); + if (0 < wlen) { + memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1)); + } } return Qnil; } @@ -1543,18 +1457,18 @@ doc_each_leaf(int argc, VALUE *argv, VALUE self) { */ static VALUE doc_move(VALUE self, VALUE str) { - Doc doc = self_doc(self); - const char *path; - int loc; + Doc doc = self_doc(self); + const char *path; + int loc; Check_Type(str, T_STRING); path = StringValuePtr(str); if ('/' == *path) { - doc->where = doc->where_path; - path++; + doc->where = doc->where_path; + path++; } if (0 != (loc = move_step(doc, path, 1))) { - rb_raise(rb_eArgError, "Failed to locate element %d of the path %s.", loc, path); + rb_raise(rb_eArgError, "Failed to locate element %d of the path %s.", loc, path); } return Qnil; } @@ -1578,43 +1492,43 @@ doc_move(VALUE self, VALUE str) { static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) { if (rb_block_given_p()) { - Leaf save_path[MAX_STACK]; - Doc doc = self_doc(self); - const char *path = 0; - size_t wlen; - - wlen = doc->where - doc->where_path; - if (0 < wlen) { - memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1)); - } - if (1 <= argc) { - Check_Type(*argv, T_STRING); - path = StringValuePtr(*argv); - if ('/' == *path) { - doc->where = doc->where_path; - path++; - } - if (0 != move_step(doc, path, 1)) { - if (0 < wlen) { - memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1)); - } - return Qnil; - } - } - if (COL_VAL == (*doc->where)->value_type && 0 != (*doc->where)->elements) { - Leaf first = (*doc->where)->elements->next; - Leaf e = first; - - doc->where++; - do { - *doc->where = e; - rb_yield(self); - e = e->next; - } while (e != first); - } - if (0 < wlen) { - memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1)); - } + Leaf save_path[MAX_STACK]; + Doc doc = self_doc(self); + const char *path = 0; + size_t wlen; + + wlen = doc->where - doc->where_path; + if (0 < wlen) { + memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1)); + } + if (1 <= argc) { + Check_Type(*argv, T_STRING); + path = StringValuePtr(*argv); + if ('/' == *path) { + doc->where = doc->where_path; + path++; + } + if (0 != move_step(doc, path, 1)) { + if (0 < wlen) { + memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1)); + } + return Qnil; + } + } + if (COL_VAL == (*doc->where)->value_type && 0 != (*doc->where)->elements) { + Leaf first = (*doc->where)->elements->next; + Leaf e = first; + + doc->where++; + do { + *doc->where = e; + rb_yield(self); + e = e->next; + } while (e != first); + } + if (0 < wlen) { + memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1)); + } } return Qnil; } @@ -1645,17 +1559,17 @@ doc_each_child(int argc, VALUE *argv, VALUE self) { static VALUE doc_each_value(int argc, VALUE *argv, VALUE self) { if (rb_block_given_p()) { - Doc doc = self_doc(self); - const char *path = 0; - Leaf leaf; - - if (1 <= argc) { - Check_Type(*argv, T_STRING); - path = StringValuePtr(*argv); - } - if (0 != (leaf = get_doc_leaf(doc, path))) { - each_value(doc, leaf); - } + Doc doc = self_doc(self); + const char *path = 0; + Leaf leaf; + + if (1 <= argc) { + Check_Type(*argv, T_STRING); + path = StringValuePtr(*argv); + } + if (0 != (leaf = get_doc_leaf(doc, path))) { + each_value(doc, leaf); + } } return Qnil; } @@ -1674,42 +1588,42 @@ doc_each_value(int argc, VALUE *argv, VALUE self) { */ static VALUE doc_dump(int argc, VALUE *argv, VALUE self) { - Doc doc = self_doc(self); - Leaf leaf; - const char *path = 0; - const char *filename = 0; + Doc doc = self_doc(self); + Leaf leaf; + const char *path = 0; + const char *filename = 0; if (1 <= argc) { - if (Qnil != *argv) { - Check_Type(*argv, T_STRING); - path = StringValuePtr(*argv); - } - if (2 <= argc) { - Check_Type(argv[1], T_STRING); - filename = StringValuePtr(argv[1]); - } + if (Qnil != *argv) { + Check_Type(*argv, T_STRING); + path = StringValuePtr(*argv); + } + if (2 <= argc) { + Check_Type(argv[1], T_STRING); + filename = StringValuePtr(argv[1]); + } } if (0 != (leaf = get_doc_leaf(doc, path))) { - volatile VALUE rjson; - - if (0 == filename) { - char buf[4096]; - struct _out out; - - out.buf = buf; - out.end = buf + sizeof(buf) - 10; - out.allocated = false; - out.omit_nil = oj_default_options.dump_opts.omit_nil; - oj_dump_leaf_to_json(leaf, &oj_default_options, &out); - rjson = rb_str_new2(out.buf); - if (out.allocated) { - xfree(out.buf); - } - } else { - oj_write_leaf_to_file(leaf, filename, &oj_default_options); - rjson = Qnil; - } - return rjson; + volatile VALUE rjson; + + if (0 == filename) { + char buf[4096]; + struct _out out; + + out.buf = buf; + out.end = buf + sizeof(buf) - 10; + out.allocated = false; + out.omit_nil = oj_default_options.dump_opts.omit_nil; + oj_dump_leaf_to_json(leaf, &oj_default_options, &out); + rjson = rb_str_new2(out.buf); + if (out.allocated) { + xfree(out.buf); + } + } else { + oj_write_leaf_to_file(leaf, filename, &oj_default_options); + rjson = Qnil; + } + return rjson; } return Qnil; } @@ -1738,14 +1652,14 @@ doc_size(VALUE self) { */ static VALUE doc_close(VALUE self) { - Doc doc = self_doc(self); + Doc doc = self_doc(self); rb_gc_unregister_address(&doc->self); DATA_PTR(doc->self) = 0; if (0 != doc) { - xfree(doc->json); - doc_free(doc); - xfree(doc); + xfree(doc->json); + doc_free(doc); + xfree(doc); } return Qnil; } diff --git a/ext/oj/hash.c b/ext/oj/hash.c index 5e0d7756..985150ac 100644 --- a/ext/oj/hash.c +++ b/ext/oj/hash.c @@ -4,41 +4,41 @@ #include "hash.h" #include -#define HASH_MASK 0x000003FF -#define HASH_SLOT_CNT 1024 +#define HASH_MASK 0x000003FF +#define HASH_SLOT_CNT 1024 typedef struct _keyVal { - struct _keyVal *next; - const char *key; - size_t len; - VALUE val; -} * KeyVal; + struct _keyVal *next; + const char *key; + size_t len; + VALUE val; +} *KeyVal; struct _hash { - struct _keyVal slots[HASH_SLOT_CNT]; + struct _keyVal slots[HASH_SLOT_CNT]; }; -struct _hash class_hash; -struct _hash intern_hash; +struct _hash class_hash; +struct _hash intern_hash; // almost the Murmur hash algorithm #define M 0x5bd1e995 #define C1 0xCC9E2D51 #define C2 0x1B873593 -#define N 0xE6546B64 +#define N 0xE6546B64 static uint32_t hash_calc(const uint8_t *key, size_t len) { - const uint8_t *end = key + len; - const uint8_t *endless = key + (len / 4 * 4); - uint32_t h = (uint32_t)len; - uint32_t k; + const uint8_t *end = key + len; + const uint8_t *endless = key + (len / 4 * 4); + uint32_t h = (uint32_t)len; + uint32_t k; while (key < endless) { - k = (uint32_t)*key++; - k |= (uint32_t)*key++ << 8; - k |= (uint32_t)*key++ << 16; - k |= (uint32_t)*key++ << 24; + k = (uint32_t)*key++; + k |= (uint32_t)*key++ << 8; + k |= (uint32_t)*key++ << 16; + k |= (uint32_t)*key++ << 24; k *= M; k ^= k >> 24; @@ -46,13 +46,13 @@ hash_calc(const uint8_t *key, size_t len) { h ^= k * M; } if (1 < end - key) { - uint16_t k16 = (uint16_t)*key++; + uint16_t k16 = (uint16_t)*key++; - k16 |= (uint16_t)*key++ << 8; - h ^= k16 << 8; + k16 |= (uint16_t)*key++ << 8; + h ^= k16 << 8; } if (key < end) { - h ^= *key; + h ^= *key; } h *= M; h ^= h >> 13; @@ -71,47 +71,47 @@ oj_hash_init() { // if slotp is 0 then just lookup static VALUE hash_get(Hash hash, const char *key, size_t len, VALUE **slotp, VALUE def_value) { - uint32_t h = hash_calc((const uint8_t *)key, len) & HASH_MASK; - KeyVal bucket = hash->slots + h; + uint32_t h = hash_calc((const uint8_t*)key, len) & HASH_MASK; + KeyVal bucket = hash->slots + h; if (0 != bucket->key) { - KeyVal b; - - for (b = bucket; 0 != b; b = b->next) { - if (len == b->len && 0 == strncmp(b->key, key, len)) { - *slotp = &b->val; - return b->val; - } - bucket = b; - } + KeyVal b; + + for (b = bucket; 0 != b; b = b->next) { + if (len == b->len && 0 == strncmp(b->key, key, len)) { + *slotp = &b->val; + return b->val; + } + bucket = b; + } } if (0 != slotp) { - if (0 != bucket->key) { - KeyVal b = ALLOC(struct _keyVal); - - b->next = 0; - bucket->next = b; - bucket = b; - } - bucket->key = oj_strndup(key, len); - bucket->len = len; - bucket->val = def_value; - *slotp = &bucket->val; + if (0 != bucket->key) { + KeyVal b = ALLOC(struct _keyVal); + + b->next = 0; + bucket->next = b; + bucket = b; + } + bucket->key = oj_strndup(key, len); + bucket->len = len; + bucket->val = def_value; + *slotp = &bucket->val; } return def_value; } void oj_hash_print() { - int i; - KeyVal b; + int i; + KeyVal b; for (i = 0; i < HASH_SLOT_CNT; i++) { - printf("%4d:", i); - for (b = class_hash.slots + i; 0 != b && 0 != b->key; b = b->next) { - printf(" %s", b->key); - } - printf("\n"); + printf("%4d:", i); + for (b = class_hash.slots + i; 0 != b && 0 != b->key; b = b->next) { + printf(" %s", b->key); + } + printf("\n"); } } @@ -122,12 +122,12 @@ oj_class_hash_get(const char *key, size_t len, VALUE **slotp) { ID oj_attr_hash_get(const char *key, size_t len, ID **slotp) { - return (ID)hash_get(&intern_hash, key, len, (VALUE **)slotp, 0); + return (ID)hash_get(&intern_hash, key, len, (VALUE**)slotp, 0); } -char * +char* oj_strndup(const char *s, size_t len) { - char *d = ALLOC_N(char, len + 1); + char *d = ALLOC_N(char, len + 1); memcpy(d, s, len); d[len] = '\0'; diff --git a/ext/oj/hash.h b/ext/oj/hash.h index 55eacf13..0a08ebaa 100644 --- a/ext/oj/hash.h +++ b/ext/oj/hash.h @@ -6,14 +6,14 @@ #include "ruby.h" -typedef struct _hash *Hash; +typedef struct _hash *Hash; -extern void oj_hash_init(); +extern void oj_hash_init(); -extern VALUE oj_class_hash_get(const char *key, size_t len, VALUE **slotp); -extern ID oj_attr_hash_get(const char *key, size_t len, ID **slotp); +extern VALUE oj_class_hash_get(const char *key, size_t len, VALUE **slotp); +extern ID oj_attr_hash_get(const char *key, size_t len, ID **slotp); -extern void oj_hash_print(); -extern char *oj_strndup(const char *s, size_t len); +extern void oj_hash_print(); +extern char* oj_strndup(const char *s, size_t len); #endif /* OJ_HASH_H */ diff --git a/ext/oj/hash_test.c b/ext/oj/hash_test.c index 18647329..e9a83398 100644 --- a/ext/oj/hash_test.c +++ b/ext/oj/hash_test.c @@ -3,19 +3,19 @@ // if windows, comment out the whole file. It's only a performance test. #ifndef _WIN32 -#include "hash.h" -#include #include #include +#include "hash.h" +#include /* Define printf formats for standard types, like PRIu64 for uint64_t. */ #define __STDC_FORMAT_MACROS #include typedef struct _strLen { - const char *str; - size_t len; -} * StrLen; + const char *str; + size_t len; +} *StrLen; static struct _strLen data[] = { { "Gem::Version", 12 }, @@ -417,7 +417,7 @@ static struct _strLen data[] = { static uint64_t micro_time() { - struct timeval tv; + struct timeval tv; gettimeofday(&tv, NULL); @@ -426,58 +426,57 @@ micro_time() { static void perf() { - StrLen d; - VALUE v; - VALUE *slot = 0; - uint64_t dt, start; - int i, iter = 1000000; - int dataCnt = sizeof(data) / sizeof(*data); + StrLen d; + VALUE v; + VALUE *slot = 0; + uint64_t dt, start; + int i, iter = 1000000; + int dataCnt = sizeof(data) / sizeof(*data); oj_hash_init(); start = micro_time(); for (i = iter; 0 < i; i--) { - for (d = data; 0 != d->str; d++) { - v = oj_class_hash_get(d->str, d->len, &slot); - if (Qundef == v) { - if (0 != slot) { - v = ID2SYM(rb_intern(d->str)); - *slot = v; - } - } - } + for (d = data; 0 != d->str; d++) { + v = oj_class_hash_get(d->str, d->len, &slot); + if (Qundef == v) { + if (0 != slot) { + v = ID2SYM(rb_intern(d->str)); + *slot = v; + } + } + } } dt = micro_time() - start; #if IS_WINDOWS printf("%d iterations took %ld msecs, %ld gets/msec\n", iter, (long)(dt / 1000), (long)(iter * dataCnt / (dt / 1000))); #else - printf("%d iterations took %" PRIu64 " msecs, %ld gets/msec\n", iter, dt / 1000, (long)(iter * dataCnt / (dt / 1000))); + printf("%d iterations took %"PRIu64" msecs, %ld gets/msec\n", iter, dt / 1000, (long)(iter * dataCnt / (dt / 1000))); #endif } void oj_hash_test() { - StrLen d; - VALUE v; - VALUE *slot = 0; - ; + StrLen d; + VALUE v; + VALUE *slot = 0;; oj_hash_init(); for (d = data; 0 != d->str; d++) { - char *s = oj_strndup(d->str, d->len); - v = oj_class_hash_get(d->str, d->len, &slot); - if (Qnil == v) { - if (0 == slot) { - printf("*** failed to get a slot for %s\n", s); - } else { - v = ID2SYM(rb_intern(d->str)); - *slot = v; - } - } else { - VALUE rs = rb_funcall2(v, rb_intern("to_s"), 0, 0); + char *s = oj_strndup(d->str, d->len); + v = oj_class_hash_get(d->str, d->len, &slot); + if (Qnil == v) { + if (0 == slot) { + printf("*** failed to get a slot for %s\n", s); + } else { + v = ID2SYM(rb_intern(d->str)); + *slot = v; + } + } else { + VALUE rs = rb_funcall2(v, rb_intern("to_s"), 0, 0); - printf("*** get on '%s' returned '%s' (%s)\n", s, StringValuePtr(rs), rb_class2name(rb_obj_class(v))); - } - /*oj_hash_print(c);*/ + printf("*** get on '%s' returned '%s' (%s)\n", s, StringValuePtr(rs), rb_class2name(rb_obj_class(v))); + } + /*oj_hash_print(c);*/ } printf("*** ---------- hash table ------------\n"); oj_hash_print(); diff --git a/ext/oj/mimic_json.c b/ext/oj/mimic_json.c index a08cd056..214165f0 100644 --- a/ext/oj/mimic_json.c +++ b/ext/oj/mimic_json.c @@ -1,25 +1,25 @@ // Copyright (c) 2012, 2017 Peter Ohler. All rights reserved. // Licensed under the MIT License. See LICENSE file in the project root for license details. -#include "dump.h" -#include "encode.h" #include "oj.h" +#include "encode.h" +#include "dump.h" #include "parse.h" -static VALUE symbolize_names_sym = Qundef; +static VALUE symbolize_names_sym = Qundef; -extern const char oj_json_class[]; +extern const char oj_json_class[]; -VALUE oj_array_nl_sym; -VALUE oj_ascii_only_sym; -VALUE oj_json_generator_error_class; -VALUE oj_json_parser_error_class; -VALUE oj_max_nesting_sym; -VALUE oj_object_nl_sym; -VALUE oj_space_before_sym; -VALUE oj_space_sym; +VALUE oj_array_nl_sym; +VALUE oj_ascii_only_sym; +VALUE oj_json_generator_error_class; +VALUE oj_json_parser_error_class; +VALUE oj_max_nesting_sym; +VALUE oj_object_nl_sym; +VALUE oj_space_before_sym; +VALUE oj_space_sym; -static VALUE state_class; +static VALUE state_class; // mimic JSON documentation @@ -54,14 +54,14 @@ static VALUE state_class; VALUE oj_get_json_err_class(const char *err_classname) { - volatile VALUE json_module; - volatile VALUE clas; - volatile VALUE json_error_class; + volatile VALUE json_module; + volatile VALUE clas; + volatile VALUE json_error_class; if (rb_const_defined_at(rb_cObject, rb_intern("JSON"))) { - json_module = rb_const_get_at(rb_cObject, rb_intern("JSON")); + json_module = rb_const_get_at(rb_cObject, rb_intern("JSON")); } else { - json_module = rb_define_module("JSON"); + json_module = rb_define_module("JSON"); } if (rb_const_defined_at(json_module, rb_intern("JSONError"))) { json_error_class = rb_const_get(json_module, rb_intern("JSONError")); @@ -69,113 +69,113 @@ oj_get_json_err_class(const char *err_classname) { json_error_class = rb_define_class_under(json_module, "JSONError", rb_eStandardError); } if (0 == strcmp(err_classname, "JSONError")) { - clas = json_error_class; + clas = json_error_class; } else { - if (rb_const_defined_at(json_module, rb_intern(err_classname))) { - clas = rb_const_get(json_module, rb_intern(err_classname)); - } else { - clas = rb_define_class_under(json_module, err_classname, json_error_class); - } + if (rb_const_defined_at(json_module, rb_intern(err_classname))) { + clas = rb_const_get(json_module, rb_intern(err_classname)); + } else { + clas = rb_define_class_under(json_module, err_classname, json_error_class); + } } return clas; } void oj_parse_mimic_dump_options(VALUE ropts, Options copts) { - VALUE v; - size_t len; + VALUE v; + size_t len; if (T_HASH != rb_type(ropts)) { - if (rb_respond_to(ropts, oj_to_hash_id)) { - ropts = rb_funcall(ropts, oj_to_hash_id, 0); - } else if (rb_respond_to(ropts, oj_to_h_id)) { - ropts = rb_funcall(ropts, oj_to_h_id, 0); - } else if (Qnil == ropts) { - return; - } else { - rb_raise(rb_eArgError, "options must be a hash."); - } + if (rb_respond_to(ropts, oj_to_hash_id)) { + ropts = rb_funcall(ropts, oj_to_hash_id, 0); + } else if (rb_respond_to(ropts, oj_to_h_id)) { + ropts = rb_funcall(ropts, oj_to_h_id, 0); + } else if (Qnil == ropts) { + return; + } else { + rb_raise(rb_eArgError, "options must be a hash."); + } } v = rb_hash_lookup(ropts, oj_max_nesting_sym); if (Qtrue == v) { - copts->dump_opts.max_depth = 100; + copts->dump_opts.max_depth = 100; } else if (Qfalse == v || Qnil == v) { - copts->dump_opts.max_depth = MAX_DEPTH; + copts->dump_opts.max_depth = MAX_DEPTH; } else if (T_FIXNUM == rb_type(v)) { - copts->dump_opts.max_depth = NUM2INT(v); - if (0 >= copts->dump_opts.max_depth) { - copts->dump_opts.max_depth = MAX_DEPTH; - } + copts->dump_opts.max_depth = NUM2INT(v); + if (0 >= copts->dump_opts.max_depth) { + copts->dump_opts.max_depth = MAX_DEPTH; + } } if (Qnil != (v = rb_hash_lookup(ropts, oj_allow_nan_sym))) { - if (Qtrue == v) { - copts->dump_opts.nan_dump = WordNan; - } else { - copts->dump_opts.nan_dump = RaiseNan; - } + if (Qtrue == v) { + copts->dump_opts.nan_dump = WordNan; + } else { + copts->dump_opts.nan_dump = RaiseNan; + } } if (Qnil != (v = rb_hash_lookup(ropts, oj_indent_sym))) { - rb_check_type(v, T_STRING); - if (sizeof(copts->dump_opts.indent_str) <= (len = RSTRING_LEN(v))) { - rb_raise(rb_eArgError, "indent string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.indent_str)); - } - strcpy(copts->dump_opts.indent_str, StringValuePtr(v)); - copts->dump_opts.indent_size = (uint8_t)len; - copts->dump_opts.use = true; + rb_check_type(v, T_STRING); + if (sizeof(copts->dump_opts.indent_str) <= (len = RSTRING_LEN(v))) { + rb_raise(rb_eArgError, "indent string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.indent_str)); + } + strcpy(copts->dump_opts.indent_str, StringValuePtr(v)); + copts->dump_opts.indent_size = (uint8_t)len; + copts->dump_opts.use = true; } if (Qnil != (v = rb_hash_lookup(ropts, oj_space_sym))) { - rb_check_type(v, T_STRING); - if (sizeof(copts->dump_opts.after_sep) <= (len = RSTRING_LEN(v))) { - rb_raise(rb_eArgError, "space string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.after_sep)); - } - strcpy(copts->dump_opts.after_sep, StringValuePtr(v)); - copts->dump_opts.after_size = (uint8_t)len; - copts->dump_opts.use = true; + rb_check_type(v, T_STRING); + if (sizeof(copts->dump_opts.after_sep) <= (len = RSTRING_LEN(v))) { + rb_raise(rb_eArgError, "space string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.after_sep)); + } + strcpy(copts->dump_opts.after_sep, StringValuePtr(v)); + copts->dump_opts.after_size = (uint8_t)len; + copts->dump_opts.use = true; } if (Qnil != (v = rb_hash_lookup(ropts, oj_space_before_sym))) { - rb_check_type(v, T_STRING); - if (sizeof(copts->dump_opts.before_sep) <= (len = RSTRING_LEN(v))) { - rb_raise(rb_eArgError, "space_before string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.before_sep)); - } - strcpy(copts->dump_opts.before_sep, StringValuePtr(v)); - copts->dump_opts.before_size = (uint8_t)len; - copts->dump_opts.use = true; + rb_check_type(v, T_STRING); + if (sizeof(copts->dump_opts.before_sep) <= (len = RSTRING_LEN(v))) { + rb_raise(rb_eArgError, "space_before string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.before_sep)); + } + strcpy(copts->dump_opts.before_sep, StringValuePtr(v)); + copts->dump_opts.before_size = (uint8_t)len; + copts->dump_opts.use = true; } if (Qnil != (v = rb_hash_lookup(ropts, oj_object_nl_sym))) { - rb_check_type(v, T_STRING); - if (sizeof(copts->dump_opts.hash_nl) <= (len = RSTRING_LEN(v))) { - rb_raise(rb_eArgError, "object_nl string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.hash_nl)); - } - strcpy(copts->dump_opts.hash_nl, StringValuePtr(v)); - copts->dump_opts.hash_size = (uint8_t)len; - copts->dump_opts.use = true; + rb_check_type(v, T_STRING); + if (sizeof(copts->dump_opts.hash_nl) <= (len = RSTRING_LEN(v))) { + rb_raise(rb_eArgError, "object_nl string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.hash_nl)); + } + strcpy(copts->dump_opts.hash_nl, StringValuePtr(v)); + copts->dump_opts.hash_size = (uint8_t)len; + copts->dump_opts.use = true; } if (Qnil != (v = rb_hash_lookup(ropts, oj_array_nl_sym))) { - rb_check_type(v, T_STRING); - if (sizeof(copts->dump_opts.array_nl) <= (len = RSTRING_LEN(v))) { - rb_raise(rb_eArgError, "array_nl string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.array_nl)); - } - strcpy(copts->dump_opts.array_nl, StringValuePtr(v)); - copts->dump_opts.array_size = (uint8_t)len; - copts->dump_opts.use = true; + rb_check_type(v, T_STRING); + if (sizeof(copts->dump_opts.array_nl) <= (len = RSTRING_LEN(v))) { + rb_raise(rb_eArgError, "array_nl string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.array_nl)); + } + strcpy(copts->dump_opts.array_nl, StringValuePtr(v)); + copts->dump_opts.array_size = (uint8_t)len; + copts->dump_opts.use = true; } if (Qnil != (v = rb_hash_lookup(ropts, oj_quirks_mode_sym))) { - copts->quirks_mode = (Qtrue == v) ? Yes : No; + copts->quirks_mode = (Qtrue == v) ? Yes : No; } if (Qnil != (v = rb_hash_lookup(ropts, oj_ascii_only_sym))) { - // generate seems to assume anything except nil and false are true. - if (Qfalse == v) { - copts->escape_mode = JXEsc; - } else { - copts->escape_mode = ASCIIEsc; - } + // generate seems to assume anything except nil and false are true. + if (Qfalse == v) { + copts->escape_mode = JXEsc; + } else { + copts->escape_mode = ASCIIEsc; + } } } static int mimic_limit_arg(VALUE a) { if (Qnil == a || T_FIXNUM != rb_type(a)) { - return -1; + return -1; } return NUM2INT(a); } @@ -193,11 +193,11 @@ mimic_limit_arg(VALUE a) { */ static VALUE mimic_dump(int argc, VALUE *argv, VALUE self) { - char buf[4096]; - struct _out out; - struct _options copts = oj_default_options; - VALUE rstr; - VALUE active_hack[1]; + char buf[4096]; + struct _out out; + struct _options copts = oj_default_options; + VALUE rstr; + VALUE active_hack[1]; copts.str_rx.head = NULL; copts.str_rx.tail = NULL; @@ -217,18 +217,18 @@ mimic_dump(int argc, VALUE *argv, VALUE self) { out.omit_nil = copts.dump_opts.omit_nil; if (2 <= argc) { - int limit; - - // The json gem take a more liberal approach to optional - // arguments. Expected are (obj, anIO=nil, limit=nil) yet the io - // argument can be left off completely and the 2nd argument is then - // the limit. - if (0 <= (limit = mimic_limit_arg(argv[1]))) { - copts.dump_opts.max_depth = limit; - } - if (3 <= argc && 0 <= (limit = mimic_limit_arg(argv[2]))) { - copts.dump_opts.max_depth = limit; - } + int limit; + + // The json gem take a more liberal approach to optional + // arguments. Expected are (obj, anIO=nil, limit=nil) yet the io + // argument can be left off completely and the 2nd argument is then + // the limit. + if (0 <= (limit = mimic_limit_arg(argv[1]))) { + copts.dump_opts.max_depth = limit; + } + if (3 <= argc && 0 <= (limit = mimic_limit_arg(argv[2]))) { + copts.dump_opts.max_depth = limit; + } } // ActiveSupport in active_support/core_ext/object/json.rb check the // optional argument type to to_json and it the argument is a @@ -240,20 +240,20 @@ mimic_dump(int argc, VALUE *argv, VALUE self) { oj_dump_obj_to_json_using_params(*argv, &copts, &out, 1, active_hack); if (0 == out.buf) { - rb_raise(rb_eNoMemError, "Not enough memory."); + rb_raise(rb_eNoMemError, "Not enough memory."); } rstr = rb_str_new2(out.buf); rstr = oj_encode(rstr); if (2 <= argc && Qnil != argv[1] && rb_respond_to(argv[1], oj_write_id)) { - VALUE io = argv[1]; - VALUE args[1]; + VALUE io = argv[1]; + VALUE args[1]; - *args = rstr; - rb_funcall2(io, oj_write_id, 1, args); - rstr = io; + *args = rstr; + rb_funcall2(io, oj_write_id, 1, args); + rstr = io; } if (out.allocated) { - xfree(out.buf); + xfree(out.buf); } return rstr; } @@ -262,30 +262,31 @@ mimic_dump(int argc, VALUE *argv, VALUE self) { static int mimic_walk(VALUE key, VALUE obj, VALUE proc) { switch (rb_type(obj)) { - case T_HASH: - rb_hash_foreach(obj, mimic_walk, proc); - break; - case T_ARRAY: { - size_t cnt = RARRAY_LEN(obj); - size_t i; - - for (i = 0; i < cnt; i++) { - mimic_walk(Qnil, rb_ary_entry(obj, i), proc); - } - break; - } - default: - break; + case T_HASH: + rb_hash_foreach(obj, mimic_walk, proc); + break; + case T_ARRAY: + { + size_t cnt = RARRAY_LEN(obj); + size_t i; + + for (i = 0; i < cnt; i++) { + mimic_walk(Qnil, rb_ary_entry(obj, i), proc); + } + break; + } + default: + break; } if (Qnil == proc) { - if (rb_block_given_p()) { - rb_yield(obj); - } + if (rb_block_given_p()) { + rb_yield(obj); + } } else { - VALUE args[1]; + VALUE args[1]; - *args = obj; - rb_proc_call_with_block(proc, 1, args, Qnil); + *args = obj; + rb_proc_call_with_block(proc, 1, args, Qnil); } return ST_CONTINUE; } @@ -317,18 +318,18 @@ mimic_walk(VALUE key, VALUE obj, VALUE proc) { */ static VALUE mimic_load(int argc, VALUE *argv, VALUE self) { - VALUE obj; - VALUE p = Qnil; + VALUE obj; + VALUE p = Qnil; obj = oj_compat_load(argc, argv, self); if (2 <= argc) { - if (rb_cProc == rb_obj_class(argv[1])) { - p = argv[1]; - } else if (3 <= argc) { - if (rb_cProc == rb_obj_class(argv[2])) { - p = argv[2]; - } - } + if (rb_cProc == rb_obj_class(argv[1])) { + p = argv[1]; + } else if (3 <= argc) { + if (rb_cProc == rb_obj_class(argv[2])) { + p = argv[2]; + } + } } mimic_walk(Qnil, obj, p); @@ -349,20 +350,20 @@ mimic_load(int argc, VALUE *argv, VALUE self) { static VALUE mimic_dump_load(int argc, VALUE *argv, VALUE self) { if (1 > argc) { - rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)"); + rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)"); } else if (T_STRING == rb_type(*argv)) { - return mimic_load(argc, argv, self); + return mimic_load(argc, argv, self); } else { - return mimic_dump(argc, argv, self); + return mimic_dump(argc, argv, self); } return Qnil; } static VALUE mimic_generate_core(int argc, VALUE *argv, Options copts) { - char buf[4096]; - struct _out out; - VALUE rstr; + char buf[4096]; + struct _out out; + VALUE rstr; memset(buf, 0, sizeof(buf)); @@ -377,7 +378,7 @@ mimic_generate_core(int argc, VALUE *argv, Options copts) { copts->mode = CompatMode; copts->to_json = Yes; if (2 == argc && Qnil != argv[1]) { - oj_parse_mimic_dump_options(argv[1], copts); + oj_parse_mimic_dump_options(argv[1], copts); } /* seems like this is not correct if (No == copts->nilnil && Qnil == *argv) { @@ -387,12 +388,12 @@ mimic_generate_core(int argc, VALUE *argv, Options copts) { oj_dump_obj_to_json_using_params(*argv, copts, &out, argc - 1, argv + 1); if (0 == out.buf) { - rb_raise(rb_eNoMemError, "Not enough memory."); + rb_raise(rb_eNoMemError, "Not enough memory."); } rstr = rb_str_new2(out.buf); rstr = oj_encode(rstr); if (out.allocated) { - xfree(out.buf); + xfree(out.buf); } return rstr; } @@ -423,7 +424,7 @@ mimic_generate_core(int argc, VALUE *argv, Options copts) { */ VALUE oj_mimic_generate(int argc, VALUE *argv, VALUE self) { - struct _options copts = oj_default_options; + struct _options copts = oj_default_options; copts.str_rx.head = NULL; copts.str_rx.tail = NULL; @@ -441,33 +442,33 @@ oj_mimic_generate(int argc, VALUE *argv, VALUE self) { */ VALUE oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) { - struct _options copts = oj_default_options; - VALUE rargs[2]; - volatile VALUE h; + struct _options copts = oj_default_options; + VALUE rargs[2]; + volatile VALUE h; // Some (all?) json gem to_json methods need a State instance and not just // a Hash. I haven't dug deep enough to find out why but using a State // instance and not a Hash gives the desired behavior. *rargs = *argv; if (1 == argc) { - h = rb_hash_new(); + h = rb_hash_new(); } else { - h = argv[1]; + h = argv[1]; } if (Qfalse == rb_funcall(h, oj_has_key_id, 1, oj_indent_sym)) { - rb_hash_aset(h, oj_indent_sym, rb_str_new2(" ")); + rb_hash_aset(h, oj_indent_sym, rb_str_new2(" ")); } if (Qfalse == rb_funcall(h, oj_has_key_id, 1, oj_space_before_sym)) { - rb_hash_aset(h, oj_space_before_sym, rb_str_new2("")); + rb_hash_aset(h, oj_space_before_sym, rb_str_new2("")); } if (Qfalse == rb_funcall(h, oj_has_key_id, 1, oj_space_sym)) { - rb_hash_aset(h, oj_space_sym, rb_str_new2(" ")); + rb_hash_aset(h, oj_space_sym, rb_str_new2(" ")); } if (Qfalse == rb_funcall(h, oj_has_key_id, 1, oj_object_nl_sym)) { - rb_hash_aset(h, oj_object_nl_sym, rb_str_new2("\n")); + rb_hash_aset(h, oj_object_nl_sym, rb_str_new2("\n")); } if (Qfalse == rb_funcall(h, oj_has_key_id, 1, oj_array_nl_sym)) { - rb_hash_aset(h, oj_array_nl_sym, rb_str_new2("\n")); + rb_hash_aset(h, oj_array_nl_sym, rb_str_new2("\n")); } rargs[1] = rb_funcall(state_class, oj_new_id, 1, h); @@ -490,9 +491,9 @@ oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) { static VALUE mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) { - struct _parseInfo pi; - VALUE ropts; - VALUE args[1]; + struct _parseInfo pi; + VALUE ropts; + VALUE args[1]; rb_scan_args(argc, argv, "11", NULL, &ropts); parse_info_init(&pi); @@ -514,74 +515,73 @@ mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) { pi.max_depth = 100; if (Qnil != ropts) { - VALUE v; - - if (T_HASH != rb_type(ropts)) { - rb_raise(rb_eArgError, "options must be a hash."); - } - if (Qundef == symbolize_names_sym) { - symbolize_names_sym = ID2SYM(rb_intern("symbolize_names")); - rb_gc_register_address(&symbolize_names_sym); - } - if (Qnil != (v = rb_hash_lookup(ropts, symbolize_names_sym))) { - pi.options.sym_key = (Qtrue == v) ? Yes : No; - } - if (Qnil != (v = rb_hash_lookup(ropts, oj_quirks_mode_sym))) { - pi.options.quirks_mode = (Qtrue == v) ? Yes : No; - } - if (Qnil != (v = rb_hash_lookup(ropts, oj_create_additions_sym))) { - pi.options.create_ok = (Qtrue == v) ? Yes : No; - } - if (Qnil != (v = rb_hash_lookup(ropts, oj_allow_nan_sym))) { - pi.options.allow_nan = (Qtrue == v) ? Yes : No; - } - - if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_hash_class_sym)) { - if (Qnil == (v = rb_hash_lookup(ropts, oj_hash_class_sym))) { - pi.options.hash_class = Qnil; - } else { - rb_check_type(v, T_CLASS); - pi.options.hash_class = v; - } - } - if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_object_class_sym)) { - if (Qnil == (v = rb_hash_lookup(ropts, oj_object_class_sym))) { - pi.options.hash_class = Qnil; - } else { - rb_check_type(v, T_CLASS); - pi.options.hash_class = v; - } - } - if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_array_class_sym)) { - if (Qnil == (v = rb_hash_lookup(ropts, oj_array_class_sym))) { - pi.options.array_class = Qnil; - } else { - rb_check_type(v, T_CLASS); - pi.options.array_class = v; - } - } - if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_decimal_class_sym)) { - pi.options.compat_bigdec = (oj_bigdecimal_class == rb_hash_lookup(ropts, oj_decimal_class_sym)); - } - v = rb_hash_lookup(ropts, oj_max_nesting_sym); - if (Qtrue == v) { - pi.max_depth = 100; - } else if (Qfalse == v || Qnil == v) { - pi.max_depth = 0; - } else if (T_FIXNUM == rb_type(v)) { - pi.max_depth = NUM2INT(v); - } - oj_parse_opt_match_string(&pi.options.str_rx, ropts); - if (Yes == pi.options.create_ok && Yes == pi.options.sym_key) { - rb_raise(rb_eArgError, ":symbolize_names and :create_additions can not both be true."); - } + VALUE v; + + if (T_HASH != rb_type(ropts)) { + rb_raise(rb_eArgError, "options must be a hash."); + } + if (Qundef == symbolize_names_sym) { + symbolize_names_sym = ID2SYM(rb_intern("symbolize_names")); rb_gc_register_address(&symbolize_names_sym); + } + if (Qnil != (v = rb_hash_lookup(ropts, symbolize_names_sym))) { + pi.options.sym_key = (Qtrue == v) ? Yes : No; + } + if (Qnil != (v = rb_hash_lookup(ropts, oj_quirks_mode_sym))) { + pi.options.quirks_mode = (Qtrue == v) ? Yes : No; + } + if (Qnil != (v = rb_hash_lookup(ropts, oj_create_additions_sym))) { + pi.options.create_ok = (Qtrue == v) ? Yes : No; + } + if (Qnil != (v = rb_hash_lookup(ropts, oj_allow_nan_sym))) { + pi.options.allow_nan = (Qtrue == v) ? Yes : No; + } + + if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_hash_class_sym)) { + if (Qnil == (v = rb_hash_lookup(ropts, oj_hash_class_sym))) { + pi.options.hash_class = Qnil; + } else { + rb_check_type(v, T_CLASS); + pi.options.hash_class = v; + } + } + if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_object_class_sym)) { + if (Qnil == (v = rb_hash_lookup(ropts, oj_object_class_sym))) { + pi.options.hash_class = Qnil; + } else { + rb_check_type(v, T_CLASS); + pi.options.hash_class = v; + } + } + if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_array_class_sym)) { + if (Qnil == (v = rb_hash_lookup(ropts, oj_array_class_sym))) { + pi.options.array_class = Qnil; + } else { + rb_check_type(v, T_CLASS); + pi.options.array_class = v; + } + } + if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_decimal_class_sym)) { + pi.options.compat_bigdec = (oj_bigdecimal_class == rb_hash_lookup(ropts, oj_decimal_class_sym)); + } + v = rb_hash_lookup(ropts, oj_max_nesting_sym); + if (Qtrue == v) { + pi.max_depth = 100; + } else if (Qfalse == v || Qnil == v) { + pi.max_depth = 0; + } else if (T_FIXNUM == rb_type(v)) { + pi.max_depth = NUM2INT(v); + } + oj_parse_opt_match_string(&pi.options.str_rx, ropts); + if (Yes == pi.options.create_ok && Yes == pi.options.sym_key) { + rb_raise(rb_eArgError, ":symbolize_names and :create_additions can not both be true."); + } } *args = *argv; if (T_STRING == rb_type(*args)) { - return oj_pi_parse(1, args, &pi, 0, 0, false); + return oj_pi_parse(1, args, &pi, 0, 0, false); } else { - return oj_pi_sparse(1, args, &pi, 0); + return oj_pi_sparse(1, args, &pi, 0); } } @@ -647,18 +647,18 @@ mimic_set_create_id(VALUE self, VALUE id) { Check_Type(id, T_STRING); if (NULL != oj_default_options.create_id) { - if (oj_json_class != oj_default_options.create_id) { - xfree((char *)oj_default_options.create_id); - } - oj_default_options.create_id = NULL; - oj_default_options.create_id_len = 0; + if (oj_json_class != oj_default_options.create_id) { + xfree((char*)oj_default_options.create_id); + } + oj_default_options.create_id = NULL; + oj_default_options.create_id_len = 0; } if (Qnil != id) { - size_t len = RSTRING_LEN(id) + 1; + size_t len = RSTRING_LEN(id) + 1; - oj_default_options.create_id = ALLOC_N(char, len); - strcpy((char *)oj_default_options.create_id, StringValuePtr(id)); - oj_default_options.create_id_len = len - 1; + oj_default_options.create_id = ALLOC_N(char, len); + strcpy((char*)oj_default_options.create_id, StringValuePtr(id)); + oj_default_options.create_id_len = len - 1; } return id; } @@ -671,78 +671,76 @@ mimic_set_create_id(VALUE self, VALUE id) { static VALUE mimic_create_id(VALUE self) { if (NULL != oj_default_options.create_id) { - return oj_encode(rb_str_new_cstr(oj_default_options.create_id)); + return oj_encode(rb_str_new_cstr(oj_default_options.create_id)); } return rb_str_new_cstr(oj_json_class); } -static struct _options mimic_object_to_json_options = { - 0, // indent - No, // circular - No, // auto_define - No, // sym_key - JXEsc, // escape_mode - CompatMode, // mode - No, // class_cache - RubyTime, // time_format - No, // bigdec_as_num - RubyDec, // bigdec_load - false, // compat_bigdec - No, // to_hash - No, // to_json - No, // as_json - No, // raw_json - No, // nilnil - No, // empty_string - Yes, // allow_gc - Yes, // quirks_mode - No, // allow_invalid - No, // create_ok - No, // allow_nan - No, // trace - No, // safe - false, // sec_prec_set - No, // ignore_under - 0, // int_range_min - 0, // int_range_max - oj_json_class, // create_id - 10, // create_id_len - 3, // sec_prec - 0, // float_prec - "%0.16g", // float_fmt - Qnil, // hash_class - Qnil, // array_class - { - // dump_opts - false, //use - "", // indent - "", // before_sep - "", // after_sep - "", // hash_nl - "", // array_nl - 0, // indent_size - 0, // before_size - 0, // after_size - 0, // hash_size - 0, // array_size - RaiseNan, // nan_dump - false, // omit_nil - 100, // max_depth +static struct _options mimic_object_to_json_options = { + 0, // indent + No, // circular + No, // auto_define + No, // sym_key + JXEsc, // escape_mode + CompatMode, // mode + No, // class_cache + RubyTime, // time_format + No, // bigdec_as_num + RubyDec, // bigdec_load + false, // compat_bigdec + No, // to_hash + No, // to_json + No, // as_json + No, // raw_json + No, // nilnil + No, // empty_string + Yes, // allow_gc + Yes, // quirks_mode + No, // allow_invalid + No, // create_ok + No, // allow_nan + No, // trace + No, // safe + false, // sec_prec_set + No, // ignore_under + 0, // int_range_min + 0, // int_range_max + oj_json_class,// create_id + 10, // create_id_len + 3, // sec_prec + 0, // float_prec + "%0.16g", // float_fmt + Qnil, // hash_class + Qnil, // array_class + { // dump_opts + false, //use + "", // indent + "", // before_sep + "", // after_sep + "", // hash_nl + "", // array_nl + 0, // indent_size + 0, // before_size + 0, // after_size + 0, // hash_size + 0, // array_size + RaiseNan,// nan_dump + false, // omit_nil + 100, // max_depth }, - { - // str_rx - NULL, // head - NULL, // tail - { '\0' }, // err + { // str_rx + NULL, // head + NULL, // tail + { '\0' }, // err } }; static VALUE mimic_object_to_json(int argc, VALUE *argv, VALUE self) { - char buf[4096]; - struct _out out; - VALUE rstr; - struct _options copts = oj_default_options; + char buf[4096]; + struct _out out; + VALUE rstr; + struct _options copts = oj_default_options; copts.str_rx.head = NULL; copts.str_rx.tail = NULL; @@ -753,19 +751,19 @@ mimic_object_to_json(int argc, VALUE *argv, VALUE self) { copts.mode = CompatMode; copts.to_json = No; if (1 <= argc && Qnil != argv[0]) { - oj_parse_mimic_dump_options(argv[0], &copts); + oj_parse_mimic_dump_options(argv[0], &copts); } // To be strict the mimic_object_to_json_options should be used but people // seem to prefer the option of changing that. //oj_dump_obj_to_json(self, &mimic_object_to_json_options, &out); oj_dump_obj_to_json_using_params(self, &copts, &out, argc, argv); if (0 == out.buf) { - rb_raise(rb_eNoMemError, "Not enough memory."); + rb_raise(rb_eNoMemError, "Not enough memory."); } rstr = rb_str_new2(out.buf); rstr = oj_encode(rstr); if (out.allocated) { - xfree(out.buf); + xfree(out.buf); } return rstr; } @@ -782,9 +780,9 @@ mimic_state(VALUE self) { void oj_mimic_json_methods(VALUE json) { - VALUE json_error; - VALUE generator; - VALUE ext; + VALUE json_error; + VALUE generator; + VALUE ext; rb_define_module_function(json, "create_id=", mimic_set_create_id, 1); rb_define_module_function(json, "create_id", mimic_create_id, 0); @@ -816,38 +814,37 @@ oj_mimic_json_methods(VALUE json) { if (rb_const_defined_at(json, rb_intern("ParserError"))) { oj_json_parser_error_class = rb_const_get(json, rb_intern("ParserError")); } else { - oj_json_parser_error_class = rb_define_class_under(json, "ParserError", json_error); + oj_json_parser_error_class = rb_define_class_under(json, "ParserError", json_error); } if (rb_const_defined_at(json, rb_intern("GeneratorError"))) { oj_json_generator_error_class = rb_const_get(json, rb_intern("GeneratorError")); } else { - oj_json_generator_error_class = rb_define_class_under(json, "GeneratorError", json_error); + oj_json_generator_error_class = rb_define_class_under(json, "GeneratorError", json_error); } if (rb_const_defined_at(json, rb_intern("NestingError"))) { rb_const_get(json, rb_intern("NestingError")); } else { - rb_define_class_under(json, "NestingError", json_error); + rb_define_class_under(json, "NestingError", json_error); } if (rb_const_defined_at(json, rb_intern("Ext"))) { - ext = rb_const_get_at(json, rb_intern("Ext")); - } else { - ext = rb_define_module_under(json, "Ext"); + ext = rb_const_get_at(json, rb_intern("Ext")); + } else { + ext = rb_define_module_under(json, "Ext"); } if (rb_const_defined_at(ext, rb_intern("Generator"))) { - generator = rb_const_get_at(ext, rb_intern("Generator")); - } else { - generator = rb_define_module_under(ext, "Generator"); + generator = rb_const_get_at(ext, rb_intern("Generator")); + } else { + generator = rb_define_module_under(ext, "Generator"); } if (!rb_const_defined_at(generator, rb_intern("State"))) { - rb_require("oj/state"); + rb_require("oj/state"); } // Pull in the JSON::State mimic file. state_class = rb_const_get_at(generator, rb_intern("State")); rb_gc_register_mark_object(state_class); - symbolize_names_sym = ID2SYM(rb_intern("symbolize_names")); - rb_gc_register_address(&symbolize_names_sym); + symbolize_names_sym = ID2SYM(rb_intern("symbolize_names")); rb_gc_register_address(&symbolize_names_sym); } /* Document-module: JSON @@ -856,31 +853,31 @@ oj_mimic_json_methods(VALUE json) { */ VALUE oj_define_mimic_json(int argc, VALUE *argv, VALUE self) { - VALUE dummy; - VALUE verbose; - VALUE json; + VALUE dummy; + VALUE verbose; + VALUE json; // Either set the paths to indicate JSON has been loaded or replaces the // methods if it has been loaded. if (rb_const_defined_at(rb_cObject, rb_intern("JSON"))) { - json = rb_const_get_at(rb_cObject, rb_intern("JSON")); + json = rb_const_get_at(rb_cObject, rb_intern("JSON")); } else { - json = rb_define_module("JSON"); + json = rb_define_module("JSON"); } verbose = rb_gv_get("$VERBOSE"); rb_gv_set("$VERBOSE", Qfalse); rb_define_module_function(rb_cObject, "JSON", mimic_dump_load, -1); dummy = rb_gv_get("$LOADED_FEATURES"); if (rb_type(dummy) == T_ARRAY) { - rb_ary_push(dummy, rb_str_new2("json")); - if (0 < argc) { - VALUE mimic_args[1]; - - *mimic_args = *argv; - rb_funcall2(Oj, rb_intern("mimic_loaded"), 1, mimic_args); - } else { - rb_funcall2(Oj, rb_intern("mimic_loaded"), 0, 0); - } + rb_ary_push(dummy, rb_str_new2("json")); + if (0 < argc) { + VALUE mimic_args[1]; + + *mimic_args = *argv; + rb_funcall2(Oj, rb_intern("mimic_loaded"), 1, mimic_args); + } else { + rb_funcall2(Oj, rb_intern("mimic_loaded"), 0, 0); + } } oj_mimic_json_methods(json); diff --git a/ext/oj/object.c b/ext/oj/object.c index b10c2889..67821ae7 100644 --- a/ext/oj/object.c +++ b/ext/oj/object.c @@ -5,67 +5,67 @@ #include #include -#include "encode.h" -#include "err.h" -#include "hash.h" -#include "odd.h" #include "oj.h" +#include "err.h" #include "parse.h" #include "resolve.h" +#include "hash.h" +#include "odd.h" +#include "encode.h" #include "trace.h" #include "util.h" inline static long read_long(const char *str, size_t len) { - long n = 0; + long n = 0; for (; 0 < len; str++, len--) { - if ('0' <= *str && *str <= '9') { - n = n * 10 + (*str - '0'); - } else { - return -1; - } + if ('0' <= *str && *str <= '9') { + n = n * 10 + (*str - '0'); + } else { + return -1; + } } return n; } static VALUE calc_hash_key(ParseInfo pi, Val kval, char k1) { - volatile VALUE rkey; + volatile VALUE rkey; if (':' == k1) { - rkey = rb_str_new(kval->key + 1, kval->klen - 1); - rkey = oj_encode(rkey); - rkey = rb_funcall(rkey, oj_to_sym_id, 0); + rkey = rb_str_new(kval->key + 1, kval->klen - 1); + rkey = oj_encode(rkey); + rkey = rb_funcall(rkey, oj_to_sym_id, 0); } else { - rkey = rb_str_new(kval->key, kval->klen); - rkey = oj_encode(rkey); - if (Yes == pi->options.sym_key) { - rkey = rb_str_intern(rkey); - } + rkey = rb_str_new(kval->key, kval->klen); + rkey = oj_encode(rkey); + if (Yes == pi->options.sym_key) { + rkey = rb_str_intern(rkey); + } } return rkey; } static VALUE str_to_value(ParseInfo pi, const char *str, size_t len, const char *orig) { - volatile VALUE rstr = Qnil; + volatile VALUE rstr = Qnil; if (':' == *orig && 0 < len) { - rstr = rb_str_new(str + 1, len - 1); - rstr = oj_encode(rstr); - rstr = rb_funcall(rstr, oj_to_sym_id, 0); + rstr = rb_str_new(str + 1, len - 1); + rstr = oj_encode(rstr); + rstr = rb_funcall(rstr, oj_to_sym_id, 0); } else if (pi->circ_array && 3 <= len && '^' == *orig && 'r' == orig[1]) { - long i = read_long(str + 2, len - 2); + long i = read_long(str + 2, len - 2); - if (0 > i) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a valid ID number"); - return Qnil; - } - rstr = oj_circ_array_get(pi->circ_array, i); + if (0 > i) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a valid ID number"); + return Qnil; + } + rstr = oj_circ_array_get(pi->circ_array, i); } else { - rstr = rb_str_new(str, len); - rstr = oj_encode(rstr); + rstr = rb_str_new(str, len); + rstr = oj_encode(rstr); } return rstr; } @@ -79,132 +79,132 @@ oj_parse_xml_time(const char *str, int len) { // The much faster approach (4x faster) static int parse_num(const char *str, const char *end, int cnt) { - int n = 0; - char c; - int i; + int n = 0; + char c; + int i; for (i = cnt; 0 < i; i--, str++) { - c = *str; - if (end <= str || c < '0' || '9' < c) { - return -1; - } - n = n * 10 + (c - '0'); + c = *str; + if (end <= str || c < '0' || '9' < c) { + return -1; + } + n = n * 10 + (c - '0'); } return n; } VALUE oj_parse_xml_time(const char *str, int len) { - VALUE args[8]; - const char *end = str + len; - int n; + VALUE args[8]; + const char *end = str + len; + int n; // year if (0 > (n = parse_num(str, end, 4))) { - return Qnil; + return Qnil; } str += 4; args[0] = LONG2NUM(n); if ('-' != *str++) { - return Qnil; + return Qnil; } // month if (0 > (n = parse_num(str, end, 2))) { - return Qnil; + return Qnil; } str += 2; args[1] = LONG2NUM(n); if ('-' != *str++) { - return Qnil; + return Qnil; } // day if (0 > (n = parse_num(str, end, 2))) { - return Qnil; + return Qnil; } str += 2; args[2] = LONG2NUM(n); if ('T' != *str++) { - return Qnil; + return Qnil; } // hour if (0 > (n = parse_num(str, end, 2))) { - return Qnil; + return Qnil; } str += 2; args[3] = LONG2NUM(n); if (':' != *str++) { - return Qnil; + return Qnil; } // minute if (0 > (n = parse_num(str, end, 2))) { - return Qnil; + return Qnil; } str += 2; args[4] = LONG2NUM(n); if (':' != *str++) { - return Qnil; + return Qnil; } // second if (0 > (n = parse_num(str, end, 2))) { - return Qnil; + return Qnil; } str += 2; if (str == end) { - args[5] = LONG2NUM(n); - args[6] = LONG2NUM(0); + args[5] = LONG2NUM(n); + args[6] = LONG2NUM(0); } else { - char c = *str++; - - if ('.' == c) { - long long nsec = 0; - - for (; str < end; str++) { - c = *str; - if (c < '0' || '9' < c) { - str++; - break; - } - nsec = nsec * 10 + (c - '0'); - } - args[5] = rb_float_new((double)n + ((double)nsec + 0.5) / 1000000000.0); - } else { - args[5] = rb_ll2inum(n); - } - if (end < str) { - args[6] = LONG2NUM(0); - } else { - if ('Z' == c) { - return rb_funcall2(rb_cTime, oj_utc_id, 6, args); - } else if ('+' == c) { - int hr = parse_num(str, end, 2); - int min; - - str += 2; - if (0 > hr || ':' != *str++) { - return Qnil; - } - min = parse_num(str, end, 2); - if (0 > min) { - return Qnil; - } - args[6] = LONG2NUM(hr * 3600 + min * 60); - } else if ('-' == c) { - int hr = parse_num(str, end, 2); - int min; - - str += 2; - if (0 > hr || ':' != *str++) { - return Qnil; - } - min = parse_num(str, end, 2); - if (0 > min) { - return Qnil; - } - args[6] = LONG2NUM(-(hr * 3600 + min * 60)); - } else { - args[6] = LONG2NUM(0); - } - } + char c = *str++; + + if ('.' == c) { + long long nsec = 0; + + for (; str < end; str++) { + c = *str; + if (c < '0' || '9' < c) { + str++; + break; + } + nsec = nsec * 10 + (c - '0'); + } + args[5] = rb_float_new((double)n + ((double)nsec + 0.5) / 1000000000.0); + } else { + args[5] = rb_ll2inum(n); + } + if (end < str) { + args[6] = LONG2NUM(0); + } else { + if ('Z' == c) { + return rb_funcall2(rb_cTime, oj_utc_id, 6, args); + } else if ('+' == c) { + int hr = parse_num(str, end, 2); + int min; + + str += 2; + if (0 > hr || ':' != *str++) { + return Qnil; + } + min = parse_num(str, end, 2); + if (0 > min) { + return Qnil; + } + args[6] = LONG2NUM(hr * 3600 + min * 60); + } else if ('-' == c) { + int hr = parse_num(str, end, 2); + int min; + + str += 2; + if (0 > hr || ':' != *str++) { + return Qnil; + } + min = parse_num(str, end, 2); + if (0 > min) { + return Qnil; + } + args[6] = LONG2NUM(-(hr * 3600 + min * 60)); + } else { + args[6] = LONG2NUM(0); + } + } } return rb_funcall2(rb_cTime, oj_new_id, 7, args); } @@ -212,56 +212,59 @@ oj_parse_xml_time(const char *str, int len) { static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t len) { - const char *key = kval->key; - int klen = kval->klen; + const char *key = kval->key; + int klen = kval->klen; if (2 == klen) { - switch (key[1]) { - case 'o': // object - { // name2class sets an error if the class is not found or created - VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError); - - if (Qundef != clas) { - parent->val = rb_obj_alloc(clas); - } - } break; - case 'O': // odd object - { - Odd odd = oj_get_oddc(str, len); - - if (0 == odd) { - return 0; - } - parent->val = odd->clas; - parent->odd_args = oj_odd_alloc_args(odd); - } break; - case 'm': - parent->val = rb_str_new(str + 1, len - 1); - parent->val = oj_encode(parent->val); - parent->val = rb_funcall(parent->val, oj_to_sym_id, 0); - break; - case 's': - parent->val = rb_str_new(str, len); - parent->val = oj_encode(parent->val); - break; - case 'c': // class - { - VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError); - - if (Qundef == clas) { - return 0; - } else { - parent->val = clas; - } - } break; - case 't': // time - parent->val = oj_parse_xml_time(str, (int)len); - break; - default: - return 0; - break; - } - return 1; // handled + switch (key[1]) { + case 'o': // object + { // name2class sets an error if the class is not found or created + VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError); + + if (Qundef != clas) { + parent->val = rb_obj_alloc(clas); + } + } + break; + case 'O': // odd object + { + Odd odd = oj_get_oddc(str, len); + + if (0 == odd) { + return 0; + } + parent->val = odd->clas; + parent->odd_args = oj_odd_alloc_args(odd); + } + break; + case 'm': + parent->val = rb_str_new(str + 1, len - 1); + parent->val = oj_encode(parent->val); + parent->val = rb_funcall(parent->val, oj_to_sym_id, 0); + break; + case 's': + parent->val = rb_str_new(str, len); + parent->val = oj_encode(parent->val); + break; + case 'c': // class + { + VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError); + + if (Qundef == clas) { + return 0; + } else { + parent->val = clas; + } + } + break; + case 't': // time + parent->val = oj_parse_xml_time(str, (int)len); + break; + default: + return 0; + break; + } + return 1; // handled } return 0; } @@ -269,61 +272,61 @@ hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t len) { static int hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) { if (2 == kval->klen) { - switch (kval->key[1]) { - case 't': // time as a float - if (0 == ni->div || 9 < ni->di) { - rb_raise(rb_eArgError, "Invalid time decimal representation."); - //parent->val = rb_time_nano_new(0, 0); - } else { - int64_t nsec = ni->num * 1000000000LL / ni->div; - - if (ni->neg) { - ni->i = -ni->i; - if (0 < nsec) { - ni->i--; - nsec = 1000000000LL - nsec; - } - } - if (86400 == ni->exp) { // UTC time - parent->val = rb_time_nano_new(ni->i, (long)nsec); - // Since the ruby C routines alway create local time, the - // offset and then a conversion to UTC keeps makes the time - // match the expected value. - parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0); - } else if (ni->has_exp) { - int64_t t = (int64_t)(ni->i + ni->exp); - struct _timeInfo ti; - VALUE args[8]; - - sec_as_time(t, &ti); - args[0] = LONG2NUM((long)(ti.year)); - args[1] = LONG2NUM(ti.mon); - args[2] = LONG2NUM(ti.day); - args[3] = LONG2NUM(ti.hour); - args[4] = LONG2NUM(ti.min); - args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0); - args[6] = LONG2NUM(ni->exp); - parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args); - } else { - parent->val = rb_time_nano_new(ni->i, (long)nsec); - } - } - break; - case 'i': // circular index - if (!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum - if (Qnil == parent->val) { - parent->val = rb_hash_new(); - } - oj_circ_array_set(pi->circ_array, parent->val, ni->i); - } else { - return 0; - } - break; - default: - return 0; - break; - } - return 1; // handled + switch (kval->key[1]) { + case 't': // time as a float + if (0 == ni->div || 9 < ni->di) { + rb_raise(rb_eArgError, "Invalid time decimal representation."); + //parent->val = rb_time_nano_new(0, 0); + } else { + int64_t nsec = ni->num * 1000000000LL / ni->div; + + if (ni->neg) { + ni->i = -ni->i; + if (0 < nsec) { + ni->i--; + nsec = 1000000000LL - nsec; + } + } + if (86400 == ni->exp) { // UTC time + parent->val = rb_time_nano_new(ni->i, (long)nsec); + // Since the ruby C routines alway create local time, the + // offset and then a conversion to UTC keeps makes the time + // match the expected value. + parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0); + } else if (ni->has_exp) { + int64_t t = (int64_t)(ni->i + ni->exp); + struct _timeInfo ti; + VALUE args[8]; + + sec_as_time(t, &ti); + args[0] = LONG2NUM((long)(ti.year)); + args[1] = LONG2NUM(ti.mon); + args[2] = LONG2NUM(ti.day); + args[3] = LONG2NUM(ti.hour); + args[4] = LONG2NUM(ti.min); + args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0); + args[6] = LONG2NUM(ni->exp); + parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args); + } else { + parent->val = rb_time_nano_new(ni->i, (long)nsec); + } + } + break; + case 'i': // circular index + if (!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum + if (Qnil == parent->val) { + parent->val = rb_hash_new(); + } + oj_circ_array_set(pi->circ_array, parent->val, ni->i); + } else { + return 0; + } + break; + default: + return 0; + break; + } + return 1; // handled } return 0; } @@ -331,79 +334,79 @@ hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) { static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, volatile VALUE value) { if (T_ARRAY == rb_type(value)) { - int len = (int)RARRAY_LEN(value); - - if (2 == klen && 'u' == key[1]) { - volatile VALUE sc; - volatile VALUE e1; - int slen; - - if (0 == len) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data"); - return 1; - } - e1 = *RARRAY_PTR(value); - // check for anonymous Struct - if (T_ARRAY == rb_type(e1)) { - VALUE args[1024]; - volatile VALUE rstr; - int i, cnt = (int)RARRAY_LEN(e1); - - for (i = 0; i < cnt; i++) { - rstr = rb_ary_entry(e1, i); - args[i] = rb_funcall(rstr, oj_to_sym_id, 0); - } - sc = rb_funcall2(rb_cStruct, oj_new_id, cnt, args); - } else { - // If struct is not defined then we let this fail and raise an exception. - sc = oj_name2struct(pi, *RARRAY_PTR(value), rb_eArgError); - } + int len = (int)RARRAY_LEN(value); + + if (2 == klen && 'u' == key[1]) { + volatile VALUE sc; + volatile VALUE e1; + int slen; + + if (0 == len) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data"); + return 1; + } + e1 = *RARRAY_PTR(value); + // check for anonymous Struct + if (T_ARRAY == rb_type(e1)) { + VALUE args[1024]; + volatile VALUE rstr; + int i, cnt = (int)RARRAY_LEN(e1); + + for (i = 0; i < cnt; i++) { + rstr = rb_ary_entry(e1, i); + args[i] = rb_funcall(rstr, oj_to_sym_id, 0); + } + sc = rb_funcall2(rb_cStruct, oj_new_id, cnt, args); + } else { + // If struct is not defined then we let this fail and raise an exception. + sc = oj_name2struct(pi, *RARRAY_PTR(value), rb_eArgError); + } // Create a properly initialized struct instance without calling the initialize method. parent->val = rb_obj_alloc(sc); // If the JSON array has more entries than the struct class allows, we record an error. #ifdef RSTRUCT_LEN #if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT - slen = (int)NUM2LONG(RSTRUCT_LEN(parent->val)); -#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT - slen = (int)RSTRUCT_LEN(parent->val); + slen = (int)NUM2LONG(RSTRUCT_LEN(parent->val)); +#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT + slen = (int)RSTRUCT_LEN(parent->val); #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT #else - slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0)); + slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0)); #endif // MRI >= 1.9 if (len - 1 > slen) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data"); } else { - int i; + int i; - for (i = 0; i < len - 1; i++) { - rb_struct_aset(parent->val, INT2FIX(i), RARRAY_PTR(value)[i + 1]); - } + for (i = 0; i < len - 1; i++) { + rb_struct_aset(parent->val, INT2FIX(i), RARRAY_PTR(value)[i + 1]); + } } - return 1; - } else if (3 <= klen && '#' == key[1]) { - volatile VALUE *a; + return 1; + } else if (3 <= klen && '#' == key[1]) { + volatile VALUE *a; - if (2 != len) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair"); - return 1; - } - parent->val = rb_hash_new(); - a = RARRAY_PTR(value); - rb_hash_aset(parent->val, *a, a[1]); + if (2 != len) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair"); + return 1; + } + parent->val = rb_hash_new(); + a = RARRAY_PTR(value); + rb_hash_aset(parent->val, *a, a[1]); - return 1; - } + return 1; + } } return 0; } void oj_set_obj_ivar(Val parent, Val kval, VALUE value) { - const char *key = kval->key; - int klen = kval->klen; - ID var_id; - ID *slot; + const char *key = kval->key; + int klen = kval->klen; + ID var_id; + ID *slot; #ifdef HAVE_PTHREAD_MUTEX_INIT pthread_mutex_lock(&oj_cache_mutex); @@ -411,33 +414,33 @@ oj_set_obj_ivar(Val parent, Val kval, VALUE value) { rb_mutex_lock(oj_cache_mutex); #endif if (0 == (var_id = oj_attr_hash_get(key, klen, &slot))) { - char attr[256]; - - if ((int)sizeof(attr) <= klen + 2) { - char *buf = ALLOC_N(char, klen + 2); - - if ('~' == *key) { - strncpy(buf, key + 1, klen - 1); - buf[klen - 1] = '\0'; - } else { - *buf = '@'; - strncpy(buf + 1, key, klen); - buf[klen + 1] = '\0'; - } - var_id = rb_intern(buf); - xfree(buf); - } else { - if ('~' == *key) { - strncpy(attr, key + 1, klen - 1); - attr[klen - 1] = '\0'; - } else { - *attr = '@'; - strncpy(attr + 1, key, klen); - attr[klen + 1] = '\0'; - } - var_id = rb_intern(attr); - } - *slot = var_id; + char attr[256]; + + if ((int)sizeof(attr) <= klen + 2) { + char *buf = ALLOC_N(char, klen + 2); + + if ('~' == *key) { + strncpy(buf, key + 1, klen - 1); + buf[klen - 1] = '\0'; + } else { + *buf = '@'; + strncpy(buf + 1, key, klen); + buf[klen + 1] = '\0'; + } + var_id = rb_intern(buf); + xfree(buf); + } else { + if ('~' == *key) { + strncpy(attr, key + 1, klen - 1); + attr[klen - 1] = '\0'; + } else { + *attr = '@'; + strncpy(attr + 1, key, klen); + attr[klen + 1] = '\0'; + } + var_id = rb_intern(attr); + } + *slot = var_id; } #ifdef HAVE_PTHREAD_MUTEX_INIT pthread_mutex_unlock(&oj_cache_mutex); @@ -449,253 +452,254 @@ oj_set_obj_ivar(Val parent, Val kval, VALUE value) { static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) { - const char *key = kval->key; - int klen = kval->klen; - Val parent = stack_peek(&pi->stack); - volatile VALUE rval = Qnil; + const char *key = kval->key; + int klen = kval->klen; + Val parent = stack_peek(&pi->stack); + volatile VALUE rval = Qnil; -WHICH_TYPE: + WHICH_TYPE: switch (rb_type(parent->val)) { - case T_NIL: - parent->odd_args = NULL; // make sure it is NULL in case not odd - if ('^' != *key || !hat_cstr(pi, parent, kval, str, len)) { - parent->val = rb_hash_new(); - goto WHICH_TYPE; - } - break; - case T_HASH: - rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), str_to_value(pi, str, len, orig)); - break; - case T_STRING: - rval = str_to_value(pi, str, len, orig); - if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) { - rb_funcall(parent->val, oj_replace_id, 1, rval); - } else { - oj_set_obj_ivar(parent, kval, rval); - } - break; - case T_OBJECT: - rval = str_to_value(pi, str, len, orig); - oj_set_obj_ivar(parent, kval, rval); - break; - case T_CLASS: - if (NULL == parent->odd_args) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val))); - return; - } else { - rval = str_to_value(pi, str, len, orig); - if (0 != oj_odd_set_arg(parent->odd_args, kval->key, kval->klen, rval)) { - char buf[256]; - - if ((int)sizeof(buf) - 1 <= klen) { - klen = sizeof(buf) - 2; - } - memcpy(buf, key, klen); - buf[klen] = '\0'; - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val))); - } - } - break; - default: - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val))); - return; + case T_NIL: + parent->odd_args = NULL; // make sure it is NULL in case not odd + if ('^' != *key || !hat_cstr(pi, parent, kval, str, len)) { + parent->val = rb_hash_new(); + goto WHICH_TYPE; + } + break; + case T_HASH: + rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), str_to_value(pi, str, len, orig)); + break; + case T_STRING: + rval = str_to_value(pi, str, len, orig); + if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) { + rb_funcall(parent->val, oj_replace_id, 1, rval); + } else { + oj_set_obj_ivar(parent, kval, rval); + } + break; + case T_OBJECT: + rval = str_to_value(pi, str, len, orig); + oj_set_obj_ivar(parent, kval, rval); + break; + case T_CLASS: + if (NULL == parent->odd_args) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val))); + return; + } else { + rval = str_to_value(pi, str, len, orig); + if (0 != oj_odd_set_arg(parent->odd_args, kval->key, kval->klen, rval)) { + char buf[256]; + + if ((int)sizeof(buf) - 1 <= klen) { + klen = sizeof(buf) - 2; + } + memcpy(buf, key, klen); + buf[klen] = '\0'; + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val))); + } + } + break; + default: + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val))); + return; } if (Yes == pi->options.trace) { - oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval); + oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval); } } static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) { - const char *key = kval->key; - int klen = kval->klen; - Val parent = stack_peek(&pi->stack); - volatile VALUE rval = Qnil; + const char *key = kval->key; + int klen = kval->klen; + Val parent = stack_peek(&pi->stack); + volatile VALUE rval = Qnil; -WHICH_TYPE: + WHICH_TYPE: switch (rb_type(parent->val)) { - case T_NIL: - parent->odd_args = NULL; // make sure it is NULL in case not odd - if ('^' != *key || !hat_num(pi, parent, kval, ni)) { - parent->val = rb_hash_new(); - goto WHICH_TYPE; - } - break; - case T_HASH: - rval = oj_num_as_value(ni); - rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), rval); - break; - case T_OBJECT: - if (2 == klen && '^' == *key && 'i' == key[1] && - !ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum - oj_circ_array_set(pi->circ_array, parent->val, ni->i); - } else { - rval = oj_num_as_value(ni); - oj_set_obj_ivar(parent, kval, rval); - } - break; - case T_CLASS: - if (NULL == parent->odd_args) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val))); - return; - } else { - rval = oj_num_as_value(ni); - if (0 != oj_odd_set_arg(parent->odd_args, key, klen, rval)) { - char buf[256]; - - if ((int)sizeof(buf) - 1 <= klen) { - klen = sizeof(buf) - 2; - } - memcpy(buf, key, klen); - buf[klen] = '\0'; - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val))); - } - } - break; - default: - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val))); - return; + case T_NIL: + parent->odd_args = NULL; // make sure it is NULL in case not odd + if ('^' != *key || !hat_num(pi, parent, kval, ni)) { + parent->val = rb_hash_new(); + goto WHICH_TYPE; + } + break; + case T_HASH: + rval = oj_num_as_value(ni); + rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), rval); + break; + case T_OBJECT: + if (2 == klen && '^' == *key && 'i' == key[1] && + !ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum + oj_circ_array_set(pi->circ_array, parent->val, ni->i); + } else { + rval = oj_num_as_value(ni); + oj_set_obj_ivar(parent, kval, rval); + } + break; + case T_CLASS: + if (NULL == parent->odd_args) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val))); + return; + } else { + rval = oj_num_as_value(ni); + if (0 != oj_odd_set_arg(parent->odd_args, key, klen, rval)) { + char buf[256]; + + if ((int)sizeof(buf) - 1 <= klen) { + klen = sizeof(buf) - 2; + } + memcpy(buf, key, klen); + buf[klen] = '\0'; + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val))); + } + } + break; + default: + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val))); + return; } if (Yes == pi->options.trace) { - oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, rval); + oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, rval); } } static void hash_set_value(ParseInfo pi, Val kval, VALUE value) { - const char *key = kval->key; - int klen = kval->klen; - Val parent = stack_peek(&pi->stack); + const char *key = kval->key; + int klen = kval->klen; + Val parent = stack_peek(&pi->stack); -WHICH_TYPE: + WHICH_TYPE: switch (rb_type(parent->val)) { - case T_NIL: - parent->odd_args = NULL; // make sure it is NULL in case not odd - if ('^' != *key || !hat_value(pi, parent, key, klen, value)) { - parent->val = rb_hash_new(); - goto WHICH_TYPE; - } - break; - case T_HASH: - if (rb_cHash != rb_obj_class(parent->val)) { - if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) { - rb_funcall(parent->val, oj_replace_id, 1, value); - } else { - oj_set_obj_ivar(parent, kval, value); - } - } else { - if (3 <= klen && '^' == *key && '#' == key[1] && T_ARRAY == rb_type(value)) { - long len = RARRAY_LEN(value); - volatile VALUE *a = RARRAY_PTR(value); - - if (2 != len) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair"); - return; - } - rb_hash_aset(parent->val, *a, a[1]); - } else { - rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), value); - } - } - break; - case T_ARRAY: - if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) { - rb_funcall(parent->val, oj_replace_id, 1, value); - } else { - oj_set_obj_ivar(parent, kval, value); - } - break; - case T_STRING: // for subclassed strings - case T_OBJECT: - oj_set_obj_ivar(parent, kval, value); - break; - case T_MODULE: - case T_CLASS: - if (NULL == parent->odd_args) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val))); - return; - } else if (0 != oj_odd_set_arg(parent->odd_args, key, klen, value)) { - char buf[256]; - - if ((int)sizeof(buf) - 1 <= klen) { - klen = sizeof(buf) - 2; - } - memcpy(buf, key, klen); - buf[klen] = '\0'; - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val))); - } - break; - default: - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val))); - return; + case T_NIL: + parent->odd_args = NULL; // make sure it is NULL in case not odd + if ('^' != *key || !hat_value(pi, parent, key, klen, value)) { + parent->val = rb_hash_new(); + goto WHICH_TYPE; + } + break; + case T_HASH: + if (rb_cHash != rb_obj_class(parent->val)) { + if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) { + rb_funcall(parent->val, oj_replace_id, 1, value); + } else { + oj_set_obj_ivar(parent, kval, value); + } + } else { + if (3 <= klen && '^' == *key && '#' == key[1] && T_ARRAY == rb_type(value)) { + long len = RARRAY_LEN(value); + volatile VALUE *a = RARRAY_PTR(value); + + if (2 != len) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair"); + return; + } + rb_hash_aset(parent->val, *a, a[1]); + } else { + rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), value); + } + } + break; + case T_ARRAY: + if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) { + rb_funcall(parent->val, oj_replace_id, 1, value); + } else { + oj_set_obj_ivar(parent, kval, value); + } + break; + case T_STRING: // for subclassed strings + case T_OBJECT: + oj_set_obj_ivar(parent, kval, value); + break; + case T_MODULE: + case T_CLASS: + if (NULL == parent->odd_args) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val))); + return; + } else if (0 != oj_odd_set_arg(parent->odd_args, key, klen, value)) { + char buf[256]; + + if ((int)sizeof(buf) - 1 <= klen) { + klen = sizeof(buf) - 2; + } + memcpy(buf, key, klen); + buf[klen] = '\0'; + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val))); + } + break; + default: + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val))); + return; } if (Yes == pi->options.trace) { - oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, value); + oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, value); } } static VALUE start_hash(ParseInfo pi) { if (Yes == pi->options.trace) { - oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__); + oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__); } return Qnil; } static void end_hash(ParseInfo pi) { - Val parent = stack_peek(&pi->stack); + Val parent = stack_peek(&pi->stack); if (Qnil == parent->val) { - parent->val = rb_hash_new(); + parent->val = rb_hash_new(); } else if (NULL != parent->odd_args) { - OddArgs oa = parent->odd_args; + OddArgs oa = parent->odd_args; - parent->val = rb_funcall2(oa->odd->create_obj, oa->odd->create_op, oa->odd->attr_cnt, oa->args); - oj_odd_free(oa); - parent->odd_args = NULL; + parent->val = rb_funcall2(oa->odd->create_obj, oa->odd->create_op, oa->odd->attr_cnt, oa->args); + oj_odd_free(oa); + parent->odd_args = NULL; } if (Yes == pi->options.trace) { - oj_trace_parse_hash_end(pi, __FILE__, __LINE__); + oj_trace_parse_hash_end(pi, __FILE__, __LINE__); } } static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { - volatile VALUE rval = Qnil; + volatile VALUE rval = Qnil; // orig lets us know whether the string was ^r1 or \u005er1 if (3 <= len && 0 != pi->circ_array && '^' == orig[0] && 0 == rb_array_len(stack_peek(&pi->stack)->val)) { - if ('i' == str[1]) { - long i = read_long(str + 2, len - 2); + if ('i' == str[1]) { + long i = read_long(str + 2, len - 2); - if (0 < i) { - oj_circ_array_set(pi->circ_array, stack_peek(&pi->stack)->val, i); - return; - } - } else if ('r' == str[1]) { - long i = read_long(str + 2, len - 2); + if (0 < i) { + oj_circ_array_set(pi->circ_array, stack_peek(&pi->stack)->val, i); + return; + } + } else if ('r' == str[1]) { + long i = read_long(str + 2, len - 2); - if (0 < i) { - rb_ary_push(stack_peek(&pi->stack)->val, oj_circ_array_get(pi->circ_array, i)); - return; - } - } + if (0 < i) { + rb_ary_push(stack_peek(&pi->stack)->val, oj_circ_array_get(pi->circ_array, i)); + return; + } + + } } rval = str_to_value(pi, str, len, orig); rb_ary_push(stack_peek(&pi->stack)->val, rval); if (Yes == pi->options.trace) { - oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rval); + oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rval); } } static void array_append_num(ParseInfo pi, NumInfo ni) { - volatile VALUE rval = oj_num_as_value(ni); + volatile VALUE rval = oj_num_as_value(ni); rb_ary_push(stack_peek(&pi->stack)->val, rval); if (Yes == pi->options.trace) { - oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval); + oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval); } } @@ -703,7 +707,7 @@ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { pi->stack.head->val = str_to_value(pi, str, len, orig); if (Yes == pi->options.trace) { - oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val); + oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val); } } @@ -711,7 +715,7 @@ static void add_num(ParseInfo pi, NumInfo ni) { pi->stack.head->val = oj_num_as_value(ni); if (Yes == pi->options.trace) { - oj_trace_parse_call("add_num", pi, __FILE__, __LINE__, pi->stack.head->val); + oj_trace_parse_call("add_num", pi, __FILE__, __LINE__, pi->stack.head->val); } } @@ -731,7 +735,7 @@ oj_set_object_callbacks(ParseInfo pi) { VALUE oj_object_parse(int argc, VALUE *argv, VALUE self) { - struct _parseInfo pi; + struct _parseInfo pi; parse_info_init(&pi); pi.options = oj_default_options; @@ -740,15 +744,15 @@ oj_object_parse(int argc, VALUE *argv, VALUE self) { oj_set_object_callbacks(&pi); if (T_STRING == rb_type(*argv)) { - return oj_pi_parse(argc, argv, &pi, 0, 0, 1); + return oj_pi_parse(argc, argv, &pi, 0, 0, 1); } else { - return oj_pi_sparse(argc, argv, &pi, 0); + return oj_pi_sparse(argc, argv, &pi, 0); } } VALUE oj_object_parse_cstr(int argc, VALUE *argv, char *json, size_t len) { - struct _parseInfo pi; + struct _parseInfo pi; parse_info_init(&pi); pi.options = oj_default_options; diff --git a/ext/oj/odd.c b/ext/oj/odd.c index bde887c8..7d3e5f9b 100644 --- a/ext/oj/odd.c +++ b/ext/oj/odd.c @@ -5,21 +5,21 @@ #include "odd.h" -static struct _odd _odds[4]; // bump up if new initial Odd classes are added -static struct _odd *odds = _odds; -static long odd_cnt = 0; -static ID sec_id; -static ID sec_fraction_id; -static ID to_f_id; -static ID numerator_id; -static ID denominator_id; -static ID rational_id; -static VALUE rational_class; +static struct _odd _odds[4]; // bump up if new initial Odd classes are added +static struct _odd *odds = _odds; +static long odd_cnt = 0; +static ID sec_id; +static ID sec_fraction_id; +static ID to_f_id; +static ID numerator_id; +static ID denominator_id; +static ID rational_id; +static VALUE rational_class; static void set_class(Odd odd, const char *classname) { - const char **np; - ID *idp; + const char **np; + ID *idp; odd->classname = classname; odd->clen = strlen(classname); @@ -29,18 +29,18 @@ set_class(Odd odd, const char *classname) { odd->is_module = (T_MODULE == rb_type(odd->clas)); odd->raw = 0; for (np = odd->attr_names, idp = odd->attrs; 0 != *np; np++, idp++) { - *idp = rb_intern(*np); + *idp = rb_intern(*np); } *idp = 0; } static VALUE get_datetime_secs(VALUE obj) { - volatile VALUE rsecs = rb_funcall(obj, sec_id, 0); - volatile VALUE rfrac = rb_funcall(obj, sec_fraction_id, 0); - long sec = NUM2LONG(rsecs); - long long num = rb_num2ll(rb_funcall(rfrac, numerator_id, 0)); - long long den = rb_num2ll(rb_funcall(rfrac, denominator_id, 0)); + volatile VALUE rsecs = rb_funcall(obj, sec_id, 0); + volatile VALUE rfrac = rb_funcall(obj, sec_fraction_id, 0); + long sec = NUM2LONG(rsecs); + long long num = rb_num2ll(rb_funcall(rfrac, numerator_id, 0)); + long long den = rb_num2ll(rb_funcall(rfrac, denominator_id, 0)); num += sec * den; @@ -49,8 +49,8 @@ get_datetime_secs(VALUE obj) { void oj_odd_init() { - Odd odd; - const char **np; + Odd odd; + const char **np; sec_id = rb_intern("sec"); sec_fraction_id = rb_intern("sec_fraction"); @@ -111,52 +111,52 @@ oj_odd_init() { Odd oj_get_odd(VALUE clas) { - Odd odd; - const char *classname = NULL; + Odd odd; + const char *classname = NULL; for (odd = odds + odd_cnt - 1; odds <= odd; odd--) { - if (clas == odd->clas) { - return odd; - } - if (odd->is_module) { - if (NULL == classname) { - classname = rb_class2name(clas); - } - if (0 == strncmp(odd->classname, classname, odd->clen) && - ':' == classname[odd->clen]) { - return odd; - } - } + if (clas == odd->clas) { + return odd; + } + if (odd->is_module) { + if (NULL == classname) { + classname = rb_class2name(clas); + } + if (0 == strncmp(odd->classname, classname, odd->clen) && + ':' == classname[odd->clen]) { + return odd; + } + } } return NULL; } Odd oj_get_oddc(const char *classname, size_t len) { - Odd odd; + Odd odd; for (odd = odds + odd_cnt - 1; odds <= odd; odd--) { - if (len == odd->clen && 0 == strncmp(classname, odd->classname, len)) { - return odd; - } - if (odd->is_module && - 0 == strncmp(odd->classname, classname, odd->clen) && - ':' == classname[odd->clen]) { - return odd; - } + if (len == odd->clen && 0 == strncmp(classname, odd->classname, len)) { + return odd; + } + if (odd->is_module && + 0 == strncmp(odd->classname, classname, odd->clen) && + ':' == classname[odd->clen]) { + return odd; + } } return 0; } OddArgs oj_odd_alloc_args(Odd odd) { - OddArgs oa = ALLOC_N(struct _oddArgs, 1); - VALUE *a; - int i; + OddArgs oa = ALLOC_N(struct _oddArgs, 1); + VALUE *a; + int i; oa->odd = odd; for (i = odd->attr_cnt, a = oa->args; 0 < i; i--, a++) { - *a = Qnil; + *a = Qnil; } return oa; } @@ -168,37 +168,37 @@ oj_odd_free(OddArgs args) { int oj_odd_set_arg(OddArgs args, const char *key, size_t klen, VALUE value) { - const char **np; - VALUE *vp; - int i; + const char **np; + VALUE *vp; + int i; for (i = args->odd->attr_cnt, np = args->odd->attr_names, vp = args->args; 0 < i; i--, np++, vp++) { - if (0 == strncmp(key, *np, klen) && '\0' == *((*np) + klen)) { - *vp = value; - return 0; - } + if (0 == strncmp(key, *np, klen) && '\0' == *((*np) + klen)) { + *vp = value; + return 0; + } } return -1; } void oj_reg_odd(VALUE clas, VALUE create_object, VALUE create_method, int mcnt, VALUE *members, bool raw) { - Odd odd; - const char **np; - ID *ap; - AttrGetFunc *fp; + Odd odd; + const char **np; + ID *ap; + AttrGetFunc *fp; if (_odds == odds) { - odds = ALLOC_N(struct _odd, odd_cnt + 1); + odds = ALLOC_N(struct _odd, odd_cnt + 1); - memcpy(odds, _odds, sizeof(struct _odd) * odd_cnt); + memcpy(odds, _odds, sizeof(struct _odd) * odd_cnt); } else { - REALLOC_N(odds, struct _odd, odd_cnt + 1); + REALLOC_N(odds, struct _odd, odd_cnt + 1); } odd = odds + odd_cnt; odd->clas = clas; if (NULL == (odd->classname = strdup(rb_class2name(clas)))) { - rb_raise(rb_eNoMemError, "for attribute name."); + rb_raise(rb_eNoMemError, "for attribute name."); } odd->clen = strlen(odd->classname); odd->create_obj = create_object; @@ -207,21 +207,21 @@ oj_reg_odd(VALUE clas, VALUE create_object, VALUE create_method, int mcnt, VALUE odd->is_module = (T_MODULE == rb_type(clas)); odd->raw = raw; for (ap = odd->attrs, np = odd->attr_names, fp = odd->attrFuncs; 0 < mcnt; mcnt--, ap++, np++, members++, fp++) { - *fp = 0; - switch (rb_type(*members)) { - case T_STRING: - if (NULL == (*np = strdup(rb_string_value_ptr(members)))) { - rb_raise(rb_eNoMemError, "for attribute name."); - } - break; - case T_SYMBOL: - *np = rb_id2name(SYM2ID(*members)); - break; - default: - rb_raise(rb_eArgError, "registered member identifiers must be Strings or Symbols."); - break; - } - *ap = rb_intern(*np); + *fp = 0; + switch (rb_type(*members)) { + case T_STRING: + if (NULL == (*np = strdup(rb_string_value_ptr(members)))) { + rb_raise(rb_eNoMemError, "for attribute name."); + } + break; + case T_SYMBOL: + *np = rb_id2name(SYM2ID(*members)); + break; + default: + rb_raise(rb_eArgError, "registered member identifiers must be Strings or Symbols."); + break; + } + *ap = rb_intern(*np); } *np = 0; *ap = 0; diff --git a/ext/oj/odd.h b/ext/oj/odd.h index 18483b4a..7bc3943e 100644 --- a/ext/oj/odd.h +++ b/ext/oj/odd.h @@ -8,35 +8,35 @@ #include "ruby.h" -#define MAX_ODD_ARGS 10 +#define MAX_ODD_ARGS 10 -typedef VALUE (*AttrGetFunc)(VALUE obj); +typedef VALUE (*AttrGetFunc)(VALUE obj); typedef struct _odd { - const char *classname; - size_t clen; - VALUE clas; // Ruby class or module - VALUE create_obj; - ID create_op; - int attr_cnt; - bool is_module; - bool raw; - const char *attr_names[MAX_ODD_ARGS]; // NULL terminated attr names - ID attrs[MAX_ODD_ARGS]; // 0 terminated attr IDs - AttrGetFunc attrFuncs[MAX_ODD_ARGS]; -} * Odd; + const char *classname; + size_t clen; + VALUE clas; // Ruby class or module + VALUE create_obj; + ID create_op; + int attr_cnt; + bool is_module; + bool raw; + const char *attr_names[MAX_ODD_ARGS]; // NULL terminated attr names + ID attrs[MAX_ODD_ARGS]; // 0 terminated attr IDs + AttrGetFunc attrFuncs[MAX_ODD_ARGS]; +} *Odd; typedef struct _oddArgs { - Odd odd; - VALUE args[MAX_ODD_ARGS]; -} * OddArgs; - -extern void oj_odd_init(void); -extern Odd oj_get_odd(VALUE clas); -extern Odd oj_get_oddc(const char *classname, size_t len); -extern OddArgs oj_odd_alloc_args(Odd odd); -extern void oj_odd_free(OddArgs args); -extern int oj_odd_set_arg(OddArgs args, const char *key, size_t klen, VALUE value); -extern void oj_reg_odd(VALUE clas, VALUE create_object, VALUE create_method, int mcnt, VALUE *members, bool raw); + Odd odd; + VALUE args[MAX_ODD_ARGS]; +} *OddArgs; + +extern void oj_odd_init(void); +extern Odd oj_get_odd(VALUE clas); +extern Odd oj_get_oddc(const char *classname, size_t len); +extern OddArgs oj_odd_alloc_args(Odd odd); +extern void oj_odd_free(OddArgs args); +extern int oj_odd_set_arg(OddArgs args, const char *key, size_t klen, VALUE value); +extern void oj_reg_odd(VALUE clas, VALUE create_object, VALUE create_method, int mcnt, VALUE *members, bool raw); #endif /* OJ_ODD_H */ diff --git a/ext/oj/oj.c b/ext/oj/oj.c index 7c8abddb..d3dc563e 100644 --- a/ext/oj/oj.c +++ b/ext/oj/oj.c @@ -1,223 +1,222 @@ // Copyright (c) 2012 Peter Ohler. All rights reserved. // Licensed under the MIT License. See LICENSE file in the project root for license details. +#include #include -#include #include -#include #include #include #include +#include -#include "dump.h" -#include "encode.h" -#include "hash.h" -#include "odd.h" #include "oj.h" #include "parse.h" +#include "hash.h" +#include "odd.h" +#include "dump.h" #include "rails.h" +#include "encode.h" typedef struct _yesNoOpt { - VALUE sym; - char *attr; -} * YesNoOpt; + VALUE sym; + char *attr; +} *YesNoOpt; void Init_oj(); -VALUE Oj = Qnil; - -ID oj_add_value_id; -ID oj_array_append_id; -ID oj_array_end_id; -ID oj_array_start_id; -ID oj_as_json_id; -ID oj_begin_id; -ID oj_bigdecimal_id; -ID oj_end_id; -ID oj_exclude_end_id; -ID oj_error_id; -ID oj_file_id; -ID oj_fileno_id; -ID oj_ftype_id; -ID oj_has_key_id; -ID oj_hash_end_id; -ID oj_hash_key_id; -ID oj_hash_set_id; -ID oj_hash_start_id; -ID oj_iconv_id; -ID oj_instance_variables_id; -ID oj_json_create_id; -ID oj_length_id; -ID oj_new_id; -ID oj_parse_id; -ID oj_pos_id; -ID oj_raw_json_id; -ID oj_read_id; -ID oj_readpartial_id; -ID oj_replace_id; -ID oj_stat_id; -ID oj_string_id; -ID oj_to_h_id; -ID oj_to_hash_id; -ID oj_to_json_id; -ID oj_to_s_id; -ID oj_to_sym_id; -ID oj_to_time_id; -ID oj_tv_nsec_id; -ID oj_tv_sec_id; -ID oj_tv_usec_id; -ID oj_utc_id; -ID oj_utc_offset_id; -ID oj_utcq_id; -ID oj_write_id; - -VALUE oj_bag_class; -VALUE oj_bigdecimal_class; -VALUE oj_cstack_class; -VALUE oj_date_class; -VALUE oj_datetime_class; -VALUE oj_enumerable_class; -VALUE oj_parse_error_class; -VALUE oj_stream_writer_class; -VALUE oj_string_writer_class; -VALUE oj_stringio_class; -VALUE oj_struct_class; - -VALUE oj_slash_string; - -VALUE oj_allow_nan_sym; -VALUE oj_array_class_sym; -VALUE oj_create_additions_sym; -VALUE oj_decimal_class_sym; -VALUE oj_hash_class_sym; -VALUE oj_indent_sym; -VALUE oj_object_class_sym; -VALUE oj_quirks_mode_sym; -VALUE oj_safe_sym; -VALUE oj_trace_sym; - -static VALUE allow_blank_sym; -static VALUE allow_gc_sym; -static VALUE allow_invalid_unicode_sym; -static VALUE ascii_sym; -static VALUE auto_define_sym; -static VALUE auto_sym; -static VALUE bigdecimal_as_decimal_sym; -static VALUE bigdecimal_load_sym; -static VALUE bigdecimal_sym; -static VALUE circular_sym; -static VALUE class_cache_sym; -static VALUE compat_bigdecimal_sym; -static VALUE compat_sym; -static VALUE create_id_sym; -static VALUE custom_sym; -static VALUE empty_string_sym; -static VALUE escape_mode_sym; -static VALUE integer_range_sym; -static VALUE fast_sym; -static VALUE float_prec_sym; -static VALUE float_sym; -static VALUE huge_sym; -static VALUE ignore_sym; -static VALUE ignore_under_sym; -static VALUE json_sym; -static VALUE match_string_sym; -static VALUE mode_sym; -static VALUE nan_sym; -static VALUE newline_sym; -static VALUE nilnil_sym; -static VALUE null_sym; -static VALUE object_sym; -static VALUE omit_nil_sym; -static VALUE rails_sym; -static VALUE raise_sym; -static VALUE ruby_sym; -static VALUE sec_prec_sym; -static VALUE strict_sym; -static VALUE symbol_keys_sym; -static VALUE time_format_sym; -static VALUE unicode_xss_sym; -static VALUE unix_sym; -static VALUE unix_zone_sym; -static VALUE use_as_json_sym; -static VALUE use_raw_json_sym; -static VALUE use_to_hash_sym; -static VALUE use_to_json_sym; -static VALUE wab_sym; -static VALUE word_sym; -static VALUE xmlschema_sym; -static VALUE xss_safe_sym; - -rb_encoding *oj_utf8_encoding = 0; +VALUE Oj = Qnil; + +ID oj_add_value_id; +ID oj_array_append_id; +ID oj_array_end_id; +ID oj_array_start_id; +ID oj_as_json_id; +ID oj_begin_id; +ID oj_bigdecimal_id; +ID oj_end_id; +ID oj_exclude_end_id; +ID oj_error_id; +ID oj_file_id; +ID oj_fileno_id; +ID oj_ftype_id; +ID oj_has_key_id; +ID oj_hash_end_id; +ID oj_hash_key_id; +ID oj_hash_set_id; +ID oj_hash_start_id; +ID oj_iconv_id; +ID oj_instance_variables_id; +ID oj_json_create_id; +ID oj_length_id; +ID oj_new_id; +ID oj_parse_id; +ID oj_pos_id; +ID oj_raw_json_id; +ID oj_read_id; +ID oj_readpartial_id; +ID oj_replace_id; +ID oj_stat_id; +ID oj_string_id; +ID oj_to_h_id; +ID oj_to_hash_id; +ID oj_to_json_id; +ID oj_to_s_id; +ID oj_to_sym_id; +ID oj_to_time_id; +ID oj_tv_nsec_id; +ID oj_tv_sec_id; +ID oj_tv_usec_id; +ID oj_utc_id; +ID oj_utc_offset_id; +ID oj_utcq_id; +ID oj_write_id; + + +VALUE oj_bag_class; +VALUE oj_bigdecimal_class; +VALUE oj_cstack_class; +VALUE oj_date_class; +VALUE oj_datetime_class; +VALUE oj_enumerable_class; +VALUE oj_parse_error_class; +VALUE oj_stream_writer_class; +VALUE oj_string_writer_class; +VALUE oj_stringio_class; +VALUE oj_struct_class; + +VALUE oj_slash_string; + +VALUE oj_allow_nan_sym; +VALUE oj_array_class_sym; +VALUE oj_create_additions_sym; +VALUE oj_decimal_class_sym; +VALUE oj_hash_class_sym; +VALUE oj_indent_sym; +VALUE oj_object_class_sym; +VALUE oj_quirks_mode_sym; +VALUE oj_safe_sym; +VALUE oj_trace_sym; + +static VALUE allow_blank_sym; +static VALUE allow_gc_sym; +static VALUE allow_invalid_unicode_sym; +static VALUE ascii_sym; +static VALUE auto_define_sym; +static VALUE auto_sym; +static VALUE bigdecimal_as_decimal_sym; +static VALUE bigdecimal_load_sym; +static VALUE bigdecimal_sym; +static VALUE circular_sym; +static VALUE class_cache_sym; +static VALUE compat_bigdecimal_sym; +static VALUE compat_sym; +static VALUE create_id_sym; +static VALUE custom_sym; +static VALUE empty_string_sym; +static VALUE escape_mode_sym; +static VALUE integer_range_sym; +static VALUE fast_sym; +static VALUE float_prec_sym; +static VALUE float_sym; +static VALUE huge_sym; +static VALUE ignore_sym; +static VALUE ignore_under_sym; +static VALUE json_sym; +static VALUE match_string_sym; +static VALUE mode_sym; +static VALUE nan_sym; +static VALUE newline_sym; +static VALUE nilnil_sym; +static VALUE null_sym; +static VALUE object_sym; +static VALUE omit_nil_sym; +static VALUE rails_sym; +static VALUE raise_sym; +static VALUE ruby_sym; +static VALUE sec_prec_sym; +static VALUE strict_sym; +static VALUE symbol_keys_sym; +static VALUE time_format_sym; +static VALUE unicode_xss_sym; +static VALUE unix_sym; +static VALUE unix_zone_sym; +static VALUE use_as_json_sym; +static VALUE use_raw_json_sym; +static VALUE use_to_hash_sym; +static VALUE use_to_json_sym; +static VALUE wab_sym; +static VALUE word_sym; +static VALUE xmlschema_sym; +static VALUE xss_safe_sym; + +rb_encoding *oj_utf8_encoding = 0; #ifdef HAVE_PTHREAD_MUTEX_INIT -pthread_mutex_t oj_cache_mutex; +pthread_mutex_t oj_cache_mutex; #else VALUE oj_cache_mutex = Qnil; #endif -const char oj_json_class[] = "json_class"; - -struct _options oj_default_options = { - 0, // indent - No, // circular - No, // auto_define - No, // sym_key - JSONEsc, // escape_mode - ObjectMode, // mode - Yes, // class_cache - UnixTime, // time_format - NotSet, // bigdec_as_num - AutoDec, // bigdec_load - false, // compat_bigdec - No, // to_hash - No, // to_json - No, // as_json - No, // raw_json - No, // nilnil - Yes, // empty_string - Yes, // allow_gc - Yes, // quirks_mode - No, // allow_invalid - No, // create_ok - Yes, // allow_nan - No, // trace - No, // safe - false, // sec_prec_set - No, // ignore_under - 0, // int_range_min - 0, // int_range_max - oj_json_class, // create_id - 10, // create_id_len - 9, // sec_prec - 16, // float_prec - "%0.15g", // float_fmt - Qnil, // hash_class - Qnil, // array_class - { - // dump_opts - false, //use - "", // indent - "", // before_sep - "", // after_sep - "", // hash_nl - "", // array_nl - 0, // indent_size - 0, // before_size - 0, // after_size - 0, // hash_size - 0, // array_size - AutoNan, // nan_dump - false, // omit_nil - MAX_DEPTH, // max_depth +const char oj_json_class[] = "json_class"; + +struct _options oj_default_options = { + 0, // indent + No, // circular + No, // auto_define + No, // sym_key + JSONEsc, // escape_mode + ObjectMode, // mode + Yes, // class_cache + UnixTime, // time_format + NotSet, // bigdec_as_num + AutoDec, // bigdec_load + false, // compat_bigdec + No, // to_hash + No, // to_json + No, // as_json + No, // raw_json + No, // nilnil + Yes, // empty_string + Yes, // allow_gc + Yes, // quirks_mode + No, // allow_invalid + No, // create_ok + Yes, // allow_nan + No, // trace + No, // safe + false, // sec_prec_set + No, // ignore_under + 0, // int_range_min + 0, // int_range_max + oj_json_class, // create_id + 10, // create_id_len + 9, // sec_prec + 16, // float_prec + "%0.15g", // float_fmt + Qnil, // hash_class + Qnil, // array_class + { // dump_opts + false, //use + "", // indent + "", // before_sep + "", // after_sep + "", // hash_nl + "", // array_nl + 0, // indent_size + 0, // before_size + 0, // after_size + 0, // hash_size + 0, // array_size + AutoNan,// nan_dump + false, // omit_nil + MAX_DEPTH, // max_depth }, - { - // str_rx - NULL, // head - NULL, // tail - { '\0' }, // err + { // str_rx + NULL, // head + NULL, // tail + { '\0' }, // err }, - NULL, // ignore + NULL, // ignore }; /* Document-method: default_options() @@ -267,12 +266,12 @@ struct _options oj_default_options = { */ static VALUE get_def_opts(VALUE self) { - VALUE opts = rb_hash_new(); + VALUE opts = rb_hash_new(); if (0 == oj_default_options.dump_opts.indent_size) { - rb_hash_aset(opts, oj_indent_sym, INT2FIX(oj_default_options.indent)); + rb_hash_aset(opts, oj_indent_sym, INT2FIX(oj_default_options.indent)); } else { - rb_hash_aset(opts, oj_indent_sym, rb_str_new2(oj_default_options.dump_opts.indent_str)); + rb_hash_aset(opts, oj_indent_sym, rb_str_new2(oj_default_options.dump_opts.indent_str)); } rb_hash_aset(opts, sec_prec_sym, INT2FIX(oj_default_options.sec_prec)); rb_hash_aset(opts, circular_sym, (Yes == oj_default_options.circular) ? Qtrue : ((No == oj_default_options.circular) ? Qfalse : Qnil)); @@ -296,92 +295,48 @@ get_def_opts(VALUE self) { rb_hash_aset(opts, float_prec_sym, INT2FIX(oj_default_options.float_prec)); rb_hash_aset(opts, ignore_under_sym, (Yes == oj_default_options.ignore_under) ? Qtrue : ((No == oj_default_options.ignore_under) ? Qfalse : Qnil)); switch (oj_default_options.mode) { - case StrictMode: - rb_hash_aset(opts, mode_sym, strict_sym); - break; - case CompatMode: - rb_hash_aset(opts, mode_sym, compat_sym); - break; - case NullMode: - rb_hash_aset(opts, mode_sym, null_sym); - break; - case ObjectMode: - rb_hash_aset(opts, mode_sym, object_sym); - break; - case CustomMode: - rb_hash_aset(opts, mode_sym, custom_sym); - break; - case RailsMode: - rb_hash_aset(opts, mode_sym, rails_sym); - break; - case WabMode: - rb_hash_aset(opts, mode_sym, wab_sym); - break; - default: - rb_hash_aset(opts, mode_sym, object_sym); - break; + case StrictMode: rb_hash_aset(opts, mode_sym, strict_sym); break; + case CompatMode: rb_hash_aset(opts, mode_sym, compat_sym); break; + case NullMode: rb_hash_aset(opts, mode_sym, null_sym); break; + case ObjectMode: rb_hash_aset(opts, mode_sym, object_sym); break; + case CustomMode: rb_hash_aset(opts, mode_sym, custom_sym); break; + case RailsMode: rb_hash_aset(opts, mode_sym, rails_sym); break; + case WabMode: rb_hash_aset(opts, mode_sym, wab_sym); break; + default: rb_hash_aset(opts, mode_sym, object_sym); break; } if (oj_default_options.int_range_max != 0 || oj_default_options.int_range_min != 0) { - VALUE range = rb_obj_alloc(rb_cRange); - VALUE min = LONG2FIX(oj_default_options.int_range_min); - VALUE max = LONG2FIX(oj_default_options.int_range_max); + VALUE range = rb_obj_alloc(rb_cRange); + VALUE min = LONG2FIX(oj_default_options.int_range_min); + VALUE max = LONG2FIX(oj_default_options.int_range_max); - rb_ivar_set(range, oj_begin_id, min); - rb_ivar_set(range, oj_end_id, max); - rb_hash_aset(opts, integer_range_sym, range); + rb_ivar_set(range, oj_begin_id, min); + rb_ivar_set(range, oj_end_id, max); + rb_hash_aset(opts, integer_range_sym, range); } else { - rb_hash_aset(opts, integer_range_sym, Qnil); + rb_hash_aset(opts, integer_range_sym, Qnil); } switch (oj_default_options.escape_mode) { - case NLEsc: - rb_hash_aset(opts, escape_mode_sym, newline_sym); - break; - case JSONEsc: - rb_hash_aset(opts, escape_mode_sym, json_sym); - break; - case XSSEsc: - rb_hash_aset(opts, escape_mode_sym, xss_safe_sym); - break; - case ASCIIEsc: - rb_hash_aset(opts, escape_mode_sym, ascii_sym); - break; - case JXEsc: - rb_hash_aset(opts, escape_mode_sym, unicode_xss_sym); - break; - default: - rb_hash_aset(opts, escape_mode_sym, json_sym); - break; + case NLEsc: rb_hash_aset(opts, escape_mode_sym, newline_sym); break; + case JSONEsc: rb_hash_aset(opts, escape_mode_sym, json_sym); break; + case XSSEsc: rb_hash_aset(opts, escape_mode_sym, xss_safe_sym); break; + case ASCIIEsc: rb_hash_aset(opts, escape_mode_sym, ascii_sym); break; + case JXEsc: rb_hash_aset(opts, escape_mode_sym, unicode_xss_sym); break; + default: rb_hash_aset(opts, escape_mode_sym, json_sym); break; } switch (oj_default_options.time_format) { - case XmlTime: - rb_hash_aset(opts, time_format_sym, xmlschema_sym); - break; - case RubyTime: - rb_hash_aset(opts, time_format_sym, ruby_sym); - break; - case UnixZTime: - rb_hash_aset(opts, time_format_sym, unix_zone_sym); - break; - case UnixTime: - default: - rb_hash_aset(opts, time_format_sym, unix_sym); - break; + case XmlTime: rb_hash_aset(opts, time_format_sym, xmlschema_sym); break; + case RubyTime: rb_hash_aset(opts, time_format_sym, ruby_sym); break; + case UnixZTime: rb_hash_aset(opts, time_format_sym, unix_zone_sym); break; + case UnixTime: + default: rb_hash_aset(opts, time_format_sym, unix_sym); break; } switch (oj_default_options.bigdec_load) { - case BigDec: - rb_hash_aset(opts, bigdecimal_load_sym, bigdecimal_sym); - break; - case FloatDec: - rb_hash_aset(opts, bigdecimal_load_sym, float_sym); - break; - case FastDec: - rb_hash_aset(opts, bigdecimal_load_sym, fast_sym); - break; - case AutoDec: - default: - rb_hash_aset(opts, bigdecimal_load_sym, auto_sym); - break; + case BigDec: rb_hash_aset(opts, bigdecimal_load_sym, bigdecimal_sym);break; + case FloatDec: rb_hash_aset(opts, bigdecimal_load_sym, float_sym); break; + case FastDec: rb_hash_aset(opts, bigdecimal_load_sym, fast_sym); break; + case AutoDec: + default: rb_hash_aset(opts, bigdecimal_load_sym, auto_sym); break; } rb_hash_aset(opts, compat_bigdecimal_sym, oj_default_options.compat_bigdec ? Qtrue : Qfalse); rb_hash_aset(opts, create_id_sym, (NULL == oj_default_options.create_id) ? Qnil : rb_str_new2(oj_default_options.create_id)); @@ -391,37 +346,27 @@ get_def_opts(VALUE self) { rb_hash_aset(opts, oj_array_nl_sym, (0 == oj_default_options.dump_opts.array_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.array_nl)); switch (oj_default_options.dump_opts.nan_dump) { - case NullNan: - rb_hash_aset(opts, nan_sym, null_sym); - break; - case RaiseNan: - rb_hash_aset(opts, nan_sym, raise_sym); - break; - case WordNan: - rb_hash_aset(opts, nan_sym, word_sym); - break; - case HugeNan: - rb_hash_aset(opts, nan_sym, huge_sym); - break; - case AutoNan: - default: - rb_hash_aset(opts, nan_sym, auto_sym); - break; + case NullNan: rb_hash_aset(opts, nan_sym, null_sym); break; + case RaiseNan: rb_hash_aset(opts, nan_sym, raise_sym); break; + case WordNan: rb_hash_aset(opts, nan_sym, word_sym); break; + case HugeNan: rb_hash_aset(opts, nan_sym, huge_sym); break; + case AutoNan: + default: rb_hash_aset(opts, nan_sym, auto_sym); break; } rb_hash_aset(opts, omit_nil_sym, oj_default_options.dump_opts.omit_nil ? Qtrue : Qfalse); rb_hash_aset(opts, oj_hash_class_sym, oj_default_options.hash_class); rb_hash_aset(opts, oj_array_class_sym, oj_default_options.array_class); if (NULL == oj_default_options.ignore) { - rb_hash_aset(opts, ignore_sym, Qnil); + rb_hash_aset(opts, ignore_sym, Qnil); } else { - VALUE *vp; - volatile VALUE a = rb_ary_new(); + VALUE *vp; + volatile VALUE a = rb_ary_new(); - for (vp = oj_default_options.ignore; Qnil != *vp; vp++) { - rb_ary_push(a, *vp); - } - rb_hash_aset(opts, ignore_sym, a); + for (vp = oj_default_options.ignore; Qnil != *vp; vp++) { + rb_ary_push(a, *vp); + } + rb_hash_aset(opts, ignore_sym, a); } return opts; } @@ -479,402 +424,402 @@ set_def_opts(VALUE self, VALUE opts) { void oj_parse_options(VALUE ropts, Options copts) { - struct _yesNoOpt ynos[] = { - { circular_sym, &copts->circular }, - { auto_define_sym, &copts->auto_define }, - { symbol_keys_sym, &copts->sym_key }, - { class_cache_sym, &copts->class_cache }, - { bigdecimal_as_decimal_sym, &copts->bigdec_as_num }, - { use_to_hash_sym, &copts->to_hash }, - { use_to_json_sym, &copts->to_json }, - { use_as_json_sym, &copts->as_json }, - { use_raw_json_sym, &copts->raw_json }, - { nilnil_sym, &copts->nilnil }, - { allow_blank_sym, &copts->nilnil }, // same as nilnil - { empty_string_sym, &copts->empty_string }, - { allow_gc_sym, &copts->allow_gc }, - { oj_quirks_mode_sym, &copts->quirks_mode }, - { allow_invalid_unicode_sym, &copts->allow_invalid }, - { oj_allow_nan_sym, &copts->allow_nan }, - { oj_trace_sym, &copts->trace }, - { oj_safe_sym, &copts->safe }, - { ignore_under_sym, &copts->ignore_under }, - { oj_create_additions_sym, &copts->create_ok }, - { Qnil, 0 } + struct _yesNoOpt ynos[] = { + { circular_sym, &copts->circular }, + { auto_define_sym, &copts->auto_define }, + { symbol_keys_sym, &copts->sym_key }, + { class_cache_sym, &copts->class_cache }, + { bigdecimal_as_decimal_sym, &copts->bigdec_as_num }, + { use_to_hash_sym, &copts->to_hash }, + { use_to_json_sym, &copts->to_json }, + { use_as_json_sym, &copts->as_json }, + { use_raw_json_sym, &copts->raw_json }, + { nilnil_sym, &copts->nilnil }, + { allow_blank_sym, &copts->nilnil }, // same as nilnil + { empty_string_sym, &copts->empty_string }, + { allow_gc_sym, &copts->allow_gc }, + { oj_quirks_mode_sym, &copts->quirks_mode }, + { allow_invalid_unicode_sym, &copts->allow_invalid }, + { oj_allow_nan_sym, &copts->allow_nan }, + { oj_trace_sym, &copts->trace }, + { oj_safe_sym, &copts->safe }, + { ignore_under_sym, &copts->ignore_under }, + { oj_create_additions_sym, &copts->create_ok }, + { Qnil, 0 } }; - YesNoOpt o; - volatile VALUE v; - size_t len; + YesNoOpt o; + volatile VALUE v; + size_t len; if (T_HASH != rb_type(ropts)) { - return; + return; } if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_indent_sym)) { - v = rb_hash_lookup(ropts, oj_indent_sym); - switch (rb_type(v)) { - case T_NIL: - copts->dump_opts.indent_size = 0; - *copts->dump_opts.indent_str = '\0'; - copts->indent = 0; - break; - case T_FIXNUM: - copts->dump_opts.indent_size = 0; - *copts->dump_opts.indent_str = '\0'; - copts->indent = FIX2INT(v); - break; - case T_STRING: - if (sizeof(copts->dump_opts.indent_str) <= (len = RSTRING_LEN(v))) { - rb_raise(rb_eArgError, "indent string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.indent_str)); - } - strcpy(copts->dump_opts.indent_str, StringValuePtr(v)); - copts->dump_opts.indent_size = (uint8_t)len; - copts->indent = 0; - break; - default: - rb_raise(rb_eTypeError, "indent must be a Fixnum, String, or nil."); - break; - } + v = rb_hash_lookup(ropts, oj_indent_sym); + switch (rb_type(v)) { + case T_NIL: + copts->dump_opts.indent_size = 0; + *copts->dump_opts.indent_str = '\0'; + copts->indent = 0; + break; + case T_FIXNUM: + copts->dump_opts.indent_size = 0; + *copts->dump_opts.indent_str = '\0'; + copts->indent = FIX2INT(v); + break; + case T_STRING: + if (sizeof(copts->dump_opts.indent_str) <= (len = RSTRING_LEN(v))) { + rb_raise(rb_eArgError, "indent string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.indent_str)); + } + strcpy(copts->dump_opts.indent_str, StringValuePtr(v)); + copts->dump_opts.indent_size = (uint8_t)len; + copts->indent = 0; + break; + default: + rb_raise(rb_eTypeError, "indent must be a Fixnum, String, or nil."); + break; + } } if (Qnil != (v = rb_hash_lookup(ropts, float_prec_sym))) { - int n; + int n; #ifdef RUBY_INTEGER_UNIFICATION - if (rb_cInteger != rb_obj_class(v)) { - rb_raise(rb_eArgError, ":float_precision must be a Integer."); - } + if (rb_cInteger != rb_obj_class(v)) { + rb_raise(rb_eArgError, ":float_precision must be a Integer."); + } #else - if (T_FIXNUM != rb_type(v)) { - rb_raise(rb_eArgError, ":float_precision must be a Fixnum."); - } + if (T_FIXNUM != rb_type(v)) { + rb_raise(rb_eArgError, ":float_precision must be a Fixnum."); + } #endif - n = FIX2INT(v); - if (0 >= n) { - *copts->float_fmt = '\0'; - copts->float_prec = 0; - } else { - if (20 < n) { - n = 20; - } - sprintf(copts->float_fmt, "%%0.%dg", n); - copts->float_prec = n; - } + n = FIX2INT(v); + if (0 >= n) { + *copts->float_fmt = '\0'; + copts->float_prec = 0; + } else { + if (20 < n) { + n = 20; + } + sprintf(copts->float_fmt, "%%0.%dg", n); + copts->float_prec = n; + } } if (Qnil != (v = rb_hash_lookup(ropts, sec_prec_sym))) { - int n; + int n; #ifdef RUBY_INTEGER_UNIFICATION - if (rb_cInteger != rb_obj_class(v)) { - rb_raise(rb_eArgError, ":second_precision must be a Integer."); - } + if (rb_cInteger != rb_obj_class(v)) { + rb_raise(rb_eArgError, ":second_precision must be a Integer."); + } #else - if (T_FIXNUM != rb_type(v)) { - rb_raise(rb_eArgError, ":second_precision must be a Fixnum."); - } + if (T_FIXNUM != rb_type(v)) { + rb_raise(rb_eArgError, ":second_precision must be a Fixnum."); + } #endif - n = NUM2INT(v); - if (0 > n) { - n = 0; - copts->sec_prec_set = false; - } else if (9 < n) { - n = 9; - copts->sec_prec_set = true; - } else { - copts->sec_prec_set = true; - } - copts->sec_prec = n; + n = NUM2INT(v); + if (0 > n) { + n = 0; + copts->sec_prec_set = false; + } else if (9 < n) { + n = 9; + copts->sec_prec_set = true; + } else { + copts->sec_prec_set = true; + } + copts->sec_prec = n; } if (Qnil != (v = rb_hash_lookup(ropts, mode_sym))) { - if (wab_sym == v) { - copts->mode = WabMode; - } else if (object_sym == v) { - copts->mode = ObjectMode; - } else if (strict_sym == v) { - copts->mode = StrictMode; - } else if (compat_sym == v || json_sym == v) { - copts->mode = CompatMode; - } else if (null_sym == v) { - copts->mode = NullMode; - } else if (custom_sym == v) { - copts->mode = CustomMode; - } else if (rails_sym == v) { - copts->mode = RailsMode; - } else { - rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, :null, :custom, :rails, or :wab."); - } + if (wab_sym == v) { + copts->mode = WabMode; + } else if (object_sym == v) { + copts->mode = ObjectMode; + } else if (strict_sym == v) { + copts->mode = StrictMode; + } else if (compat_sym == v || json_sym == v) { + copts->mode = CompatMode; + } else if (null_sym == v) { + copts->mode = NullMode; + } else if (custom_sym == v) { + copts->mode = CustomMode; + } else if (rails_sym == v) { + copts->mode = RailsMode; + } else { + rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, :null, :custom, :rails, or :wab."); + } } if (Qnil != (v = rb_hash_lookup(ropts, time_format_sym))) { - if (unix_sym == v) { - copts->time_format = UnixTime; - } else if (unix_zone_sym == v) { - copts->time_format = UnixZTime; - } else if (xmlschema_sym == v) { - copts->time_format = XmlTime; - } else if (ruby_sym == v) { - copts->time_format = RubyTime; - } else { - rb_raise(rb_eArgError, ":time_format must be :unix, :unix_zone, :xmlschema, or :ruby."); - } + if (unix_sym == v) { + copts->time_format = UnixTime; + } else if (unix_zone_sym == v) { + copts->time_format = UnixZTime; + } else if (xmlschema_sym == v) { + copts->time_format = XmlTime; + } else if (ruby_sym == v) { + copts->time_format = RubyTime; + } else { + rb_raise(rb_eArgError, ":time_format must be :unix, :unix_zone, :xmlschema, or :ruby."); + } } if (Qnil != (v = rb_hash_lookup(ropts, escape_mode_sym))) { - if (newline_sym == v) { - copts->escape_mode = NLEsc; - } else if (json_sym == v) { - copts->escape_mode = JSONEsc; - } else if (xss_safe_sym == v) { - copts->escape_mode = XSSEsc; - } else if (ascii_sym == v) { - copts->escape_mode = ASCIIEsc; - } else if (unicode_xss_sym == v) { - copts->escape_mode = JXEsc; - } else { - rb_raise(rb_eArgError, ":encoding must be :newline, :json, :xss_safe, :unicode_xss, or :ascii."); - } + if (newline_sym == v) { + copts->escape_mode = NLEsc; + } else if (json_sym == v) { + copts->escape_mode = JSONEsc; + } else if (xss_safe_sym == v) { + copts->escape_mode = XSSEsc; + } else if (ascii_sym == v) { + copts->escape_mode = ASCIIEsc; + } else if (unicode_xss_sym == v) { + copts->escape_mode = JXEsc; + } else { + rb_raise(rb_eArgError, ":encoding must be :newline, :json, :xss_safe, :unicode_xss, or :ascii."); + } } if (Qnil != (v = rb_hash_lookup(ropts, bigdecimal_load_sym))) { - if (bigdecimal_sym == v || Qtrue == v) { - copts->bigdec_load = BigDec; - } else if (float_sym == v) { - copts->bigdec_load = FloatDec; - } else if (fast_sym == v) { - copts->bigdec_load = FastDec; - } else if (auto_sym == v || Qfalse == v) { - copts->bigdec_load = AutoDec; - } else { - rb_raise(rb_eArgError, ":bigdecimal_load must be :bigdecimal, :float, or :auto."); - } + if (bigdecimal_sym == v || Qtrue == v) { + copts->bigdec_load = BigDec; + } else if (float_sym == v) { + copts->bigdec_load = FloatDec; + } else if (fast_sym == v) { + copts->bigdec_load = FastDec; + } else if (auto_sym == v || Qfalse == v) { + copts->bigdec_load = AutoDec; + } else { + rb_raise(rb_eArgError, ":bigdecimal_load must be :bigdecimal, :float, or :auto."); + } } if (Qnil != (v = rb_hash_lookup(ropts, compat_bigdecimal_sym))) { - copts->compat_bigdec = (Qtrue == v); + copts->compat_bigdec = (Qtrue == v); } if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_decimal_class_sym)) { - v = rb_hash_lookup(ropts, oj_decimal_class_sym); - if (rb_cFloat == v) { - copts->compat_bigdec = false; - } else if (oj_bigdecimal_class == v) { - copts->compat_bigdec = true; - } else { - rb_raise(rb_eArgError, ":decimal_class must be BigDecimal or Float."); - } - } + v = rb_hash_lookup(ropts, oj_decimal_class_sym); + if (rb_cFloat == v) { + copts->compat_bigdec = false; + } else if (oj_bigdecimal_class == v) { + copts->compat_bigdec = true; + } else { + rb_raise(rb_eArgError, ":decimal_class must be BigDecimal or Float."); + } + } if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, create_id_sym)) { - v = rb_hash_lookup(ropts, create_id_sym); - if (Qnil == v) { - if (oj_json_class != oj_default_options.create_id && NULL != copts->create_id) { - xfree((char *)oj_default_options.create_id); - } - copts->create_id = NULL; - copts->create_id_len = 0; - } else if (T_STRING == rb_type(v)) { - const char *str = StringValuePtr(v); - - len = RSTRING_LEN(v); - if (len != copts->create_id_len || - 0 != strcmp(copts->create_id, str)) { - copts->create_id = ALLOC_N(char, len + 1); - strcpy((char *)copts->create_id, str); - copts->create_id_len = len; - } - } else { - rb_raise(rb_eArgError, ":create_id must be string."); - } + v = rb_hash_lookup(ropts, create_id_sym); + if (Qnil == v) { + if (oj_json_class != oj_default_options.create_id && NULL != copts->create_id) { + xfree((char*)oj_default_options.create_id); + } + copts->create_id = NULL; + copts->create_id_len = 0; + } else if (T_STRING == rb_type(v)) { + const char *str = StringValuePtr(v); + + len = RSTRING_LEN(v); + if (len != copts->create_id_len || + 0 != strcmp(copts->create_id, str)) { + copts->create_id = ALLOC_N(char, len + 1); + strcpy((char*)copts->create_id, str); + copts->create_id_len = len; + } + } else { + rb_raise(rb_eArgError, ":create_id must be string."); + } } for (o = ynos; 0 != o->attr; o++) { - if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, o->sym)) { - v = rb_hash_lookup(ropts, o->sym); - if (Qnil == v) { - *o->attr = NotSet; - } else if (Qtrue == v) { - *o->attr = Yes; - } else if (Qfalse == v) { - *o->attr = No; - } else { - rb_raise(rb_eArgError, "%s must be true, false, or nil.", rb_id2name(SYM2ID(o->sym))); - } - } + if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, o->sym)) { + v = rb_hash_lookup(ropts, o->sym); + if (Qnil == v) { + *o->attr = NotSet; + } else if (Qtrue == v) { + *o->attr = Yes; + } else if (Qfalse == v) { + *o->attr = No; + } else { + rb_raise(rb_eArgError, "%s must be true, false, or nil.", rb_id2name(SYM2ID(o->sym))); + } + } } if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_space_sym)) { - if (Qnil == (v = rb_hash_lookup(ropts, oj_space_sym))) { - copts->dump_opts.after_size = 0; - *copts->dump_opts.after_sep = '\0'; - } else { - rb_check_type(v, T_STRING); - if (sizeof(copts->dump_opts.after_sep) <= (len = RSTRING_LEN(v))) { - rb_raise(rb_eArgError, "space string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.after_sep)); - } - strcpy(copts->dump_opts.after_sep, StringValuePtr(v)); - copts->dump_opts.after_size = (uint8_t)len; - } + if (Qnil == (v = rb_hash_lookup(ropts, oj_space_sym))) { + copts->dump_opts.after_size = 0; + *copts->dump_opts.after_sep = '\0'; + } else { + rb_check_type(v, T_STRING); + if (sizeof(copts->dump_opts.after_sep) <= (len = RSTRING_LEN(v))) { + rb_raise(rb_eArgError, "space string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.after_sep)); + } + strcpy(copts->dump_opts.after_sep, StringValuePtr(v)); + copts->dump_opts.after_size = (uint8_t)len; + } } if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_space_before_sym)) { - if (Qnil == (v = rb_hash_lookup(ropts, oj_space_before_sym))) { - copts->dump_opts.before_size = 0; - *copts->dump_opts.before_sep = '\0'; - } else { - rb_check_type(v, T_STRING); - if (sizeof(copts->dump_opts.before_sep) <= (len = RSTRING_LEN(v))) { - rb_raise(rb_eArgError, "sapce_before string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.before_sep)); - } - strcpy(copts->dump_opts.before_sep, StringValuePtr(v)); - copts->dump_opts.before_size = (uint8_t)len; - } + if (Qnil == (v = rb_hash_lookup(ropts, oj_space_before_sym))) { + copts->dump_opts.before_size = 0; + *copts->dump_opts.before_sep = '\0'; + } else { + rb_check_type(v, T_STRING); + if (sizeof(copts->dump_opts.before_sep) <= (len = RSTRING_LEN(v))) { + rb_raise(rb_eArgError, "sapce_before string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.before_sep)); + } + strcpy(copts->dump_opts.before_sep, StringValuePtr(v)); + copts->dump_opts.before_size = (uint8_t)len; + } } if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_object_nl_sym)) { - if (Qnil == (v = rb_hash_lookup(ropts, oj_object_nl_sym))) { - copts->dump_opts.hash_size = 0; - *copts->dump_opts.hash_nl = '\0'; - } else { - rb_check_type(v, T_STRING); - if (sizeof(copts->dump_opts.hash_nl) <= (len = RSTRING_LEN(v))) { - rb_raise(rb_eArgError, "object_nl string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.hash_nl)); - } - strcpy(copts->dump_opts.hash_nl, StringValuePtr(v)); - copts->dump_opts.hash_size = (uint8_t)len; - } + if (Qnil == (v = rb_hash_lookup(ropts, oj_object_nl_sym))) { + copts->dump_opts.hash_size = 0; + *copts->dump_opts.hash_nl = '\0'; + } else { + rb_check_type(v, T_STRING); + if (sizeof(copts->dump_opts.hash_nl) <= (len = RSTRING_LEN(v))) { + rb_raise(rb_eArgError, "object_nl string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.hash_nl)); + } + strcpy(copts->dump_opts.hash_nl, StringValuePtr(v)); + copts->dump_opts.hash_size = (uint8_t)len; + } } if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_array_nl_sym)) { - if (Qnil == (v = rb_hash_lookup(ropts, oj_array_nl_sym))) { - copts->dump_opts.array_size = 0; - *copts->dump_opts.array_nl = '\0'; - } else { - rb_check_type(v, T_STRING); - if (sizeof(copts->dump_opts.array_nl) <= (len = RSTRING_LEN(v))) { - rb_raise(rb_eArgError, "array_nl string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.array_nl)); - } - strcpy(copts->dump_opts.array_nl, StringValuePtr(v)); - copts->dump_opts.array_size = (uint8_t)len; - } + if (Qnil == (v = rb_hash_lookup(ropts, oj_array_nl_sym))) { + copts->dump_opts.array_size = 0; + *copts->dump_opts.array_nl = '\0'; + } else { + rb_check_type(v, T_STRING); + if (sizeof(copts->dump_opts.array_nl) <= (len = RSTRING_LEN(v))) { + rb_raise(rb_eArgError, "array_nl string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.array_nl)); + } + strcpy(copts->dump_opts.array_nl, StringValuePtr(v)); + copts->dump_opts.array_size = (uint8_t)len; + } } if (Qnil != (v = rb_hash_lookup(ropts, nan_sym))) { - if (null_sym == v) { - copts->dump_opts.nan_dump = NullNan; - } else if (huge_sym == v) { - copts->dump_opts.nan_dump = HugeNan; - } else if (word_sym == v) { - copts->dump_opts.nan_dump = WordNan; - } else if (raise_sym == v) { - copts->dump_opts.nan_dump = RaiseNan; - } else if (auto_sym == v) { - copts->dump_opts.nan_dump = AutoNan; - } else { - rb_raise(rb_eArgError, ":nan must be :null, :huge, :word, :raise, or :auto."); - } + if (null_sym == v) { + copts->dump_opts.nan_dump = NullNan; + } else if (huge_sym == v) { + copts->dump_opts.nan_dump = HugeNan; + } else if (word_sym == v) { + copts->dump_opts.nan_dump = WordNan; + } else if (raise_sym == v) { + copts->dump_opts.nan_dump = RaiseNan; + } else if (auto_sym == v) { + copts->dump_opts.nan_dump = AutoNan; + } else { + rb_raise(rb_eArgError, ":nan must be :null, :huge, :word, :raise, or :auto."); + } } copts->dump_opts.use = (0 < copts->dump_opts.indent_size || - 0 < copts->dump_opts.after_size || - 0 < copts->dump_opts.before_size || - 0 < copts->dump_opts.hash_size || - 0 < copts->dump_opts.array_size); + 0 < copts->dump_opts.after_size || + 0 < copts->dump_opts.before_size || + 0 < copts->dump_opts.hash_size || + 0 < copts->dump_opts.array_size); if (Qnil != (v = rb_hash_lookup(ropts, omit_nil_sym))) { - if (Qtrue == v) { - copts->dump_opts.omit_nil = true; - } else if (Qfalse == v) { - copts->dump_opts.omit_nil = false; - } else { - rb_raise(rb_eArgError, ":omit_nil must be true or false."); - } + if (Qtrue == v) { + copts->dump_opts.omit_nil = true; + } else if (Qfalse == v) { + copts->dump_opts.omit_nil = false; + } else { + rb_raise(rb_eArgError, ":omit_nil must be true or false."); + } } // This is here only for backwards compatibility with the original Oj. v = rb_hash_lookup(ropts, oj_ascii_only_sym); if (Qtrue == v) { - copts->escape_mode = ASCIIEsc; + copts->escape_mode = ASCIIEsc; } else if (Qfalse == v) { - copts->escape_mode = JSONEsc; + copts->escape_mode = JSONEsc; } if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_hash_class_sym)) { - if (Qnil == (v = rb_hash_lookup(ropts, oj_hash_class_sym))) { - copts->hash_class = Qnil; - } else { - rb_check_type(v, T_CLASS); - copts->hash_class = v; - } + if (Qnil == (v = rb_hash_lookup(ropts, oj_hash_class_sym))) { + copts->hash_class = Qnil; + } else { + rb_check_type(v, T_CLASS); + copts->hash_class = v; + } } if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_object_class_sym)) { - if (Qnil == (v = rb_hash_lookup(ropts, oj_object_class_sym))) { - copts->hash_class = Qnil; - } else { - rb_check_type(v, T_CLASS); - copts->hash_class = v; - } + if (Qnil == (v = rb_hash_lookup(ropts, oj_object_class_sym))) { + copts->hash_class = Qnil; + } else { + rb_check_type(v, T_CLASS); + copts->hash_class = v; + } } if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_array_class_sym)) { - if (Qnil == (v = rb_hash_lookup(ropts, oj_array_class_sym))) { - copts->array_class = Qnil; - } else { - rb_check_type(v, T_CLASS); - copts->array_class = v; - } + if (Qnil == (v = rb_hash_lookup(ropts, oj_array_class_sym))) { + copts->array_class = Qnil; + } else { + rb_check_type(v, T_CLASS); + copts->array_class = v; + } } oj_parse_opt_match_string(&copts->str_rx, ropts); if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, ignore_sym)) { - xfree(copts->ignore); - copts->ignore = NULL; - if (Qnil != (v = rb_hash_lookup(ropts, ignore_sym))) { - int cnt; - - rb_check_type(v, T_ARRAY); - cnt = (int)RARRAY_LEN(v); - if (0 < cnt) { - int i; - - copts->ignore = ALLOC_N(VALUE, cnt + 1); - for (i = 0; i < cnt; i++) { - copts->ignore[i] = rb_ary_entry(v, i); - } - copts->ignore[i] = Qnil; - } - } + xfree(copts->ignore); + copts->ignore = NULL; + if (Qnil != (v = rb_hash_lookup(ropts, ignore_sym))) { + int cnt; + + rb_check_type(v, T_ARRAY); + cnt = (int)RARRAY_LEN(v); + if (0 < cnt) { + int i; + + copts->ignore = ALLOC_N(VALUE, cnt + 1); + for (i = 0; i < cnt; i++) { + copts->ignore[i] = rb_ary_entry(v, i); + } + copts->ignore[i] = Qnil; + } + } } if (Qnil != (v = rb_hash_lookup(ropts, integer_range_sym))) { - if (TYPE(v) == T_STRUCT && rb_obj_class(v) == rb_cRange) { - VALUE min = rb_funcall(v, oj_begin_id, 0); - VALUE max = rb_funcall(v, oj_end_id, 0); - - if (TYPE(min) != T_FIXNUM || TYPE(max) != T_FIXNUM) { - rb_raise(rb_eArgError, ":integer_range range bounds is not Fixnum."); - } - - copts->int_range_min = FIX2LONG(min); - copts->int_range_max = FIX2LONG(max); - } else if (Qfalse != v) { - rb_raise(rb_eArgError, ":integer_range must be a range of Fixnum."); - } + if (TYPE(v) == T_STRUCT && rb_obj_class(v) == rb_cRange) { + VALUE min = rb_funcall(v, oj_begin_id, 0); + VALUE max = rb_funcall(v, oj_end_id, 0); + + if (TYPE(min) != T_FIXNUM || TYPE(max) != T_FIXNUM) { + rb_raise(rb_eArgError, ":integer_range range bounds is not Fixnum."); + } + + copts->int_range_min = FIX2LONG(min); + copts->int_range_max = FIX2LONG(max); + } else if (Qfalse != v) { + rb_raise(rb_eArgError, ":integer_range must be a range of Fixnum."); + } } } static int match_string_cb(VALUE key, VALUE value, VALUE rx) { - RxClass rc = (RxClass)rx; + RxClass rc = (RxClass)rx; if (T_CLASS != rb_type(value)) { - rb_raise(rb_eArgError, "for :match_string, the hash values must be a Class."); + rb_raise(rb_eArgError, "for :match_string, the hash values must be a Class."); } switch (rb_type(key)) { - case T_REGEXP: - oj_rxclass_rappend(rc, key, value); - break; - case T_STRING: - if (0 != oj_rxclass_append(rc, StringValuePtr(key), value)) { - rb_raise(rb_eArgError, "%s", rc->err); - } - break; - default: - rb_raise(rb_eArgError, "for :match_string, keys must either a String or RegExp."); - break; + case T_REGEXP: + oj_rxclass_rappend(rc, key, value); + break; + case T_STRING: + if (0 != oj_rxclass_append(rc, StringValuePtr(key), value)) { + rb_raise(rb_eArgError, "%s", rc->err); + } + break; + default: + rb_raise(rb_eArgError, "for :match_string, keys must either a String or RegExp."); + break; } return ST_CONTINUE; } void oj_parse_opt_match_string(RxClass rc, VALUE ropts) { - VALUE v; + VALUE v; if (Qnil != (v = rb_hash_lookup(ropts, match_string_sym))) { - rb_check_type(v, T_HASH); - // Zero out rc. Pattern are not appended but override. - rc->head = NULL; - rc->tail = NULL; - *rc->err = '\0'; - rb_hash_foreach(v, match_string_cb, (VALUE)rc); + rb_check_type(v, T_HASH); + // Zero out rc. Pattern are not appended but override. + rc->head = NULL; + rc->tail = NULL; + *rc->err = '\0'; + rb_hash_foreach(v, match_string_cb, (VALUE)rc); } } @@ -912,52 +857,52 @@ oj_parse_opt_match_string(RxClass rc, VALUE ropts) { */ static VALUE load(int argc, VALUE *argv, VALUE self) { - Mode mode = oj_default_options.mode; + Mode mode = oj_default_options.mode; if (1 > argc) { - rb_raise(rb_eArgError, "Wrong number of arguments to load()."); + rb_raise(rb_eArgError, "Wrong number of arguments to load()."); } if (2 <= argc) { - VALUE ropts = argv[1]; - VALUE v; - - if (Qnil != ropts || CompatMode != mode) { - Check_Type(ropts, T_HASH); - if (Qnil != (v = rb_hash_lookup(ropts, mode_sym))) { - if (object_sym == v) { - mode = ObjectMode; - } else if (strict_sym == v) { - mode = StrictMode; - } else if (compat_sym == v || json_sym == v) { - mode = CompatMode; - } else if (null_sym == v) { - mode = NullMode; - } else if (custom_sym == v) { - mode = CustomMode; - } else if (rails_sym == v) { - mode = RailsMode; - } else if (wab_sym == v) { - mode = WabMode; - } else { - rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, :null, :custom, :rails, or :wab."); - } - } - } + VALUE ropts = argv[1]; + VALUE v; + + if (Qnil != ropts || CompatMode != mode) { + Check_Type(ropts, T_HASH); + if (Qnil != (v = rb_hash_lookup(ropts, mode_sym))) { + if (object_sym == v) { + mode = ObjectMode; + } else if (strict_sym == v) { + mode = StrictMode; + } else if (compat_sym == v || json_sym == v) { + mode = CompatMode; + } else if (null_sym == v) { + mode = NullMode; + } else if (custom_sym == v) { + mode = CustomMode; + } else if (rails_sym == v) { + mode = RailsMode; + } else if (wab_sym == v) { + mode = WabMode; + } else { + rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, :null, :custom, :rails, or :wab."); + } + } + } } switch (mode) { - case StrictMode: - case NullMode: - return oj_strict_parse(argc, argv, self); - case CompatMode: - case RailsMode: - return oj_compat_parse(argc, argv, self); - case CustomMode: - return oj_custom_parse(argc, argv, self); - case WabMode: - return oj_wab_parse(argc, argv, self); - case ObjectMode: - default: - break; + case StrictMode: + case NullMode: + return oj_strict_parse(argc, argv, self); + case CompatMode: + case RailsMode: + return oj_compat_parse(argc, argv, self); + case CustomMode: + return oj_custom_parse(argc, argv, self); + case WabMode: + return oj_wab_parse(argc, argv, self); + case ObjectMode: + default: + break; } return oj_object_parse(argc, argv, self); } @@ -998,13 +943,13 @@ load(int argc, VALUE *argv, VALUE self) { */ static VALUE load_file(int argc, VALUE *argv, VALUE self) { - char *path; - int fd; - Mode mode = oj_default_options.mode; - struct _parseInfo pi; + char *path; + int fd; + Mode mode = oj_default_options.mode; + struct _parseInfo pi; if (1 > argc) { - rb_raise(rb_eArgError, "Wrong number of arguments to load()."); + rb_raise(rb_eArgError, "Wrong number of arguments to load()."); } Check_Type(*argv, T_STRING); parse_info_init(&pi); @@ -1013,52 +958,52 @@ load_file(int argc, VALUE *argv, VALUE self) { pi.err_class = Qnil; pi.max_depth = 0; if (2 <= argc) { - VALUE ropts = argv[1]; - VALUE v; - - Check_Type(ropts, T_HASH); - if (Qnil != (v = rb_hash_lookup(ropts, mode_sym))) { - if (object_sym == v) { - mode = ObjectMode; - } else if (strict_sym == v) { - mode = StrictMode; - } else if (compat_sym == v || json_sym == v) { - mode = CompatMode; - } else if (null_sym == v) { - mode = NullMode; - } else if (custom_sym == v) { - mode = CustomMode; - } else if (rails_sym == v) { - mode = RailsMode; - } else if (wab_sym == v) { - mode = WabMode; - } else { - rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, :null, :custom, :rails, or :wab."); - } - } + VALUE ropts = argv[1]; + VALUE v; + + Check_Type(ropts, T_HASH); + if (Qnil != (v = rb_hash_lookup(ropts, mode_sym))) { + if (object_sym == v) { + mode = ObjectMode; + } else if (strict_sym == v) { + mode = StrictMode; + } else if (compat_sym == v || json_sym == v) { + mode = CompatMode; + } else if (null_sym == v) { + mode = NullMode; + } else if (custom_sym == v) { + mode = CustomMode; + } else if (rails_sym == v) { + mode = RailsMode; + } else if (wab_sym == v) { + mode = WabMode; + } else { + rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, :null, :custom, :rails, or :wab."); + } + } } path = StringValuePtr(*argv); if (0 == (fd = open(path, O_RDONLY))) { - rb_raise(rb_eIOError, "%s", strerror(errno)); + rb_raise(rb_eIOError, "%s", strerror(errno)); } switch (mode) { - case StrictMode: - case NullMode: - oj_set_strict_callbacks(&pi); - return oj_pi_sparse(argc, argv, &pi, fd); - case CustomMode: - oj_set_custom_callbacks(&pi); - return oj_pi_sparse(argc, argv, &pi, fd); - case CompatMode: - case RailsMode: - oj_set_compat_callbacks(&pi); - return oj_pi_sparse(argc, argv, &pi, fd); - case WabMode: - oj_set_wab_callbacks(&pi); - return oj_pi_sparse(argc, argv, &pi, fd); - case ObjectMode: - default: - break; + case StrictMode: + case NullMode: + oj_set_strict_callbacks(&pi); + return oj_pi_sparse(argc, argv, &pi, fd); + case CustomMode: + oj_set_custom_callbacks(&pi); + return oj_pi_sparse(argc, argv, &pi, fd); + case CompatMode: + case RailsMode: + oj_set_compat_callbacks(&pi); + return oj_pi_sparse(argc, argv, &pi, fd); + case WabMode: + oj_set_wab_callbacks(&pi); + return oj_pi_sparse(argc, argv, &pi, fd); + case ObjectMode: + default: + break; } oj_set_object_callbacks(&pi); @@ -1078,8 +1023,8 @@ load_file(int argc, VALUE *argv, VALUE self) { */ static VALUE safe_load(VALUE self, VALUE doc) { - struct _parseInfo pi; - VALUE args[1]; + struct _parseInfo pi; + VALUE args[1]; parse_info_init(&pi); pi.err_class = Qnil; @@ -1129,36 +1074,36 @@ safe_load(VALUE self, VALUE doc) { */ static VALUE dump(int argc, VALUE *argv, VALUE self) { - char buf[4096]; - struct _out out; - struct _options copts = oj_default_options; - VALUE rstr; + char buf[4096]; + struct _out out; + struct _options copts = oj_default_options; + VALUE rstr; if (1 > argc) { - rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)."); + rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)."); } if (CompatMode == copts.mode) { - copts.dump_opts.nan_dump = WordNan; + copts.dump_opts.nan_dump = WordNan; } if (2 == argc) { - oj_parse_options(argv[1], &copts); + oj_parse_options(argv[1], &copts); } if (CompatMode == copts.mode && copts.escape_mode != ASCIIEsc) { - copts.escape_mode = JSONEsc; + copts.escape_mode = JSONEsc; } out.buf = buf; out.end = buf + sizeof(buf) - 10; out.allocated = false; out.omit_nil = copts.dump_opts.omit_nil; out.caller = CALLER_DUMP; - oj_dump_obj_to_json_using_params(*argv, &copts, &out, argc - 1, argv + 1); + oj_dump_obj_to_json_using_params(*argv, &copts, &out, argc - 1,argv + 1); if (0 == out.buf) { - rb_raise(rb_eNoMemError, "Not enough memory."); + rb_raise(rb_eNoMemError, "Not enough memory."); } rstr = rb_str_new2(out.buf); rstr = oj_encode(rstr); if (out.allocated) { - xfree(out.buf); + xfree(out.buf); } return rstr; } @@ -1184,18 +1129,18 @@ dump(int argc, VALUE *argv, VALUE self) { */ static VALUE to_json(int argc, VALUE *argv, VALUE self) { - char buf[4096]; - struct _out out; - struct _options copts = oj_default_options; - VALUE rstr; + char buf[4096]; + struct _out out; + struct _options copts = oj_default_options; + VALUE rstr; if (1 > argc) { - rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)."); + rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)."); } copts.escape_mode = JXEsc; copts.dump_opts.nan_dump = RaiseNan; if (2 == argc) { - oj_parse_mimic_dump_options(argv[1], &copts); + oj_parse_mimic_dump_options(argv[1], &copts); } copts.mode = CompatMode; copts.to_json = Yes; @@ -1208,12 +1153,12 @@ to_json(int argc, VALUE *argv, VALUE self) { oj_dump_obj_to_json_using_params(*argv, &copts, &out, argc - 1, argv + 1); if (0 == out.buf) { - rb_raise(rb_eNoMemError, "Not enough memory."); + rb_raise(rb_eNoMemError, "Not enough memory."); } rstr = rb_str_new2(out.buf); rstr = oj_encode(rstr); if (out.allocated) { - xfree(out.buf); + xfree(out.buf); } return rstr; } @@ -1230,10 +1175,10 @@ to_json(int argc, VALUE *argv, VALUE self) { */ static VALUE to_file(int argc, VALUE *argv, VALUE self) { - struct _options copts = oj_default_options; + struct _options copts = oj_default_options; if (3 == argc) { - oj_parse_options(argv[2], &copts); + oj_parse_options(argv[2], &copts); } Check_Type(*argv, T_STRING); oj_write_obj_to_file(argv[1], StringValuePtr(*argv), &copts); @@ -1253,10 +1198,10 @@ to_file(int argc, VALUE *argv, VALUE self) { */ static VALUE to_stream(int argc, VALUE *argv, VALUE self) { - struct _options copts = oj_default_options; + struct _options copts = oj_default_options; if (3 == argc) { - oj_parse_options(argv[2], &copts); + oj_parse_options(argv[2], &copts); } oj_write_obj_to_stream(argv[1], *argv, &copts); @@ -1280,19 +1225,19 @@ to_stream(int argc, VALUE *argv, VALUE self) { static VALUE register_odd(int argc, VALUE *argv, VALUE self) { if (3 > argc) { - rb_raise(rb_eArgError, "incorrect number of arguments."); + rb_raise(rb_eArgError, "incorrect number of arguments."); } switch (rb_type(*argv)) { - case T_CLASS: - case T_MODULE: - break; - default: - rb_raise(rb_eTypeError, "expected a class or module."); - break; + case T_CLASS: + case T_MODULE: + break; + default: + rb_raise(rb_eTypeError, "expected a class or module."); + break; } Check_Type(argv[2], T_SYMBOL); if (MAX_ODD_ARGS < argc - 2) { - rb_raise(rb_eArgError, "too many members."); + rb_raise(rb_eArgError, "too many members."); } oj_reg_odd(argv[0], argv[1], argv[2], argc - 3, argv + 3, false); @@ -1318,19 +1263,19 @@ register_odd(int argc, VALUE *argv, VALUE self) { static VALUE register_odd_raw(int argc, VALUE *argv, VALUE self) { if (3 > argc) { - rb_raise(rb_eArgError, "incorrect number of arguments."); + rb_raise(rb_eArgError, "incorrect number of arguments."); } switch (rb_type(*argv)) { - case T_CLASS: - case T_MODULE: - break; - default: - rb_raise(rb_eTypeError, "expected a class or module."); - break; + case T_CLASS: + case T_MODULE: + break; + default: + rb_raise(rb_eTypeError, "expected a class or module."); + break; } Check_Type(argv[2], T_SYMBOL); if (MAX_ODD_ARGS < argc - 2) { - rb_raise(rb_eArgError, "too many members."); + rb_raise(rb_eArgError, "too many members."); } oj_reg_odd(argv[0], argv[1], argv[2], 1, argv + 3, true); @@ -1376,7 +1321,7 @@ register_odd_raw(int argc, VALUE *argv, VALUE self) { * * Returns [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] */ -extern VALUE oj_strict_parse(int argc, VALUE *argv, VALUE self); +extern VALUE oj_strict_parse(int argc, VALUE *argv, VALUE self); /* Document-method: compat_load * call-seq: compat_load(json, options) { _|_obj, start, len_|_ } @@ -1410,7 +1355,7 @@ extern VALUE oj_strict_parse(int argc, VALUE *argv, VALUE self); * * Returns [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] */ -extern VALUE oj_compat_parse(int argc, VALUE *argv, VALUE self); +extern VALUE oj_compat_parse(int argc, VALUE *argv, VALUE self); /* Document-method: object_load * call-seq: object_load(json, options) { _|_obj, start, len_|_ } @@ -1440,7 +1385,7 @@ extern VALUE oj_compat_parse(int argc, VALUE *argv, VALUE self); * * Returns [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] */ -extern VALUE oj_object_parse(int argc, VALUE *argv, VALUE self); +extern VALUE oj_object_parse(int argc, VALUE *argv, VALUE self); /* Document-method: wab_load * call-seq: wab_load(json, options) { _|_obj, start, len_|_ } @@ -1475,7 +1420,7 @@ extern VALUE oj_object_parse(int argc, VALUE *argv, VALUE self); * * Returns [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] */ -extern VALUE oj_wab_parse(int argc, VALUE *argv, VALUE self); +extern VALUE oj_wab_parse(int argc, VALUE *argv, VALUE self); /* Document-method: add_to_json * call-seq: add_to_json(*args) @@ -1492,7 +1437,7 @@ extern VALUE oj_wab_parse(int argc, VALUE *argv, VALUE self); * * - *args( [_Class_] zero or more classes to optimize. */ -extern VALUE oj_add_to_json(int argc, VALUE *argv, VALUE self); +extern VALUE oj_add_to_json(int argc, VALUE *argv, VALUE self); /* @!method remove_to_json(*args) * @@ -1508,7 +1453,7 @@ extern VALUE oj_add_to_json(int argc, VALUE *argv, VALUE self); * * - *args* [_Class_] zero or more classes to optimize. */ -extern VALUE oj_remove_to_json(int argc, VALUE *argv, VALUE self); +extern VALUE oj_remove_to_json(int argc, VALUE *argv, VALUE self); /* Document-method: mimic_JSON * call-seq: mimic_JSON() @@ -1526,7 +1471,7 @@ extern VALUE oj_remove_to_json(int argc, VALUE *argv, VALUE self); * * Returns [_Module_] the JSON module. */ -extern VALUE oj_define_mimic_json(int argc, VALUE *argv, VALUE self); +extern VALUE oj_define_mimic_json(int argc, VALUE *argv, VALUE self); /* Document-method: generate * call-seq: generate(obj, opts=nil) @@ -1546,14 +1491,14 @@ extern VALUE oj_define_mimic_json(int argc, VALUE *argv, VALUE self); * * Returns [_String_]generated JSON. */ -extern VALUE oj_mimic_generate(int argc, VALUE *argv, VALUE self); +extern VALUE oj_mimic_generate(int argc, VALUE *argv, VALUE self); /* Document-module: Oj.optimize_rails() * * Sets the Oj as the Rails encoder and decoder. Oj::Rails.optimize is also * called. */ -extern VALUE oj_optimize_rails(VALUE self); +extern VALUE oj_optimize_rails(VALUE self); /* extern void oj_hash_test(); @@ -1602,7 +1547,7 @@ protect_require(VALUE x) { */ void Init_oj() { - int err = 0; + int err = 0; Oj = rb_define_module("Oj"); @@ -1721,143 +1666,75 @@ Init_oj() { oj_json_parser_error_class = rb_eEncodingError; // replaced if mimic is called oj_json_generator_error_class = rb_eEncodingError; // replaced if mimic is called - allow_blank_sym = ID2SYM(rb_intern("allow_blank")); - rb_gc_register_address(&allow_blank_sym); - allow_gc_sym = ID2SYM(rb_intern("allow_gc")); - rb_gc_register_address(&allow_gc_sym); - allow_invalid_unicode_sym = ID2SYM(rb_intern("allow_invalid_unicode")); - rb_gc_register_address(&allow_invalid_unicode_sym); - ascii_sym = ID2SYM(rb_intern("ascii")); - rb_gc_register_address(&ascii_sym); - auto_define_sym = ID2SYM(rb_intern("auto_define")); - rb_gc_register_address(&auto_define_sym); - auto_sym = ID2SYM(rb_intern("auto")); - rb_gc_register_address(&auto_sym); - bigdecimal_as_decimal_sym = ID2SYM(rb_intern("bigdecimal_as_decimal")); - rb_gc_register_address(&bigdecimal_as_decimal_sym); - bigdecimal_load_sym = ID2SYM(rb_intern("bigdecimal_load")); - rb_gc_register_address(&bigdecimal_load_sym); - bigdecimal_sym = ID2SYM(rb_intern("bigdecimal")); - rb_gc_register_address(&bigdecimal_sym); - circular_sym = ID2SYM(rb_intern("circular")); - rb_gc_register_address(&circular_sym); - class_cache_sym = ID2SYM(rb_intern("class_cache")); - rb_gc_register_address(&class_cache_sym); - compat_bigdecimal_sym = ID2SYM(rb_intern("compat_bigdecimal")); - rb_gc_register_address(&compat_bigdecimal_sym); - compat_sym = ID2SYM(rb_intern("compat")); - rb_gc_register_address(&compat_sym); - create_id_sym = ID2SYM(rb_intern("create_id")); - rb_gc_register_address(&create_id_sym); - custom_sym = ID2SYM(rb_intern("custom")); - rb_gc_register_address(&custom_sym); - empty_string_sym = ID2SYM(rb_intern("empty_string")); - rb_gc_register_address(&empty_string_sym); - escape_mode_sym = ID2SYM(rb_intern("escape_mode")); - rb_gc_register_address(&escape_mode_sym); - integer_range_sym = ID2SYM(rb_intern("integer_range")); - rb_gc_register_address(&integer_range_sym); - fast_sym = ID2SYM(rb_intern("fast")); - rb_gc_register_address(&fast_sym); - float_prec_sym = ID2SYM(rb_intern("float_precision")); - rb_gc_register_address(&float_prec_sym); - float_sym = ID2SYM(rb_intern("float")); - rb_gc_register_address(&float_sym); - huge_sym = ID2SYM(rb_intern("huge")); - rb_gc_register_address(&huge_sym); - ignore_sym = ID2SYM(rb_intern("ignore")); - rb_gc_register_address(&ignore_sym); - ignore_under_sym = ID2SYM(rb_intern("ignore_under")); - rb_gc_register_address(&ignore_under_sym); - json_sym = ID2SYM(rb_intern("json")); - rb_gc_register_address(&json_sym); - match_string_sym = ID2SYM(rb_intern("match_string")); - rb_gc_register_address(&match_string_sym); - mode_sym = ID2SYM(rb_intern("mode")); - rb_gc_register_address(&mode_sym); - nan_sym = ID2SYM(rb_intern("nan")); - rb_gc_register_address(&nan_sym); - newline_sym = ID2SYM(rb_intern("newline")); - rb_gc_register_address(&newline_sym); - nilnil_sym = ID2SYM(rb_intern("nilnil")); - rb_gc_register_address(&nilnil_sym); - null_sym = ID2SYM(rb_intern("null")); - rb_gc_register_address(&null_sym); - object_sym = ID2SYM(rb_intern("object")); - rb_gc_register_address(&object_sym); - oj_allow_nan_sym = ID2SYM(rb_intern("allow_nan")); - rb_gc_register_address(&oj_allow_nan_sym); - oj_array_class_sym = ID2SYM(rb_intern("array_class")); - rb_gc_register_address(&oj_array_class_sym); - oj_array_nl_sym = ID2SYM(rb_intern("array_nl")); - rb_gc_register_address(&oj_array_nl_sym); - oj_ascii_only_sym = ID2SYM(rb_intern("ascii_only")); - rb_gc_register_address(&oj_ascii_only_sym); - oj_create_additions_sym = ID2SYM(rb_intern("create_additions")); - rb_gc_register_address(&oj_create_additions_sym); - oj_decimal_class_sym = ID2SYM(rb_intern("decimal_class")); - rb_gc_register_address(&oj_decimal_class_sym); - oj_hash_class_sym = ID2SYM(rb_intern("hash_class")); - rb_gc_register_address(&oj_hash_class_sym); - oj_indent_sym = ID2SYM(rb_intern("indent")); - rb_gc_register_address(&oj_indent_sym); - oj_max_nesting_sym = ID2SYM(rb_intern("max_nesting")); - rb_gc_register_address(&oj_max_nesting_sym); - oj_object_class_sym = ID2SYM(rb_intern("object_class")); - rb_gc_register_address(&oj_object_class_sym); - oj_object_nl_sym = ID2SYM(rb_intern("object_nl")); - rb_gc_register_address(&oj_object_nl_sym); - oj_quirks_mode_sym = ID2SYM(rb_intern("quirks_mode")); - rb_gc_register_address(&oj_quirks_mode_sym); - oj_safe_sym = ID2SYM(rb_intern("safe")); - rb_gc_register_address(&oj_safe_sym); - oj_space_before_sym = ID2SYM(rb_intern("space_before")); - rb_gc_register_address(&oj_space_before_sym); - oj_space_sym = ID2SYM(rb_intern("space")); - rb_gc_register_address(&oj_space_sym); - oj_trace_sym = ID2SYM(rb_intern("trace")); - rb_gc_register_address(&oj_trace_sym); - omit_nil_sym = ID2SYM(rb_intern("omit_nil")); - rb_gc_register_address(&omit_nil_sym); - rails_sym = ID2SYM(rb_intern("rails")); - rb_gc_register_address(&rails_sym); - raise_sym = ID2SYM(rb_intern("raise")); - rb_gc_register_address(&raise_sym); - ruby_sym = ID2SYM(rb_intern("ruby")); - rb_gc_register_address(&ruby_sym); - sec_prec_sym = ID2SYM(rb_intern("second_precision")); - rb_gc_register_address(&sec_prec_sym); - strict_sym = ID2SYM(rb_intern("strict")); - rb_gc_register_address(&strict_sym); - symbol_keys_sym = ID2SYM(rb_intern("symbol_keys")); - rb_gc_register_address(&symbol_keys_sym); - time_format_sym = ID2SYM(rb_intern("time_format")); - rb_gc_register_address(&time_format_sym); - unicode_xss_sym = ID2SYM(rb_intern("unicode_xss")); - rb_gc_register_address(&unicode_xss_sym); - unix_sym = ID2SYM(rb_intern("unix")); - rb_gc_register_address(&unix_sym); - unix_zone_sym = ID2SYM(rb_intern("unix_zone")); - rb_gc_register_address(&unix_zone_sym); - use_as_json_sym = ID2SYM(rb_intern("use_as_json")); - rb_gc_register_address(&use_as_json_sym); - use_raw_json_sym = ID2SYM(rb_intern("use_raw_json")); - rb_gc_register_address(&use_raw_json_sym); - use_to_hash_sym = ID2SYM(rb_intern("use_to_hash")); - rb_gc_register_address(&use_to_hash_sym); - use_to_json_sym = ID2SYM(rb_intern("use_to_json")); - rb_gc_register_address(&use_to_json_sym); - wab_sym = ID2SYM(rb_intern("wab")); - rb_gc_register_address(&wab_sym); - word_sym = ID2SYM(rb_intern("word")); - rb_gc_register_address(&word_sym); - xmlschema_sym = ID2SYM(rb_intern("xmlschema")); - rb_gc_register_address(&xmlschema_sym); - xss_safe_sym = ID2SYM(rb_intern("xss_safe")); - rb_gc_register_address(&xss_safe_sym); - - oj_slash_string = rb_str_new2("/"); - rb_gc_register_address(&oj_slash_string); + allow_blank_sym = ID2SYM(rb_intern("allow_blank")); rb_gc_register_address(&allow_blank_sym); + allow_gc_sym = ID2SYM(rb_intern("allow_gc")); rb_gc_register_address(&allow_gc_sym); + allow_invalid_unicode_sym = ID2SYM(rb_intern("allow_invalid_unicode"));rb_gc_register_address(&allow_invalid_unicode_sym); + ascii_sym = ID2SYM(rb_intern("ascii")); rb_gc_register_address(&ascii_sym); + auto_define_sym = ID2SYM(rb_intern("auto_define")); rb_gc_register_address(&auto_define_sym); + auto_sym = ID2SYM(rb_intern("auto")); rb_gc_register_address(&auto_sym); + bigdecimal_as_decimal_sym = ID2SYM(rb_intern("bigdecimal_as_decimal"));rb_gc_register_address(&bigdecimal_as_decimal_sym); + bigdecimal_load_sym = ID2SYM(rb_intern("bigdecimal_load")); rb_gc_register_address(&bigdecimal_load_sym); + bigdecimal_sym = ID2SYM(rb_intern("bigdecimal")); rb_gc_register_address(&bigdecimal_sym); + circular_sym = ID2SYM(rb_intern("circular")); rb_gc_register_address(&circular_sym); + class_cache_sym = ID2SYM(rb_intern("class_cache")); rb_gc_register_address(&class_cache_sym); + compat_bigdecimal_sym = ID2SYM(rb_intern("compat_bigdecimal"));rb_gc_register_address(&compat_bigdecimal_sym); + compat_sym = ID2SYM(rb_intern("compat")); rb_gc_register_address(&compat_sym); + create_id_sym = ID2SYM(rb_intern("create_id")); rb_gc_register_address(&create_id_sym); + custom_sym = ID2SYM(rb_intern("custom")); rb_gc_register_address(&custom_sym); + empty_string_sym = ID2SYM(rb_intern("empty_string")); rb_gc_register_address(&empty_string_sym); + escape_mode_sym = ID2SYM(rb_intern("escape_mode")); rb_gc_register_address(&escape_mode_sym); + integer_range_sym = ID2SYM(rb_intern("integer_range")); rb_gc_register_address(&integer_range_sym); + fast_sym = ID2SYM(rb_intern("fast")); rb_gc_register_address(&fast_sym); + float_prec_sym = ID2SYM(rb_intern("float_precision")); rb_gc_register_address(&float_prec_sym); + float_sym = ID2SYM(rb_intern("float")); rb_gc_register_address(&float_sym); + huge_sym = ID2SYM(rb_intern("huge")); rb_gc_register_address(&huge_sym); + ignore_sym = ID2SYM(rb_intern("ignore")); rb_gc_register_address(&ignore_sym); + ignore_under_sym = ID2SYM(rb_intern("ignore_under")); rb_gc_register_address(&ignore_under_sym); + json_sym = ID2SYM(rb_intern("json")); rb_gc_register_address(&json_sym); + match_string_sym = ID2SYM(rb_intern("match_string")); rb_gc_register_address(&match_string_sym); + mode_sym = ID2SYM(rb_intern("mode")); rb_gc_register_address(&mode_sym); + nan_sym = ID2SYM(rb_intern("nan")); rb_gc_register_address(&nan_sym); + newline_sym = ID2SYM(rb_intern("newline")); rb_gc_register_address(&newline_sym); + nilnil_sym = ID2SYM(rb_intern("nilnil")); rb_gc_register_address(&nilnil_sym); + null_sym = ID2SYM(rb_intern("null")); rb_gc_register_address(&null_sym); + object_sym = ID2SYM(rb_intern("object")); rb_gc_register_address(&object_sym); + oj_allow_nan_sym = ID2SYM(rb_intern("allow_nan")); rb_gc_register_address(&oj_allow_nan_sym); + oj_array_class_sym = ID2SYM(rb_intern("array_class")); rb_gc_register_address(&oj_array_class_sym); + oj_array_nl_sym = ID2SYM(rb_intern("array_nl")); rb_gc_register_address(&oj_array_nl_sym); + oj_ascii_only_sym = ID2SYM(rb_intern("ascii_only")); rb_gc_register_address(&oj_ascii_only_sym); + oj_create_additions_sym = ID2SYM(rb_intern("create_additions"));rb_gc_register_address(&oj_create_additions_sym); + oj_decimal_class_sym = ID2SYM(rb_intern("decimal_class")); rb_gc_register_address(&oj_decimal_class_sym); + oj_hash_class_sym = ID2SYM(rb_intern("hash_class")); rb_gc_register_address(&oj_hash_class_sym); + oj_indent_sym = ID2SYM(rb_intern("indent")); rb_gc_register_address(&oj_indent_sym); + oj_max_nesting_sym = ID2SYM(rb_intern("max_nesting")); rb_gc_register_address(&oj_max_nesting_sym); + oj_object_class_sym = ID2SYM(rb_intern("object_class")); rb_gc_register_address(&oj_object_class_sym); + oj_object_nl_sym = ID2SYM(rb_intern("object_nl")); rb_gc_register_address(&oj_object_nl_sym); + oj_quirks_mode_sym = ID2SYM(rb_intern("quirks_mode")); rb_gc_register_address(&oj_quirks_mode_sym); + oj_safe_sym = ID2SYM(rb_intern("safe")); rb_gc_register_address(&oj_safe_sym); + oj_space_before_sym = ID2SYM(rb_intern("space_before")); rb_gc_register_address(&oj_space_before_sym); + oj_space_sym = ID2SYM(rb_intern("space")); rb_gc_register_address(&oj_space_sym); + oj_trace_sym = ID2SYM(rb_intern("trace")); rb_gc_register_address(&oj_trace_sym); + omit_nil_sym = ID2SYM(rb_intern("omit_nil")); rb_gc_register_address(&omit_nil_sym); + rails_sym = ID2SYM(rb_intern("rails")); rb_gc_register_address(&rails_sym); + raise_sym = ID2SYM(rb_intern("raise")); rb_gc_register_address(&raise_sym); + ruby_sym = ID2SYM(rb_intern("ruby")); rb_gc_register_address(&ruby_sym); + sec_prec_sym = ID2SYM(rb_intern("second_precision")); rb_gc_register_address(&sec_prec_sym); + strict_sym = ID2SYM(rb_intern("strict")); rb_gc_register_address(&strict_sym); + symbol_keys_sym = ID2SYM(rb_intern("symbol_keys")); rb_gc_register_address(&symbol_keys_sym); + time_format_sym = ID2SYM(rb_intern("time_format")); rb_gc_register_address(&time_format_sym); + unicode_xss_sym = ID2SYM(rb_intern("unicode_xss")); rb_gc_register_address(&unicode_xss_sym); + unix_sym = ID2SYM(rb_intern("unix")); rb_gc_register_address(&unix_sym); + unix_zone_sym = ID2SYM(rb_intern("unix_zone")); rb_gc_register_address(&unix_zone_sym); + use_as_json_sym = ID2SYM(rb_intern("use_as_json")); rb_gc_register_address(&use_as_json_sym); + use_raw_json_sym = ID2SYM(rb_intern("use_raw_json")); rb_gc_register_address(&use_raw_json_sym); + use_to_hash_sym = ID2SYM(rb_intern("use_to_hash")); rb_gc_register_address(&use_to_hash_sym); + use_to_json_sym = ID2SYM(rb_intern("use_to_json")); rb_gc_register_address(&use_to_json_sym); + wab_sym = ID2SYM(rb_intern("wab")); rb_gc_register_address(&wab_sym); + word_sym = ID2SYM(rb_intern("word")); rb_gc_register_address(&word_sym); + xmlschema_sym = ID2SYM(rb_intern("xmlschema")); rb_gc_register_address(&xmlschema_sym); + xss_safe_sym = ID2SYM(rb_intern("xss_safe")); rb_gc_register_address(&xss_safe_sym); + + oj_slash_string = rb_str_new2("/"); rb_gc_register_address(&oj_slash_string); OBJ_FREEZE(oj_slash_string); oj_default_options.mode = ObjectMode; @@ -1868,7 +1745,7 @@ Init_oj() { #ifdef HAVE_PTHREAD_MUTEX_INIT if (0 != (err = pthread_mutex_init(&oj_cache_mutex, 0))) { - rb_raise(rb_eException, "failed to initialize a mutex. %s", strerror(err)); + rb_raise(rb_eException, "failed to initialize a mutex. %s", strerror(err)); } #else oj_cache_mutex = rb_mutex_new(); diff --git a/ext/oj/oj.h b/ext/oj/oj.h index 758aa902..c1fb5078 100644 --- a/ext/oj/oj.h +++ b/ext/oj/oj.h @@ -16,8 +16,8 @@ extern "C" { #include "ruby.h" #include "ruby/encoding.h" -#include #include +#include #ifdef HAVE_PTHREAD_MUTEX_INIT #include @@ -27,366 +27,363 @@ extern "C" { #ifdef RUBINIUS_RUBY #undef T_RATIONAL #undef T_COMPLEX -enum st_retval { ST_CONTINUE = 0, - ST_STOP = 1, - ST_DELETE = 2, - ST_CHECK }; +enum st_retval {ST_CONTINUE = 0, ST_STOP = 1, ST_DELETE = 2, ST_CHECK}; #else #include "ruby/st.h" #endif -#include "err.h" #include "rxclass.h" +#include "err.h" -#define INF_VAL "3.0e14159265358979323846" -#define NINF_VAL "-3.0e14159265358979323846" -#define NAN_VAL "3.3e14159265358979323846" +#define INF_VAL "3.0e14159265358979323846" +#define NINF_VAL "-3.0e14159265358979323846" +#define NAN_VAL "3.3e14159265358979323846" typedef enum { - Yes = 'y', - No = 'n', + Yes = 'y', + No = 'n', NotSet = 0 } YesNo; typedef enum { - StrictMode = 's', - ObjectMode = 'o', - NullMode = 'n', - CompatMode = 'c', - RailsMode = 'r', - CustomMode = 'C', - WabMode = 'w', + StrictMode = 's', + ObjectMode = 'o', + NullMode = 'n', + CompatMode = 'c', + RailsMode = 'r', + CustomMode = 'C', + WabMode = 'w', } Mode; typedef enum { - UnixTime = 'u', - UnixZTime = 'z', - XmlTime = 'x', - RubyTime = 'r' + UnixTime = 'u', + UnixZTime = 'z', + XmlTime = 'x', + RubyTime = 'r' } TimeFormat; typedef enum { - NLEsc = 'n', - JSONEsc = 'j', - XSSEsc = 'x', - ASCIIEsc = 'a', - JXEsc = 'g', // json gem - RailsXEsc = 'r', // rails xss mode - RailsEsc = 'R', // rails non escape + NLEsc = 'n', + JSONEsc = 'j', + XSSEsc = 'x', + ASCIIEsc = 'a', + JXEsc = 'g', // json gem + RailsXEsc = 'r', // rails xss mode + RailsEsc = 'R', // rails non escape } Encoding; typedef enum { - BigDec = 'b', - FloatDec = 'f', - AutoDec = 'a', - FastDec = 'F', - RubyDec = 'r', + BigDec = 'b', + FloatDec = 'f', + AutoDec = 'a', + FastDec = 'F', + RubyDec = 'r', } BigLoad; typedef enum { - ArrayNew = 'A', - ArrayType = 'a', - ObjectNew = 'O', - ObjectType = 'o', + ArrayNew = 'A', + ArrayType = 'a', + ObjectNew = 'O', + ObjectType = 'o', } DumpType; typedef enum { - AutoNan = 'a', - NullNan = 'n', - HugeNan = 'h', - WordNan = 'w', - RaiseNan = 'r', + AutoNan = 'a', + NullNan = 'n', + HugeNan = 'h', + WordNan = 'w', + RaiseNan = 'r', } NanDump; typedef enum { - STRING_IO = 'c', - STREAM_IO = 's', - FILE_IO = 'f', + STRING_IO = 'c', + STREAM_IO = 's', + FILE_IO = 'f', } StreamWriterType; typedef enum { - CALLER_DUMP = 'd', - CALLER_TO_JSON = 't', - CALLER_GENERATE = 'g', + CALLER_DUMP = 'd', + CALLER_TO_JSON = 't', + CALLER_GENERATE = 'g', // Add the fast versions if necessary. Maybe unparse as well if needed. } DumpCaller; typedef struct _dumpOpts { - bool use; - char indent_str[16]; - char before_sep[16]; - char after_sep[16]; - char hash_nl[16]; - char array_nl[16]; - uint8_t indent_size; - uint8_t before_size; - uint8_t after_size; - uint8_t hash_size; - uint8_t array_size; - char nan_dump; // NanDump - bool omit_nil; - int max_depth; -} * DumpOpts; + bool use; + char indent_str[16]; + char before_sep[16]; + char after_sep[16]; + char hash_nl[16]; + char array_nl[16]; + uint8_t indent_size; + uint8_t before_size; + uint8_t after_size; + uint8_t hash_size; + uint8_t array_size; + char nan_dump; // NanDump + bool omit_nil; + int max_depth; +} *DumpOpts; typedef struct _options { - int indent; // indention for dump, default 2 - char circular; // YesNo - char auto_define; // YesNo - char sym_key; // YesNo - char escape_mode; // Escape_Mode - char mode; // Mode - char class_cache; // YesNo - char time_format; // TimeFormat - char bigdec_as_num; // YesNo - char bigdec_load; // BigLoad - char compat_bigdec; // boolean (0 or 1) - char to_hash; // YesNo - char to_json; // YesNo - char as_json; // YesNo - char raw_json; // YesNo - char nilnil; // YesNo - char empty_string; // YesNo - char allow_gc; // allow GC during parse - char quirks_mode; // allow single JSON values instead of documents - char allow_invalid; // YesNo - allow invalid unicode - char create_ok; // YesNo allow create_id - char allow_nan; // YEsyNo for parsing only - char trace; // YesNo - char safe; // YesNo - char sec_prec_set; // boolean (0 or 1) - char ignore_under; // YesNo - ignore attrs starting with _ if true in object and custom modes - int64_t int_range_min; // dump numbers below as string - int64_t int_range_max; // dump numbers above as string - const char *create_id; // 0 or string - size_t create_id_len; // length of create_id - int sec_prec; // second precision when dumping time - char float_prec; // float precision, linked to float_fmt - char float_fmt[7]; // float format for dumping, if empty use Ruby - VALUE hash_class; // class to use in place of Hash on load - VALUE array_class; // class to use in place of Array on load - struct _dumpOpts dump_opts; - struct _rxClass str_rx; - VALUE *ignore; // Qnil terminated array of classes or NULL -} * Options; + int indent; // indention for dump, default 2 + char circular; // YesNo + char auto_define; // YesNo + char sym_key; // YesNo + char escape_mode; // Escape_Mode + char mode; // Mode + char class_cache; // YesNo + char time_format; // TimeFormat + char bigdec_as_num; // YesNo + char bigdec_load; // BigLoad + char compat_bigdec; // boolean (0 or 1) + char to_hash; // YesNo + char to_json; // YesNo + char as_json; // YesNo + char raw_json; // YesNo + char nilnil; // YesNo + char empty_string; // YesNo + char allow_gc; // allow GC during parse + char quirks_mode; // allow single JSON values instead of documents + char allow_invalid; // YesNo - allow invalid unicode + char create_ok; // YesNo allow create_id + char allow_nan; // YEsyNo for parsing only + char trace; // YesNo + char safe; // YesNo + char sec_prec_set; // boolean (0 or 1) + char ignore_under; // YesNo - ignore attrs starting with _ if true in object and custom modes + int64_t int_range_min; // dump numbers below as string + int64_t int_range_max; // dump numbers above as string + const char *create_id; // 0 or string + size_t create_id_len; // length of create_id + int sec_prec; // second precision when dumping time + char float_prec; // float precision, linked to float_fmt + char float_fmt[7]; // float format for dumping, if empty use Ruby + VALUE hash_class; // class to use in place of Hash on load + VALUE array_class; // class to use in place of Array on load + struct _dumpOpts dump_opts; + struct _rxClass str_rx; + VALUE *ignore; // Qnil terminated array of classes or NULL +} *Options; struct _out; -typedef void (*DumpFunc)(VALUE obj, int depth, struct _out *out, bool as_ok); +typedef void (*DumpFunc)(VALUE obj, int depth, struct _out *out, bool as_ok); // rails optimize typedef struct _rOpt { - VALUE clas; - bool on; - DumpFunc dump; -} * ROpt; + VALUE clas; + bool on; + DumpFunc dump; +} *ROpt; typedef struct _rOptTable { - int len; - int alen; - ROpt table; -} * ROptTable; + int len; + int alen; + ROpt table; +} *ROptTable; typedef struct _out { - char *buf; - char *end; - char *cur; - Cache8 circ_cache; - slot_t circ_cnt; - int indent; - int depth; // used by dump_hash - Options opts; - uint32_t hash_cnt; - bool allocated; - bool omit_nil; - int argc; - VALUE *argv; - DumpCaller caller; // used for the mimic json only - ROptTable ropts; -} * Out; + char *buf; + char *end; + char *cur; + Cache8 circ_cache; + slot_t circ_cnt; + int indent; + int depth; // used by dump_hash + Options opts; + uint32_t hash_cnt; + bool allocated; + bool omit_nil; + int argc; + VALUE *argv; + DumpCaller caller; // used for the mimic json only + ROptTable ropts; +} *Out; typedef struct _strWriter { - struct _out out; - struct _options opts; - int depth; - char *types; // DumpType - char *types_end; - int keyWritten; + struct _out out; + struct _options opts; + int depth; + char *types; // DumpType + char *types_end; + int keyWritten; -} * StrWriter; +} *StrWriter; typedef struct _streamWriter { - struct _strWriter sw; - StreamWriterType type; - VALUE stream; - int fd; - int flush_limit; // indicator of when to flush -} * StreamWriter; + struct _strWriter sw; + StreamWriterType type; + VALUE stream; + int fd; + int flush_limit; // indicator of when to flush +} *StreamWriter; enum { - NO_VAL = 0x00, - STR_VAL = 0x01, - COL_VAL = 0x02, + NO_VAL = 0x00, + STR_VAL = 0x01, + COL_VAL = 0x02, RUBY_VAL = 0x03 }; typedef struct _leaf { - struct _leaf *next; + struct _leaf *next; union { - const char *key; // hash key - size_t index; // array index, 0 is not set + const char *key; // hash key + size_t index; // array index, 0 is not set }; union { - char *str; // pointer to location in json string or allocated - struct _leaf *elements; // array and hash elements - VALUE value; + char *str; // pointer to location in json string or allocated + struct _leaf *elements; // array and hash elements + VALUE value; }; - uint8_t rtype; - uint8_t parent_type; - uint8_t value_type; -} * Leaf; - -extern VALUE oj_saj_parse(int argc, VALUE *argv, VALUE self); -extern VALUE oj_sc_parse(int argc, VALUE *argv, VALUE self); - -extern VALUE oj_strict_parse(int argc, VALUE *argv, VALUE self); -extern VALUE oj_strict_sparse(int argc, VALUE *argv, VALUE self); -extern VALUE oj_compat_parse(int argc, VALUE *argv, VALUE self); -extern VALUE oj_compat_load(int argc, VALUE *argv, VALUE self); -extern VALUE oj_object_parse(int argc, VALUE *argv, VALUE self); -extern VALUE oj_custom_parse(int argc, VALUE *argv, VALUE self); -extern VALUE oj_wab_parse(int argc, VALUE *argv, VALUE self); - -extern VALUE oj_strict_parse_cstr(int argc, VALUE *argv, char *json, size_t len); -extern VALUE oj_compat_parse_cstr(int argc, VALUE *argv, char *json, size_t len); -extern VALUE oj_object_parse_cstr(int argc, VALUE *argv, char *json, size_t len); -extern VALUE oj_custom_parse_cstr(int argc, VALUE *argv, char *json, size_t len); - -extern void oj_parse_options(VALUE ropts, Options copts); - -extern void oj_dump_obj_to_json(VALUE obj, Options copts, Out out); -extern void oj_dump_obj_to_json_using_params(VALUE obj, Options copts, Out out, int argc, VALUE *argv); -extern void oj_write_obj_to_file(VALUE obj, const char *path, Options copts); -extern void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts); -extern void oj_dump_leaf_to_json(Leaf leaf, Options copts, Out out); -extern void oj_write_leaf_to_file(Leaf leaf, const char *path, Options copts); - -extern void oj_str_writer_push_key(StrWriter sw, const char *key); -extern void oj_str_writer_push_object(StrWriter sw, const char *key); -extern void oj_str_writer_push_array(StrWriter sw, const char *key); -extern void oj_str_writer_push_value(StrWriter sw, VALUE val, const char *key); -extern void oj_str_writer_push_json(StrWriter sw, const char *json, const char *key); -extern void oj_str_writer_pop(StrWriter sw); -extern void oj_str_writer_pop_all(StrWriter sw); - -extern void oj_init_doc(void); -extern void oj_string_writer_init(); -extern void oj_stream_writer_init(); -extern void oj_str_writer_init(StrWriter sw, int buf_size); -extern VALUE oj_define_mimic_json(int argc, VALUE *argv, VALUE self); -extern VALUE oj_mimic_generate(int argc, VALUE *argv, VALUE self); -extern VALUE oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self); -extern void oj_parse_mimic_dump_options(VALUE ropts, Options copts); - -extern VALUE oj_mimic_parse(int argc, VALUE *argv, VALUE self); -extern VALUE oj_get_json_err_class(const char *err_classname); -extern void oj_parse_opt_match_string(RxClass rc, VALUE ropts); - -extern VALUE oj_rails_encode(int argc, VALUE *argv, VALUE self); - -extern VALUE Oj; -extern struct _options oj_default_options; -extern rb_encoding *oj_utf8_encoding; - -extern VALUE oj_bag_class; -extern VALUE oj_bigdecimal_class; -extern VALUE oj_cstack_class; -extern VALUE oj_date_class; -extern VALUE oj_datetime_class; -extern VALUE oj_doc_class; -extern VALUE oj_enumerable_class; -extern VALUE oj_json_generator_error_class; -extern VALUE oj_json_parser_error_class; -extern VALUE oj_stream_writer_class; -extern VALUE oj_string_writer_class; -extern VALUE oj_stringio_class; -extern VALUE oj_struct_class; - -extern VALUE oj_allow_nan_sym; -extern VALUE oj_array_class_sym; -extern VALUE oj_array_nl_sym; -extern VALUE oj_ascii_only_sym; -extern VALUE oj_create_additions_sym; -extern VALUE oj_decimal_class_sym; -extern VALUE oj_hash_class_sym; -extern VALUE oj_indent_sym; -extern VALUE oj_max_nesting_sym; -extern VALUE oj_object_class_sym; -extern VALUE oj_object_nl_sym; -extern VALUE oj_quirks_mode_sym; -extern VALUE oj_space_before_sym; -extern VALUE oj_space_sym; -extern VALUE oj_trace_sym; - -extern VALUE oj_slash_string; - -extern ID oj_add_value_id; -extern ID oj_array_append_id; -extern ID oj_array_end_id; -extern ID oj_array_start_id; -extern ID oj_as_json_id; -extern ID oj_begin_id; -extern ID oj_bigdecimal_id; -extern ID oj_end_id; -extern ID oj_error_id; -extern ID oj_exclude_end_id; -extern ID oj_file_id; -extern ID oj_fileno_id; -extern ID oj_ftype_id; -extern ID oj_has_key_id; -extern ID oj_hash_end_id; -extern ID oj_hash_key_id; -extern ID oj_hash_set_id; -extern ID oj_hash_start_id; -extern ID oj_iconv_id; -extern ID oj_instance_variables_id; -extern ID oj_json_create_id; -extern ID oj_length_id; -extern ID oj_new_id; -extern ID oj_parse_id; -extern ID oj_pos_id; -extern ID oj_read_id; -extern ID oj_readpartial_id; -extern ID oj_replace_id; -extern ID oj_stat_id; -extern ID oj_string_id; -extern ID oj_raw_json_id; -extern ID oj_to_h_id; -extern ID oj_to_hash_id; -extern ID oj_to_json_id; -extern ID oj_to_s_id; -extern ID oj_to_sym_id; -extern ID oj_to_time_id; -extern ID oj_tv_nsec_id; -extern ID oj_tv_sec_id; -extern ID oj_tv_usec_id; -extern ID oj_utc_id; -extern ID oj_utc_offset_id; -extern ID oj_utcq_id; -extern ID oj_write_id; - -extern bool oj_use_hash_alt; -extern bool oj_use_array_alt; -extern bool string_writer_optimized; + uint8_t rtype; + uint8_t parent_type; + uint8_t value_type; +} *Leaf; + +extern VALUE oj_saj_parse(int argc, VALUE *argv, VALUE self); +extern VALUE oj_sc_parse(int argc, VALUE *argv, VALUE self); + +extern VALUE oj_strict_parse(int argc, VALUE *argv, VALUE self); +extern VALUE oj_strict_sparse(int argc, VALUE *argv, VALUE self); +extern VALUE oj_compat_parse(int argc, VALUE *argv, VALUE self); +extern VALUE oj_compat_load(int argc, VALUE *argv, VALUE self); +extern VALUE oj_object_parse(int argc, VALUE *argv, VALUE self); +extern VALUE oj_custom_parse(int argc, VALUE *argv, VALUE self); +extern VALUE oj_wab_parse(int argc, VALUE *argv, VALUE self); + +extern VALUE oj_strict_parse_cstr(int argc, VALUE *argv, char *json, size_t len); +extern VALUE oj_compat_parse_cstr(int argc, VALUE *argv, char *json, size_t len); +extern VALUE oj_object_parse_cstr(int argc, VALUE *argv, char *json, size_t len); +extern VALUE oj_custom_parse_cstr(int argc, VALUE *argv, char *json, size_t len); + +extern void oj_parse_options(VALUE ropts, Options copts); + +extern void oj_dump_obj_to_json(VALUE obj, Options copts, Out out); +extern void oj_dump_obj_to_json_using_params(VALUE obj, Options copts, Out out, int argc, VALUE *argv); +extern void oj_write_obj_to_file(VALUE obj, const char *path, Options copts); +extern void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts); +extern void oj_dump_leaf_to_json(Leaf leaf, Options copts, Out out); +extern void oj_write_leaf_to_file(Leaf leaf, const char *path, Options copts); + +extern void oj_str_writer_push_key(StrWriter sw, const char *key); +extern void oj_str_writer_push_object(StrWriter sw, const char *key); +extern void oj_str_writer_push_array(StrWriter sw, const char *key); +extern void oj_str_writer_push_value(StrWriter sw, VALUE val, const char *key); +extern void oj_str_writer_push_json(StrWriter sw, const char *json, const char *key); +extern void oj_str_writer_pop(StrWriter sw); +extern void oj_str_writer_pop_all(StrWriter sw); + +extern void oj_init_doc(void); +extern void oj_string_writer_init(); +extern void oj_stream_writer_init(); +extern void oj_str_writer_init(StrWriter sw, int buf_size); +extern VALUE oj_define_mimic_json(int argc, VALUE *argv, VALUE self); +extern VALUE oj_mimic_generate(int argc, VALUE *argv, VALUE self); +extern VALUE oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self); +extern void oj_parse_mimic_dump_options(VALUE ropts, Options copts); + +extern VALUE oj_mimic_parse(int argc, VALUE *argv, VALUE self); +extern VALUE oj_get_json_err_class(const char *err_classname); +extern void oj_parse_opt_match_string(RxClass rc, VALUE ropts); + +extern VALUE oj_rails_encode(int argc, VALUE *argv, VALUE self); + +extern VALUE Oj; +extern struct _options oj_default_options; +extern rb_encoding *oj_utf8_encoding; + +extern VALUE oj_bag_class; +extern VALUE oj_bigdecimal_class; +extern VALUE oj_cstack_class; +extern VALUE oj_date_class; +extern VALUE oj_datetime_class; +extern VALUE oj_doc_class; +extern VALUE oj_enumerable_class; +extern VALUE oj_json_generator_error_class; +extern VALUE oj_json_parser_error_class; +extern VALUE oj_stream_writer_class; +extern VALUE oj_string_writer_class; +extern VALUE oj_stringio_class; +extern VALUE oj_struct_class; + +extern VALUE oj_allow_nan_sym; +extern VALUE oj_array_class_sym; +extern VALUE oj_array_nl_sym; +extern VALUE oj_ascii_only_sym; +extern VALUE oj_create_additions_sym; +extern VALUE oj_decimal_class_sym; +extern VALUE oj_hash_class_sym; +extern VALUE oj_indent_sym; +extern VALUE oj_max_nesting_sym; +extern VALUE oj_object_class_sym; +extern VALUE oj_object_nl_sym; +extern VALUE oj_quirks_mode_sym; +extern VALUE oj_space_before_sym; +extern VALUE oj_space_sym; +extern VALUE oj_trace_sym; + +extern VALUE oj_slash_string; + +extern ID oj_add_value_id; +extern ID oj_array_append_id; +extern ID oj_array_end_id; +extern ID oj_array_start_id; +extern ID oj_as_json_id; +extern ID oj_begin_id; +extern ID oj_bigdecimal_id; +extern ID oj_end_id; +extern ID oj_error_id; +extern ID oj_exclude_end_id; +extern ID oj_file_id; +extern ID oj_fileno_id; +extern ID oj_ftype_id; +extern ID oj_has_key_id; +extern ID oj_hash_end_id; +extern ID oj_hash_key_id; +extern ID oj_hash_set_id; +extern ID oj_hash_start_id; +extern ID oj_iconv_id; +extern ID oj_instance_variables_id; +extern ID oj_json_create_id; +extern ID oj_length_id; +extern ID oj_new_id; +extern ID oj_parse_id; +extern ID oj_pos_id; +extern ID oj_read_id; +extern ID oj_readpartial_id; +extern ID oj_replace_id; +extern ID oj_stat_id; +extern ID oj_string_id; +extern ID oj_raw_json_id; +extern ID oj_to_h_id; +extern ID oj_to_hash_id; +extern ID oj_to_json_id; +extern ID oj_to_s_id; +extern ID oj_to_sym_id; +extern ID oj_to_time_id; +extern ID oj_tv_nsec_id; +extern ID oj_tv_sec_id; +extern ID oj_tv_usec_id; +extern ID oj_utc_id; +extern ID oj_utc_offset_id; +extern ID oj_utcq_id; +extern ID oj_write_id; + +extern bool oj_use_hash_alt; +extern bool oj_use_array_alt; +extern bool string_writer_optimized; #ifdef HAVE_PTHREAD_MUTEX_INIT -extern pthread_mutex_t oj_cache_mutex; +extern pthread_mutex_t oj_cache_mutex; #else -extern VALUE oj_cache_mutex; +extern VALUE oj_cache_mutex; #endif #if defined(cplusplus) #if 0 { /* satisfy cc-mode */ #endif -} /* extern "C" { */ +} /* extern "C" { */ #endif #endif /* OJ_H */ diff --git a/ext/oj/parse.c b/ext/oj/parse.c index d68a2627..529dbdc7 100644 --- a/ext/oj/parse.c +++ b/ext/oj/parse.c @@ -1,151 +1,151 @@ // Copyright (c) 2013 Peter Ohler. All rights reserved. // Licensed under the MIT License. See LICENSE file in the project root for license details. -#include -#include -#include #include +#include #include #include +#include +#include -#include "buf.h" -#include "encode.h" #include "oj.h" +#include "encode.h" #include "parse.h" -#include "rxclass.h" +#include "buf.h" #include "val_stack.h" +#include "rxclass.h" // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS -#define OJ_INFINITY (1.0 / 0.0) +#define OJ_INFINITY (1.0/0.0) //#define EXP_MAX 1023 -#define EXP_MAX 100000 -#define DEC_MAX 15 +#define EXP_MAX 100000 +#define DEC_MAX 15 static void next_non_white(ParseInfo pi) { for (; 1; pi->cur++) { - switch (*pi->cur) { - case ' ': - case '\t': - case '\f': - case '\n': - case '\r': - break; - default: - return; - } + switch(*pi->cur) { + case ' ': + case '\t': + case '\f': + case '\n': + case '\r': + break; + default: + return; + } } } static void skip_comment(ParseInfo pi) { if ('*' == *pi->cur) { - pi->cur++; - for (; pi->cur < pi->end; pi->cur++) { - if ('*' == *pi->cur && '/' == *(pi->cur + 1)) { - pi->cur += 2; - return; - } else if (pi->end <= pi->cur) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "comment not terminated"); - return; - } - } + pi->cur++; + for (; pi->cur < pi->end; pi->cur++) { + if ('*' == *pi->cur && '/' == *(pi->cur + 1)) { + pi->cur += 2; + return; + } else if (pi->end <= pi->cur) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "comment not terminated"); + return; + } + } } else if ('/' == *pi->cur) { - for (; 1; pi->cur++) { - switch (*pi->cur) { - case '\n': - case '\r': - case '\f': - case '\0': - return; - default: - break; - } - } + for (; 1; pi->cur++) { + switch (*pi->cur) { + case '\n': + case '\r': + case '\f': + case '\0': + return; + default: + break; + } + } } else { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid comment format"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid comment format"); } } static void add_value(ParseInfo pi, VALUE rval) { - Val parent = stack_peek(&pi->stack); + Val parent = stack_peek(&pi->stack); if (0 == parent) { // simple add - pi->add_value(pi, rval); + pi->add_value(pi, rval); } else { - switch (parent->next) { - case NEXT_ARRAY_NEW: - case NEXT_ARRAY_ELEMENT: - pi->array_append_value(pi, rval); - parent->next = NEXT_ARRAY_COMMA; - break; - case NEXT_HASH_VALUE: - pi->hash_set_value(pi, parent, rval); - if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) { - xfree((char *)parent->key); - parent->key = 0; - } - parent->next = NEXT_HASH_COMMA; - break; - case NEXT_HASH_NEW: - case NEXT_HASH_KEY: - case NEXT_HASH_COMMA: - case NEXT_NONE: - case NEXT_ARRAY_COMMA: - case NEXT_HASH_COLON: - default: - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s", oj_stack_next_string(parent->next)); - break; - } + switch (parent->next) { + case NEXT_ARRAY_NEW: + case NEXT_ARRAY_ELEMENT: + pi->array_append_value(pi, rval); + parent->next = NEXT_ARRAY_COMMA; + break; + case NEXT_HASH_VALUE: + pi->hash_set_value(pi, parent, rval); + if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) { + xfree((char*)parent->key); + parent->key = 0; + } + parent->next = NEXT_HASH_COMMA; + break; + case NEXT_HASH_NEW: + case NEXT_HASH_KEY: + case NEXT_HASH_COMMA: + case NEXT_NONE: + case NEXT_ARRAY_COMMA: + case NEXT_HASH_COLON: + default: + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s", oj_stack_next_string(parent->next)); + break; + } } } static void read_null(ParseInfo pi) { if ('u' == *pi->cur++ && 'l' == *pi->cur++ && 'l' == *pi->cur++) { - add_value(pi, Qnil); + add_value(pi, Qnil); } else { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected null"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected null"); } } static void read_true(ParseInfo pi) { if ('r' == *pi->cur++ && 'u' == *pi->cur++ && 'e' == *pi->cur++) { - add_value(pi, Qtrue); + add_value(pi, Qtrue); } else { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected true"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected true"); } } static void read_false(ParseInfo pi) { if ('a' == *pi->cur++ && 'l' == *pi->cur++ && 's' == *pi->cur++ && 'e' == *pi->cur++) { - add_value(pi, Qfalse); + add_value(pi, Qfalse); } else { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected false"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected false"); } } static uint32_t read_hex(ParseInfo pi, const char *h) { - uint32_t b = 0; - int i; + uint32_t b = 0; + int i; for (i = 0; i < 4; i++, h++) { - b = b << 4; - if ('0' <= *h && *h <= '9') { - b += *h - '0'; - } else if ('A' <= *h && *h <= 'F') { - b += *h - 'A' + 10; - } else if ('a' <= *h && *h <= 'f') { - b += *h - 'a' + 10; - } else { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hex character"); - return 0; - } + b = b << 4; + if ('0' <= *h && *h <= '9') { + b += *h - '0'; + } else if ('A' <= *h && *h <= 'F') { + b += *h - 'A' + 10; + } else if ('a' <= *h && *h <= 'f') { + b += *h - 'a' + 10; + } else { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hex character"); + return 0; + } } return b; } @@ -153,175 +153,159 @@ read_hex(ParseInfo pi, const char *h) { static void unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) { if (0x0000007F >= code) { - buf_append(buf, (char)code); + buf_append(buf, (char)code); } else if (0x000007FF >= code) { - buf_append(buf, 0xC0 | (code >> 6)); - buf_append(buf, 0x80 | (0x3F & code)); + buf_append(buf, 0xC0 | (code >> 6)); + buf_append(buf, 0x80 | (0x3F & code)); } else if (0x0000FFFF >= code) { - buf_append(buf, 0xE0 | (code >> 12)); - buf_append(buf, 0x80 | ((code >> 6) & 0x3F)); - buf_append(buf, 0x80 | (0x3F & code)); + buf_append(buf, 0xE0 | (code >> 12)); + buf_append(buf, 0x80 | ((code >> 6) & 0x3F)); + buf_append(buf, 0x80 | (0x3F & code)); } else if (0x001FFFFF >= code) { - buf_append(buf, 0xF0 | (code >> 18)); - buf_append(buf, 0x80 | ((code >> 12) & 0x3F)); - buf_append(buf, 0x80 | ((code >> 6) & 0x3F)); - buf_append(buf, 0x80 | (0x3F & code)); + buf_append(buf, 0xF0 | (code >> 18)); + buf_append(buf, 0x80 | ((code >> 12) & 0x3F)); + buf_append(buf, 0x80 | ((code >> 6) & 0x3F)); + buf_append(buf, 0x80 | (0x3F & code)); } else if (0x03FFFFFF >= code) { - buf_append(buf, 0xF8 | (code >> 24)); - buf_append(buf, 0x80 | ((code >> 18) & 0x3F)); - buf_append(buf, 0x80 | ((code >> 12) & 0x3F)); - buf_append(buf, 0x80 | ((code >> 6) & 0x3F)); - buf_append(buf, 0x80 | (0x3F & code)); + buf_append(buf, 0xF8 | (code >> 24)); + buf_append(buf, 0x80 | ((code >> 18) & 0x3F)); + buf_append(buf, 0x80 | ((code >> 12) & 0x3F)); + buf_append(buf, 0x80 | ((code >> 6) & 0x3F)); + buf_append(buf, 0x80 | (0x3F & code)); } else if (0x7FFFFFFF >= code) { - buf_append(buf, 0xFC | (code >> 30)); - buf_append(buf, 0x80 | ((code >> 24) & 0x3F)); - buf_append(buf, 0x80 | ((code >> 18) & 0x3F)); - buf_append(buf, 0x80 | ((code >> 12) & 0x3F)); - buf_append(buf, 0x80 | ((code >> 6) & 0x3F)); - buf_append(buf, 0x80 | (0x3F & code)); + buf_append(buf, 0xFC | (code >> 30)); + buf_append(buf, 0x80 | ((code >> 24) & 0x3F)); + buf_append(buf, 0x80 | ((code >> 18) & 0x3F)); + buf_append(buf, 0x80 | ((code >> 12) & 0x3F)); + buf_append(buf, 0x80 | ((code >> 6) & 0x3F)); + buf_append(buf, 0x80 | (0x3F & code)); } else { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid Unicode character"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid Unicode character"); } } // entered at / static void read_escaped_str(ParseInfo pi, const char *start) { - struct _buf buf; - const char *s; - int cnt = (int)(pi->cur - start); - uint32_t code; - Val parent = stack_peek(&pi->stack); + struct _buf buf; + const char *s; + int cnt = (int)(pi->cur - start); + uint32_t code; + Val parent = stack_peek(&pi->stack); buf_init(&buf); if (0 < cnt) { - buf_append_string(&buf, start, cnt); + buf_append_string(&buf, start, cnt); } for (s = pi->cur; '"' != *s; s++) { - if (s >= pi->end) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated"); - buf_cleanup(&buf); - return; - } else if ('\\' == *s) { - s++; - switch (*s) { - case 'n': - buf_append(&buf, '\n'); - break; - case 'r': - buf_append(&buf, '\r'); - break; - case 't': - buf_append(&buf, '\t'); - break; - case 'f': - buf_append(&buf, '\f'); - break; - case 'b': - buf_append(&buf, '\b'); - break; - case '"': - buf_append(&buf, '"'); - break; - case '/': - buf_append(&buf, '/'); - break; - case '\\': - buf_append(&buf, '\\'); - break; - case 'u': - s++; - if (0 == (code = read_hex(pi, s)) && err_has(&pi->err)) { - buf_cleanup(&buf); - return; - } - s += 3; - if (0x0000D800 <= code && code <= 0x0000DFFF) { - uint32_t c1 = (code - 0x0000D800) & 0x000003FF; - uint32_t c2; - - s++; - if ('\\' != *s || 'u' != *(s + 1)) { - if (Yes == pi->options.allow_invalid) { - s--; - unicode_to_chars(pi, &buf, code); - break; - } - pi->cur = s; - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character"); - buf_cleanup(&buf); - return; - } - s += 2; - if (0 == (c2 = read_hex(pi, s)) && err_has(&pi->err)) { - buf_cleanup(&buf); - return; - } - s += 3; - c2 = (c2 - 0x0000DC00) & 0x000003FF; - code = ((c1 << 10) | c2) + 0x00010000; - } - unicode_to_chars(pi, &buf, code); - if (err_has(&pi->err)) { - buf_cleanup(&buf); - return; - } - break; - default: - // The json gem claims this is not an error despite the - // ECMA-404 indicating it is not valid. - if (CompatMode == pi->options.mode) { - buf_append(&buf, *s); - break; - } - pi->cur = s; - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character"); - buf_cleanup(&buf); - return; - } - } else { - buf_append(&buf, *s); - } + if (s >= pi->end) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated"); + buf_cleanup(&buf); + return; + } else if ('\\' == *s) { + s++; + switch (*s) { + case 'n': buf_append(&buf, '\n'); break; + case 'r': buf_append(&buf, '\r'); break; + case 't': buf_append(&buf, '\t'); break; + case 'f': buf_append(&buf, '\f'); break; + case 'b': buf_append(&buf, '\b'); break; + case '"': buf_append(&buf, '"'); break; + case '/': buf_append(&buf, '/'); break; + case '\\': buf_append(&buf, '\\'); break; + case 'u': + s++; + if (0 == (code = read_hex(pi, s)) && err_has(&pi->err)) { + buf_cleanup(&buf); + return; + } + s += 3; + if (0x0000D800 <= code && code <= 0x0000DFFF) { + uint32_t c1 = (code - 0x0000D800) & 0x000003FF; + uint32_t c2; + + s++; + if ('\\' != *s || 'u' != *(s + 1)) { + if (Yes == pi->options.allow_invalid) { + s--; + unicode_to_chars(pi, &buf, code); + break; + } + pi->cur = s; + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character"); + buf_cleanup(&buf); + return; + } + s += 2; + if (0 == (c2 = read_hex(pi, s)) && err_has(&pi->err)) { + buf_cleanup(&buf); + return; + } + s += 3; + c2 = (c2 - 0x0000DC00) & 0x000003FF; + code = ((c1 << 10) | c2) + 0x00010000; + } + unicode_to_chars(pi, &buf, code); + if (err_has(&pi->err)) { + buf_cleanup(&buf); + return; + } + break; + default: + // The json gem claims this is not an error despite the + // ECMA-404 indicating it is not valid. + if (CompatMode == pi->options.mode) { + buf_append(&buf, *s); + break; + } + pi->cur = s; + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character"); + buf_cleanup(&buf); + return; + } + } else { + buf_append(&buf, *s); + } } if (0 == parent) { - pi->add_cstr(pi, buf.head, buf_len(&buf), start); + pi->add_cstr(pi, buf.head, buf_len(&buf), start); } else { - switch (parent->next) { - case NEXT_ARRAY_NEW: - case NEXT_ARRAY_ELEMENT: - pi->array_append_cstr(pi, buf.head, buf_len(&buf), start); - parent->next = NEXT_ARRAY_COMMA; - break; - case NEXT_HASH_NEW: - case NEXT_HASH_KEY: - if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) { - parent->klen = buf_len(&buf); - parent->key = malloc(parent->klen + 1); - memcpy((char *)parent->key, buf.head, parent->klen); - *(char *)(parent->key + parent->klen) = '\0'; - } else { - parent->key = ""; - parent->klen = 0; - } - parent->k1 = *start; - parent->next = NEXT_HASH_COLON; - break; - case NEXT_HASH_VALUE: - pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), start); - if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) { - xfree((char *)parent->key); - parent->key = 0; - } - parent->next = NEXT_HASH_COMMA; - break; - case NEXT_HASH_COMMA: - case NEXT_NONE: - case NEXT_ARRAY_COMMA: - case NEXT_HASH_COLON: - default: - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a string", oj_stack_next_string(parent->next)); - break; - } + switch (parent->next) { + case NEXT_ARRAY_NEW: + case NEXT_ARRAY_ELEMENT: + pi->array_append_cstr(pi, buf.head, buf_len(&buf), start); + parent->next = NEXT_ARRAY_COMMA; + break; + case NEXT_HASH_NEW: + case NEXT_HASH_KEY: + if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) { + parent->klen = buf_len(&buf); + parent->key = malloc(parent->klen + 1); + memcpy((char*)parent->key, buf.head, parent->klen); + *(char*)(parent->key + parent->klen) = '\0'; + } else { + parent->key = ""; + parent->klen = 0; + } + parent->k1 = *start; + parent->next = NEXT_HASH_COLON; + break; + case NEXT_HASH_VALUE: + pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), start); + if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) { + xfree((char*)parent->key); + parent->key = 0; + } + parent->next = NEXT_HASH_COMMA; + break; + case NEXT_HASH_COMMA: + case NEXT_NONE: + case NEXT_ARRAY_COMMA: + case NEXT_HASH_COLON: + default: + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a string", oj_stack_next_string(parent->next)); + break; + } } pi->cur = s + 1; buf_cleanup(&buf); @@ -329,66 +313,66 @@ read_escaped_str(ParseInfo pi, const char *start) { static void read_str(ParseInfo pi) { - const char *str = pi->cur; - Val parent = stack_peek(&pi->stack); + const char *str = pi->cur; + Val parent = stack_peek(&pi->stack); for (; '"' != *pi->cur; pi->cur++) { - if (pi->end <= pi->cur) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated"); - return; - } else if ('\0' == *pi->cur) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "NULL byte in string"); - return; - } else if ('\\' == *pi->cur) { - read_escaped_str(pi, str); - return; - } + if (pi->end <= pi->cur) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated"); + return; + } else if ('\0' == *pi->cur) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "NULL byte in string"); + return; + } else if ('\\' == *pi->cur) { + read_escaped_str(pi, str); + return; + } } if (0 == parent) { // simple add - pi->add_cstr(pi, str, pi->cur - str, str); + pi->add_cstr(pi, str, pi->cur - str, str); } else { - switch (parent->next) { - case NEXT_ARRAY_NEW: - case NEXT_ARRAY_ELEMENT: - pi->array_append_cstr(pi, str, pi->cur - str, str); - parent->next = NEXT_ARRAY_COMMA; - break; - case NEXT_HASH_NEW: - case NEXT_HASH_KEY: - if (Qundef == (parent->key_val = pi->hash_key(pi, str, pi->cur - str))) { - parent->key = str; - parent->klen = pi->cur - str; - } else { - parent->key = ""; - parent->klen = 0; - } - parent->k1 = *str; - parent->next = NEXT_HASH_COLON; - break; - case NEXT_HASH_VALUE: - pi->hash_set_cstr(pi, parent, str, pi->cur - str, str); - if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) { - xfree((char *)parent->key); - parent->key = 0; - } - parent->next = NEXT_HASH_COMMA; - break; - case NEXT_HASH_COMMA: - case NEXT_NONE: - case NEXT_ARRAY_COMMA: - case NEXT_HASH_COLON: - default: - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a string", oj_stack_next_string(parent->next)); - break; - } + switch (parent->next) { + case NEXT_ARRAY_NEW: + case NEXT_ARRAY_ELEMENT: + pi->array_append_cstr(pi, str, pi->cur - str, str); + parent->next = NEXT_ARRAY_COMMA; + break; + case NEXT_HASH_NEW: + case NEXT_HASH_KEY: + if (Qundef == (parent->key_val = pi->hash_key(pi, str, pi->cur - str))) { + parent->key = str; + parent->klen = pi->cur - str; + } else { + parent->key = ""; + parent->klen = 0; + } + parent->k1 = *str; + parent->next = NEXT_HASH_COLON; + break; + case NEXT_HASH_VALUE: + pi->hash_set_cstr(pi, parent, str, pi->cur - str, str); + if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) { + xfree((char*)parent->key); + parent->key = 0; + } + parent->next = NEXT_HASH_COMMA; + break; + case NEXT_HASH_COMMA: + case NEXT_NONE: + case NEXT_ARRAY_COMMA: + case NEXT_HASH_COLON: + default: + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a string", oj_stack_next_string(parent->next)); + break; + } } pi->cur++; // move past " } static void read_num(ParseInfo pi) { - struct _numInfo ni; - Val parent = stack_peek(&pi->stack); + struct _numInfo ni; + Val parent = stack_peek(&pi->stack); ni.str = pi->cur; ni.i = 0; @@ -403,366 +387,366 @@ read_num(ParseInfo pi) { ni.neg = 0; ni.has_exp = 0; if (CompatMode == pi->options.mode) { - ni.no_big = !pi->options.compat_bigdec; - ni.bigdec_load = pi->options.compat_bigdec; + ni.no_big = !pi->options.compat_bigdec; + ni.bigdec_load = pi->options.compat_bigdec; } else { - ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load || RubyDec == pi->options.bigdec_load); - ni.bigdec_load = pi->options.bigdec_load; + ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load || RubyDec == pi->options.bigdec_load); + ni.bigdec_load = pi->options.bigdec_load; } if ('-' == *pi->cur) { - pi->cur++; - ni.neg = 1; + pi->cur++; + ni.neg = 1; } else if ('+' == *pi->cur) { - if (StrictMode == pi->options.mode) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); - return; - } - pi->cur++; + if (StrictMode == pi->options.mode) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); + return; + } + pi->cur++; } if ('I' == *pi->cur) { - if (No == pi->options.allow_nan || 0 != strncmp("Infinity", pi->cur, 8)) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); - return; - } - pi->cur += 8; - ni.infinity = 1; + if (No == pi->options.allow_nan || 0 != strncmp("Infinity", pi->cur, 8)) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); + return; + } + pi->cur += 8; + ni.infinity = 1; } else if ('N' == *pi->cur || 'n' == *pi->cur) { - if ('a' != pi->cur[1] || ('N' != pi->cur[2] && 'n' != pi->cur[2])) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); - return; - } - pi->cur += 3; - ni.nan = 1; + if ('a' != pi->cur[1] || ('N' != pi->cur[2] && 'n' != pi->cur[2])) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); + return; + } + pi->cur += 3; + ni.nan = 1; } else { - int dec_cnt = 0; - bool zero1 = false; - - for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) { - if (0 == ni.i && '0' == *pi->cur) { - zero1 = true; - } - if (0 < ni.i) { - dec_cnt++; - } - if (!ni.big) { - int d = (*pi->cur - '0'); - - if (0 < d) { - if (zero1 && CompatMode == pi->options.mode) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number"); - return; - } - zero1 = false; - } - ni.i = ni.i * 10 + d; - if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) { - ni.big = 1; - } - } - } - if ('.' == *pi->cur) { - pi->cur++; - // A trailing . is not a valid decimal but if encountered allow it - // except when mimicing the JSON gem or in strict mode. - if (StrictMode == pi->options.mode || CompatMode == pi->options.mode) { - int pos = (int)(pi->cur - ni.str); - - if (1 == pos || (2 == pos && ni.neg)) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number"); - return; - } - if (*pi->cur < '0' || '9' < *pi->cur) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number"); - return; - } - } - for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) { - int d = (*pi->cur - '0'); - - if (0 < ni.num || 0 < ni.i) { - dec_cnt++; - } - if (INT64_MAX <= ni.div) { - if (!ni.no_big) { - ni.big = true; - } - } else { - ni.num = ni.num * 10 + d; - ni.div *= 10; - ni.di++; - if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) { - if (!ni.no_big) { - ni.big = true; - } - } - } - } - } - if ('e' == *pi->cur || 'E' == *pi->cur) { - int eneg = 0; - - ni.has_exp = 1; - pi->cur++; - if ('-' == *pi->cur) { - pi->cur++; - eneg = 1; - } else if ('+' == *pi->cur) { - pi->cur++; - } - for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) { - ni.exp = ni.exp * 10 + (*pi->cur - '0'); - if (EXP_MAX <= ni.exp) { - ni.big = true; - } - } - if (eneg) { - ni.exp = -ni.exp; - } - } - ni.len = pi->cur - ni.str; + int dec_cnt = 0; + bool zero1 = false; + + for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) { + if (0 == ni.i && '0' == *pi->cur) { + zero1 = true; + } + if (0 < ni.i) { + dec_cnt++; + } + if (!ni.big) { + int d = (*pi->cur - '0'); + + if (0 < d) { + if (zero1 && CompatMode == pi->options.mode) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number"); + return; + } + zero1 = false; + } + ni.i = ni.i * 10 + d; + if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) { + ni.big = 1; + } + } + } + if ('.' == *pi->cur) { + pi->cur++; + // A trailing . is not a valid decimal but if encountered allow it + // except when mimicing the JSON gem or in strict mode. + if (StrictMode == pi->options.mode || CompatMode == pi->options.mode) { + int pos = (int)(pi->cur - ni.str); + + if (1 == pos || (2 == pos && ni.neg)) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number"); + return; + } + if (*pi->cur < '0' || '9' < *pi->cur) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number"); + return; + } + } + for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) { + int d = (*pi->cur - '0'); + + if (0 < ni.num || 0 < ni.i) { + dec_cnt++; + } + if (INT64_MAX <= ni.div) { + if (!ni.no_big) { + ni.big = true; + } + } else { + ni.num = ni.num * 10 + d; + ni.div *= 10; + ni.di++; + if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) { + if (!ni.no_big) { + ni.big = true; + } + } + } + } + } + if ('e' == *pi->cur || 'E' == *pi->cur) { + int eneg = 0; + + ni.has_exp = 1; + pi->cur++; + if ('-' == *pi->cur) { + pi->cur++; + eneg = 1; + } else if ('+' == *pi->cur) { + pi->cur++; + } + for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) { + ni.exp = ni.exp * 10 + (*pi->cur - '0'); + if (EXP_MAX <= ni.exp) { + ni.big = true; + } + } + if (eneg) { + ni.exp = -ni.exp; + } + } + ni.len = pi->cur - ni.str; } // Check for special reserved values for Infinity and NaN. if (ni.big) { - if (0 == strcasecmp(INF_VAL, ni.str)) { - ni.infinity = 1; - } else if (0 == strcasecmp(NINF_VAL, ni.str)) { - ni.infinity = 1; - ni.neg = 1; - } else if (0 == strcasecmp(NAN_VAL, ni.str)) { - ni.nan = 1; - } + if (0 == strcasecmp(INF_VAL, ni.str)) { + ni.infinity = 1; + } else if (0 == strcasecmp(NINF_VAL, ni.str)) { + ni.infinity = 1; + ni.neg = 1; + } else if (0 == strcasecmp(NAN_VAL, ni.str)) { + ni.nan = 1; + } } if (CompatMode == pi->options.mode) { - if (pi->options.compat_bigdec) { - ni.big = 1; - } + if (pi->options.compat_bigdec) { + ni.big = 1; + } } else if (BigDec == pi->options.bigdec_load) { - ni.big = 1; + ni.big = 1; } if (0 == parent) { - pi->add_num(pi, &ni); + pi->add_num(pi, &ni); } else { - switch (parent->next) { - case NEXT_ARRAY_NEW: - case NEXT_ARRAY_ELEMENT: - pi->array_append_num(pi, &ni); - parent->next = NEXT_ARRAY_COMMA; - break; - case NEXT_HASH_VALUE: - pi->hash_set_num(pi, parent, &ni); - if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) { - xfree((char *)parent->key); - parent->key = 0; - } - parent->next = NEXT_HASH_COMMA; - break; - default: - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s", oj_stack_next_string(parent->next)); - break; - } + switch (parent->next) { + case NEXT_ARRAY_NEW: + case NEXT_ARRAY_ELEMENT: + pi->array_append_num(pi, &ni); + parent->next = NEXT_ARRAY_COMMA; + break; + case NEXT_HASH_VALUE: + pi->hash_set_num(pi, parent, &ni); + if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) { + xfree((char*)parent->key); + parent->key = 0; + } + parent->next = NEXT_HASH_COMMA; + break; + default: + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s", oj_stack_next_string(parent->next)); + break; + } } } static void array_start(ParseInfo pi) { - volatile VALUE v = pi->start_array(pi); + volatile VALUE v = pi->start_array(pi); stack_push(&pi->stack, v, NEXT_ARRAY_NEW); } static void array_end(ParseInfo pi) { - Val array = stack_pop(&pi->stack); + Val array = stack_pop(&pi->stack); if (0 == array) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected array close"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected array close"); } else if (NEXT_ARRAY_COMMA != array->next && NEXT_ARRAY_NEW != array->next) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not an array close", oj_stack_next_string(array->next)); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not an array close", oj_stack_next_string(array->next)); } else { - pi->end_array(pi); - add_value(pi, array->val); + pi->end_array(pi); + add_value(pi, array->val); } } static void hash_start(ParseInfo pi) { - volatile VALUE v = pi->start_hash(pi); + volatile VALUE v = pi->start_hash(pi); stack_push(&pi->stack, v, NEXT_HASH_NEW); } static void hash_end(ParseInfo pi) { - volatile Val hash = stack_peek(&pi->stack); + volatile Val hash = stack_peek(&pi->stack); // leave hash on stack until just before if (0 == hash) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected hash close"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected hash close"); } else if (NEXT_HASH_COMMA != hash->next && NEXT_HASH_NEW != hash->next) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a hash close", oj_stack_next_string(hash->next)); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a hash close", oj_stack_next_string(hash->next)); } else { - pi->end_hash(pi); - stack_pop(&pi->stack); - add_value(pi, hash->val); + pi->end_hash(pi); + stack_pop(&pi->stack); + add_value(pi, hash->val); } } static void comma(ParseInfo pi) { - Val parent = stack_peek(&pi->stack); + Val parent = stack_peek(&pi->stack); if (0 == parent) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma"); } else if (NEXT_ARRAY_COMMA == parent->next) { - parent->next = NEXT_ARRAY_ELEMENT; + parent->next = NEXT_ARRAY_ELEMENT; } else if (NEXT_HASH_COMMA == parent->next) { - parent->next = NEXT_HASH_KEY; + parent->next = NEXT_HASH_KEY; } else { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma"); } } static void colon(ParseInfo pi) { - Val parent = stack_peek(&pi->stack); + Val parent = stack_peek(&pi->stack); if (0 != parent && NEXT_HASH_COLON == parent->next) { - parent->next = NEXT_HASH_VALUE; + parent->next = NEXT_HASH_VALUE; } else { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected colon"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected colon"); } } void oj_parse2(ParseInfo pi) { - int first = 1; - long start = 0; + int first = 1; + long start = 0; pi->cur = pi->json; err_init(&pi->err); while (1) { - if (0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1) { - VALUE err_clas = oj_get_json_err_class("NestingError"); - - oj_set_error_at(pi, err_clas, __FILE__, __LINE__, "Too deeply nested."); - pi->err_class = err_clas; - return; - } - next_non_white(pi); - if (!first && '\0' != *pi->cur) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected characters after the JSON document"); - } - - // If no tokens are consumed (i.e. empty string), throw a parse error - // this is the behavior of JSON.parse in both Ruby and JS. - if (No == pi->options.empty_string && 1 == first && '\0' == *pi->cur) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); - } - - switch (*pi->cur++) { - case '{': - hash_start(pi); - break; - case '}': - hash_end(pi); - break; - case ':': - colon(pi); - break; - case '[': - array_start(pi); - break; - case ']': - array_end(pi); - break; - case ',': - comma(pi); - break; - case '"': - read_str(pi); - break; - //case '+': - case '+': - if (CompatMode == pi->options.mode) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); - return; - } - pi->cur--; - read_num(pi); - break; - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - pi->cur--; - read_num(pi); - break; - case 'I': - case 'N': - if (Yes == pi->options.allow_nan) { - pi->cur--; - read_num(pi); - } else { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); - } - break; - case 't': - read_true(pi); - break; - case 'f': - read_false(pi); - break; - case 'n': - if ('u' == *pi->cur) { - read_null(pi); - } else { - pi->cur--; - read_num(pi); - } - break; - case '/': - skip_comment(pi); - if (first) { - continue; - } - break; - case '\0': - pi->cur--; - return; - default: - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); - return; - } - if (err_has(&pi->err)) { - return; - } - if (stack_empty(&pi->stack)) { - if (Qundef != pi->proc) { - VALUE args[3]; - long len = (pi->cur - pi->json) - start; - - *args = stack_head_val(&pi->stack); - args[1] = LONG2NUM(start); - args[2] = LONG2NUM(len); - - if (Qnil == pi->proc) { - rb_yield_values2(3, args); - } else { - rb_proc_call_with_block(pi->proc, 3, args, Qnil); - } - } else if (!pi->has_callbacks) { - first = 0; - } - start = pi->cur - pi->json; - } + if (0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1) { + VALUE err_clas = oj_get_json_err_class("NestingError"); + + oj_set_error_at(pi, err_clas, __FILE__, __LINE__, "Too deeply nested."); + pi->err_class = err_clas; + return; + } + next_non_white(pi); + if (!first && '\0' != *pi->cur) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected characters after the JSON document"); + } + + // If no tokens are consumed (i.e. empty string), throw a parse error + // this is the behavior of JSON.parse in both Ruby and JS. + if (No == pi->options.empty_string && 1 == first && '\0' == *pi->cur) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); + } + + switch (*pi->cur++) { + case '{': + hash_start(pi); + break; + case '}': + hash_end(pi); + break; + case ':': + colon(pi); + break; + case '[': + array_start(pi); + break; + case ']': + array_end(pi); + break; + case ',': + comma(pi); + break; + case '"': + read_str(pi); + break; + //case '+': + case '+': + if (CompatMode == pi->options.mode) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); + return; + } + pi->cur--; + read_num(pi); + break; + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + pi->cur--; + read_num(pi); + break; + case 'I': + case 'N': + if (Yes == pi->options.allow_nan) { + pi->cur--; + read_num(pi); + } else { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); + } + break; + case 't': + read_true(pi); + break; + case 'f': + read_false(pi); + break; + case 'n': + if ('u' == *pi->cur) { + read_null(pi); + } else { + pi->cur--; + read_num(pi); + } + break; + case '/': + skip_comment(pi); + if (first) { + continue; + } + break; + case '\0': + pi->cur--; + return; + default: + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); + return; + } + if (err_has(&pi->err)) { + return; + } + if (stack_empty(&pi->stack)) { + if (Qundef != pi->proc) { + VALUE args[3]; + long len = (pi->cur - pi->json) - start; + + *args = stack_head_val(&pi->stack); + args[1] = LONG2NUM(start); + args[2] = LONG2NUM(len); + + if (Qnil == pi->proc) { + rb_yield_values2(3, args); + } else { + rb_proc_call_with_block(pi->proc, 3, args, Qnil); + } + } else if (!pi->has_callbacks) { + first = 0; + } + start = pi->cur - pi->json; + } } } @@ -777,7 +761,7 @@ parse_big_decimal(VALUE str) { return rb_funcall(rb_cObject, oj_bigdecimal_id, 1, str); } -static long double exp_plus[] = { +static long double exp_plus[] = { 1.0, 1.0e1, 1.0e2, @@ -832,134 +816,134 @@ static long double exp_plus[] = { VALUE oj_num_as_value(NumInfo ni) { - volatile VALUE rnum = Qnil; + volatile VALUE rnum = Qnil; if (ni->infinity) { - if (ni->neg) { - rnum = rb_float_new(-OJ_INFINITY); - } else { - rnum = rb_float_new(OJ_INFINITY); - } + if (ni->neg) { + rnum = rb_float_new(-OJ_INFINITY); + } else { + rnum = rb_float_new(OJ_INFINITY); + } } else if (ni->nan) { - rnum = rb_float_new(0.0 / 0.0); + rnum = rb_float_new(0.0/0.0); } else if (1 == ni->div && 0 == ni->exp && !ni->has_exp) { // fixnum - if (ni->big) { - if (256 > ni->len) { - char buf[256]; - - memcpy(buf, ni->str, ni->len); - buf[ni->len] = '\0'; - rnum = rb_cstr_to_inum(buf, 10, 0); - } else { - char *buf = ALLOC_N(char, ni->len + 1); - - memcpy(buf, ni->str, ni->len); - buf[ni->len] = '\0'; - rnum = rb_cstr_to_inum(buf, 10, 0); - xfree(buf); - } - } else { - if (ni->neg) { - rnum = rb_ll2inum(-ni->i); - } else { - rnum = rb_ll2inum(ni->i); - } - } + if (ni->big) { + if (256 > ni->len) { + char buf[256]; + + memcpy(buf, ni->str, ni->len); + buf[ni->len] = '\0'; + rnum = rb_cstr_to_inum(buf, 10, 0); + } else { + char *buf = ALLOC_N(char, ni->len + 1); + + memcpy(buf, ni->str, ni->len); + buf[ni->len] = '\0'; + rnum = rb_cstr_to_inum(buf, 10, 0); + xfree(buf); + } + } else { + if (ni->neg) { + rnum = rb_ll2inum(-ni->i); + } else { + rnum = rb_ll2inum(ni->i); + } + } } else { // decimal - if (ni->big) { - volatile VALUE bd = rb_str_new(ni->str, ni->len); - - rnum = rb_rescue2(parse_big_decimal, bd, rescue_big_decimal, bd, rb_eException, 0); - if (ni->no_big) { - rnum = rb_funcall(rnum, rb_intern("to_f"), 0); - } - } else if (FastDec == ni->bigdec_load) { - long double ld = (long double)ni->i * (long double)ni->div + (long double)ni->num; - int x = (int)((int64_t)ni->exp - ni->di); - - if (0 < x) { - if (x < (int)(sizeof(exp_plus) / sizeof(*exp_plus))) { - ld *= exp_plus[x]; - } else { - ld *= powl(10.0, x); - } - } else if (x < 0) { - if (-x < (int)(sizeof(exp_plus) / sizeof(*exp_plus))) { - ld /= exp_plus[-x]; - } else { - ld /= powl(10.0, -x); - } - } - if (ni->neg) { - ld = -ld; - } - rnum = rb_float_new((double)ld); - } else if (RubyDec == ni->bigdec_load) { - volatile VALUE sv = rb_str_new(ni->str, ni->len); - - rnum = rb_funcall(sv, rb_intern("to_f"), 0); - } else { - char *end; - double d = strtod(ni->str, &end); - - if ((long)ni->len != (long)(end - ni->str)) { - rb_raise(oj_parse_error_class, "Invalid float"); - } - rnum = rb_float_new(d); - } + if (ni->big) { + volatile VALUE bd = rb_str_new(ni->str, ni->len); + + rnum = rb_rescue2(parse_big_decimal, bd, rescue_big_decimal, bd, rb_eException, 0); + if (ni->no_big) { + rnum = rb_funcall(rnum, rb_intern("to_f"), 0); + } + } else if (FastDec == ni->bigdec_load) { + long double ld = (long double)ni->i * (long double)ni->div + (long double)ni->num; + int x = (int)((int64_t)ni->exp - ni->di); + + if (0 < x) { + if (x < (int)(sizeof(exp_plus) / sizeof(*exp_plus))) { + ld *= exp_plus[x]; + } else { + ld *= powl(10.0, x); + } + } else if (x < 0) { + if (-x < (int)(sizeof(exp_plus) / sizeof(*exp_plus))) { + ld /= exp_plus[-x]; + } else { + ld /= powl(10.0, -x); + } + } + if (ni->neg) { + ld = -ld; + } + rnum = rb_float_new((double)ld); + } else if (RubyDec == ni->bigdec_load) { + volatile VALUE sv = rb_str_new(ni->str, ni->len); + + rnum = rb_funcall(sv, rb_intern("to_f"), 0); + } else { + char *end; + double d = strtod(ni->str, &end); + + if ((long)ni->len != (long)(end - ni->str)) { + rb_raise(oj_parse_error_class, "Invalid float"); + } + rnum = rb_float_new(d); + } } return rnum; } void -oj_set_error_at(ParseInfo pi, VALUE err_clas, const char *file, int line, const char *format, ...) { - va_list ap; - char msg[256]; - char *p = msg; - char *end = p + sizeof(msg) - 2; - char *start; - Val vp; +oj_set_error_at(ParseInfo pi, VALUE err_clas, const char* file, int line, const char *format, ...) { + va_list ap; + char msg[256]; + char *p = msg; + char *end = p + sizeof(msg) - 2; + char *start; + Val vp; va_start(ap, format); p += vsnprintf(msg, sizeof(msg) - 1, format, ap); va_end(ap); pi->err.clas = err_clas; if (p + 3 < end) { - *p++ = ' '; - *p++ = '('; - *p++ = 'a'; - *p++ = 'f'; - *p++ = 't'; - *p++ = 'e'; - *p++ = 'r'; - *p++ = ' '; - start = p; - for (vp = pi->stack.head; vp < pi->stack.tail; vp++) { - if (end <= p + 1 + vp->klen) { - break; - } - if (NULL != vp->key) { - if (start < p) { - *p++ = '.'; - } - memcpy(p, vp->key, vp->klen); - p += vp->klen; - } else { - if (RUBY_T_ARRAY == rb_type(vp->val)) { - if (end <= p + 12) { - break; - } - p += snprintf(p, end - p, "[%ld]", RARRAY_LEN(vp->val)); - } - } - } - *p++ = ')'; + *p++ = ' '; + *p++ = '('; + *p++ = 'a'; + *p++ = 'f'; + *p++ = 't'; + *p++ = 'e'; + *p++ = 'r'; + *p++ = ' '; + start = p; + for (vp = pi->stack.head; vp < pi->stack.tail; vp++) { + if (end <= p + 1 + vp->klen) { + break; + } + if (NULL != vp->key) { + if (start < p) { + *p++ = '.'; + } + memcpy(p, vp->key, vp->klen); + p += vp->klen; + } else { + if (RUBY_T_ARRAY == rb_type(vp->val)) { + if (end <= p + 12) { + break; + } + p += snprintf(p, end - p, "[%ld]", RARRAY_LEN(vp->val)); + } + } + } + *p++ = ')'; } *p = '\0'; if (0 == pi->json) { - oj_err_set(&pi->err, err_clas, "%s at line %d, column %d [%s:%d]", msg, pi->rd.line, pi->rd.col, file, line); + oj_err_set(&pi->err, err_clas, "%s at line %d, column %d [%s:%d]", msg, pi->rd.line, pi->rd.col, file, line); } else { - _oj_err_set_with_location(&pi->err, err_clas, msg, pi->json, pi->cur - 1, file, line); + _oj_err_set_with_location(&pi->err, err_clas, msg, pi->json, pi->cur - 1, file, line); } } @@ -974,100 +958,100 @@ extern int oj_utf8_index; static void oj_pi_set_input_str(ParseInfo pi, volatile VALUE *inputp) { - rb_encoding *enc = rb_to_encoding(rb_obj_encoding(*inputp)); + rb_encoding *enc = rb_to_encoding(rb_obj_encoding(*inputp)); if (rb_utf8_encoding() != enc) { - *inputp = rb_str_conv_enc(*inputp, enc, rb_utf8_encoding()); + *inputp = rb_str_conv_enc(*inputp, enc, rb_utf8_encoding()); } - pi->json = rb_string_value_ptr((VALUE *)inputp); + pi->json = rb_string_value_ptr((VALUE*)inputp); pi->end = pi->json + RSTRING_LEN(*inputp); } VALUE oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk) { - char *buf = 0; - volatile VALUE input; - volatile VALUE wrapped_stack; - volatile VALUE result = Qnil; - int line = 0; - int free_json = 0; + char *buf = 0; + volatile VALUE input; + volatile VALUE wrapped_stack; + volatile VALUE result = Qnil; + int line = 0; + int free_json = 0; if (argc < 1) { - rb_raise(rb_eArgError, "Wrong number of arguments to parse."); + rb_raise(rb_eArgError, "Wrong number of arguments to parse."); } input = argv[0]; if (2 <= argc) { - if (T_HASH == rb_type(argv[1])) { - oj_parse_options(argv[1], &pi->options); - } else if (3 <= argc && T_HASH == rb_type(argv[2])) { - oj_parse_options(argv[2], &pi->options); - } + if (T_HASH == rb_type(argv[1])) { + oj_parse_options(argv[1], &pi->options); + } else if (3 <= argc && T_HASH == rb_type(argv[2])) { + oj_parse_options(argv[2], &pi->options); + } } if (yieldOk && rb_block_given_p()) { - pi->proc = Qnil; + pi->proc = Qnil; } else { - pi->proc = Qundef; + pi->proc = Qundef; } if (0 != json) { - pi->json = json; - pi->end = json + len; - free_json = 1; + pi->json = json; + pi->end = json + len; + free_json = 1; } else if (T_STRING == rb_type(input)) { - if (CompatMode == pi->options.mode) { - if (No == pi->options.nilnil && 0 == RSTRING_LEN(input)) { - rb_raise(oj_json_parser_error_class, "An empty string is not a valid JSON string."); - } - } - oj_pi_set_input_str(pi, &input); + if (CompatMode == pi->options.mode) { + if (No == pi->options.nilnil && 0 == RSTRING_LEN(input)) { + rb_raise(oj_json_parser_error_class, "An empty string is not a valid JSON string."); + } + } + oj_pi_set_input_str(pi, &input); } else if (Qnil == input) { - if (Yes == pi->options.nilnil) { - return Qnil; - } else { - rb_raise(rb_eTypeError, "Nil is not a valid JSON source."); - } + if (Yes == pi->options.nilnil) { + return Qnil; + } else { + rb_raise(rb_eTypeError, "Nil is not a valid JSON source."); + } } else { - VALUE clas = rb_obj_class(input); - volatile VALUE s; + VALUE clas = rb_obj_class(input); + volatile VALUE s; - if (oj_stringio_class == clas) { - s = rb_funcall2(input, oj_string_id, 0, 0); - oj_pi_set_input_str(pi, &s); + if (oj_stringio_class == clas) { + s = rb_funcall2(input, oj_string_id, 0, 0); + oj_pi_set_input_str(pi, &s); #if !IS_WINDOWS - } else if (rb_cFile == clas && 0 == FIX2INT(rb_funcall(input, oj_pos_id, 0))) { - int fd = FIX2INT(rb_funcall(input, oj_fileno_id, 0)); - ssize_t cnt; - size_t len = lseek(fd, 0, SEEK_END); - - lseek(fd, 0, SEEK_SET); - buf = ALLOC_N(char, len + 1); - pi->json = buf; - pi->end = buf + len; - if (0 >= (cnt = read(fd, (char *)pi->json, len)) || cnt != (ssize_t)len) { - if (0 != buf) { - xfree(buf); - } - rb_raise(rb_eIOError, "failed to read from IO Object."); - } - ((char *)pi->json)[len] = '\0'; - /* skip UTF-8 BOM if present */ - if (0xEF == (uint8_t)*pi->json && 0xBB == (uint8_t)pi->json[1] && 0xBF == (uint8_t)pi->json[2]) { - pi->cur += 3; - } + } else if (rb_cFile == clas && 0 == FIX2INT(rb_funcall(input, oj_pos_id, 0))) { + int fd = FIX2INT(rb_funcall(input, oj_fileno_id, 0)); + ssize_t cnt; + size_t len = lseek(fd, 0, SEEK_END); + + lseek(fd, 0, SEEK_SET); + buf = ALLOC_N(char, len + 1); + pi->json = buf; + pi->end = buf + len; + if (0 >= (cnt = read(fd, (char*)pi->json, len)) || cnt != (ssize_t)len) { + if (0 != buf) { + xfree(buf); + } + rb_raise(rb_eIOError, "failed to read from IO Object."); + } + ((char*)pi->json)[len] = '\0'; + /* skip UTF-8 BOM if present */ + if (0xEF == (uint8_t)*pi->json && 0xBB == (uint8_t)pi->json[1] && 0xBF == (uint8_t)pi->json[2]) { + pi->cur += 3; + } #endif - } else if (rb_respond_to(input, oj_read_id)) { - // use stream parser instead - return oj_pi_sparse(argc, argv, pi, 0); - } else { - rb_raise(rb_eArgError, "parse() expected a String or IO Object."); - } + } else if (rb_respond_to(input, oj_read_id)) { + // use stream parser instead + return oj_pi_sparse(argc, argv, pi, 0); + } else { + rb_raise(rb_eArgError, "parse() expected a String or IO Object."); +} } if (Yes == pi->options.circular) { - pi->circ_array = oj_circ_array_new(); + pi->circ_array = oj_circ_array_new(); } else { - pi->circ_array = 0; + pi->circ_array = 0; } if (No == pi->options.allow_gc) { - rb_gc_disable(); + rb_gc_disable(); } // GC can run at any time. When it runs any Object created by C will be // freed. We protect against this by wrapping the value stack in a ruby @@ -1076,116 +1060,116 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie wrapped_stack = oj_stack_init(&pi->stack); rb_protect(protect_parse, (VALUE)pi, &line); if (Qundef == pi->stack.head->val && !empty_ok(&pi->options)) { - if (No == pi->options.nilnil || (CompatMode == pi->options.mode && 0 < pi->cur - pi->json)) { - oj_set_error_at(pi, oj_json_parser_error_class, __FILE__, __LINE__, "Empty input"); - } + if (No == pi->options.nilnil || (CompatMode == pi->options.mode && 0 < pi->cur - pi->json)) { + oj_set_error_at(pi, oj_json_parser_error_class, __FILE__, __LINE__, "Empty input"); + } } result = stack_head_val(&pi->stack); DATA_PTR(wrapped_stack) = 0; if (No == pi->options.allow_gc) { - rb_gc_enable(); + rb_gc_enable(); } if (!err_has(&pi->err)) { - // If the stack is not empty then the JSON terminated early. - Val v; - VALUE err_class = oj_parse_error_class; - - if (0 != line) { - VALUE ec = rb_obj_class(rb_errinfo()); - - if (rb_eArgError != ec && 0 != ec) { - err_class = ec; - } - if (rb_eIOError != ec) { - goto CLEANUP; - } - } - if (NULL != (v = stack_peek(&pi->stack))) { - switch (v->next) { - case NEXT_ARRAY_NEW: - case NEXT_ARRAY_ELEMENT: - case NEXT_ARRAY_COMMA: - oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated"); - break; - case NEXT_HASH_NEW: - case NEXT_HASH_KEY: - case NEXT_HASH_COLON: - case NEXT_HASH_VALUE: - case NEXT_HASH_COMMA: - oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Hash/Object not terminated"); - break; - default: - oj_set_error_at(pi, err_class, __FILE__, __LINE__, "not terminated"); - } - } + // If the stack is not empty then the JSON terminated early. + Val v; + VALUE err_class = oj_parse_error_class; + + if (0 != line) { + VALUE ec = rb_obj_class(rb_errinfo()); + + if (rb_eArgError != ec && 0 != ec) { + err_class = ec; + } + if (rb_eIOError != ec) { + goto CLEANUP; + } + } + if (NULL != (v = stack_peek(&pi->stack))) { + switch (v->next) { + case NEXT_ARRAY_NEW: + case NEXT_ARRAY_ELEMENT: + case NEXT_ARRAY_COMMA: + oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated"); + break; + case NEXT_HASH_NEW: + case NEXT_HASH_KEY: + case NEXT_HASH_COLON: + case NEXT_HASH_VALUE: + case NEXT_HASH_COMMA: + oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Hash/Object not terminated"); + break; + default: + oj_set_error_at(pi, err_class, __FILE__, __LINE__, "not terminated"); + } + } } CLEANUP: // proceed with cleanup if (0 != pi->circ_array) { - oj_circ_array_free(pi->circ_array); + oj_circ_array_free(pi->circ_array); } if (0 != buf) { - xfree(buf); + xfree(buf); } else if (free_json) { - xfree(json); + xfree(json); } stack_cleanup(&pi->stack); if (pi->str_rx.head != oj_default_options.str_rx.head) { - oj_rxclass_cleanup(&pi->str_rx); + oj_rxclass_cleanup(&pi->str_rx); } if (err_has(&pi->err)) { - rb_set_errinfo(Qnil); - if (Qnil != pi->err_class) { - pi->err.clas = pi->err_class; - } - if (CompatMode == pi->options.mode && Yes != pi->options.safe) { - // The json gem requires the error message be UTF-8 encoded. In - // additional the complete JSON source must be returned. There - // does not seem to be a size limit. - VALUE msg = oj_encode(rb_str_new2(pi->err.msg)); - VALUE args[1]; - - if (NULL != pi->json) { - msg = rb_str_append(msg, oj_encode(rb_str_new2(" in '"))); - msg = rb_str_append(msg, oj_encode(rb_str_new2(pi->json))); - } - args[0] = msg; - if (pi->err.clas == oj_parse_error_class) { - // The error was an Oj::ParseError so change to a JSON::ParserError. - pi->err.clas = oj_json_parser_error_class; - } - rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas)); - } else { - oj_err_raise(&pi->err); - } + rb_set_errinfo(Qnil); + if (Qnil != pi->err_class) { + pi->err.clas = pi->err_class; + } + if (CompatMode == pi->options.mode && Yes != pi->options.safe) { + // The json gem requires the error message be UTF-8 encoded. In + // additional the complete JSON source must be returned. There + // does not seem to be a size limit. + VALUE msg = oj_encode(rb_str_new2(pi->err.msg)); + VALUE args[1]; + + if (NULL != pi->json) { + msg = rb_str_append(msg, oj_encode(rb_str_new2(" in '"))); + msg = rb_str_append(msg, oj_encode(rb_str_new2(pi->json))); + } + args[0] = msg; + if (pi->err.clas == oj_parse_error_class) { + // The error was an Oj::ParseError so change to a JSON::ParserError. + pi->err.clas = oj_json_parser_error_class; + } + rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas)); + } else { + oj_err_raise(&pi->err); + } } else if (0 != line) { - rb_jump_tag(line); + rb_jump_tag(line); } if (pi->options.quirks_mode == No) { - switch (rb_type(result)) { - case T_NIL: - case T_TRUE: - case T_FALSE: - case T_FIXNUM: - case T_FLOAT: - case T_CLASS: - case T_STRING: - case T_SYMBOL: { - struct _err err; - - if (Qnil == pi->err_class) { - err.clas = oj_parse_error_class; - } else { - err.clas = pi->err_class; - } - snprintf(err.msg, sizeof(err.msg), "unexpected non-document value"); - oj_err_raise(&err); - break; - } - default: - // okay - break; - } + switch (rb_type(result)) { + case T_NIL: + case T_TRUE: + case T_FALSE: + case T_FIXNUM: + case T_FLOAT: + case T_CLASS: + case T_STRING: + case T_SYMBOL: { + struct _err err; + + if (Qnil == pi->err_class) { + err.clas = oj_parse_error_class; + } else { + err.clas = pi->err_class; + } + snprintf(err.msg, sizeof(err.msg), "unexpected non-document value"); + oj_err_raise(&err); + break; + } + default: + // okay + break; + } } return result; } diff --git a/ext/oj/parse.h b/ext/oj/parse.h index 9d7e582b..0f233618 100644 --- a/ext/oj/parse.h +++ b/ext/oj/parse.h @@ -8,85 +8,82 @@ #include #include -#include "circarray.h" +#include "ruby.h" #include "oj.h" +#include "val_stack.h" +#include "circarray.h" #include "reader.h" -#include "ruby.h" #include "rxclass.h" -#include "val_stack.h" struct _rxClass; typedef struct _numInfo { - int64_t i; - int64_t num; - int64_t div; - int64_t di; - const char *str; - size_t len; - long exp; - int big; - int infinity; - int nan; - int neg; - int has_exp; - int no_big; - int bigdec_load; -} * NumInfo; + int64_t i; + int64_t num; + int64_t div; + int64_t di; + const char *str; + size_t len; + long exp; + int big; + int infinity; + int nan; + int neg; + int has_exp; + int no_big; + int bigdec_load; +} *NumInfo; typedef struct _parseInfo { // used for the string parser - const char *json; - const char *cur; - const char *end; + const char *json; + const char *cur; + const char *end; // used for the stream parser - struct _reader rd; + struct _reader rd; - struct _err err; - struct _options options; - VALUE handler; - struct _valStack stack; - CircArray circ_array; - struct _rxClass str_rx; - int expect_value; - int max_depth; // just for the json gem - VALUE proc; - VALUE (*start_hash) - (struct _parseInfo *pi); - void (*end_hash)(struct _parseInfo *pi); - VALUE (*hash_key) - (struct _parseInfo *pi, const char *key, size_t klen); - void (*hash_set_cstr)(struct _parseInfo *pi, Val kval, const char *str, size_t len, const char *orig); - void (*hash_set_num)(struct _parseInfo *pi, Val kval, NumInfo ni); - void (*hash_set_value)(struct _parseInfo *pi, Val kval, VALUE value); + struct _err err; + struct _options options; + VALUE handler; + struct _valStack stack; + CircArray circ_array; + struct _rxClass str_rx; + int expect_value; + int max_depth; // just for the json gem + VALUE proc; + VALUE (*start_hash)(struct _parseInfo *pi); + void (*end_hash)(struct _parseInfo *pi); + VALUE (*hash_key)(struct _parseInfo *pi, const char *key, size_t klen); + void (*hash_set_cstr)(struct _parseInfo *pi, Val kval, const char *str, size_t len, const char *orig); + void (*hash_set_num)(struct _parseInfo *pi, Val kval, NumInfo ni); + void (*hash_set_value)(struct _parseInfo *pi, Val kval, VALUE value); - VALUE (*start_array) - (struct _parseInfo *pi); - void (*end_array)(struct _parseInfo *pi); - void (*array_append_cstr)(struct _parseInfo *pi, const char *str, size_t len, const char *orig); - void (*array_append_num)(struct _parseInfo *pi, NumInfo ni); - void (*array_append_value)(struct _parseInfo *pi, VALUE value); + VALUE (*start_array)(struct _parseInfo *pi); + void (*end_array)(struct _parseInfo *pi); + void (*array_append_cstr)(struct _parseInfo *pi, const char *str, size_t len, const char *orig); + void (*array_append_num)(struct _parseInfo *pi, NumInfo ni); + void (*array_append_value)(struct _parseInfo *pi, VALUE value); - void (*add_cstr)(struct _parseInfo *pi, const char *str, size_t len, const char *orig); - void (*add_num)(struct _parseInfo *pi, NumInfo ni); - void (*add_value)(struct _parseInfo *pi, VALUE val); - VALUE err_class; - bool has_callbacks; -} * ParseInfo; + void (*add_cstr)(struct _parseInfo *pi, const char *str, size_t len, const char *orig); + void (*add_num)(struct _parseInfo *pi, NumInfo ni); + void (*add_value)(struct _parseInfo *pi, VALUE val); + VALUE err_class; + bool has_callbacks; +} *ParseInfo; -extern void oj_parse2(ParseInfo pi); -extern void oj_set_error_at(ParseInfo pi, VALUE err_clas, const char *file, int line, const char *format, ...); -extern VALUE oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk); -extern VALUE oj_num_as_value(NumInfo ni); +extern void oj_parse2(ParseInfo pi); +extern void oj_set_error_at(ParseInfo pi, VALUE err_clas, const char* file, int line, const char *format, ...); +extern VALUE oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk); +extern VALUE oj_num_as_value(NumInfo ni); -extern void oj_set_strict_callbacks(ParseInfo pi); -extern void oj_set_object_callbacks(ParseInfo pi); -extern void oj_set_compat_callbacks(ParseInfo pi); -extern void oj_set_custom_callbacks(ParseInfo pi); -extern void oj_set_wab_callbacks(ParseInfo pi); +extern void oj_set_strict_callbacks(ParseInfo pi); +extern void oj_set_object_callbacks(ParseInfo pi); +extern void oj_set_compat_callbacks(ParseInfo pi); +extern void oj_set_custom_callbacks(ParseInfo pi); +extern void oj_set_wab_callbacks(ParseInfo pi); -extern void oj_sparse2(ParseInfo pi); -extern VALUE oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd); +extern void oj_sparse2(ParseInfo pi); +extern VALUE oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd); static inline void parse_info_init(ParseInfo pi) { @@ -96,17 +93,17 @@ parse_info_init(ParseInfo pi) { static inline bool empty_ok(Options options) { switch (options->mode) { - case ObjectMode: - case WabMode: - return true; - case CompatMode: - case RailsMode: - return false; - case StrictMode: - case NullMode: - case CustomMode: - default: - break; + case ObjectMode: + case WabMode: + return true; + case CompatMode: + case RailsMode: + return false; + case StrictMode: + case NullMode: + case CustomMode: + default: + break; } return Yes == options->empty_string; } diff --git a/ext/oj/rails.c b/ext/oj/rails.c index 0591e300..8e1ed899 100644 --- a/ext/oj/rails.c +++ b/ext/oj/rails.c @@ -2,70 +2,71 @@ // Licensed under the MIT License. See LICENSE file in the project root for license details. #include "rails.h" +#include "encode.h" #include "code.h" #include "encode.h" #include "trace.h" #include "util.h" -#define OJ_INFINITY (1.0 / 0.0) +#define OJ_INFINITY (1.0/0.0) // TBD keep static array of strings and functions to help with rails optimization typedef struct _encoder { - struct _rOptTable ropts; - struct _options opts; - VALUE arg; -} * Encoder; + struct _rOptTable ropts; + struct _options opts; + VALUE arg; +} *Encoder; -bool oj_rails_hash_opt = false; -bool oj_rails_array_opt = false; -bool oj_rails_float_opt = false; +bool oj_rails_hash_opt = false; +bool oj_rails_array_opt = false; +bool oj_rails_float_opt = false; -extern void oj_mimic_json_methods(VALUE json); +extern void oj_mimic_json_methods(VALUE json); -static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok); +static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok); -extern VALUE Oj; +extern VALUE Oj; -static struct _rOptTable ropts = { 0, 0, NULL }; +static struct _rOptTable ropts = { 0, 0, NULL }; -static VALUE encoder_class = Qnil; -static bool escape_html = true; -static bool xml_time = true; +static VALUE encoder_class = Qnil; +static bool escape_html = true; +static bool xml_time = true; -static ROpt create_opt(ROptTable rot, VALUE clas); +static ROpt create_opt(ROptTable rot, VALUE clas); ROpt oj_rails_get_opt(ROptTable rot, VALUE clas) { if (NULL == rot) { - rot = &ropts; + rot = &ropts; } if (0 < rot->len) { - int lo = 0; - int hi = rot->len - 1; - int mid; - VALUE v; - - if (clas < rot->table->clas || rot->table[hi].clas < clas) { - return NULL; - } - if (rot->table[lo].clas == clas) { - return rot->table; - } - if (rot->table[hi].clas == clas) { - return &rot->table[hi]; - } - while (2 <= hi - lo) { - mid = (hi + lo) / 2; - v = rot->table[mid].clas; - if (v == clas) { - return &rot->table[mid]; - } - if (v < clas) { - lo = mid; - } else { - hi = mid; - } - } + int lo = 0; + int hi = rot->len - 1; + int mid; + VALUE v; + + if (clas < rot->table->clas || rot->table[hi].clas < clas) { + return NULL; + } + if (rot->table[lo].clas == clas) { + return rot->table; + } + if (rot->table[hi].clas == clas) { + return &rot->table[hi]; + } + while (2 <= hi - lo) { + mid = (hi + lo) / 2; + v = rot->table[mid].clas; + if (v == clas) { + return &rot->table[mid]; + } + if (v < clas) { + lo = mid; + } else { + hi = mid; + } + } } return NULL; } @@ -75,41 +76,41 @@ copy_opts(ROptTable src, ROptTable dest) { dest->len = src->len; dest->alen = src->alen; if (NULL == src->table) { - dest->table = NULL; + dest->table = NULL; } else { - dest->table = ALLOC_N(struct _rOpt, dest->alen); - memcpy(dest->table, src->table, sizeof(struct _rOpt) * dest->alen); + dest->table = ALLOC_N(struct _rOpt, dest->alen); + memcpy(dest->table, src->table, sizeof(struct _rOpt) * dest->alen); } return NULL; } static int dump_attr_cb(ID key, VALUE value, VALUE ov) { - Out out = (Out)ov; - int depth = out->depth; - size_t size = depth * out->indent + 1; - const char *attr = rb_id2name(key); + Out out = (Out)ov; + int depth = out->depth; + size_t size = depth * out->indent + 1; + const char *attr = rb_id2name(key); // Some exceptions such as NoMethodError have an invisible attribute where // the key name is NULL. Not an empty string but NULL. if (NULL == attr) { - attr = ""; + attr = ""; } if (0 == strcmp("bt", attr) || 0 == strcmp("mesg", attr)) { - return ST_CONTINUE; + return ST_CONTINUE; } assure_size(out, size); fill_indent(out, depth); if ('@' == *attr) { - attr++; - oj_dump_cstr(attr, strlen(attr), 0, 0, out); + attr++; + oj_dump_cstr(attr, strlen(attr), 0, 0, out); } else { - char buf[32]; + char buf[32]; - *buf = '~'; - strncpy(buf + 1, attr, sizeof(buf) - 2); - buf[sizeof(buf) - 1] = '\0'; - oj_dump_cstr(buf, strlen(buf), 0, 0, out); + *buf = '~'; + strncpy(buf + 1, attr, sizeof(buf) - 2); + buf[sizeof(buf) - 1] = '\0'; + oj_dump_cstr(buf, strlen(buf), 0, 0, out); } *out->cur++ = ':'; dump_rails_val(value, depth, out, true); @@ -126,7 +127,7 @@ dump_obj_attrs(VALUE obj, int depth, Out out, bool as_ok) { out->depth = depth + 1; rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out); if (',' == *(out->cur - 1)) { - out->cur--; // backup to overwrite last comma + out->cur--; // backup to overwrite last comma } out->depth = depth; fill_indent(out, depth); @@ -136,20 +137,20 @@ dump_obj_attrs(VALUE obj, int depth, Out out, bool as_ok) { static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) { - int d3 = depth + 2; - size_t size = d3 * out->indent + 2; - size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2; - volatile VALUE ma; - volatile VALUE v; - int cnt; - int i; - int len; - const char *name; + int d3 = depth + 2; + size_t size = d3 * out->indent + 2; + size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2; + volatile VALUE ma; + volatile VALUE v; + int cnt; + int i; + int len; + const char *name; #ifdef RSTRUCT_LEN #if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT cnt = (int)NUM2LONG(RSTRUCT_LEN(obj)); -#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT +#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT cnt = (int)RSTRUCT_LEN(obj); #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT #else @@ -161,91 +162,91 @@ dump_struct(VALUE obj, int depth, Out out, bool as_ok) { assure_size(out, 2); *out->cur++ = '{'; for (i = 0; i < cnt; i++) { - volatile VALUE s = rb_sym_to_s(rb_ary_entry(ma, i)); - - name = rb_string_value_ptr((VALUE *)&s); - len = (int)RSTRING_LEN(s); - assure_size(out, size + sep_len + 6); - if (0 < i) { - *out->cur++ = ','; - } - fill_indent(out, d3); - *out->cur++ = '"'; - memcpy(out->cur, name, len); - out->cur += len; - *out->cur++ = '"'; - if (0 < out->opts->dump_opts.before_size) { - strcpy(out->cur, out->opts->dump_opts.before_sep); - out->cur += out->opts->dump_opts.before_size; - } - *out->cur++ = ':'; - if (0 < out->opts->dump_opts.after_size) { - strcpy(out->cur, out->opts->dump_opts.after_sep); - out->cur += out->opts->dump_opts.after_size; - } + volatile VALUE s = rb_sym_to_s(rb_ary_entry(ma, i)); + + name = rb_string_value_ptr((VALUE*)&s); + len = (int)RSTRING_LEN(s); + assure_size(out, size + sep_len + 6); + if (0 < i) { + *out->cur++ = ','; + } + fill_indent(out, d3); + *out->cur++ = '"'; + memcpy(out->cur, name, len); + out->cur += len; + *out->cur++ = '"'; + if (0 < out->opts->dump_opts.before_size) { + strcpy(out->cur, out->opts->dump_opts.before_sep); + out->cur += out->opts->dump_opts.before_size; + } + *out->cur++ = ':'; + if (0 < out->opts->dump_opts.after_size) { + strcpy(out->cur, out->opts->dump_opts.after_sep); + out->cur += out->opts->dump_opts.after_size; + } #ifdef RSTRUCT_LEN - v = RSTRUCT_GET(obj, i); + v = RSTRUCT_GET(obj, i); #else - v = rb_struct_aref(obj, INT2FIX(i)); + v = rb_struct_aref(obj, INT2FIX(i)); #endif - dump_rails_val(v, d3, out, true); + dump_rails_val(v, d3, out, true); } fill_indent(out, depth); *out->cur++ = '}'; *out->cur = '\0'; } -static ID to_a_id = 0; +static ID to_a_id = 0; static void dump_enumerable(VALUE obj, int depth, Out out, bool as_ok) { if (0 == to_a_id) { - to_a_id = rb_intern("to_a"); + to_a_id = rb_intern("to_a"); } dump_rails_val(rb_funcall(obj, to_a_id, 0), depth, out, false); } static void dump_bigdecimal(VALUE obj, int depth, Out out, bool as_ok) { - volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); - const char *str = rb_string_value_ptr((VALUE *)&rstr); + volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); + const char *str = rb_string_value_ptr((VALUE*)&rstr); if ('I' == *str || 'N' == *str || ('-' == *str && 'I' == str[1])) { - oj_dump_nil(Qnil, depth, out, false); + oj_dump_nil(Qnil, depth, out, false); } else if (out->opts->int_range_max != 0 || out->opts->int_range_min != 0) { - oj_dump_cstr(str, (int)RSTRING_LEN(rstr), 0, 0, out); + oj_dump_cstr(str, (int)RSTRING_LEN(rstr), 0, 0, out); } else if (Yes == out->opts->bigdec_as_num) { - oj_dump_raw(str, (int)RSTRING_LEN(rstr), out); + oj_dump_raw(str, (int)RSTRING_LEN(rstr), out); } else { - oj_dump_cstr(str, (int)RSTRING_LEN(rstr), 0, 0, out); + oj_dump_cstr(str, (int)RSTRING_LEN(rstr), 0, 0, out); } } static void dump_sec_nano(VALUE obj, int64_t sec, long nsec, Out out) { - char buf[64]; - struct _timeInfo ti; - long one = 1000000000; - long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0)); - int tzhour, tzmin; - char tzsign = '+'; - int len; + char buf[64]; + struct _timeInfo ti; + long one = 1000000000; + long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0)); + int tzhour, tzmin; + char tzsign = '+'; + int len; if (out->end - out->cur <= 36) { - assure_size(out, 36); + assure_size(out, 36); } if (9 > out->opts->sec_prec) { - int i; - - // Rails does not round when reducing precision but instead floors, - for (i = 9 - out->opts->sec_prec; 0 < i; i--) { - nsec = nsec / 10; - one /= 10; - } - if (one <= nsec) { - nsec -= one; - sec++; - } + int i; + + // Rails does not round when reducing precision but instead floors, + for (i = 9 - out->opts->sec_prec; 0 < i; i--) { + nsec = nsec / 10; + one /= 10; + } + if (one <= nsec) { + nsec -= one; + sec++; + } } // 2012-01-05T23:58:07.123456000+09:00 or 2012/01/05 23:58:07 +0900 sec += tzsecs; @@ -259,49 +260,49 @@ dump_sec_nano(VALUE obj, int64_t sec, long nsec, Out out) { tzmin = (int)(tzsecs / 60) - (tzhour * 60); } if (!xml_time) { - len = sprintf(buf, "%04d/%02d/%02d %02d:%02d:%02d %c%02d%02d", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, tzsign, tzhour, tzmin); + len = sprintf(buf, "%04d/%02d/%02d %02d:%02d:%02d %c%02d%02d", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, tzsign, tzhour, tzmin); } else if (0 == out->opts->sec_prec) { - if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) { - len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec); - } else { - len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, tzsign, tzhour, tzmin); - } + if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) { + len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec); + } else { + len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, tzsign, tzhour, tzmin); + } } else if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) { - char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ"; - - len = 30; - if (9 > out->opts->sec_prec) { - format[32] = '0' + out->opts->sec_prec; - len -= 9 - out->opts->sec_prec; - } - len = sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, nsec); + char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ"; + + len = 30; + if (9 > out->opts->sec_prec) { + format[32] = '0' + out->opts->sec_prec; + len -= 9 - out->opts->sec_prec; + } + len = sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, nsec); } else { - char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d"; + char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d"; - len = 35; - if (9 > out->opts->sec_prec) { - format[32] = '0' + out->opts->sec_prec; - len -= 9 - out->opts->sec_prec; - } - len = sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, nsec, tzsign, tzhour, tzmin); + len = 35; + if (9 > out->opts->sec_prec) { + format[32] = '0' + out->opts->sec_prec; + len -= 9 - out->opts->sec_prec; + } + len = sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, nsec, tzsign, tzhour, tzmin); } oj_dump_cstr(buf, len, 0, 0, out); } static void dump_time(VALUE obj, int depth, Out out, bool as_ok) { - long long sec; - long long nsec; + long long sec; + long long nsec; #ifdef HAVE_RB_TIME_TIMESPEC if (16 <= sizeof(struct timespec)) { - struct timespec ts = rb_time_timespec(obj); + struct timespec ts = rb_time_timespec(obj); - sec = (long long)ts.tv_sec; - nsec = ts.tv_nsec; + sec = (long long)ts.tv_sec; + nsec = ts.tv_nsec; } else { - sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0)); - nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0)); + sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0)); + nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0)); } #else sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0)); @@ -312,35 +313,35 @@ dump_time(VALUE obj, int depth, Out out, bool as_ok) { static void dump_timewithzone(VALUE obj, int depth, Out out, bool as_ok) { - int64_t sec = NUM2LONG(rb_funcall2(obj, oj_tv_sec_id, 0, 0)); - long long nsec = 0; + int64_t sec = NUM2LONG(rb_funcall2(obj, oj_tv_sec_id, 0, 0)); + long long nsec = 0; if (rb_respond_to(obj, oj_tv_nsec_id)) { - nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0)); + nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0)); } else if (rb_respond_to(obj, oj_tv_usec_id)) { - nsec = rb_num2ll(rb_funcall2(obj, oj_tv_usec_id, 0, 0)) * 1000; + nsec = rb_num2ll(rb_funcall2(obj, oj_tv_usec_id, 0, 0)) * 1000; } dump_sec_nano(obj, sec, nsec, out); } static void dump_to_s(VALUE obj, int depth, Out out, bool as_ok) { - volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); + volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); - oj_dump_cstr(rb_string_value_ptr((VALUE *)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out); + oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out); } -static ID parameters_id = 0; +static ID parameters_id = 0; typedef struct _strLen { - const char *str; - int len; -} * StrLen; + const char *str; + int len; +} *StrLen; static void dump_actioncontroller_parameters(VALUE obj, int depth, Out out, bool as_ok) { if (0 == parameters_id) { - parameters_id = rb_intern("@parameters"); + parameters_id = rb_intern("@parameters"); } out->argc = 0; dump_rails_val(rb_ivar_get(obj, parameters_id), depth, out, true); @@ -348,94 +349,94 @@ dump_actioncontroller_parameters(VALUE obj, int depth, Out out, bool as_ok) { static StrLen columns_array(VALUE rcols, int *ccnt) { - volatile VALUE v; - StrLen cp; - StrLen cols; - int i; - int cnt = (int)RARRAY_LEN(rcols); + volatile VALUE v; + StrLen cp; + StrLen cols; + int i; + int cnt = (int)RARRAY_LEN(rcols); *ccnt = cnt; cols = ALLOC_N(struct _strLen, cnt); for (i = 0, cp = cols; i < cnt; i++, cp++) { - v = rb_ary_entry(rcols, i); - if (T_STRING != rb_type(v)) { - v = rb_funcall(v, oj_to_s_id, 0); - } - cp->str = StringValuePtr(v); - cp->len = (int)RSTRING_LEN(v); + v = rb_ary_entry(rcols, i); + if (T_STRING != rb_type(v)) { + v = rb_funcall(v, oj_to_s_id, 0); + } + cp->str = StringValuePtr(v); + cp->len = (int)RSTRING_LEN(v); } return cols; } static void dump_row(VALUE row, StrLen cols, int ccnt, int depth, Out out) { - size_t size; - int d2 = depth + 1; - int i; + size_t size; + int d2 = depth + 1; + int i; assure_size(out, 2); *out->cur++ = '{'; size = depth * out->indent + 3; for (i = 0; i < ccnt; i++, cols++) { - assure_size(out, size); - if (out->opts->dump_opts.use) { - if (0 < out->opts->dump_opts.array_size) { - strcpy(out->cur, out->opts->dump_opts.array_nl); - out->cur += out->opts->dump_opts.array_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - for (i = d2; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - } else { - fill_indent(out, d2); - } - oj_dump_cstr(cols->str, cols->len, 0, 0, out); - *out->cur++ = ':'; - dump_rails_val(rb_ary_entry(row, i), depth, out, true); - if (i < ccnt - 1) { - *out->cur++ = ','; - } + assure_size(out, size); + if (out->opts->dump_opts.use) { + if (0 < out->opts->dump_opts.array_size) { + strcpy(out->cur, out->opts->dump_opts.array_nl); + out->cur += out->opts->dump_opts.array_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + for (i = d2; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + } else { + fill_indent(out, d2); + } + oj_dump_cstr(cols->str, cols->len, 0, 0, out); + *out->cur++ = ':'; + dump_rails_val(rb_ary_entry(row, i), depth, out, true); + if (i < ccnt - 1) { + *out->cur++ = ','; + } } size = depth * out->indent + 1; assure_size(out, size); if (out->opts->dump_opts.use) { - if (0 < out->opts->dump_opts.array_size) { - strcpy(out->cur, out->opts->dump_opts.array_nl); - out->cur += out->opts->dump_opts.array_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - - for (i = depth; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } + if (0 < out->opts->dump_opts.array_size) { + strcpy(out->cur, out->opts->dump_opts.array_nl); + out->cur += out->opts->dump_opts.array_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + + for (i = depth; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } } else { - fill_indent(out, depth); + fill_indent(out, depth); } *out->cur++ = '}'; } -static ID rows_id = 0; -static ID columns_id = 0; +static ID rows_id = 0; +static ID columns_id = 0; static void dump_activerecord_result(VALUE obj, int depth, Out out, bool as_ok) { - volatile VALUE rows; - StrLen cols; - int ccnt = 0; - int i, rcnt; - size_t size; - int d2 = depth + 1; + volatile VALUE rows; + StrLen cols; + int ccnt = 0; + int i, rcnt; + size_t size; + int d2 = depth + 1; if (0 == rows_id) { - rows_id = rb_intern("@rows"); - columns_id = rb_intern("@columns"); + rows_id = rb_intern("@rows"); + columns_id = rb_intern("@columns"); } out->argc = 0; cols = columns_array(rb_ivar_get(obj, columns_id), &ccnt); @@ -444,113 +445,113 @@ dump_activerecord_result(VALUE obj, int depth, Out out, bool as_ok) { assure_size(out, 2); *out->cur++ = '['; if (out->opts->dump_opts.use) { - size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1; + size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1; } else { - size = d2 * out->indent + 2; + size = d2 * out->indent + 2; } assure_size(out, 2); for (i = 0; i < rcnt; i++) { - assure_size(out, size); - if (out->opts->dump_opts.use) { - if (0 < out->opts->dump_opts.array_size) { - strcpy(out->cur, out->opts->dump_opts.array_nl); - out->cur += out->opts->dump_opts.array_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - for (i = d2; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - } else { - fill_indent(out, d2); - } - dump_row(rb_ary_entry(rows, i), cols, ccnt, d2, out); - if (i < rcnt - 1) { - *out->cur++ = ','; - } + assure_size(out, size); + if (out->opts->dump_opts.use) { + if (0 < out->opts->dump_opts.array_size) { + strcpy(out->cur, out->opts->dump_opts.array_nl); + out->cur += out->opts->dump_opts.array_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + for (i = d2; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + } else { + fill_indent(out, d2); + } + dump_row(rb_ary_entry(rows, i), cols, ccnt, d2, out); + if (i < rcnt - 1) { + *out->cur++ = ','; + } } xfree(cols); size = depth * out->indent + 1; assure_size(out, size); if (out->opts->dump_opts.use) { - if (0 < out->opts->dump_opts.array_size) { - strcpy(out->cur, out->opts->dump_opts.array_nl); - out->cur += out->opts->dump_opts.array_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - - for (i = depth; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } + if (0 < out->opts->dump_opts.array_size) { + strcpy(out->cur, out->opts->dump_opts.array_nl); + out->cur += out->opts->dump_opts.array_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + + for (i = depth; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } } else { - fill_indent(out, depth); + fill_indent(out, depth); } *out->cur++ = ']'; } typedef struct _namedFunc { - const char *name; - DumpFunc func; -} * NamedFunc; + const char *name; + DumpFunc func; +} *NamedFunc; static void dump_as_string(VALUE obj, int depth, Out out, bool as_ok) { if (oj_code_dump(oj_compat_codes, obj, depth, out)) { - out->argc = 0; - return; + out->argc = 0; + return; } oj_dump_obj_to_s(obj, out); } static void dump_as_json(VALUE obj, int depth, Out out, bool as_ok) { - volatile VALUE ja; + volatile VALUE ja; if (Yes == out->opts->trace) { - oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn); + oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn); } // Some classes elect to not take an options argument so check the arity // of as_json. if (0 == rb_obj_method_arity(obj, oj_as_json_id)) { - ja = rb_funcall(obj, oj_as_json_id, 0); + ja = rb_funcall(obj, oj_as_json_id, 0); } else { - ja = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv); + ja = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv); } if (Yes == out->opts->trace) { - oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut); + oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut); } out->argc = 0; if (ja == obj || !as_ok) { - // Once as_json is called it should never be called again on the same - // object with as_ok. - dump_rails_val(ja, depth, out, false); + // Once as_json is called it should never be called again on the same + // object with as_ok. + dump_rails_val(ja, depth, out, false); } else { - int type = rb_type(ja); + int type = rb_type(ja); - if (T_HASH == type || T_ARRAY == type) { - dump_rails_val(ja, depth, out, true); - } else { - dump_rails_val(ja, depth, out, true); - } + if (T_HASH == type || T_ARRAY == type) { + dump_rails_val(ja, depth, out, true); + } else { + dump_rails_val(ja, depth, out, true); + } } } static void dump_regexp(VALUE obj, int depth, Out out, bool as_ok) { if (as_ok && rb_respond_to(obj, oj_as_json_id)) { - dump_as_json(obj, depth, out, false); - return; + dump_as_json(obj, depth, out, false); + return; } dump_as_string(obj, depth, out, as_ok); } -static struct _namedFunc dump_map[] = { +static struct _namedFunc dump_map[] = { { "ActionController::Parameters", dump_actioncontroller_parameters }, { "ActiveRecord::Result", dump_activerecord_result }, { "ActiveSupport::TimeWithZone", dump_timewithzone }, @@ -562,13 +563,13 @@ static struct _namedFunc dump_map[] = { { NULL, NULL }, }; -static VALUE activerecord_base = Qundef; -static ID attributes_id = 0; +static VALUE activerecord_base = Qundef; +static ID attributes_id = 0; static void dump_activerecord(VALUE obj, int depth, Out out, bool as_ok) { if (0 == attributes_id) { - attributes_id = rb_intern("@attributes"); + attributes_id = rb_intern("@attributes"); } out->argc = 0; dump_rails_val(rb_ivar_get(obj, attributes_id), depth, out, true); @@ -576,62 +577,62 @@ dump_activerecord(VALUE obj, int depth, Out out, bool as_ok) { static ROpt create_opt(ROptTable rot, VALUE clas) { - ROpt ro; - NamedFunc nf; - const char *classname = rb_class2name(clas); - int olen = rot->len; + ROpt ro; + NamedFunc nf; + const char *classname = rb_class2name(clas); + int olen = rot->len; rot->len++; if (NULL == rot->table) { - rot->alen = 256; - rot->table = ALLOC_N(struct _rOpt, rot->alen); - memset(rot->table, 0, sizeof(struct _rOpt) * rot->alen); + rot->alen = 256; + rot->table = ALLOC_N(struct _rOpt, rot->alen); + memset(rot->table, 0, sizeof(struct _rOpt) * rot->alen); } else if (rot->alen <= rot->len) { - rot->alen *= 2; - REALLOC_N(rot->table, struct _rOpt, rot->alen); - memset(rot->table + olen, 0, sizeof(struct _rOpt) * olen); + rot->alen *= 2; + REALLOC_N(rot->table, struct _rOpt, rot->alen); + memset(rot->table + olen, 0, sizeof(struct _rOpt) * olen); } if (0 == olen) { - ro = rot->table; + ro = rot->table; } else if (rot->table[olen - 1].clas < clas) { - ro = &rot->table[olen]; + ro = &rot->table[olen]; } else { - int i; + int i; - for (i = 0, ro = rot->table; i < olen; i++, ro++) { - if (clas < ro->clas) { - memmove(ro + 1, ro, sizeof(struct _rOpt) * (olen - i)); - break; - } - } + for (i = 0, ro = rot->table; i < olen; i++, ro++) { + if (clas < ro->clas) { + memmove(ro + 1, ro, sizeof(struct _rOpt) * (olen - i)); + break; + } + } } ro->clas = clas; ro->on = true; ro->dump = dump_obj_attrs; for (nf = dump_map; NULL != nf->name; nf++) { - if (0 == strcmp(nf->name, classname)) { - ro->dump = nf->func; - break; - } + if (0 == strcmp(nf->name, classname)) { + ro->dump = nf->func; + break; + } } if (ro->dump == dump_obj_attrs) { - if (Qundef == activerecord_base) { - // If not defined let an exception be raised. - VALUE ar = rb_const_get_at(rb_cObject, rb_intern("ActiveRecord")); - - if (Qundef != ar) { - activerecord_base = rb_const_get_at(ar, rb_intern("Base")); - } - } - if (Qundef != activerecord_base && Qtrue == rb_class_inherited_p(clas, activerecord_base)) { - ro->dump = dump_activerecord; - } else if (Qtrue == rb_class_inherited_p(clas, rb_cStruct)) { // check before enumerable - ro->dump = dump_struct; - } else if (Qtrue == rb_class_inherited_p(clas, rb_mEnumerable)) { - ro->dump = dump_enumerable; - } else if (Qtrue == rb_class_inherited_p(clas, rb_eException)) { - ro->dump = dump_to_s; - } + if (Qundef == activerecord_base) { + // If not defined let an exception be raised. + VALUE ar = rb_const_get_at(rb_cObject, rb_intern("ActiveRecord")); + + if (Qundef != ar) { + activerecord_base = rb_const_get_at(ar, rb_intern("Base")); + } + } + if (Qundef != activerecord_base && Qtrue == rb_class_inherited_p(clas, activerecord_base)) { + ro->dump = dump_activerecord; + } else if (Qtrue == rb_class_inherited_p(clas, rb_cStruct)) { // check before enumerable + ro->dump = dump_struct; + } else if (Qtrue == rb_class_inherited_p(clas, rb_mEnumerable)) { + ro->dump = dump_enumerable; + } else if (Qtrue == rb_class_inherited_p(clas, rb_eException)) { + ro->dump = dump_to_s; + } } return ro; } @@ -639,23 +640,23 @@ create_opt(ROptTable rot, VALUE clas) { static void encoder_free(void *ptr) { if (NULL != ptr) { - Encoder e = (Encoder)ptr; + Encoder e = (Encoder)ptr; - if (NULL != e->ropts.table) { - xfree(e->ropts.table); - } - xfree(ptr); + if (NULL != e->ropts.table) { + xfree(e->ropts.table); + } + xfree(ptr); } } static void encoder_mark(void *ptr) { if (NULL != ptr) { - Encoder e = (Encoder)ptr; + Encoder e = (Encoder)ptr; - if (Qnil != e->arg) { - rb_gc_mark(e->arg); - } + if (Qnil != e->arg) { + rb_gc_mark(e->arg); + } } } @@ -667,52 +668,52 @@ encoder_mark(void *ptr) { */ static VALUE encoder_new(int argc, VALUE *argv, VALUE self) { - Encoder e = ALLOC(struct _encoder); + Encoder e = ALLOC(struct _encoder); e->opts = oj_default_options; e->arg = Qnil; copy_opts(&ropts, &e->ropts); if (1 <= argc && Qnil != *argv) { - oj_parse_options(*argv, &e->opts); - e->arg = *argv; + oj_parse_options(*argv, &e->opts); + e->arg = *argv; } return Data_Wrap_Struct(encoder_class, encoder_mark, encoder_free, e); } static VALUE resolve_classpath(const char *name) { - char class_name[1024]; - VALUE clas; - char *end = class_name + sizeof(class_name) - 1; - char *s; - const char *n = name; - ID cid; + char class_name[1024]; + VALUE clas; + char *end = class_name + sizeof(class_name) - 1; + char *s; + const char *n = name; + ID cid; clas = rb_cObject; for (s = class_name; '\0' != *n; n++) { - if (':' == *n) { - *s = '\0'; - n++; - if (':' != *n) { - return Qnil; - } - cid = rb_intern(class_name); - if (!rb_const_defined_at(clas, cid)) { - return Qnil; - } - clas = rb_const_get_at(clas, cid); - s = class_name; - } else if (end <= s) { - return Qnil; - } else { - *s++ = *n; - } + if (':' == *n) { + *s = '\0'; + n++; + if (':' != *n) { + return Qnil; + } + cid = rb_intern(class_name); + if (!rb_const_defined_at(clas, cid)) { + return Qnil; + } + clas = rb_const_get_at(clas, cid); + s = class_name; + } else if (end <= s) { + return Qnil; + } else { + *s++ = *n; + } } *s = '\0'; cid = rb_intern(class_name); if (!rb_const_defined_at(clas, cid)) { - return Qnil; + return Qnil; } clas = rb_const_get_at(clas, cid); @@ -721,41 +722,41 @@ resolve_classpath(const char *name) { static void optimize(int argc, VALUE *argv, ROptTable rot, bool on) { - ROpt ro; + ROpt ro; if (0 == argc) { - int i; - NamedFunc nf; - VALUE clas; - - oj_rails_hash_opt = on; - oj_rails_array_opt = on; - oj_rails_float_opt = on; - - for (nf = dump_map; NULL != nf->name; nf++) { - if (Qnil != (clas = resolve_classpath(nf->name))) { - if (NULL == oj_rails_get_opt(rot, clas)) { - create_opt(rot, clas); - } - } - } - for (i = 0; i < rot->len; i++) { - rot->table[i].on = on; - } + int i; + NamedFunc nf; + VALUE clas; + + oj_rails_hash_opt = on; + oj_rails_array_opt = on; + oj_rails_float_opt = on; + + for (nf = dump_map; NULL != nf->name; nf++) { + if (Qnil != (clas = resolve_classpath(nf->name))) { + if (NULL == oj_rails_get_opt(rot, clas)) { + create_opt(rot, clas); + } + } + } + for (i = 0; i < rot->len; i++) { + rot->table[i].on = on; + } } for (; 0 < argc; argc--, argv++) { - if (rb_cHash == *argv) { - oj_rails_hash_opt = on; - } else if (rb_cArray == *argv) { - oj_rails_array_opt = on; - } else if (rb_cFloat == *argv) { - oj_rails_float_opt = on; - } else if (oj_string_writer_class == *argv) { - string_writer_optimized = on; - } else if (NULL != (ro = oj_rails_get_opt(rot, *argv)) || - NULL != (ro = create_opt(rot, *argv))) { - ro->on = on; - } + if (rb_cHash == *argv) { + oj_rails_hash_opt = on; + } else if (rb_cArray == *argv) { + oj_rails_array_opt = on; + } else if (rb_cFloat == *argv) { + oj_rails_float_opt = on; + } else if (oj_string_writer_class == *argv) { + string_writer_optimized = on; + } else if (NULL != (ro = oj_rails_get_opt(rot, *argv)) || + NULL != (ro = create_opt(rot, *argv))) { + ro->on = on; + } } } @@ -773,7 +774,7 @@ optimize(int argc, VALUE *argv, ROptTable rot, bool on) { */ static VALUE encoder_optimize(int argc, VALUE *argv, VALUE self) { - Encoder e = (Encoder)DATA_PTR(self); + Encoder e = (Encoder)DATA_PTR(self); optimize(argc, argv, &e->ropts, true); @@ -808,12 +809,12 @@ rails_optimize(int argc, VALUE *argv, VALUE self) { */ VALUE rails_mimic_json(VALUE self) { - VALUE json; + VALUE json; if (rb_const_defined_at(rb_cObject, rb_intern("JSON"))) { - json = rb_const_get_at(rb_cObject, rb_intern("JSON")); + json = rb_const_get_at(rb_cObject, rb_intern("JSON")); } else { - json = rb_define_module("JSON"); + json = rb_define_module("JSON"); } oj_mimic_json_methods(json); //oj_default_options.mode = RailsMode; @@ -830,7 +831,7 @@ rails_mimic_json(VALUE self) { */ static VALUE encoder_deoptimize(int argc, VALUE *argv, VALUE self) { - Encoder e = (Encoder)DATA_PTR(self); + Encoder e = (Encoder)DATA_PTR(self); optimize(argc, argv, &e->ropts, false); @@ -861,11 +862,11 @@ rails_deoptimize(int argc, VALUE *argv, VALUE self) { */ static VALUE encoder_optimized(VALUE self, VALUE clas) { - Encoder e = (Encoder)DATA_PTR(self); - ROpt ro = oj_rails_get_opt(&e->ropts, clas); + Encoder e = (Encoder)DATA_PTR(self); + ROpt ro = oj_rails_get_opt(&e->ropts, clas); if (NULL == ro) { - return Qfalse; + return Qfalse; } return (ro->on) ? Qtrue : Qfalse; } @@ -877,22 +878,22 @@ encoder_optimized(VALUE self, VALUE clas) { */ static VALUE rails_optimized(VALUE self, VALUE clas) { - ROpt ro = oj_rails_get_opt(&ropts, clas); + ROpt ro = oj_rails_get_opt(&ropts, clas); if (NULL == ro) { - return Qfalse; + return Qfalse; } return (ro->on) ? Qtrue : Qfalse; } typedef struct _oo { - Out out; - VALUE obj; -} * OO; + Out out; + VALUE obj; +} *OO; static VALUE protect_dump(VALUE ov) { - OO oo = (OO)ov; + OO oo = (OO)ov; dump_rails_val(oo->obj, 0, oo->out, true); @@ -901,12 +902,12 @@ protect_dump(VALUE ov) { static VALUE encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *argv) { - char buf[4096]; - struct _out out; - struct _options copts = *opts; - volatile VALUE rstr = Qnil; - struct _oo oo; - int line = 0; + char buf[4096]; + struct _out out; + struct _options copts = *opts; + volatile VALUE rstr = Qnil; + struct _oo oo; + int line = 0; oo.out = &out; oo.obj = obj; @@ -914,9 +915,9 @@ encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *argv) { copts.str_rx.tail = NULL; copts.mode = RailsMode; if (escape_html) { - copts.escape_mode = RailsXEsc; + copts.escape_mode = RailsXEsc; } else { - copts.escape_mode = RailsEsc; + copts.escape_mode = RailsEsc; } out.buf = buf; out.end = buf + sizeof(buf) - 10; @@ -932,38 +933,38 @@ encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *argv) { out.argv = argv; out.ropts = ropts; if (Yes == copts.circular) { - oj_cache8_new(&out.circ_cache); + oj_cache8_new(&out.circ_cache); } //dump_rails_val(*argv, 0, &out, true); rb_protect(protect_dump, (VALUE)&oo, &line); if (0 == line) { - if (0 < out.indent) { - switch (*(out.cur - 1)) { - case ']': - case '}': - assure_size(&out, 2); - *out.cur++ = '\n'; - default: - break; - } - } - *out.cur = '\0'; - - if (0 == out.buf) { - rb_raise(rb_eNoMemError, "Not enough memory."); - } - rstr = rb_str_new2(out.buf); - rstr = oj_encode(rstr); + if (0 < out.indent) { + switch (*(out.cur - 1)) { + case ']': + case '}': + assure_size(&out, 2); + *out.cur++ = '\n'; + default: + break; + } + } + *out.cur = '\0'; + + if (0 == out.buf) { + rb_raise(rb_eNoMemError, "Not enough memory."); + } + rstr = rb_str_new2(out.buf); + rstr = oj_encode(rstr); } if (Yes == copts.circular) { - oj_cache8_delete(out.circ_cache); + oj_cache8_delete(out.circ_cache); } if (out.allocated) { - xfree(out.buf); + xfree(out.buf); } if (0 != line) { - rb_jump_tag(line); + rb_jump_tag(line); } return rstr; } @@ -977,12 +978,12 @@ encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *argv) { */ static VALUE encoder_encode(VALUE self, VALUE obj) { - Encoder e = (Encoder)DATA_PTR(self); + Encoder e = (Encoder)DATA_PTR(self); if (Qnil != e->arg) { - VALUE argv[1] = { e->arg }; + VALUE argv[1] = { e->arg }; - return encode(obj, &e->ropts, &e->opts, 1, argv); + return encode(obj, &e->ropts, &e->opts, 1, argv); } return encode(obj, &e->ropts, &e->opts, 0, NULL); } @@ -1000,23 +1001,23 @@ encoder_encode(VALUE self, VALUE obj) { static VALUE rails_encode(int argc, VALUE *argv, VALUE self) { if (1 > argc) { - rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)."); + rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)."); } if (1 == argc) { - return encode(*argv, NULL, &oj_default_options, 0, NULL); + return encode(*argv, NULL, &oj_default_options, 0, NULL); } else { - return encode(*argv, NULL, &oj_default_options, argc - 1, argv + 1); + return encode(*argv, NULL, &oj_default_options, argc - 1, argv + 1); } } static VALUE rails_use_standard_json_time_format(VALUE self, VALUE state) { if (Qtrue == state || Qfalse == state) { - // no change needed + // no change needed } else if (Qnil == state) { - state = Qfalse; + state = Qfalse; } else { - state = Qtrue; + state = Qtrue; } rb_iv_set(self, "@use_standard_json_time_format", state); xml_time = Qtrue == state; @@ -1060,21 +1061,21 @@ rails_time_precision(VALUE self, VALUE prec) { */ static VALUE rails_set_encoder(VALUE self) { - VALUE active; - VALUE json; - VALUE encoding; - VALUE pv; - VALUE verbose; - VALUE enc = resolve_classpath("ActiveSupport::JSON::Encoding"); + VALUE active; + VALUE json; + VALUE encoding; + VALUE pv; + VALUE verbose; + VALUE enc = resolve_classpath("ActiveSupport::JSON::Encoding"); if (Qnil != enc) { - escape_html = Qtrue == rb_iv_get(self, "@escape_html_entities_in_json"); - xml_time = Qtrue == rb_iv_get(enc, "@use_standard_json_time_format"); + escape_html = Qtrue == rb_iv_get(self, "@escape_html_entities_in_json"); + xml_time = Qtrue == rb_iv_get(enc, "@use_standard_json_time_format"); } if (rb_const_defined_at(rb_cObject, rb_intern("ActiveSupport"))) { - active = rb_const_get_at(rb_cObject, rb_intern("ActiveSupport")); + active = rb_const_get_at(rb_cObject, rb_intern("ActiveSupport")); } else { - rb_raise(rb_eStandardError, "ActiveSupport not loaded."); + rb_raise(rb_eStandardError, "ActiveSupport not loaded."); } rb_funcall(active, rb_intern("json_encoder="), 1, encoder_class); @@ -1115,14 +1116,14 @@ rails_set_encoder(VALUE self) { */ static VALUE rails_set_decoder(VALUE self) { - VALUE json; - VALUE json_error; - VALUE verbose; + VALUE json; + VALUE json_error; + VALUE verbose; if (rb_const_defined_at(rb_cObject, rb_intern("JSON"))) { - json = rb_const_get_at(rb_cObject, rb_intern("JSON")); + json = rb_const_get_at(rb_cObject, rb_intern("JSON")); } else { - json = rb_define_module("JSON"); + json = rb_define_module("JSON"); } if (rb_const_defined_at(json, rb_intern("JSONError"))) { json_error = rb_const_get(json, rb_intern("JSONError")); @@ -1132,7 +1133,7 @@ rails_set_decoder(VALUE self) { if (rb_const_defined_at(json, rb_intern("ParserError"))) { oj_json_parser_error_class = rb_const_get(json, rb_intern("ParserError")); } else { - oj_json_parser_error_class = rb_define_class_under(json, "ParserError", json_error); + oj_json_parser_error_class = rb_define_class_under(json, "ParserError", json_error); } // rb_undef_method doesn't work for modules or maybe sometimes // doesn't. Anyway setting verbose should hide the warning. @@ -1170,7 +1171,7 @@ oj_optimize_rails(VALUE self) { */ void oj_mimic_rails_init() { - VALUE rails = rb_define_module_under(Oj, "Rails"); + VALUE rails = rb_define_module_under(Oj, "Rails"); rb_define_module_function(rails, "encode", rails_encode, -1); @@ -1197,169 +1198,169 @@ dump_to_hash(VALUE obj, int depth, Out out) { static void dump_float(VALUE obj, int depth, Out out, bool as_ok) { - char buf[64]; - char *b; - double d = rb_num2dbl(obj); - int cnt = 0; + char buf[64]; + char *b; + double d = rb_num2dbl(obj); + int cnt = 0; if (0.0 == d) { - b = buf; - *b++ = '0'; - *b++ = '.'; - *b++ = '0'; - *b++ = '\0'; - cnt = 3; + b = buf; + *b++ = '0'; + *b++ = '.'; + *b++ = '0'; + *b++ = '\0'; + cnt = 3; } else { - if (isnan(d) || OJ_INFINITY == d || -OJ_INFINITY == d) { - strcpy(buf, "null"); - cnt = 4; - } else if (d == (double)(long long int)d) { - cnt = snprintf(buf, sizeof(buf), "%.1f", d); - } else if (oj_rails_float_opt) { - cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, "%0.16g"); - } else { - volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); - - strcpy(buf, rb_string_value_ptr((VALUE *)&rstr)); - cnt = (int)RSTRING_LEN(rstr); - } + if (isnan(d) || OJ_INFINITY == d || -OJ_INFINITY == d) { + strcpy(buf, "null"); + cnt = 4; + } else if (d == (double)(long long int)d) { + cnt = snprintf(buf, sizeof(buf), "%.1f", d); + } else if (oj_rails_float_opt) { + cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, "%0.16g"); + } else { + volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); + + strcpy(buf, rb_string_value_ptr((VALUE*)&rstr)); + cnt = (int)RSTRING_LEN(rstr); + } } assure_size(out, cnt); for (b = buf; '\0' != *b; b++) { - *out->cur++ = *b; + *out->cur++ = *b; } *out->cur = '\0'; } static void dump_array(VALUE a, int depth, Out out, bool as_ok) { - size_t size; - int i, cnt; - int d2 = depth + 1; + size_t size; + int i, cnt; + int d2 = depth + 1; if (Yes == out->opts->circular) { - if (0 > oj_check_circular(a, out)) { - oj_dump_nil(Qnil, 0, out, false); - return; - } + if (0 > oj_check_circular(a, out)) { + oj_dump_nil(Qnil, 0, out, false); + return; + } } //if (!oj_rails_array_opt && as_ok && 0 < out->argc && rb_respond_to(a, oj_as_json_id)) { if (as_ok && 0 < out->argc && rb_respond_to(a, oj_as_json_id)) { - dump_as_json(a, depth, out, false); - return; + dump_as_json(a, depth, out, false); + return; } cnt = (int)RARRAY_LEN(a); *out->cur++ = '['; size = 2; assure_size(out, size); if (0 == cnt) { - *out->cur++ = ']'; + *out->cur++ = ']'; } else { - if (out->opts->dump_opts.use) { - size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1; - } else { - size = d2 * out->indent + 2; - } - cnt--; - for (i = 0; i <= cnt; i++) { - assure_size(out, size); - if (out->opts->dump_opts.use) { - if (0 < out->opts->dump_opts.array_size) { - strcpy(out->cur, out->opts->dump_opts.array_nl); - out->cur += out->opts->dump_opts.array_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - for (i = d2; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - } else { - fill_indent(out, d2); - } - dump_rails_val(rb_ary_entry(a, i), d2, out, true); - if (i < cnt) { - *out->cur++ = ','; - } - } - size = depth * out->indent + 1; - assure_size(out, size); - if (out->opts->dump_opts.use) { - if (0 < out->opts->dump_opts.array_size) { - strcpy(out->cur, out->opts->dump_opts.array_nl); - out->cur += out->opts->dump_opts.array_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - - for (i = depth; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - } else { - fill_indent(out, depth); - } - *out->cur++ = ']'; + if (out->opts->dump_opts.use) { + size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1; + } else { + size = d2 * out->indent + 2; + } + cnt--; + for (i = 0; i <= cnt; i++) { + assure_size(out, size); + if (out->opts->dump_opts.use) { + if (0 < out->opts->dump_opts.array_size) { + strcpy(out->cur, out->opts->dump_opts.array_nl); + out->cur += out->opts->dump_opts.array_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + for (i = d2; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + } else { + fill_indent(out, d2); + } + dump_rails_val(rb_ary_entry(a, i), d2, out, true); + if (i < cnt) { + *out->cur++ = ','; + } + } + size = depth * out->indent + 1; + assure_size(out, size); + if (out->opts->dump_opts.use) { + if (0 < out->opts->dump_opts.array_size) { + strcpy(out->cur, out->opts->dump_opts.array_nl); + out->cur += out->opts->dump_opts.array_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + + for (i = depth; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + } else { + fill_indent(out, depth); + } + *out->cur++ = ']'; } *out->cur = '\0'; } static int hash_cb(VALUE key, VALUE value, VALUE ov) { - Out out = (Out)ov; - int depth = out->depth; - long size; - int rtype = rb_type(key); + Out out = (Out)ov; + int depth = out->depth; + long size; + int rtype = rb_type(key); if (out->omit_nil && Qnil == value) { - return ST_CONTINUE; + return ST_CONTINUE; } if (rtype != T_STRING && rtype != T_SYMBOL) { - key = rb_funcall(key, oj_to_s_id, 0); - rtype = rb_type(key); + key = rb_funcall(key, oj_to_s_id, 0); + rtype = rb_type(key); } if (!out->opts->dump_opts.use) { - size = depth * out->indent + 1; - assure_size(out, size); - fill_indent(out, depth); - if (rtype == T_STRING) { - oj_dump_str(key, 0, out, false); - } else { - oj_dump_sym(key, 0, out, false); - } - *out->cur++ = ':'; + size = depth * out->indent + 1; + assure_size(out, size); + fill_indent(out, depth); + if (rtype == T_STRING) { + oj_dump_str(key, 0, out, false); + } else { + oj_dump_sym(key, 0, out, false); + } + *out->cur++ = ':'; } else { - size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1; - assure_size(out, size); - if (0 < out->opts->dump_opts.hash_size) { - strcpy(out->cur, out->opts->dump_opts.hash_nl); - out->cur += out->opts->dump_opts.hash_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - for (i = depth; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - if (rtype == T_STRING) { - oj_dump_str(key, 0, out, false); - } else { - oj_dump_sym(key, 0, out, false); - } - size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2; - assure_size(out, size); - if (0 < out->opts->dump_opts.before_size) { - strcpy(out->cur, out->opts->dump_opts.before_sep); - out->cur += out->opts->dump_opts.before_size; - } - *out->cur++ = ':'; - if (0 < out->opts->dump_opts.after_size) { - strcpy(out->cur, out->opts->dump_opts.after_sep); - out->cur += out->opts->dump_opts.after_size; - } + size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1; + assure_size(out, size); + if (0 < out->opts->dump_opts.hash_size) { + strcpy(out->cur, out->opts->dump_opts.hash_nl); + out->cur += out->opts->dump_opts.hash_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + for (i = depth; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + if (rtype == T_STRING) { + oj_dump_str(key, 0, out, false); + } else { + oj_dump_sym(key, 0, out, false); + } + size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2; + assure_size(out, size); + if (0 < out->opts->dump_opts.before_size) { + strcpy(out->cur, out->opts->dump_opts.before_sep); + out->cur += out->opts->dump_opts.before_size; + } + *out->cur++ = ':'; + if (0 < out->opts->dump_opts.after_size) { + strcpy(out->cur, out->opts->dump_opts.after_sep); + out->cur += out->opts->dump_opts.after_size; + } } dump_rails_val(value, depth, out, true); out->depth = depth; @@ -1370,145 +1371,145 @@ hash_cb(VALUE key, VALUE value, VALUE ov) { static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) { - int cnt; - size_t size; + int cnt; + size_t size; if (Yes == out->opts->circular) { - if (0 > oj_check_circular(obj, out)) { - oj_dump_nil(Qnil, 0, out, false); - return; - } + if (0 > oj_check_circular(obj, out)) { + oj_dump_nil(Qnil, 0, out, false); + return; + } } if ((!oj_rails_hash_opt || 0 < out->argc) && as_ok && rb_respond_to(obj, oj_as_json_id)) { - dump_as_json(obj, depth, out, false); - return; + dump_as_json(obj, depth, out, false); + return; } cnt = (int)RHASH_SIZE(obj); size = depth * out->indent + 2; assure_size(out, 2); *out->cur++ = '{'; if (0 == cnt) { - *out->cur++ = '}'; + *out->cur++ = '}'; } else { - out->depth = depth + 1; - rb_hash_foreach(obj, hash_cb, (VALUE)out); - if (',' == *(out->cur - 1)) { - out->cur--; // backup to overwrite last comma - } - if (!out->opts->dump_opts.use) { - assure_size(out, size); - fill_indent(out, depth); - } else { - size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1; - assure_size(out, size); - if (0 < out->opts->dump_opts.hash_size) { - strcpy(out->cur, out->opts->dump_opts.hash_nl); - out->cur += out->opts->dump_opts.hash_size; - } - if (0 < out->opts->dump_opts.indent_size) { - int i; - - for (i = depth; 0 < i; i--) { - strcpy(out->cur, out->opts->dump_opts.indent_str); - out->cur += out->opts->dump_opts.indent_size; - } - } - } - *out->cur++ = '}'; + out->depth = depth + 1; + rb_hash_foreach(obj, hash_cb, (VALUE)out); + if (',' == *(out->cur - 1)) { + out->cur--; // backup to overwrite last comma + } + if (!out->opts->dump_opts.use) { + assure_size(out, size); + fill_indent(out, depth); + } else { + size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1; + assure_size(out, size); + if (0 < out->opts->dump_opts.hash_size) { + strcpy(out->cur, out->opts->dump_opts.hash_nl); + out->cur += out->opts->dump_opts.hash_size; + } + if (0 < out->opts->dump_opts.indent_size) { + int i; + + for (i = depth; 0 < i; i--) { + strcpy(out->cur, out->opts->dump_opts.indent_str); + out->cur += out->opts->dump_opts.indent_size; + } + } + } + *out->cur++ = '}'; } *out->cur = '\0'; } static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) { - VALUE clas; + VALUE clas; if (oj_code_dump(oj_compat_codes, obj, depth, out)) { - out->argc = 0; - return; + out->argc = 0; + return; } clas = rb_obj_class(obj); if (as_ok) { - ROpt ro; - - if (NULL != (ro = oj_rails_get_opt(out->ropts, clas)) && ro->on) { - ro->dump(obj, depth, out, as_ok); - } else if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) { - oj_dump_raw_json(obj, depth, out); - } else if (rb_respond_to(obj, oj_as_json_id)) { - dump_as_json(obj, depth, out, true); - } else if (rb_respond_to(obj, oj_to_hash_id)) { - dump_to_hash(obj, depth, out); - } else if (oj_bigdecimal_class == clas) { - dump_bigdecimal(obj, depth, out, false); - } else { - oj_dump_obj_to_s(obj, out); - } + ROpt ro; + + if (NULL != (ro = oj_rails_get_opt(out->ropts, clas)) && ro->on) { + ro->dump(obj, depth, out, as_ok); + } else if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) { + oj_dump_raw_json(obj, depth, out); + } else if (rb_respond_to(obj, oj_as_json_id)) { + dump_as_json(obj, depth, out, true); + } else if (rb_respond_to(obj, oj_to_hash_id)) { + dump_to_hash(obj, depth, out); + } else if (oj_bigdecimal_class == clas) { + dump_bigdecimal(obj, depth, out, false); + } else { + oj_dump_obj_to_s(obj, out); + } } else if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) { - oj_dump_raw_json(obj, depth, out); + oj_dump_raw_json(obj, depth, out); } else if (rb_respond_to(obj, oj_to_hash_id)) { - // Always attempt to_hash. - dump_to_hash(obj, depth, out); + // Always attempt to_hash. + dump_to_hash(obj, depth, out); } else if (oj_bigdecimal_class == clas) { - dump_bigdecimal(obj, depth, out, false); + dump_bigdecimal(obj, depth, out, false); } else { - oj_dump_obj_to_s(obj, out); + oj_dump_obj_to_s(obj, out); } } -static DumpFunc rails_funcs[] = { - NULL, // RUBY_T_NONE = 0x00, - dump_obj, // RUBY_T_OBJECT = 0x01, - oj_dump_class, // RUBY_T_CLASS = 0x02, - oj_dump_class, // RUBY_T_MODULE = 0x03, - dump_float, // RUBY_T_FLOAT = 0x04, - oj_dump_str, // RUBY_T_STRING = 0x05, - dump_regexp, // RUBY_T_REGEXP = 0x06, +static DumpFunc rails_funcs[] = { + NULL, // RUBY_T_NONE = 0x00, + dump_obj, // RUBY_T_OBJECT = 0x01, + oj_dump_class, // RUBY_T_CLASS = 0x02, + oj_dump_class, // RUBY_T_MODULE = 0x03, + dump_float, // RUBY_T_FLOAT = 0x04, + oj_dump_str, // RUBY_T_STRING = 0x05, + dump_regexp, // RUBY_T_REGEXP = 0x06, //dump_as_string, // RUBY_T_REGEXP = 0x06, - dump_array, // RUBY_T_ARRAY = 0x07, - dump_hash, // RUBY_T_HASH = 0x08, - dump_obj, // RUBY_T_STRUCT = 0x09, - oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a, - dump_as_string, // RUBY_T_FILE = 0x0b, - dump_obj, // RUBY_T_DATA = 0x0c, - NULL, // RUBY_T_MATCH = 0x0d, + dump_array, // RUBY_T_ARRAY = 0x07, + dump_hash, // RUBY_T_HASH = 0x08, + dump_obj, // RUBY_T_STRUCT = 0x09, + oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a, + dump_as_string, // RUBY_T_FILE = 0x0b, + dump_obj, // RUBY_T_DATA = 0x0c, + NULL, // RUBY_T_MATCH = 0x0d, // Rails raises a stack error on Complex and Rational. It also corrupts // something which causes a segfault on the next call. Oj will not mimic // that behavior. - dump_as_string, // RUBY_T_COMPLEX = 0x0e, - dump_as_string, // RUBY_T_RATIONAL = 0x0f, - NULL, // 0x10 - oj_dump_nil, // RUBY_T_NIL = 0x11, - oj_dump_true, // RUBY_T_TRUE = 0x12, - oj_dump_false, // RUBY_T_FALSE = 0x13, - oj_dump_sym, // RUBY_T_SYMBOL = 0x14, - oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15, + dump_as_string, // RUBY_T_COMPLEX = 0x0e, + dump_as_string, // RUBY_T_RATIONAL = 0x0f, + NULL, // 0x10 + oj_dump_nil, // RUBY_T_NIL = 0x11, + oj_dump_true, // RUBY_T_TRUE = 0x12, + oj_dump_false, // RUBY_T_FALSE = 0x13, + oj_dump_sym, // RUBY_T_SYMBOL = 0x14, + oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15, }; static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) { - int type = rb_type(obj); + int type = rb_type(obj); if (Yes == out->opts->trace) { - oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn); + oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn); } if (MAX_DEPTH < depth) { - rb_raise(rb_eNoMemError, "Too deeply nested.\n"); + rb_raise(rb_eNoMemError, "Too deeply nested.\n"); } if (0 < type && type <= RUBY_T_FIXNUM) { - DumpFunc f = rails_funcs[type]; + DumpFunc f = rails_funcs[type]; - if (NULL != f) { - f(obj, depth, out, as_ok); - if (Yes == out->opts->trace) { - oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut); - } - return; - } + if (NULL != f) { + f(obj, depth, out, as_ok); + if (Yes == out->opts->trace) { + oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut); + } + return; + } } oj_dump_nil(Qnil, depth, out, false); if (Yes == out->opts->trace) { - oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut); + oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut); } } @@ -1517,9 +1518,9 @@ oj_dump_rails_val(VALUE obj, int depth, Out out) { out->opts->str_rx.head = NULL; out->opts->str_rx.tail = NULL; if (escape_html) { - out->opts->escape_mode = RailsXEsc; + out->opts->escape_mode = RailsXEsc; } else { - out->opts->escape_mode = RailsEsc; + out->opts->escape_mode = RailsEsc; } dump_rails_val(obj, depth, out, true); } diff --git a/ext/oj/rails.h b/ext/oj/rails.h index 82c383bd..7b49950b 100644 --- a/ext/oj/rails.h +++ b/ext/oj/rails.h @@ -6,13 +6,14 @@ #include "dump.h" -extern void oj_mimic_rails_init(); -extern ROpt oj_rails_get_opt(ROptTable rot, VALUE clas); +extern void oj_mimic_rails_init(); +extern ROpt oj_rails_get_opt(ROptTable rot, VALUE clas); -extern bool oj_rails_hash_opt; -extern bool oj_rails_array_opt; -extern bool oj_rails_float_opt; +extern bool oj_rails_hash_opt; +extern bool oj_rails_array_opt; +extern bool oj_rails_float_opt; + +extern VALUE oj_optimize_rails(VALUE self); -extern VALUE oj_optimize_rails(VALUE self); #endif /* OJ_RAILS_H */ diff --git a/ext/oj/reader.c b/ext/oj/reader.c index 001329db..a82b2e9f 100644 --- a/ext/oj/reader.c +++ b/ext/oj/reader.c @@ -1,39 +1,39 @@ // Copyright (c) 2011 Peter Ohler. All rights reserved. // Licensed under the MIT License. See LICENSE file in the project root for license details. +#include #include #include -#include #include #include #if NEEDS_UIO #include #endif -#include #include +#include +#include "ruby.h" #include "oj.h" #include "reader.h" -#include "ruby.h" -#define BUF_PAD 4 +#define BUF_PAD 4 -static VALUE rescue_cb(VALUE rdr, VALUE err); -static VALUE io_cb(VALUE rdr); -static VALUE partial_io_cb(VALUE rdr); -static int read_from_io(Reader reader); -static int read_from_fd(Reader reader); -static int read_from_io_partial(Reader reader); +static VALUE rescue_cb(VALUE rdr, VALUE err); +static VALUE io_cb(VALUE rdr); +static VALUE partial_io_cb(VALUE rdr); +static int read_from_io(Reader reader); +static int read_from_fd(Reader reader); +static int read_from_io_partial(Reader reader); //static int read_from_str(Reader reader); void oj_reader_init(Reader reader, VALUE io, int fd, bool to_s) { - VALUE io_class = rb_obj_class(io); - VALUE stat; - VALUE ftype; + VALUE io_class = rb_obj_class(io); + VALUE stat; + VALUE ftype; reader->head = reader->base; - *((char *)reader->head) = '\0'; + *((char*)reader->head) = '\0'; reader->end = reader->head + sizeof(reader->base) - BUF_PAD; reader->tail = reader->head; reader->read_end = reader->head; @@ -45,125 +45,125 @@ oj_reader_init(Reader reader, VALUE io, int fd, bool to_s) { reader->free_head = 0; if (0 != fd) { - reader->read_func = read_from_fd; - reader->fd = fd; + reader->read_func = read_from_fd; + reader->fd = fd; } else if (rb_cString == io_class) { - reader->read_func = 0; - reader->in_str = StringValuePtr(io); - reader->head = (char *)reader->in_str; - reader->tail = reader->head; - reader->read_end = reader->head + RSTRING_LEN(io); + reader->read_func = 0; + reader->in_str = StringValuePtr(io); + reader->head = (char*)reader->in_str; + reader->tail = reader->head; + reader->read_end = reader->head + RSTRING_LEN(io); } else if (oj_stringio_class == io_class) { - VALUE s = rb_funcall2(io, oj_string_id, 0, 0); + VALUE s = rb_funcall2(io, oj_string_id, 0, 0); - reader->read_func = 0; - reader->in_str = StringValuePtr(s); - reader->head = (char *)reader->in_str; - reader->tail = reader->head; - reader->read_end = reader->head + RSTRING_LEN(s); + reader->read_func = 0; + reader->in_str = StringValuePtr(s); + reader->head = (char*)reader->in_str; + reader->tail = reader->head; + reader->read_end = reader->head + RSTRING_LEN(s); } else if (rb_cFile == io_class && - Qnil != (stat = rb_funcall(io, oj_stat_id, 0)) && - Qnil != (ftype = rb_funcall(stat, oj_ftype_id, 0)) && - 0 == strcmp("file", StringValuePtr(ftype)) && - 0 == FIX2INT(rb_funcall(io, oj_pos_id, 0))) { - reader->read_func = read_from_fd; - reader->fd = FIX2INT(rb_funcall(io, oj_fileno_id, 0)); + Qnil != (stat = rb_funcall(io, oj_stat_id, 0)) && + Qnil != (ftype = rb_funcall(stat, oj_ftype_id, 0)) && + 0 == strcmp("file", StringValuePtr(ftype)) && + 0 == FIX2INT(rb_funcall(io, oj_pos_id, 0))) { + reader->read_func = read_from_fd; + reader->fd = FIX2INT(rb_funcall(io, oj_fileno_id, 0)); } else if (rb_respond_to(io, oj_readpartial_id)) { - reader->read_func = read_from_io_partial; - reader->io = io; + reader->read_func = read_from_io_partial; + reader->io = io; } else if (rb_respond_to(io, oj_read_id)) { - reader->read_func = read_from_io; - reader->io = io; + reader->read_func = read_from_io; + reader->io = io; } else if (to_s) { - volatile VALUE rstr = rb_funcall(io, oj_to_s_id, 0); + volatile VALUE rstr = rb_funcall(io, oj_to_s_id, 0); - reader->read_func = 0; - reader->in_str = StringValuePtr(rstr); - reader->head = (char *)reader->in_str; - reader->tail = reader->head; - reader->read_end = reader->head + RSTRING_LEN(rstr); + reader->read_func = 0; + reader->in_str = StringValuePtr(rstr); + reader->head = (char*)reader->in_str; + reader->tail = reader->head; + reader->read_end = reader->head + RSTRING_LEN(rstr); } else { - rb_raise(rb_eArgError, "parser io argument must be a String or respond to readpartial() or read().\n"); + rb_raise(rb_eArgError, "parser io argument must be a String or respond to readpartial() or read().\n"); } } int oj_reader_read(Reader reader) { - int err; - size_t shift = 0; + int err; + size_t shift = 0; if (0 == reader->read_func) { - return -1; + return -1; } // if there is not much room to read into, shift or realloc a larger buffer. if (reader->head < reader->tail && 4096 > reader->end - reader->tail) { - if (0 == reader->pro) { - shift = reader->tail - reader->head; - } else { - shift = reader->pro - reader->head - 1; // leave one character so we can backup one - } - if (0 >= shift) { /* no space left so allocate more */ - const char *old = reader->head; - size_t size = reader->end - reader->head + BUF_PAD; - - if (reader->head == reader->base) { - reader->head = ALLOC_N(char, size * 2); - memcpy((char *)reader->head, old, size); - } else { - REALLOC_N(reader->head, char, size * 2); - } - reader->free_head = 1; - reader->end = reader->head + size * 2 - BUF_PAD; - reader->tail = reader->head + (reader->tail - old); - reader->read_end = reader->head + (reader->read_end - old); - if (0 != reader->pro) { - reader->pro = reader->head + (reader->pro - old); - } - if (0 != reader->str) { - reader->str = reader->head + (reader->str - old); - } - } else { - memmove((char *)reader->head, reader->head + shift, reader->read_end - (reader->head + shift)); - reader->tail -= shift; - reader->read_end -= shift; - if (0 != reader->pro) { - reader->pro -= shift; - } - if (0 != reader->str) { - reader->str -= shift; - } - } + if (0 == reader->pro) { + shift = reader->tail - reader->head; + } else { + shift = reader->pro - reader->head - 1; // leave one character so we can backup one + } + if (0 >= shift) { /* no space left so allocate more */ + const char *old = reader->head; + size_t size = reader->end - reader->head + BUF_PAD; + + if (reader->head == reader->base) { + reader->head = ALLOC_N(char, size * 2); + memcpy((char*)reader->head, old, size); + } else { + REALLOC_N(reader->head, char, size * 2); + } + reader->free_head = 1; + reader->end = reader->head + size * 2 - BUF_PAD; + reader->tail = reader->head + (reader->tail - old); + reader->read_end = reader->head + (reader->read_end - old); + if (0 != reader->pro) { + reader->pro = reader->head + (reader->pro - old); + } + if (0 != reader->str) { + reader->str = reader->head + (reader->str - old); + } + } else { + memmove((char*)reader->head, reader->head + shift, reader->read_end - (reader->head + shift)); + reader->tail -= shift; + reader->read_end -= shift; + if (0 != reader->pro) { + reader->pro -= shift; + } + if (0 != reader->str) { + reader->str -= shift; + } + } } err = reader->read_func(reader); - *(char *)reader->read_end = '\0'; + *(char*)reader->read_end = '\0'; return err; } static VALUE rescue_cb(VALUE rbuf, VALUE err) { - VALUE clas = rb_obj_class(err); + VALUE clas = rb_obj_class(err); if (rb_eTypeError != clas && rb_eEOFError != clas) { - Reader reader = (Reader)rbuf; + Reader reader = (Reader)rbuf; - rb_raise(clas, "at line %d, column %d\n", reader->line, reader->col); + rb_raise(clas, "at line %d, column %d\n", reader->line, reader->col); } return Qfalse; } static VALUE partial_io_cb(VALUE rbuf) { - Reader reader = (Reader)rbuf; - VALUE args[1]; - VALUE rstr; - char *str; - size_t cnt; + Reader reader = (Reader)rbuf; + VALUE args[1]; + VALUE rstr; + char *str; + size_t cnt; args[0] = ULONG2NUM(reader->end - reader->tail); rstr = rb_funcall2(reader->io, oj_readpartial_id, 1, args); if (Qnil == rstr) { - return Qfalse; + return Qfalse; } str = StringValuePtr(rstr); cnt = RSTRING_LEN(rstr); @@ -176,16 +176,16 @@ partial_io_cb(VALUE rbuf) { static VALUE io_cb(VALUE rbuf) { - Reader reader = (Reader)rbuf; - VALUE args[1]; - VALUE rstr; - char *str; - size_t cnt; + Reader reader = (Reader)rbuf; + VALUE args[1]; + VALUE rstr; + char *str; + size_t cnt; args[0] = ULONG2NUM(reader->end - reader->tail); rstr = rb_funcall2(reader->io, oj_read_id, 1, args); if (Qnil == rstr) { - return Qfalse; + return Qfalse; } str = StringValuePtr(rstr); cnt = RSTRING_LEN(rstr); @@ -208,14 +208,14 @@ read_from_io(Reader reader) { static int read_from_fd(Reader reader) { - ssize_t cnt; - size_t max = reader->end - reader->tail; + ssize_t cnt; + size_t max = reader->end - reader->tail; cnt = read(reader->fd, reader->tail, max); if (cnt <= 0) { - return -1; + return -1; } else if (0 != cnt) { - reader->read_end = reader->tail + cnt; + reader->read_end = reader->tail + cnt; } return 0; } diff --git a/ext/oj/reader.h b/ext/oj/reader.h index 1d58c74f..283d8a30 100644 --- a/ext/oj/reader.h +++ b/ext/oj/reader.h @@ -5,39 +5,39 @@ #define OJ_READER_H typedef struct _reader { - char base[0x00001000]; - char *head; - char *end; - char *tail; - char *read_end; /* one past last character read */ - char *pro; /* protection start, buffer can not slide past this point */ - char *str; /* start of current string being read */ - long pos; - int line; - int col; - int free_head; - int (*read_func)(struct _reader *reader); + char base[0x00001000]; + char *head; + char *end; + char *tail; + char *read_end; /* one past last character read */ + char *pro; /* protection start, buffer can not slide past this point */ + char *str; /* start of current string being read */ + long pos; + int line; + int col; + int free_head; + int (*read_func)(struct _reader *reader); union { - int fd; - VALUE io; - const char *in_str; + int fd; + VALUE io; + const char *in_str; }; -} * Reader; +} *Reader; -extern void oj_reader_init(Reader reader, VALUE io, int fd, bool to_s); -extern int oj_reader_read(Reader reader); +extern void oj_reader_init(Reader reader, VALUE io, int fd, bool to_s); +extern int oj_reader_read(Reader reader); static inline char reader_get(Reader reader) { //printf("*** drive get from '%s' from start: %ld buf: %p from read_end: %ld\n", reader->tail, reader->tail - reader->head, reader->head, reader->read_end - reader->tail); if (reader->read_end <= reader->tail) { - if (0 != oj_reader_read(reader)) { - return '\0'; - } + if (0 != oj_reader_read(reader)) { + return '\0'; + } } if ('\n' == *reader->tail) { - reader->line++; - reader->col = 0; + reader->line++; + reader->col = 0; } reader->col++; reader->pos++; @@ -51,8 +51,8 @@ reader_backup(Reader reader) { reader->col--; reader->pos--; if (0 >= reader->col) { - reader->line--; - // allow col to be negative since we never backup twice in a row + reader->line--; + // allow col to be negative since we never backup twice in a row } } @@ -72,19 +72,19 @@ reader_release(Reader reader) { */ static inline char reader_next_non_white(Reader reader) { - char c; + char c; while ('\0' != (c = reader_get(reader))) { - switch (c) { - case ' ': - case '\t': - case '\f': - case '\n': - case '\r': - break; - default: - return c; - } + switch(c) { + case ' ': + case '\t': + case '\f': + case '\n': + case '\r': + break; + default: + return c; + } } return '\0'; } @@ -94,20 +94,20 @@ reader_next_non_white(Reader reader) { */ static inline char reader_next_white(Reader reader) { - char c; + char c; while ('\0' != (c = reader_get(reader))) { - switch (c) { - case ' ': - case '\t': - case '\f': - case '\n': - case '\r': - case '\0': - return c; - default: - break; - } + switch(c) { + case ' ': + case '\t': + case '\f': + case '\n': + case '\r': + case '\0': + return c; + default: + break; + } } return '\0'; } @@ -115,9 +115,9 @@ reader_next_white(Reader reader) { static inline int reader_expect(Reader reader, const char *s) { for (; '\0' != *s; s++) { - if (reader_get(reader) != *s) { - return -1; - } + if (reader_get(reader) != *s) { + return -1; + } } return 0; } @@ -125,23 +125,23 @@ reader_expect(Reader reader, const char *s) { static inline void reader_cleanup(Reader reader) { if (reader->free_head && 0 != reader->head) { - xfree((char *)reader->head); - reader->head = 0; - reader->free_head = 0; + xfree((char*)reader->head); + reader->head = 0; + reader->free_head = 0; } } static inline int is_white(char c) { - switch (c) { - case ' ': - case '\t': - case '\f': - case '\n': - case '\r': - return 1; - default: - break; + switch(c) { + case ' ': + case '\t': + case '\f': + case '\n': + case '\r': + return 1; + default: + break; } return 0; } diff --git a/ext/oj/resolve.c b/ext/oj/resolve.c index c2443c08..ae11b9e6 100644 --- a/ext/oj/resolve.c +++ b/ext/oj/resolve.c @@ -1,77 +1,77 @@ // Copyright (c) 2012 Peter Ohler. All rights reserved. // Licensed under the MIT License. See LICENSE file in the project root for license details. -#include #include +#include #include #ifdef HAVE_PTHREAD_MUTEX_INIT #include #endif -#include "err.h" -#include "hash.h" #include "oj.h" +#include "err.h" #include "parse.h" +#include "hash.h" inline static VALUE resolve_classname(VALUE mod, const char *classname, int auto_define) { - VALUE clas; - ID ci = rb_intern(classname); + VALUE clas; + ID ci = rb_intern(classname); if (rb_const_defined_at(mod, ci)) { - clas = rb_const_get_at(mod, ci); + clas = rb_const_get_at(mod, ci); } else if (auto_define) { - clas = rb_define_class_under(mod, classname, oj_bag_class); + clas = rb_define_class_under(mod, classname, oj_bag_class); } else { - clas = Qundef; + clas = Qundef; } return clas; } static VALUE resolve_classpath(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class) { - char class_name[1024]; - VALUE clas; - char *end = class_name + sizeof(class_name) - 1; - char *s; - const char *n = name; + char class_name[1024]; + VALUE clas; + char *end = class_name + sizeof(class_name) - 1; + char *s; + const char *n = name; clas = rb_cObject; for (s = class_name; 0 < len; n++, len--) { - if (':' == *n) { - *s = '\0'; - n++; - len--; - if (':' != *n) { - return Qundef; - } - if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) { - return Qundef; - } - s = class_name; - } else if (end <= s) { - return Qundef; - } else { - *s++ = *n; - } + if (':' == *n) { + *s = '\0'; + n++; + len--; + if (':' != *n) { + return Qundef; + } + if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) { + return Qundef; + } + s = class_name; + } else if (end <= s) { + return Qundef; + } else { + *s++ = *n; + } } *s = '\0'; if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) { - oj_set_error_at(pi, error_class, __FILE__, __LINE__, "class %s is not defined", name); - if (Qnil != error_class) { - pi->err_class = error_class; - } + oj_set_error_at(pi, error_class, __FILE__, __LINE__, "class %s is not defined", name); + if (Qnil != error_class) { + pi->err_class = error_class; + } } return clas; } VALUE oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class) { - VALUE clas; - VALUE *slot; + VALUE clas; + VALUE *slot; if (No == pi->options.class_cache) { - return resolve_classpath(pi, name, len, auto_define, error_class); + return resolve_classpath(pi, name, len, auto_define, error_class); } #ifdef HAVE_PTHREAD_MUTEX_INIT pthread_mutex_lock(&oj_cache_mutex); @@ -79,9 +79,9 @@ oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE rb_mutex_lock(oj_cache_mutex); #endif if (Qnil == (clas = oj_class_hash_get(name, len, &slot))) { - if (Qundef != (clas = resolve_classpath(pi, name, len, auto_define, error_class))) { - *slot = clas; - } + if (Qundef != (clas = resolve_classpath(pi, name, len, auto_define, error_class))) { + *slot = clas; + } } #ifdef HAVE_PTHREAD_MUTEX_INIT pthread_mutex_unlock(&oj_cache_mutex); @@ -93,8 +93,8 @@ oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE VALUE oj_name2struct(ParseInfo pi, VALUE nameVal, VALUE error_class) { - size_t len = RSTRING_LEN(nameVal); - const char *str = StringValuePtr(nameVal); + size_t len = RSTRING_LEN(nameVal); + const char *str = StringValuePtr(nameVal); return resolve_classpath(pi, str, len, 0, error_class); } diff --git a/ext/oj/resolve.h b/ext/oj/resolve.h index 31373594..d3204ea4 100644 --- a/ext/oj/resolve.h +++ b/ext/oj/resolve.h @@ -6,7 +6,7 @@ #include "ruby.h" -extern VALUE oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class); -extern VALUE oj_name2struct(ParseInfo pi, VALUE nameVal, VALUE error_class); +extern VALUE oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class); +extern VALUE oj_name2struct(ParseInfo pi, VALUE nameVal, VALUE error_class); #endif /* OJ_RESOLVE_H */ diff --git a/ext/oj/rxclass.c b/ext/oj/rxclass.c index 8cec8cb0..096b0fb0 100644 --- a/ext/oj/rxclass.c +++ b/ext/oj/rxclass.c @@ -1,11 +1,11 @@ // Copyright (c) 2017 Peter Ohler. All rights reserved. // Licensed under the MIT License. See LICENSE file in the project root for license details. -#include -#include +#include #include +#include #include -#include +#include #if !IS_WINDOWS #include #endif @@ -13,14 +13,14 @@ #include "rxclass.h" typedef struct _rxC { - struct _rxC *next; - VALUE rrx; + struct _rxC *next; + VALUE rrx; #if !IS_WINDOWS - regex_t rx; + regex_t rx; #endif - VALUE clas; - char src[256]; -} * RxC; + VALUE clas; + char src[256]; +} *RxC; void oj_rxclass_init(RxClass rc) { @@ -31,30 +31,30 @@ oj_rxclass_init(RxClass rc) { void oj_rxclass_cleanup(RxClass rc) { - RxC rxc; + RxC rxc; while (NULL != (rxc = rc->head)) { - rc->head = rc->head->next; + rc->head = rc->head->next; #if !IS_WINDOWS - if (Qnil == rxc->rrx) { - regfree(&rxc->rx); - } - xfree(rxc); + if (Qnil == rxc->rrx) { + regfree(&rxc->rx); + } + xfree(rxc); #endif } } void oj_rxclass_rappend(RxClass rc, VALUE rx, VALUE clas) { - RxC rxc = ALLOC_N(struct _rxC, 1); + RxC rxc = ALLOC_N(struct _rxC, 1); memset(rxc, 0, sizeof(struct _rxC)); rxc->rrx = rx; rxc->clas = clas; if (NULL == rc->tail) { - rc->head = rxc; + rc->head = rxc; } else { - rc->tail->next = rxc; + rc->tail->next = rxc; } rc->tail = rxc; } @@ -62,14 +62,14 @@ oj_rxclass_rappend(RxClass rc, VALUE rx, VALUE clas) { // Attempt to compile the expression. If it fails populate the error code.. int oj_rxclass_append(RxClass rc, const char *expr, VALUE clas) { - RxC rxc; + RxC rxc; #if !IS_WINDOWS - int err; - int flags = 0; + int err; + int flags = 0; #endif if (sizeof(rxc->src) <= strlen(expr)) { - snprintf(rc->err, sizeof(rc->err), "expressions must be less than %lu characters", (unsigned long)sizeof(rxc->src)); - return EINVAL; + snprintf(rc->err, sizeof(rc->err), "expressions must be less than %lu characters", (unsigned long)sizeof(rxc->src)); + return EINVAL; } rxc = ALLOC_N(struct _rxC, 1); rxc->next = 0; @@ -80,15 +80,15 @@ oj_rxclass_append(RxClass rc, const char *expr, VALUE clas) { #else rxc->rrx = Qnil; if (0 != (err = regcomp(&rxc->rx, expr, flags))) { - regerror(err, &rxc->rx, rc->err, sizeof(rc->err)); - free(rxc); - return err; + regerror(err, &rxc->rx, rc->err, sizeof(rc->err)); + free(rxc); + return err; } #endif if (NULL == rc->tail) { - rc->head = rxc; + rc->head = rxc; } else { - rc->tail->next = rxc; + rc->tail->next = rxc; } rc->tail = rxc; @@ -97,30 +97,30 @@ oj_rxclass_append(RxClass rc, const char *expr, VALUE clas) { VALUE oj_rxclass_match(RxClass rc, const char *str, int len) { - RxC rxc; - char buf[4096]; + RxC rxc; + char buf[4096]; for (rxc = rc->head; NULL != rxc; rxc = rxc->next) { - if (Qnil != rxc->rrx) { - // Must use a valiabel for this to work. - volatile VALUE rstr = rb_str_new(str, len); - - //if (Qtrue == rb_funcall(rxc->rrx, rb_intern("match?"), 1, rstr)) { - if (Qnil != rb_funcall(rxc->rrx, rb_intern("match"), 1, rstr)) { - return rxc->clas; - } - } else if (len < (int)sizeof(buf)) { + if (Qnil != rxc->rrx) { + // Must use a valiabel for this to work. + volatile VALUE rstr = rb_str_new(str, len); + + //if (Qtrue == rb_funcall(rxc->rrx, rb_intern("match?"), 1, rstr)) { + if (Qnil != rb_funcall(rxc->rrx, rb_intern("match"), 1, rstr)) { + return rxc->clas; + } + } else if (len < (int)sizeof(buf)) { #if !IS_WINDOWS - // string is not \0 terminated so copy and atempt a match - memcpy(buf, str, len); - buf[len] = '\0'; - if (0 == regexec(&rxc->rx, buf, 0, NULL, 0)) { // match - return rxc->clas; - } + // string is not \0 terminated so copy and atempt a match + memcpy(buf, str, len); + buf[len] = '\0'; + if (0 == regexec(&rxc->rx, buf, 0, NULL, 0)) { // match + return rxc->clas; + } #endif - } else { - // TBD allocate a larger buffer and attempt - } + } else { + // TBD allocate a larger buffer and attempt + } } return Qnil; } @@ -130,16 +130,16 @@ oj_rxclass_copy(RxClass src, RxClass dest) { dest->head = NULL; dest->tail = NULL; if (NULL != src->head) { - RxC rxc; + RxC rxc; - for (rxc = src->head; NULL != rxc; rxc = rxc->next) { - if (Qnil != rxc->rrx) { - oj_rxclass_rappend(dest, rxc->rrx, rxc->clas); - } else { + for (rxc = src->head; NULL != rxc; rxc = rxc->next) { + if (Qnil != rxc->rrx) { + oj_rxclass_rappend(dest, rxc->rrx, rxc->clas); + } else { #if !IS_WINDOWS - oj_rxclass_append(dest, rxc->src, rxc->clas); + oj_rxclass_append(dest, rxc->src, rxc->clas); #endif - } - } + } + } } } diff --git a/ext/oj/rxclass.h b/ext/oj/rxclass.h index b99358fd..4b451110 100644 --- a/ext/oj/rxclass.h +++ b/ext/oj/rxclass.h @@ -4,22 +4,22 @@ #ifndef OJ_RXCLASS_H #define OJ_RXCLASS_H -#include "ruby.h" #include +#include "ruby.h" struct _rxC; typedef struct _rxClass { - struct _rxC *head; - struct _rxC *tail; - char err[128]; -} * RxClass; + struct _rxC *head; + struct _rxC *tail; + char err[128]; +} *RxClass; -extern void oj_rxclass_init(RxClass rc); -extern void oj_rxclass_cleanup(RxClass rc); -extern int oj_rxclass_append(RxClass rc, const char *expr, VALUE clas); -extern VALUE oj_rxclass_match(RxClass rc, const char *str, int len); -extern void oj_rxclass_copy(RxClass src, RxClass dest); -extern void oj_rxclass_rappend(RxClass rc, VALUE rx, VALUE clas); +extern void oj_rxclass_init(RxClass rc); +extern void oj_rxclass_cleanup(RxClass rc); +extern int oj_rxclass_append(RxClass rc, const char *expr, VALUE clas); +extern VALUE oj_rxclass_match(RxClass rc, const char *str, int len); +extern void oj_rxclass_copy(RxClass src, RxClass dest); +extern void oj_rxclass_rappend(RxClass rc, VALUE rx, VALUE clas); #endif /* OJ_RXCLASS_H */ diff --git a/ext/oj/saj.c b/ext/oj/saj.c index aa7cdbb5..378312f5 100644 --- a/ext/oj/saj.c +++ b/ext/oj/saj.c @@ -2,45 +2,45 @@ // Licensed under the MIT License. See LICENSE file in the project root for license details. #if !IS_WINDOWS -#include /* for getrlimit() on linux */ +#include /* for getrlimit() on linux */ #endif -#include -#include #include +#include #include +#include #include #include // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS -#define OJ_INFINITY (1.0 / 0.0) +#define OJ_INFINITY (1.0/0.0) -#include "encode.h" #include "oj.h" +#include "encode.h" typedef struct _parseInfo { - char *str; /* buffer being read from */ - char *s; /* current position in buffer */ - void *stack_min; - VALUE handler; - int has_hash_start; - int has_hash_end; - int has_array_start; - int has_array_end; - int has_add_value; - int has_error; -} * ParseInfo; - -static void read_next(ParseInfo pi, const char *key); -static void read_hash(ParseInfo pi, const char *key); -static void read_array(ParseInfo pi, const char *key); -static void read_str(ParseInfo pi, const char *key); -static void read_num(ParseInfo pi, const char *key); -static void read_true(ParseInfo pi, const char *key); -static void read_false(ParseInfo pi, const char *key); -static void read_nil(ParseInfo pi, const char *key); -static void next_non_white(ParseInfo pi); -static char *read_quoted_value(ParseInfo pi); -static void skip_comment(ParseInfo pi); + char *str; /* buffer being read from */ + char *s; /* current position in buffer */ + void *stack_min; + VALUE handler; + int has_hash_start; + int has_hash_end; + int has_array_start; + int has_array_end; + int has_add_value; + int has_error; +} *ParseInfo; + +static void read_next(ParseInfo pi, const char *key); +static void read_hash(ParseInfo pi, const char *key); +static void read_array(ParseInfo pi, const char *key); +static void read_str(ParseInfo pi, const char *key); +static void read_num(ParseInfo pi, const char *key); +static void read_true(ParseInfo pi, const char *key); +static void read_false(ParseInfo pi, const char *key); +static void read_nil(ParseInfo pi, const char *key); +static void next_non_white(ParseInfo pi); +static char* read_quoted_value(ParseInfo pi); +static void skip_comment(ParseInfo pi); /* This JSON parser is a single pass, destructive, callback parser. It is a * single pass parse since it only make one pass over the characters in the @@ -56,19 +56,19 @@ static void skip_comment(ParseInfo pi); */ inline static void -call_error(const char *msg, ParseInfo pi, const char *file, int line) { - char buf[128]; - const char *s = pi->s; - int jline = 1; - int col = 1; +call_error(const char *msg, ParseInfo pi, const char* file, int line) { + char buf[128]; + const char *s = pi->s; + int jline = 1; + int col = 1; for (; pi->str < s && '\n' != *s; s--) { - col++; + col++; } for (; pi->str < s; s--) { - if ('\n' == *s) { - jline++; - } + if ('\n' == *s) { + jline++; + } } sprintf(buf, "%s at line %d, column %d [%s:%d]", msg, jline, col, file, line); rb_funcall(pi->handler, oj_error_id, 3, rb_str_new2(buf), LONG2NUM(jline), LONG2NUM(col)); @@ -77,44 +77,44 @@ call_error(const char *msg, ParseInfo pi, const char *file, int line) { inline static void next_non_white(ParseInfo pi) { for (; 1; pi->s++) { - switch (*pi->s) { - case ' ': - case '\t': - case '\f': - case '\n': - case '\r': - break; - case '/': - skip_comment(pi); - break; - default: - return; - } + switch(*pi->s) { + case ' ': + case '\t': + case '\f': + case '\n': + case '\r': + break; + case '/': + skip_comment(pi); + break; + default: + return; + } } } inline static void call_add_value(VALUE handler, VALUE value, const char *key) { - volatile VALUE k; + volatile VALUE k; if (0 == key) { - k = Qnil; + k = Qnil; } else { - k = rb_str_new2(key); - k = oj_encode(k); + k = rb_str_new2(key); + k = oj_encode(k); } rb_funcall(handler, oj_add_value_id, 2, value, k); } inline static void call_no_value(VALUE handler, ID method, const char *key) { - volatile VALUE k; + volatile VALUE k; if (0 == key) { - k = Qnil; + k = Qnil; } else { - k = rb_str_new2(key); - k = oj_encode(k); + k = rb_str_new2(key); + k = oj_encode(k); } rb_funcall(handler, method, 1, k); } @@ -123,176 +123,176 @@ static void skip_comment(ParseInfo pi) { pi->s++; /* skip first / */ if ('*' == *pi->s) { - pi->s++; - for (; '\0' != *pi->s; pi->s++) { - if ('*' == *pi->s && '/' == *(pi->s + 1)) { - pi->s++; - return; - } else if ('\0' == *pi->s) { - if (pi->has_error) { - call_error("comment not terminated", pi, __FILE__, __LINE__); - } else { - raise_error("comment not terminated", pi->str, pi->s); - } - } - } + pi->s++; + for (; '\0' != *pi->s; pi->s++) { + if ('*' == *pi->s && '/' == *(pi->s + 1)) { + pi->s++; + return; + } else if ('\0' == *pi->s) { + if (pi->has_error) { + call_error("comment not terminated", pi, __FILE__, __LINE__); + } else { + raise_error("comment not terminated", pi->str, pi->s); + } + } + } } else if ('/' == *pi->s) { - for (; 1; pi->s++) { - switch (*pi->s) { - case '\n': - case '\r': - case '\f': - case '\0': - return; - default: - break; - } - } + for (; 1; pi->s++) { + switch (*pi->s) { + case '\n': + case '\r': + case '\f': + case '\0': + return; + default: + break; + } + } } else { - if (pi->has_error) { - call_error("invalid comment", pi, __FILE__, __LINE__); - } else { - raise_error("invalid comment", pi->str, pi->s); - } + if (pi->has_error) { + call_error("invalid comment", pi, __FILE__, __LINE__); + } else { + raise_error("invalid comment", pi->str, pi->s); + } } } static void read_next(ParseInfo pi, const char *key) { - VALUE obj; + VALUE obj; - if ((void *)&obj < pi->stack_min) { - rb_raise(rb_eSysStackError, "JSON is too deeply nested"); + if ((void*)&obj < pi->stack_min) { + rb_raise(rb_eSysStackError, "JSON is too deeply nested"); } - next_non_white(pi); /* skip white space */ + next_non_white(pi); /* skip white space */ switch (*pi->s) { - case '{': - read_hash(pi, key); - break; - case '[': - read_array(pi, key); - break; - case '"': - read_str(pi, key); - break; - case '+': - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - read_num(pi, key); - break; - case 'I': - read_num(pi, key); - break; - case 't': - read_true(pi, key); - break; - case 'f': - read_false(pi, key); - break; - case 'n': - read_nil(pi, key); - break; - case '\0': - return; - default: - return; + case '{': + read_hash(pi, key); + break; + case '[': + read_array(pi, key); + break; + case '"': + read_str(pi, key); + break; + case '+': + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + read_num(pi, key); + break; + case 'I': + read_num(pi, key); + break; + case 't': + read_true(pi, key); + break; + case 'f': + read_false(pi, key); + break; + case 'n': + read_nil(pi, key); + break; + case '\0': + return; + default: + return; } } static void read_hash(ParseInfo pi, const char *key) { - const char *ks; + const char *ks; if (pi->has_hash_start) { - call_no_value(pi->handler, oj_hash_start_id, key); + call_no_value(pi->handler, oj_hash_start_id, key); } pi->s++; next_non_white(pi); if ('}' == *pi->s) { - pi->s++; + pi->s++; } else { - while (1) { - next_non_white(pi); - ks = read_quoted_value(pi); - next_non_white(pi); - if (':' == *pi->s) { - pi->s++; - } else { - if (pi->has_error) { - call_error("invalid format, expected :", pi, __FILE__, __LINE__); - } - raise_error("invalid format, expected :", pi->str, pi->s); - } - read_next(pi, ks); - next_non_white(pi); - if ('}' == *pi->s) { - pi->s++; - break; - } else if (',' == *pi->s) { - pi->s++; - } else { - if (pi->has_error) { - call_error("invalid format, expected , or } while in an object", pi, __FILE__, __LINE__); - } - raise_error("invalid format, expected , or } while in an object", pi->str, pi->s); - } - } + while (1) { + next_non_white(pi); + ks = read_quoted_value(pi); + next_non_white(pi); + if (':' == *pi->s) { + pi->s++; + } else { + if (pi->has_error) { + call_error("invalid format, expected :", pi, __FILE__, __LINE__); + } + raise_error("invalid format, expected :", pi->str, pi->s); + } + read_next(pi, ks); + next_non_white(pi); + if ('}' == *pi->s) { + pi->s++; + break; + } else if (',' == *pi->s) { + pi->s++; + } else { + if (pi->has_error) { + call_error("invalid format, expected , or } while in an object", pi, __FILE__, __LINE__); + } + raise_error("invalid format, expected , or } while in an object", pi->str, pi->s); + } + } } if (pi->has_hash_end) { - call_no_value(pi->handler, oj_hash_end_id, key); + call_no_value(pi->handler, oj_hash_end_id, key); } } static void read_array(ParseInfo pi, const char *key) { if (pi->has_array_start) { - call_no_value(pi->handler, oj_array_start_id, key); + call_no_value(pi->handler, oj_array_start_id, key); } pi->s++; next_non_white(pi); if (']' == *pi->s) { - pi->s++; + pi->s++; } else { - while (1) { - read_next(pi, 0); - next_non_white(pi); - if (',' == *pi->s) { - pi->s++; - } else if (']' == *pi->s) { - pi->s++; - break; - } else { - if (pi->has_error) { - call_error("invalid format, expected , or ] while in an array", pi, __FILE__, __LINE__); - } - raise_error("invalid format, expected , or ] while in an array", pi->str, pi->s); - } - } + while (1) { + read_next(pi, 0); + next_non_white(pi); + if (',' == *pi->s) { + pi->s++; + } else if (']' == *pi->s) { + pi->s++; + break; + } else { + if (pi->has_error) { + call_error("invalid format, expected , or ] while in an array", pi, __FILE__, __LINE__); + } + raise_error("invalid format, expected , or ] while in an array", pi->str, pi->s); + } + } } if (pi->has_array_end) { - call_no_value(pi->handler, oj_array_end_id, key); + call_no_value(pi->handler, oj_array_end_id, key); } } static void read_str(ParseInfo pi, const char *key) { - char *text; + char *text; text = read_quoted_value(pi); if (pi->has_add_value) { - VALUE s = rb_str_new2(text); + VALUE s = rb_str_new2(text); - s = oj_encode(s); - call_add_value(pi->handler, s, key); + s = oj_encode(s); + call_add_value(pi->handler, s, key); } } @@ -304,121 +304,121 @@ read_str(ParseInfo pi, const char *key) { static void read_num(ParseInfo pi, const char *key) { - char *start = pi->s; - int64_t n = 0; - long a = 0; - long div = 1; - long e = 0; - int neg = 0; - int eneg = 0; - int big = 0; + char *start = pi->s; + int64_t n = 0; + long a = 0; + long div = 1; + long e = 0; + int neg = 0; + int eneg = 0; + int big = 0; if ('-' == *pi->s) { - pi->s++; - neg = 1; + pi->s++; + neg = 1; } else if ('+' == *pi->s) { - pi->s++; + pi->s++; } if ('I' == *pi->s) { - if (0 != strncmp("Infinity", pi->s, 8)) { - if (pi->has_error) { - call_error("number or other value", pi, __FILE__, __LINE__); - } - raise_error("number or other value", pi->str, pi->s); - } - pi->s += 8; - if (neg) { - if (pi->has_add_value) { - call_add_value(pi->handler, rb_float_new(-OJ_INFINITY), key); - } - } else { - if (pi->has_add_value) { - call_add_value(pi->handler, rb_float_new(OJ_INFINITY), key); - } - } - return; + if (0 != strncmp("Infinity", pi->s, 8)) { + if (pi->has_error) { + call_error("number or other value", pi, __FILE__, __LINE__); + } + raise_error("number or other value", pi->str, pi->s); + } + pi->s += 8; + if (neg) { + if (pi->has_add_value) { + call_add_value(pi->handler, rb_float_new(-OJ_INFINITY), key); + } + } else { + if (pi->has_add_value) { + call_add_value(pi->handler, rb_float_new(OJ_INFINITY), key); + } + } + return; } for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) { - if (big) { - big++; - } else { - n = n * 10 + (*pi->s - '0'); - if (NUM_MAX <= n) { - big = 1; - } - } + if (big) { + big++; + } else { + n = n * 10 + (*pi->s - '0'); + if (NUM_MAX <= n) { + big = 1; + } + } } if ('.' == *pi->s) { - pi->s++; - for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) { - a = a * 10 + (*pi->s - '0'); - div *= 10; - if (NUM_MAX <= div) { - big = 1; - } - } + pi->s++; + for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) { + a = a * 10 + (*pi->s - '0'); + div *= 10; + if (NUM_MAX <= div) { + big = 1; + } + } } if ('e' == *pi->s || 'E' == *pi->s) { - pi->s++; - if ('-' == *pi->s) { - pi->s++; - eneg = 1; - } else if ('+' == *pi->s) { - pi->s++; - } - for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) { - e = e * 10 + (*pi->s - '0'); - if (NUM_MAX <= e) { - big = 1; - } - } + pi->s++; + if ('-' == *pi->s) { + pi->s++; + eneg = 1; + } else if ('+' == *pi->s) { + pi->s++; + } + for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) { + e = e * 10 + (*pi->s - '0'); + if (NUM_MAX <= e) { + big = 1; + } + } } if (0 == e && 0 == a && 1 == div) { - if (big) { - char c = *pi->s; - - *pi->s = '\0'; - if (pi->has_add_value) { - call_add_value(pi->handler, rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new2(start)), key); - } - *pi->s = c; - } else { - if (neg) { - n = -n; - } - if (pi->has_add_value) { - call_add_value(pi->handler, LONG2NUM(n), key); - } - } - return; + if (big) { + char c = *pi->s; + + *pi->s = '\0'; + if (pi->has_add_value) { + call_add_value(pi->handler, rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new2(start)), key); + } + *pi->s = c; + } else { + if (neg) { + n = -n; + } + if (pi->has_add_value) { + call_add_value(pi->handler, LONG2NUM(n), key); + } + } + return; } else { /* decimal */ - if (big) { - char c = *pi->s; - - *pi->s = '\0'; - if (pi->has_add_value) { - call_add_value(pi->handler, rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new2(start)), key); - } - *pi->s = c; - } else { - double d = (double)n + (double)a / (double)div; - - if (neg) { - d = -d; - } - if (1 < big) { - e += big - 1; - } - if (0 != e) { - if (eneg) { - e = -e; - } - d *= pow(10.0, e); - } - if (pi->has_add_value) { - call_add_value(pi->handler, rb_float_new(d), key); - } - } + if (big) { + char c = *pi->s; + + *pi->s = '\0'; + if (pi->has_add_value) { + call_add_value(pi->handler, rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new2(start)), key); + } + *pi->s = c; + } else { + double d = (double)n + (double)a / (double)div; + + if (neg) { + d = -d; + } + if (1 < big) { + e += big - 1; + } + if (0 != e) { + if (eneg) { + e = -e; + } + d *= pow(10.0, e); + } + if (pi->has_add_value) { + call_add_value(pi->handler, rb_float_new(d), key); + } + } } } @@ -426,14 +426,14 @@ static void read_true(ParseInfo pi, const char *key) { pi->s++; if ('r' != *pi->s || 'u' != *(pi->s + 1) || 'e' != *(pi->s + 2)) { - if (pi->has_error) { - call_error("invalid format, expected 'true'", pi, __FILE__, __LINE__); - } - raise_error("invalid format, expected 'true'", pi->str, pi->s); + if (pi->has_error) { + call_error("invalid format, expected 'true'", pi, __FILE__, __LINE__); + } + raise_error("invalid format, expected 'true'", pi->str, pi->s); } pi->s += 3; if (pi->has_add_value) { - call_add_value(pi->handler, Qtrue, key); + call_add_value(pi->handler, Qtrue, key); } } @@ -441,14 +441,14 @@ static void read_false(ParseInfo pi, const char *key) { pi->s++; if ('a' != *pi->s || 'l' != *(pi->s + 1) || 's' != *(pi->s + 2) || 'e' != *(pi->s + 3)) { - if (pi->has_error) { - call_error("invalid format, expected 'false'", pi, __FILE__, __LINE__); - } - raise_error("invalid format, expected 'false'", pi->str, pi->s); + if (pi->has_error) { + call_error("invalid format, expected 'false'", pi, __FILE__, __LINE__); + } + raise_error("invalid format, expected 'false'", pi->str, pi->s); } pi->s += 4; if (pi->has_add_value) { - call_add_value(pi->handler, Qfalse, key); + call_add_value(pi->handler, Qfalse, key); } } @@ -456,76 +456,76 @@ static void read_nil(ParseInfo pi, const char *key) { pi->s++; if ('u' != *pi->s || 'l' != *(pi->s + 1) || 'l' != *(pi->s + 2)) { - if (pi->has_error) { - call_error("invalid format, expected 'null'", pi, __FILE__, __LINE__); - } - raise_error("invalid format, expected 'null'", pi->str, pi->s); + if (pi->has_error) { + call_error("invalid format, expected 'null'", pi, __FILE__, __LINE__); + } + raise_error("invalid format, expected 'null'", pi->str, pi->s); } pi->s += 3; if (pi->has_add_value) { - call_add_value(pi->handler, Qnil, key); + call_add_value(pi->handler, Qnil, key); } } static uint32_t read_hex(ParseInfo pi, char *h) { - uint32_t b = 0; - int i; + uint32_t b = 0; + int i; /* TBD this can be made faster with a table */ for (i = 0; i < 4; i++, h++) { - b = b << 4; - if ('0' <= *h && *h <= '9') { - b += *h - '0'; - } else if ('A' <= *h && *h <= 'F') { - b += *h - 'A' + 10; - } else if ('a' <= *h && *h <= 'f') { - b += *h - 'a' + 10; - } else { - pi->s = h; - if (pi->has_error) { - call_error("invalid hex character", pi, __FILE__, __LINE__); - } - raise_error("invalid hex character", pi->str, pi->s); - } + b = b << 4; + if ('0' <= *h && *h <= '9') { + b += *h - '0'; + } else if ('A' <= *h && *h <= 'F') { + b += *h - 'A' + 10; + } else if ('a' <= *h && *h <= 'f') { + b += *h - 'a' + 10; + } else { + pi->s = h; + if (pi->has_error) { + call_error("invalid hex character", pi, __FILE__, __LINE__); + } + raise_error("invalid hex character", pi->str, pi->s); + } } return b; } -static char * +static char* unicode_to_chars(ParseInfo pi, char *t, uint32_t code) { if (0x0000007F >= code) { - *t = (char)code; + *t = (char)code; } else if (0x000007FF >= code) { - *t++ = 0xC0 | (code >> 6); - *t = 0x80 | (0x3F & code); + *t++ = 0xC0 | (code >> 6); + *t = 0x80 | (0x3F & code); } else if (0x0000FFFF >= code) { - *t++ = 0xE0 | (code >> 12); - *t++ = 0x80 | ((code >> 6) & 0x3F); - *t = 0x80 | (0x3F & code); + *t++ = 0xE0 | (code >> 12); + *t++ = 0x80 | ((code >> 6) & 0x3F); + *t = 0x80 | (0x3F & code); } else if (0x001FFFFF >= code) { - *t++ = 0xF0 | (code >> 18); - *t++ = 0x80 | ((code >> 12) & 0x3F); - *t++ = 0x80 | ((code >> 6) & 0x3F); - *t = 0x80 | (0x3F & code); + *t++ = 0xF0 | (code >> 18); + *t++ = 0x80 | ((code >> 12) & 0x3F); + *t++ = 0x80 | ((code >> 6) & 0x3F); + *t = 0x80 | (0x3F & code); } else if (0x03FFFFFF >= code) { - *t++ = 0xF8 | (code >> 24); - *t++ = 0x80 | ((code >> 18) & 0x3F); - *t++ = 0x80 | ((code >> 12) & 0x3F); - *t++ = 0x80 | ((code >> 6) & 0x3F); - *t = 0x80 | (0x3F & code); + *t++ = 0xF8 | (code >> 24); + *t++ = 0x80 | ((code >> 18) & 0x3F); + *t++ = 0x80 | ((code >> 12) & 0x3F); + *t++ = 0x80 | ((code >> 6) & 0x3F); + *t = 0x80 | (0x3F & code); } else if (0x7FFFFFFF >= code) { - *t++ = 0xFC | (code >> 30); - *t++ = 0x80 | ((code >> 24) & 0x3F); - *t++ = 0x80 | ((code >> 18) & 0x3F); - *t++ = 0x80 | ((code >> 12) & 0x3F); - *t++ = 0x80 | ((code >> 6) & 0x3F); - *t = 0x80 | (0x3F & code); + *t++ = 0xFC | (code >> 30); + *t++ = 0x80 | ((code >> 24) & 0x3F); + *t++ = 0x80 | ((code >> 18) & 0x3F); + *t++ = 0x80 | ((code >> 12) & 0x3F); + *t++ = 0x80 | ((code >> 6) & 0x3F); + *t = 0x80 | (0x3F & code); } else { - if (pi->has_error) { - call_error("invalid Unicode", pi, __FILE__, __LINE__); - } - raise_error("invalid Unicode", pi->str, pi->s); + if (pi->has_error) { + call_error("invalid Unicode", pi, __FILE__, __LINE__); + } + raise_error("invalid Unicode", pi->str, pi->s); } return t; } @@ -533,82 +533,66 @@ unicode_to_chars(ParseInfo pi, char *t, uint32_t code) { /* Assume the value starts immediately and goes until the quote character is * reached again. Do not read the character after the terminating quote. */ -static char * +static char* read_quoted_value(ParseInfo pi) { - char *value = 0; - char *h = pi->s; /* head */ - char *t = h; /* tail */ - uint32_t code; + char *value = 0; + char *h = pi->s; /* head */ + char *t = h; /* tail */ + uint32_t code; - h++; /* skip quote character */ + h++; /* skip quote character */ t++; value = h; for (; '"' != *h; h++, t++) { - if ('\0' == *h) { - pi->s = h; - raise_error("quoted string not terminated", pi->str, pi->s); - } else if ('\\' == *h) { - h++; - switch (*h) { - case 'n': - *t = '\n'; - break; - case 'r': - *t = '\r'; - break; - case 't': - *t = '\t'; - break; - case 'f': - *t = '\f'; - break; - case 'b': - *t = '\b'; - break; - case '"': - *t = '"'; - break; - case '/': - *t = '/'; - break; - case '\\': - *t = '\\'; - break; - case 'u': - h++; - code = read_hex(pi, h); - h += 3; - if (0x0000D800 <= code && code <= 0x0000DFFF) { - uint32_t c1 = (code - 0x0000D800) & 0x000003FF; - uint32_t c2; - - h++; - if ('\\' != *h || 'u' != *(h + 1)) { - pi->s = h; - if (pi->has_error) { - call_error("invalid escaped character", pi, __FILE__, __LINE__); - } - raise_error("invalid escaped character", pi->str, pi->s); - } - h += 2; - c2 = read_hex(pi, h); - h += 3; - c2 = (c2 - 0x0000DC00) & 0x000003FF; - code = ((c1 << 10) | c2) + 0x00010000; - } - t = unicode_to_chars(pi, t, code); - break; - default: - pi->s = h; - if (pi->has_error) { - call_error("invalid escaped character", pi, __FILE__, __LINE__); - } - raise_error("invalid escaped character", pi->str, pi->s); - break; - } - } else if (t != h) { - *t = *h; - } + if ('\0' == *h) { + pi->s = h; + raise_error("quoted string not terminated", pi->str, pi->s); + } else if ('\\' == *h) { + h++; + switch (*h) { + case 'n': *t = '\n'; break; + case 'r': *t = '\r'; break; + case 't': *t = '\t'; break; + case 'f': *t = '\f'; break; + case 'b': *t = '\b'; break; + case '"': *t = '"'; break; + case '/': *t = '/'; break; + case '\\': *t = '\\'; break; + case 'u': + h++; + code = read_hex(pi, h); + h += 3; + if (0x0000D800 <= code && code <= 0x0000DFFF) { + uint32_t c1 = (code - 0x0000D800) & 0x000003FF; + uint32_t c2; + + h++; + if ('\\' != *h || 'u' != *(h + 1)) { + pi->s = h; + if (pi->has_error) { + call_error("invalid escaped character", pi, __FILE__, __LINE__); + } + raise_error("invalid escaped character", pi->str, pi->s); + } + h += 2; + c2 = read_hex(pi, h); + h += 3; + c2 = (c2 - 0x0000DC00) & 0x000003FF; + code = ((c1 << 10) | c2) + 0x00010000; + } + t = unicode_to_chars(pi, t, code); + break; + default: + pi->s = h; + if (pi->has_error) { + call_error("invalid escaped character", pi, __FILE__, __LINE__); + } + raise_error("invalid escaped character", pi->str, pi->s); + break; + } + } else if (t != h) { + *t = *h; + } } *t = '\0'; /* terminate value */ pi->s = h + 1; @@ -618,33 +602,33 @@ read_quoted_value(ParseInfo pi) { static void saj_parse(VALUE handler, char *json) { - volatile VALUE obj = Qnil; - struct _parseInfo pi; + volatile VALUE obj = Qnil; + struct _parseInfo pi; if (0 == json) { - if (pi.has_error) { - call_error("Invalid arg, xml string can not be null", &pi, __FILE__, __LINE__); - } - raise_error("Invalid arg, xml string can not be null", json, 0); + if (pi.has_error) { + call_error("Invalid arg, xml string can not be null", &pi, __FILE__, __LINE__); + } + raise_error("Invalid arg, xml string can not be null", json, 0); } /* skip UTF-8 BOM if present */ if (0xEF == (uint8_t)*json && 0xBB == (uint8_t)json[1] && 0xBF == (uint8_t)json[2]) { - json += 3; + json += 3; } /* initialize parse info */ pi.str = json; pi.s = json; #if IS_WINDOWS - pi.stack_min = (void *)((char *)&obj - (512 * 1024)); /* assume a 1M stack and give half to ruby */ + pi.stack_min = (void*)((char*)&obj - (512 * 1024)); /* assume a 1M stack and give half to ruby */ #else { - struct rlimit lim; + struct rlimit lim; - if (0 == getrlimit(RLIMIT_STACK, &lim) && RLIM_INFINITY != lim.rlim_cur) { - pi.stack_min = (void *)((char *)&obj - (lim.rlim_cur / 4 * 3)); /* let 3/4ths of the stack be used only */ - } else { - pi.stack_min = 0; /* indicates not to check stack limit */ - } + if (0 == getrlimit(RLIMIT_STACK, &lim) && RLIM_INFINITY != lim.rlim_cur) { + pi.stack_min = (void*)((char*)&obj - (lim.rlim_cur / 4 * 3)); /* let 3/4ths of the stack be used only */ + } else { + pi.stack_min = 0; /* indicates not to check stack limit */ + } } #endif pi.handler = handler; @@ -657,11 +641,11 @@ saj_parse(VALUE handler, char *json) { read_next(&pi, 0); next_non_white(&pi); if ('\0' != *pi.s) { - if (pi.has_error) { - call_error("invalid format, extra characters", &pi, __FILE__, __LINE__); - } else { - raise_error("invalid format, extra characters", pi.str, pi.s); - } + if (pi.has_error) { + call_error("invalid format, extra characters", &pi, __FILE__, __LINE__); + } else { + raise_error("invalid format, extra characters", pi.str, pi.s); + } } } @@ -678,48 +662,48 @@ saj_parse(VALUE handler, char *json) { */ VALUE oj_saj_parse(int argc, VALUE *argv, VALUE self) { - char *json = 0; - size_t len = 0; - VALUE input = argv[1]; + char *json = 0; + size_t len = 0; + VALUE input = argv[1]; if (argc < 2) { - rb_raise(rb_eArgError, "Wrong number of arguments to saj_parse.\n"); + rb_raise(rb_eArgError, "Wrong number of arguments to saj_parse.\n"); } if (rb_type(input) == T_STRING) { - // the json string gets modified so make a copy of it - len = RSTRING_LEN(input) + 1; - json = ALLOC_N(char, len); - strcpy(json, StringValuePtr(input)); + // the json string gets modified so make a copy of it + len = RSTRING_LEN(input) + 1; + json = ALLOC_N(char, len); + strcpy(json, StringValuePtr(input)); } else { - VALUE clas = rb_obj_class(input); - volatile VALUE s; - - if (oj_stringio_class == clas) { - s = rb_funcall2(input, oj_string_id, 0, 0); - len = RSTRING_LEN(s) + 1; - json = ALLOC_N(char, len); - strcpy(json, rb_string_value_cstr((VALUE *)&s)); + VALUE clas = rb_obj_class(input); + volatile VALUE s; + + if (oj_stringio_class == clas) { + s = rb_funcall2(input, oj_string_id, 0, 0); + len = RSTRING_LEN(s) + 1; + json = ALLOC_N(char, len); + strcpy(json, rb_string_value_cstr((VALUE*)&s)); #if !IS_WINDOWS - } else if (rb_cFile == clas && 0 == FIX2INT(rb_funcall(input, oj_pos_id, 0))) { - int fd = FIX2INT(rb_funcall(input, oj_fileno_id, 0)); - ssize_t cnt; - - len = lseek(fd, 0, SEEK_END); - lseek(fd, 0, SEEK_SET); - json = ALLOC_N(char, len + 1); - if (0 >= (cnt = read(fd, json, len)) || cnt != (ssize_t)len) { - rb_raise(rb_eIOError, "failed to read from IO Object."); - } - json[len] = '\0'; + } else if (rb_cFile == clas && 0 == FIX2INT(rb_funcall(input, oj_pos_id, 0))) { + int fd = FIX2INT(rb_funcall(input, oj_fileno_id, 0)); + ssize_t cnt; + + len = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + json = ALLOC_N(char, len + 1); + if (0 >= (cnt = read(fd, json, len)) || cnt != (ssize_t)len) { + rb_raise(rb_eIOError, "failed to read from IO Object."); + } + json[len] = '\0'; #endif - } else if (rb_respond_to(input, oj_read_id)) { - s = rb_funcall2(input, oj_read_id, 0, 0); - len = RSTRING_LEN(s) + 1; - json = ALLOC_N(char, len); - strcpy(json, rb_string_value_cstr((VALUE *)&s)); - } else { - rb_raise(rb_eArgError, "saj_parse() expected a String or IO Object."); - } + } else if (rb_respond_to(input, oj_read_id)) { + s = rb_funcall2(input, oj_read_id, 0, 0); + len = RSTRING_LEN(s) + 1; + json = ALLOC_N(char, len); + strcpy(json, rb_string_value_cstr((VALUE*)&s)); + } else { + rb_raise(rb_eArgError, "saj_parse() expected a String or IO Object."); + } } saj_parse(*argv, json); xfree(json); diff --git a/ext/oj/scp.c b/ext/oj/scp.c index 907ca1c4..c8af29bc 100644 --- a/ext/oj/scp.c +++ b/ext/oj/scp.c @@ -1,16 +1,16 @@ // Copyright (c) 2012 Peter Ohler. All rights reserved. // Licensed under the MIT License. See LICENSE file in the project root for license details. -#include -#include #include +#include #include +#include #include #include -#include "encode.h" #include "oj.h" #include "parse.h" +#include "encode.h" static VALUE noop_start(ParseInfo pi) { @@ -69,7 +69,7 @@ add_value(ParseInfo pi, VALUE val) { static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { - volatile VALUE rstr = rb_str_new(str, len); + volatile VALUE rstr = rb_str_new(str, len); rstr = oj_encode(rstr); rb_funcall(pi->handler, oj_add_value_id, 1, rstr); @@ -102,14 +102,14 @@ end_array(ParseInfo pi) { static VALUE calc_hash_key(ParseInfo pi, Val kval) { - volatile VALUE rkey = kval->key_val; + volatile VALUE rkey = kval->key_val; if (Qundef == rkey) { - rkey = rb_str_new(kval->key, kval->klen); - rkey = oj_encode(rkey); - if (Yes == pi->options.sym_key) { - rkey = rb_str_intern(rkey); - } + rkey = rb_str_new(kval->key, kval->klen); + rkey = oj_encode(rkey); + if (Yes == pi->options.sym_key) { + rkey = rb_str_intern(rkey); + } } return rkey; } @@ -121,7 +121,7 @@ hash_key(ParseInfo pi, const char *key, size_t klen) { static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) { - volatile VALUE rstr = rb_str_new(str, len); + volatile VALUE rstr = rb_str_new(str, len); rstr = oj_encode(rstr); rb_funcall(pi->handler, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, calc_hash_key(pi, kval), rstr); @@ -139,7 +139,7 @@ hash_set_value(ParseInfo pi, Val kval, VALUE value) { static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { - volatile VALUE rstr = rb_str_new(str, len); + volatile VALUE rstr = rb_str_new(str, len); rstr = oj_encode(rstr); rb_funcall(pi->handler, oj_array_append_id, 2, stack_peek(&pi->stack)->val, rstr); @@ -157,20 +157,20 @@ array_append_value(ParseInfo pi, VALUE value) { VALUE oj_sc_parse(int argc, VALUE *argv, VALUE self) { - struct _parseInfo pi; - VALUE input = argv[1]; + struct _parseInfo pi; + VALUE input = argv[1]; parse_info_init(&pi); pi.err_class = Qnil; pi.max_depth = 0; pi.options = oj_default_options; if (3 == argc) { - oj_parse_options(argv[2], &pi.options); + oj_parse_options(argv[2], &pi.options); } if (rb_block_given_p()) { - pi.proc = Qnil; + pi.proc = Qnil; } else { - pi.proc = Qundef; + pi.proc = Qundef; } pi.handler = *argv; @@ -180,43 +180,43 @@ oj_sc_parse(int argc, VALUE *argv, VALUE self) { pi.start_array = rb_respond_to(pi.handler, oj_array_start_id) ? start_array : noop_start; pi.end_array = rb_respond_to(pi.handler, oj_array_end_id) ? end_array : noop_end; if (rb_respond_to(pi.handler, oj_hash_set_id)) { - pi.hash_set_value = hash_set_value; - pi.hash_set_cstr = hash_set_cstr; - pi.hash_set_num = hash_set_num; - pi.expect_value = 1; + pi.hash_set_value = hash_set_value; + pi.hash_set_cstr = hash_set_cstr; + pi.hash_set_num = hash_set_num; + pi.expect_value = 1; } else { - pi.hash_set_value = noop_hash_set_value; - pi.hash_set_cstr = noop_hash_set_cstr; - pi.hash_set_num = noop_hash_set_num; - pi.expect_value = 0; + pi.hash_set_value = noop_hash_set_value; + pi.hash_set_cstr = noop_hash_set_cstr; + pi.hash_set_num = noop_hash_set_num; + pi.expect_value = 0; } if (rb_respond_to(pi.handler, oj_array_append_id)) { - pi.array_append_value = array_append_value; - pi.array_append_cstr = array_append_cstr; - pi.array_append_num = array_append_num; - pi.expect_value = 1; + pi.array_append_value = array_append_value; + pi.array_append_cstr = array_append_cstr; + pi.array_append_num = array_append_num; + pi.expect_value = 1; } else { - pi.array_append_value = noop_array_append_value; - pi.array_append_cstr = noop_array_append_cstr; - pi.array_append_num = noop_array_append_num; - pi.expect_value = 0; + pi.array_append_value = noop_array_append_value; + pi.array_append_cstr = noop_array_append_cstr; + pi.array_append_num = noop_array_append_num; + pi.expect_value = 0; } if (rb_respond_to(pi.handler, oj_add_value_id)) { - pi.add_cstr = add_cstr; - pi.add_num = add_num; - pi.add_value = add_value; - pi.expect_value = 1; + pi.add_cstr = add_cstr; + pi.add_num = add_num; + pi.add_value = add_value; + pi.expect_value = 1; } else { - pi.add_cstr = noop_add_cstr; - pi.add_num = noop_add_num; - pi.add_value = noop_add_value; - pi.expect_value = 0; + pi.add_cstr = noop_add_cstr; + pi.add_num = noop_add_num; + pi.add_value = noop_add_value; + pi.expect_value = 0; } pi.has_callbacks = true; if (T_STRING == rb_type(input)) { - return oj_pi_parse(argc - 1, argv + 1, &pi, 0, 0, 1); + return oj_pi_parse(argc - 1, argv + 1, &pi, 0, 0, 1); } else { - return oj_pi_sparse(argc - 1, argv + 1, &pi, 0); + return oj_pi_sparse(argc - 1, argv + 1, &pi, 0); } } diff --git a/ext/oj/sparse.c b/ext/oj/sparse.c index 3d39ec12..596dc92f 100644 --- a/ext/oj/sparse.c +++ b/ext/oj/sparse.c @@ -1,165 +1,165 @@ // Copyright (c) 2013 Peter Ohler. All rights reserved. // Licensed under the MIT License. See LICENSE file in the project root for license details. -#include -#include #include +#include #include #include +#include -#include "buf.h" -#include "encode.h" -#include "hash.h" // for oj_strndup() #include "oj.h" +#include "encode.h" #include "parse.h" +#include "buf.h" +#include "hash.h" // for oj_strndup() #include "val_stack.h" // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS -#define OJ_INFINITY (1.0 / 0.0) +#define OJ_INFINITY (1.0/0.0) #ifdef RUBINIUS_RUBY -#define NUM_MAX 0x07FFFFFF +#define NUM_MAX 0x07FFFFFF #else -#define NUM_MAX (FIXNUM_MAX >> 8) +#define NUM_MAX (FIXNUM_MAX >> 8) #endif -#define EXP_MAX 100000 -#define DEC_MAX 15 +#define EXP_MAX 100000 +#define DEC_MAX 15 static void skip_comment(ParseInfo pi) { - char c = reader_get(&pi->rd); + char c = reader_get(&pi->rd); if ('*' == c) { - while ('\0' != (c = reader_get(&pi->rd))) { - if ('*' == c) { - c = reader_get(&pi->rd); - if ('/' == c) { - return; - } - } - } + while ('\0' != (c = reader_get(&pi->rd))) { + if ('*' == c) { + c = reader_get(&pi->rd); + if ('/' == c) { + return; + } + } + } } else if ('/' == c) { - while ('\0' != (c = reader_get(&pi->rd))) { - switch (c) { - case '\n': - case '\r': - case '\f': - case '\0': - return; - default: - break; - } - } + while ('\0' != (c = reader_get(&pi->rd))) { + switch (c) { + case '\n': + case '\r': + case '\f': + case '\0': + return; + default: + break; + } + } } else { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid comment format"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid comment format"); } if ('\0' == c) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "comment not terminated"); - return; + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "comment not terminated"); + return; } } static void add_value(ParseInfo pi, VALUE rval) { - Val parent = stack_peek(&pi->stack); + Val parent = stack_peek(&pi->stack); if (0 == parent) { // simple add - pi->add_value(pi, rval); + pi->add_value(pi, rval); } else { - switch (parent->next) { - case NEXT_ARRAY_NEW: - case NEXT_ARRAY_ELEMENT: - pi->array_append_value(pi, rval); - parent->next = NEXT_ARRAY_COMMA; - break; - case NEXT_HASH_VALUE: - pi->hash_set_value(pi, parent, rval); - if (parent->kalloc) { - xfree((char *)parent->key); - } - parent->key = 0; - parent->kalloc = 0; - parent->next = NEXT_HASH_COMMA; - break; - case NEXT_HASH_NEW: - case NEXT_HASH_KEY: - case NEXT_HASH_COMMA: - case NEXT_NONE: - case NEXT_ARRAY_COMMA: - case NEXT_HASH_COLON: - default: - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s", oj_stack_next_string(parent->next)); - break; - } + switch (parent->next) { + case NEXT_ARRAY_NEW: + case NEXT_ARRAY_ELEMENT: + pi->array_append_value(pi, rval); + parent->next = NEXT_ARRAY_COMMA; + break; + case NEXT_HASH_VALUE: + pi->hash_set_value(pi, parent, rval); + if (parent->kalloc) { + xfree((char*)parent->key); + } + parent->key = 0; + parent->kalloc = 0; + parent->next = NEXT_HASH_COMMA; + break; + case NEXT_HASH_NEW: + case NEXT_HASH_KEY: + case NEXT_HASH_COMMA: + case NEXT_NONE: + case NEXT_ARRAY_COMMA: + case NEXT_HASH_COLON: + default: + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s", oj_stack_next_string(parent->next)); + break; + } } } static void add_num_value(ParseInfo pi, NumInfo ni) { - Val parent = stack_peek(&pi->stack); + Val parent = stack_peek(&pi->stack); if (0 == parent) { - pi->add_num(pi, ni); + pi->add_num(pi, ni); } else { - switch (parent->next) { - case NEXT_ARRAY_NEW: - case NEXT_ARRAY_ELEMENT: - pi->array_append_num(pi, ni); - parent->next = NEXT_ARRAY_COMMA; - break; - case NEXT_HASH_VALUE: - pi->hash_set_num(pi, parent, ni); - if (parent->kalloc) { - xfree((char *)parent->key); - } - parent->key = 0; - parent->kalloc = 0; - parent->next = NEXT_HASH_COMMA; - break; - default: - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s", oj_stack_next_string(parent->next)); - break; - } + switch (parent->next) { + case NEXT_ARRAY_NEW: + case NEXT_ARRAY_ELEMENT: + pi->array_append_num(pi, ni); + parent->next = NEXT_ARRAY_COMMA; + break; + case NEXT_HASH_VALUE: + pi->hash_set_num(pi, parent, ni); + if (parent->kalloc) { + xfree((char*)parent->key); + } + parent->key = 0; + parent->kalloc = 0; + parent->next = NEXT_HASH_COMMA; + break; + default: + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s", oj_stack_next_string(parent->next)); + break; + } } } static void read_true(ParseInfo pi) { if (0 == reader_expect(&pi->rd, "rue")) { - add_value(pi, Qtrue); + add_value(pi, Qtrue); } else { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected true"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected true"); } } static void read_false(ParseInfo pi) { if (0 == reader_expect(&pi->rd, "alse")) { - add_value(pi, Qfalse); + add_value(pi, Qfalse); } else { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected false"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected false"); } } static uint32_t read_hex(ParseInfo pi) { - uint32_t b = 0; - int i; - char c; + uint32_t b = 0; + int i; + char c; for (i = 0; i < 4; i++) { - c = reader_get(&pi->rd); - b = b << 4; - if ('0' <= c && c <= '9') { - b += c - '0'; - } else if ('A' <= c && c <= 'F') { - b += c - 'A' + 10; - } else if ('a' <= c && c <= 'f') { - b += c - 'a' + 10; - } else { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hex character"); - return 0; - } + c = reader_get(&pi->rd); + b = b << 4; + if ('0' <= c && c <= '9') { + b += c - '0'; + } else if ('A' <= c && c <= 'F') { + b += c - 'A' + 10; + } else if ('a' <= c && c <= 'f') { + b += c - 'a' + 10; + } else { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hex character"); + return 0; + } } return b; } @@ -167,243 +167,227 @@ read_hex(ParseInfo pi) { static void unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) { if (0x0000007F >= code) { - buf_append(buf, (char)code); + buf_append(buf, (char)code); } else if (0x000007FF >= code) { - buf_append(buf, 0xC0 | (code >> 6)); - buf_append(buf, 0x80 | (0x3F & code)); + buf_append(buf, 0xC0 | (code >> 6)); + buf_append(buf, 0x80 | (0x3F & code)); } else if (0x0000FFFF >= code) { - buf_append(buf, 0xE0 | (code >> 12)); - buf_append(buf, 0x80 | ((code >> 6) & 0x3F)); - buf_append(buf, 0x80 | (0x3F & code)); + buf_append(buf, 0xE0 | (code >> 12)); + buf_append(buf, 0x80 | ((code >> 6) & 0x3F)); + buf_append(buf, 0x80 | (0x3F & code)); } else if (0x001FFFFF >= code) { - buf_append(buf, 0xF0 | (code >> 18)); - buf_append(buf, 0x80 | ((code >> 12) & 0x3F)); - buf_append(buf, 0x80 | ((code >> 6) & 0x3F)); - buf_append(buf, 0x80 | (0x3F & code)); + buf_append(buf, 0xF0 | (code >> 18)); + buf_append(buf, 0x80 | ((code >> 12) & 0x3F)); + buf_append(buf, 0x80 | ((code >> 6) & 0x3F)); + buf_append(buf, 0x80 | (0x3F & code)); } else if (0x03FFFFFF >= code) { - buf_append(buf, 0xF8 | (code >> 24)); - buf_append(buf, 0x80 | ((code >> 18) & 0x3F)); - buf_append(buf, 0x80 | ((code >> 12) & 0x3F)); - buf_append(buf, 0x80 | ((code >> 6) & 0x3F)); - buf_append(buf, 0x80 | (0x3F & code)); + buf_append(buf, 0xF8 | (code >> 24)); + buf_append(buf, 0x80 | ((code >> 18) & 0x3F)); + buf_append(buf, 0x80 | ((code >> 12) & 0x3F)); + buf_append(buf, 0x80 | ((code >> 6) & 0x3F)); + buf_append(buf, 0x80 | (0x3F & code)); } else if (0x7FFFFFFF >= code) { - buf_append(buf, 0xFC | (code >> 30)); - buf_append(buf, 0x80 | ((code >> 24) & 0x3F)); - buf_append(buf, 0x80 | ((code >> 18) & 0x3F)); - buf_append(buf, 0x80 | ((code >> 12) & 0x3F)); - buf_append(buf, 0x80 | ((code >> 6) & 0x3F)); - buf_append(buf, 0x80 | (0x3F & code)); + buf_append(buf, 0xFC | (code >> 30)); + buf_append(buf, 0x80 | ((code >> 24) & 0x3F)); + buf_append(buf, 0x80 | ((code >> 18) & 0x3F)); + buf_append(buf, 0x80 | ((code >> 12) & 0x3F)); + buf_append(buf, 0x80 | ((code >> 6) & 0x3F)); + buf_append(buf, 0x80 | (0x3F & code)); } else { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid Unicode character"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid Unicode character"); } } // entered at backslash static void read_escaped_str(ParseInfo pi) { - struct _buf buf; - char c; - uint32_t code; - Val parent = stack_peek(&pi->stack); + struct _buf buf; + char c; + uint32_t code; + Val parent = stack_peek(&pi->stack); buf_init(&buf); if (pi->rd.str < pi->rd.tail) { - buf_append_string(&buf, pi->rd.str, pi->rd.tail - pi->rd.str); + buf_append_string(&buf, pi->rd.str, pi->rd.tail - pi->rd.str); } while ('\"' != (c = reader_get(&pi->rd))) { - if ('\0' == c) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated"); - buf_cleanup(&buf); - return; - } else if ('\\' == c) { - c = reader_get(&pi->rd); - switch (c) { - case 'n': - buf_append(&buf, '\n'); - break; - case 'r': - buf_append(&buf, '\r'); - break; - case 't': - buf_append(&buf, '\t'); - break; - case 'f': - buf_append(&buf, '\f'); - break; - case 'b': - buf_append(&buf, '\b'); - break; - case '"': - buf_append(&buf, '"'); - break; - case '/': - buf_append(&buf, '/'); - break; - case '\\': - buf_append(&buf, '\\'); - break; - case 'u': - if (0 == (code = read_hex(pi)) && err_has(&pi->err)) { - buf_cleanup(&buf); - return; - } - if (0x0000D800 <= code && code <= 0x0000DFFF) { - uint32_t c1 = (code - 0x0000D800) & 0x000003FF; - uint32_t c2; - char ch2; - - c = reader_get(&pi->rd); - ch2 = reader_get(&pi->rd); - if ('\\' != c || 'u' != ch2) { - if (Yes == pi->options.allow_invalid) { - unicode_to_chars(pi, &buf, code); - reader_backup(&pi->rd); - reader_backup(&pi->rd); - break; - } - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character"); - buf_cleanup(&buf); - return; - } - if (0 == (c2 = read_hex(pi)) && err_has(&pi->err)) { - buf_cleanup(&buf); - return; - } - c2 = (c2 - 0x0000DC00) & 0x000003FF; - code = ((c1 << 10) | c2) + 0x00010000; - } - unicode_to_chars(pi, &buf, code); - if (err_has(&pi->err)) { - buf_cleanup(&buf); - return; - } - break; - default: - // The json gem claims this is not an error despite the - // ECMA-404 indicating it is not valid. - if (CompatMode == pi->options.mode) { - buf_append(&buf, c); - break; - } - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character"); - buf_cleanup(&buf); - return; - } - } else { - buf_append(&buf, c); - } + if ('\0' == c) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated"); + buf_cleanup(&buf); + return; + } else if ('\\' == c) { + c = reader_get(&pi->rd); + switch (c) { + case 'n': buf_append(&buf, '\n'); break; + case 'r': buf_append(&buf, '\r'); break; + case 't': buf_append(&buf, '\t'); break; + case 'f': buf_append(&buf, '\f'); break; + case 'b': buf_append(&buf, '\b'); break; + case '"': buf_append(&buf, '"'); break; + case '/': buf_append(&buf, '/'); break; + case '\\': buf_append(&buf, '\\'); break; + case 'u': + if (0 == (code = read_hex(pi)) && err_has(&pi->err)) { + buf_cleanup(&buf); + return; + } + if (0x0000D800 <= code && code <= 0x0000DFFF) { + uint32_t c1 = (code - 0x0000D800) & 0x000003FF; + uint32_t c2; + char ch2; + + c = reader_get(&pi->rd); + ch2 = reader_get(&pi->rd); + if ('\\' != c || 'u' != ch2) { + if (Yes == pi->options.allow_invalid) { + unicode_to_chars(pi, &buf, code); + reader_backup(&pi->rd); + reader_backup(&pi->rd); + break; + } + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character"); + buf_cleanup(&buf); + return; + } + if (0 == (c2 = read_hex(pi)) && err_has(&pi->err)) { + buf_cleanup(&buf); + return; + } + c2 = (c2 - 0x0000DC00) & 0x000003FF; + code = ((c1 << 10) | c2) + 0x00010000; + } + unicode_to_chars(pi, &buf, code); + if (err_has(&pi->err)) { + buf_cleanup(&buf); + return; + } + break; + default: + // The json gem claims this is not an error despite the + // ECMA-404 indicating it is not valid. + if (CompatMode == pi->options.mode) { + buf_append(&buf, c); + break; + } + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character"); + buf_cleanup(&buf); + return; + } + } else { + buf_append(&buf, c); + } } if (0 == parent) { - pi->add_cstr(pi, buf.head, buf_len(&buf), pi->rd.str); + pi->add_cstr(pi, buf.head, buf_len(&buf), pi->rd.str); } else { - switch (parent->next) { - case NEXT_ARRAY_NEW: - case NEXT_ARRAY_ELEMENT: - pi->array_append_cstr(pi, buf.head, buf_len(&buf), pi->rd.str); - parent->next = NEXT_ARRAY_COMMA; - break; - case NEXT_HASH_NEW: - case NEXT_HASH_KEY: - if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) { - parent->klen = buf_len(&buf); - parent->key = malloc(parent->klen + 1); - memcpy((char *)parent->key, buf.head, parent->klen); - *(char *)(parent->key + parent->klen) = '\0'; - } else { - parent->key = ""; - parent->klen = 0; - } - parent->k1 = *pi->rd.str; - parent->next = NEXT_HASH_COLON; - break; - case NEXT_HASH_VALUE: - pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), pi->rd.str); - if (parent->kalloc) { - xfree((char *)parent->key); - } - parent->key = 0; - parent->kalloc = 0; - parent->next = NEXT_HASH_COMMA; - break; - case NEXT_HASH_COMMA: - case NEXT_NONE: - case NEXT_ARRAY_COMMA: - case NEXT_HASH_COLON: - default: - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a string", oj_stack_next_string(parent->next)); - break; - } + switch (parent->next) { + case NEXT_ARRAY_NEW: + case NEXT_ARRAY_ELEMENT: + pi->array_append_cstr(pi, buf.head, buf_len(&buf), pi->rd.str); + parent->next = NEXT_ARRAY_COMMA; + break; + case NEXT_HASH_NEW: + case NEXT_HASH_KEY: + if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) { + parent->klen = buf_len(&buf); + parent->key = malloc(parent->klen + 1); + memcpy((char*)parent->key, buf.head, parent->klen); + *(char*)(parent->key + parent->klen) = '\0'; + } else { + parent->key = ""; + parent->klen = 0; + } + parent->k1 = *pi->rd.str; + parent->next = NEXT_HASH_COLON; + break; + case NEXT_HASH_VALUE: + pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), pi->rd.str); + if (parent->kalloc) { + xfree((char*)parent->key); + } + parent->key = 0; + parent->kalloc = 0; + parent->next = NEXT_HASH_COMMA; + break; + case NEXT_HASH_COMMA: + case NEXT_NONE: + case NEXT_ARRAY_COMMA: + case NEXT_HASH_COLON: + default: + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a string", oj_stack_next_string(parent->next)); + break; + } } buf_cleanup(&buf); } static void read_str(ParseInfo pi) { - Val parent = stack_peek(&pi->stack); - char c; + Val parent = stack_peek(&pi->stack); + char c; reader_protect(&pi->rd); while ('\"' != (c = reader_get(&pi->rd))) { - if ('\0' == c) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated"); - return; - } else if ('\\' == c) { - reader_backup(&pi->rd); - read_escaped_str(pi); - reader_release(&pi->rd); - return; - } + if ('\0' == c) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated"); + return; + } else if ('\\' == c) { + reader_backup(&pi->rd); + read_escaped_str(pi); + reader_release(&pi->rd); + return; + } } if (0 == parent) { // simple add - pi->add_cstr(pi, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str); + pi->add_cstr(pi, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str); } else { - switch (parent->next) { - case NEXT_ARRAY_NEW: - case NEXT_ARRAY_ELEMENT: - pi->array_append_cstr(pi, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str); - parent->next = NEXT_ARRAY_COMMA; - break; - case NEXT_HASH_NEW: - case NEXT_HASH_KEY: - parent->klen = pi->rd.tail - pi->rd.str - 1; - if (sizeof(parent->karray) <= parent->klen) { - parent->key = oj_strndup(pi->rd.str, parent->klen); - parent->kalloc = 1; - } else { - memcpy(parent->karray, pi->rd.str, parent->klen); - parent->karray[parent->klen] = '\0'; - parent->key = parent->karray; - parent->kalloc = 0; - } - parent->key_val = pi->hash_key(pi, parent->key, parent->klen); - parent->k1 = *pi->rd.str; - parent->next = NEXT_HASH_COLON; - break; - case NEXT_HASH_VALUE: - pi->hash_set_cstr(pi, parent, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str); - if (parent->kalloc) { - xfree((char *)parent->key); - } - parent->key = 0; - parent->kalloc = 0; - parent->next = NEXT_HASH_COMMA; - break; - case NEXT_HASH_COMMA: - case NEXT_NONE: - case NEXT_ARRAY_COMMA: - case NEXT_HASH_COLON: - default: - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a string", oj_stack_next_string(parent->next)); - break; - } + switch (parent->next) { + case NEXT_ARRAY_NEW: + case NEXT_ARRAY_ELEMENT: + pi->array_append_cstr(pi, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str); + parent->next = NEXT_ARRAY_COMMA; + break; + case NEXT_HASH_NEW: + case NEXT_HASH_KEY: + parent->klen = pi->rd.tail - pi->rd.str - 1; + if (sizeof(parent->karray) <= parent->klen) { + parent->key = oj_strndup(pi->rd.str, parent->klen); + parent->kalloc = 1; + } else { + memcpy(parent->karray, pi->rd.str, parent->klen); + parent->karray[parent->klen] = '\0'; + parent->key = parent->karray; + parent->kalloc = 0; + } + parent->key_val = pi->hash_key(pi, parent->key, parent->klen); + parent->k1 = *pi->rd.str; + parent->next = NEXT_HASH_COLON; + break; + case NEXT_HASH_VALUE: + pi->hash_set_cstr(pi, parent, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str); + if (parent->kalloc) { + xfree((char*)parent->key); + } + parent->key = 0; + parent->kalloc = 0; + parent->next = NEXT_HASH_COMMA; + break; + case NEXT_HASH_COMMA: + case NEXT_NONE: + case NEXT_ARRAY_COMMA: + case NEXT_HASH_COLON: + default: + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a string", oj_stack_next_string(parent->next)); + break; + } } reader_release(&pi->rd); } static void read_num(ParseInfo pi) { - struct _numInfo ni; - char c; + struct _numInfo ni; + char c; reader_protect(&pi->rd); ni.i = 0; @@ -418,134 +402,134 @@ read_num(ParseInfo pi) { ni.neg = 0; ni.has_exp = 0; if (CompatMode == pi->options.mode) { - ni.no_big = !pi->options.compat_bigdec; - ni.bigdec_load = pi->options.compat_bigdec; + ni.no_big = !pi->options.compat_bigdec; + ni.bigdec_load = pi->options.compat_bigdec; } else { - ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load || RubyDec == pi->options.bigdec_load); - ni.bigdec_load = pi->options.bigdec_load; + ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load || RubyDec == pi->options.bigdec_load); + ni.bigdec_load = pi->options.bigdec_load; } c = reader_get(&pi->rd); if ('-' == c) { - c = reader_get(&pi->rd); - ni.neg = 1; + c = reader_get(&pi->rd); + ni.neg = 1; } else if ('+' == c) { - c = reader_get(&pi->rd); + c = reader_get(&pi->rd); } if ('I' == c) { - if (No == pi->options.allow_nan) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); - return; - } else if (0 != reader_expect(&pi->rd, "nfinity")) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); - return; - } - ni.infinity = 1; + if (No == pi->options.allow_nan) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); + return; + } else if (0 != reader_expect(&pi->rd, "nfinity")) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); + return; + } + ni.infinity = 1; } else { - int dec_cnt = 0; - bool zero1 = false; - - for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) { - if (0 == ni.i && '0' == c) { - zero1 = true; - } - if (0 < ni.i) { - dec_cnt++; - } - if (ni.big) { - ni.big++; - } else { - int d = (c - '0'); - - if (0 < d) { - if (zero1 && CompatMode == pi->options.mode) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number"); - return; - } - zero1 = false; - } - ni.i = ni.i * 10 + d; - if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) { - ni.big = 1; - } - } - } - if ('.' == c) { - c = reader_get(&pi->rd); - // A trailing . is not a valid decimal but if encountered allow it - // except when mimicing the JSON gem. - if (CompatMode == pi->options.mode) { - if (c < '0' || '9' < c) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number"); - } - } - for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) { - int d = (c - '0'); - - if (0 < ni.num || 0 < ni.i) { - dec_cnt++; - } - if (INT64_MAX <= ni.div) { - if (!ni.no_big) { - ni.big = true; - } - } else { - ni.num = ni.num * 10 + d; - ni.div *= 10; - ni.di++; - if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) { - if (!ni.no_big) { - ni.big = true; - } - } - } - } - } - if ('e' == c || 'E' == c) { - int eneg = 0; - - ni.has_exp = 1; - c = reader_get(&pi->rd); - if ('-' == c) { - c = reader_get(&pi->rd); - eneg = 1; - } else if ('+' == c) { - c = reader_get(&pi->rd); - } - for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) { - ni.exp = ni.exp * 10 + (c - '0'); - if (EXP_MAX <= ni.exp) { - ni.big = 1; - } - } - if (eneg) { - ni.exp = -ni.exp; - } - } - ni.len = pi->rd.tail - pi->rd.str; - if (0 != c) { - reader_backup(&pi->rd); - } + int dec_cnt = 0; + bool zero1 = false; + + for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) { + if (0 == ni.i && '0' == c) { + zero1 = true; + } + if (0 < ni.i) { + dec_cnt++; + } + if (ni.big) { + ni.big++; + } else { + int d = (c - '0'); + + if (0 < d) { + if (zero1 && CompatMode == pi->options.mode) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number"); + return; + } + zero1 = false; + } + ni.i = ni.i * 10 + d; + if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) { + ni.big = 1; + } + } + } + if ('.' == c) { + c = reader_get(&pi->rd); + // A trailing . is not a valid decimal but if encountered allow it + // except when mimicing the JSON gem. + if (CompatMode == pi->options.mode) { + if (c < '0' || '9' < c) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number"); + } + } + for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) { + int d = (c - '0'); + + if (0 < ni.num || 0 < ni.i) { + dec_cnt++; + } + if (INT64_MAX <= ni.div) { + if (!ni.no_big) { + ni.big = true; + } + } else { + ni.num = ni.num * 10 + d; + ni.div *= 10; + ni.di++; + if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) { + if (!ni.no_big) { + ni.big = true; + } + } + } + } + } + if ('e' == c || 'E' == c) { + int eneg = 0; + + ni.has_exp = 1; + c = reader_get(&pi->rd); + if ('-' == c) { + c = reader_get(&pi->rd); + eneg = 1; + } else if ('+' == c) { + c = reader_get(&pi->rd); + } + for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) { + ni.exp = ni.exp * 10 + (c - '0'); + if (EXP_MAX <= ni.exp) { + ni.big = 1; + } + } + if (eneg) { + ni.exp = -ni.exp; + } + } + ni.len = pi->rd.tail - pi->rd.str; + if (0 != c) { + reader_backup(&pi->rd); + } } ni.str = pi->rd.str; ni.len = pi->rd.tail - pi->rd.str; // Check for special reserved values for Infinity and NaN. if (ni.big) { - if (0 == strcasecmp(INF_VAL, ni.str)) { - ni.infinity = 1; - } else if (0 == strcasecmp(NINF_VAL, ni.str)) { - ni.infinity = 1; - ni.neg = 1; - } else if (0 == strcasecmp(NAN_VAL, ni.str)) { - ni.nan = 1; - } + if (0 == strcasecmp(INF_VAL, ni.str)) { + ni.infinity = 1; + } else if (0 == strcasecmp(NINF_VAL, ni.str)) { + ni.infinity = 1; + ni.neg = 1; + } else if (0 == strcasecmp(NAN_VAL, ni.str)) { + ni.nan = 1; + } } if (CompatMode == pi->options.mode) { - if (pi->options.compat_bigdec) { - ni.big = 1; - } + if (pi->options.compat_bigdec) { + ni.big = 1; + } } else if (BigDec == pi->options.bigdec_load) { - ni.big = 1; + ni.big = 1; } add_num_value(pi, &ni); reader_release(&pi->rd); @@ -553,8 +537,8 @@ read_num(ParseInfo pi) { static void read_nan(ParseInfo pi) { - struct _numInfo ni; - char c; + struct _numInfo ni; + char c; ni.str = pi->rd.str; ni.i = 0; @@ -568,259 +552,259 @@ read_nan(ParseInfo pi) { ni.nan = 1; ni.neg = 0; if (CompatMode == pi->options.mode) { - ni.no_big = !pi->options.compat_bigdec; - ni.bigdec_load = pi->options.compat_bigdec; + ni.no_big = !pi->options.compat_bigdec; + ni.bigdec_load = pi->options.compat_bigdec; } else { - ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load || RubyDec == pi->options.bigdec_load); - ni.bigdec_load = pi->options.bigdec_load; + ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load || RubyDec == pi->options.bigdec_load); + ni.bigdec_load = pi->options.bigdec_load; } if ('a' != reader_get(&pi->rd) || - ('N' != (c = reader_get(&pi->rd)) && 'n' != c)) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); - return; + ('N' != (c = reader_get(&pi->rd)) && 'n' != c)) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); + return; } if (CompatMode == pi->options.mode) { - if (pi->options.compat_bigdec) { - ni.big = 1; - } + if (pi->options.compat_bigdec) { + ni.big = 1; + } } else if (BigDec == pi->options.bigdec_load) { - ni.big = 1; + ni.big = 1; } add_num_value(pi, &ni); } static void array_start(ParseInfo pi) { - VALUE v = pi->start_array(pi); + VALUE v = pi->start_array(pi); stack_push(&pi->stack, v, NEXT_ARRAY_NEW); } static void array_end(ParseInfo pi) { - Val array = stack_pop(&pi->stack); + Val array = stack_pop(&pi->stack); if (0 == array) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected array close"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected array close"); } else if (NEXT_ARRAY_COMMA != array->next && NEXT_ARRAY_NEW != array->next) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not an array close", oj_stack_next_string(array->next)); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not an array close", oj_stack_next_string(array->next)); } else { - pi->end_array(pi); - add_value(pi, array->val); + pi->end_array(pi); + add_value(pi, array->val); } } static void hash_start(ParseInfo pi) { - volatile VALUE v = pi->start_hash(pi); + volatile VALUE v = pi->start_hash(pi); stack_push(&pi->stack, v, NEXT_HASH_NEW); } static void hash_end(ParseInfo pi) { - volatile Val hash = stack_peek(&pi->stack); + volatile Val hash = stack_peek(&pi->stack); // leave hash on stack until just before if (0 == hash) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected hash close"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected hash close"); } else if (NEXT_HASH_COMMA != hash->next && NEXT_HASH_NEW != hash->next) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a hash close", oj_stack_next_string(hash->next)); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a hash close", oj_stack_next_string(hash->next)); } else { - pi->end_hash(pi); - stack_pop(&pi->stack); - add_value(pi, hash->val); + pi->end_hash(pi); + stack_pop(&pi->stack); + add_value(pi, hash->val); } } static void comma(ParseInfo pi) { - Val parent = stack_peek(&pi->stack); + Val parent = stack_peek(&pi->stack); if (0 == parent) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma"); } else if (NEXT_ARRAY_COMMA == parent->next) { - parent->next = NEXT_ARRAY_ELEMENT; + parent->next = NEXT_ARRAY_ELEMENT; } else if (NEXT_HASH_COMMA == parent->next) { - parent->next = NEXT_HASH_KEY; + parent->next = NEXT_HASH_KEY; } else { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma"); } } static void colon(ParseInfo pi) { - Val parent = stack_peek(&pi->stack); + Val parent = stack_peek(&pi->stack); if (0 != parent && NEXT_HASH_COLON == parent->next) { - parent->next = NEXT_HASH_VALUE; + parent->next = NEXT_HASH_VALUE; } else { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected colon"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected colon"); } } void oj_sparse2(ParseInfo pi) { - int first = 1; - char c; - long start = 0; + int first = 1; + char c; + long start = 0; err_init(&pi->err); while (1) { - if (0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1) { - VALUE err_clas = oj_get_json_err_class("NestingError"); - - oj_set_error_at(pi, err_clas, __FILE__, __LINE__, "Too deeply nested."); - pi->err_class = err_clas; - return; - } - c = reader_next_non_white(&pi->rd); - if (!first && '\0' != c) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected characters after the JSON document"); - } - switch (c) { - case '{': - hash_start(pi); - break; - case '}': - hash_end(pi); - break; - case ':': - colon(pi); - break; - case '[': - array_start(pi); - break; - case ']': - array_end(pi); - break; - case ',': - comma(pi); - break; - case '"': - read_str(pi); - break; - case '+': - if (CompatMode == pi->options.mode) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); - return; - } - pi->cur--; - read_num(pi); - break; - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - reader_backup(&pi->rd); - read_num(pi); - break; - case 'I': - if (Yes == pi->options.allow_nan) { - reader_backup(&pi->rd); - read_num(pi); - } else { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); - return; - } - break; - case 'N': - if (Yes == pi->options.allow_nan) { - read_nan(pi); - } else { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); - return; - } - break; - case 't': - read_true(pi); - break; - case 'f': - read_false(pi); - break; - case 'n': - c = reader_get(&pi->rd); - if ('u' == c) { - if (0 == reader_expect(&pi->rd, "ll")) { - add_value(pi, Qnil); - } else { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected null"); - return; - } - } else if ('a' == c) { - struct _numInfo ni; - - c = reader_get(&pi->rd); - if ('N' != c && 'n' != c) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected NaN"); - return; - } - ni.str = pi->rd.str; - ni.i = 0; - ni.num = 0; - ni.div = 1; - ni.di = 0; - ni.len = 0; - ni.exp = 0; - ni.big = 0; - ni.infinity = 0; - ni.nan = 1; - ni.neg = 0; - if (CompatMode == pi->options.mode) { - ni.no_big = !pi->options.compat_bigdec; - ni.bigdec_load = pi->options.compat_bigdec; - } else { - ni.no_big = (FloatDec == pi->options.bigdec_load || - FastDec == pi->options.bigdec_load || - RubyDec == pi->options.bigdec_load); - ni.bigdec_load = pi->options.bigdec_load; - } - add_num_value(pi, &ni); - } else { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid token"); - return; - } - break; - case '/': - skip_comment(pi); - break; - case '\0': - return; - default: - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character '%c' [0x%02x]", c, c); - return; - } - if (err_has(&pi->err)) { - return; - } - if (stack_empty(&pi->stack)) { - if (Qundef != pi->proc) { - VALUE args[3]; - long len = pi->rd.pos - start; - - *args = stack_head_val(&pi->stack); - args[1] = LONG2NUM(start); - args[2] = LONG2NUM(len); - - if (Qnil == pi->proc) { - rb_yield_values2(3, args); - } else { - rb_proc_call_with_block(pi->proc, 3, args, Qnil); - } - } else if (!pi->has_callbacks) { - first = 0; - } - start = pi->rd.pos; - // TBD break if option set to allow that - } + if (0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1) { + VALUE err_clas = oj_get_json_err_class("NestingError"); + + oj_set_error_at(pi, err_clas, __FILE__, __LINE__, "Too deeply nested."); + pi->err_class = err_clas; + return; + } + c = reader_next_non_white(&pi->rd); + if (!first && '\0' != c) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected characters after the JSON document"); + } + switch (c) { + case '{': + hash_start(pi); + break; + case '}': + hash_end(pi); + break; + case ':': + colon(pi); + break; + case '[': + array_start(pi); + break; + case ']': + array_end(pi); + break; + case ',': + comma(pi); + break; + case '"': + read_str(pi); + break; + case '+': + if (CompatMode == pi->options.mode) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); + return; + } + pi->cur--; + read_num(pi); + break; + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + reader_backup(&pi->rd); + read_num(pi); + break; + case 'I': + if (Yes == pi->options.allow_nan) { + reader_backup(&pi->rd); + read_num(pi); + } else { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); + return; + } + break; + case 'N': + if (Yes == pi->options.allow_nan) { + read_nan(pi); + } else { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); + return; + } + break; + case 't': + read_true(pi); + break; + case 'f': + read_false(pi); + break; + case 'n': + c = reader_get(&pi->rd); + if ('u' == c) { + if (0 == reader_expect(&pi->rd, "ll")) { + add_value(pi, Qnil); + } else { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected null"); + return; + } + } else if ('a' == c) { + struct _numInfo ni; + + c = reader_get(&pi->rd); + if ('N' != c && 'n' != c) { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected NaN"); + return; + } + ni.str = pi->rd.str; + ni.i = 0; + ni.num = 0; + ni.div = 1; + ni.di = 0; + ni.len = 0; + ni.exp = 0; + ni.big = 0; + ni.infinity = 0; + ni.nan = 1; + ni.neg = 0; + if (CompatMode == pi->options.mode) { + ni.no_big = !pi->options.compat_bigdec; + ni.bigdec_load = pi->options.compat_bigdec; + } else { + ni.no_big = (FloatDec == pi->options.bigdec_load || + FastDec == pi->options.bigdec_load || + RubyDec == pi->options.bigdec_load); + ni.bigdec_load = pi->options.bigdec_load; + } + add_num_value(pi, &ni); + } else { + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid token"); + return; + } + break; + case '/': + skip_comment(pi); + break; + case '\0': + return; + default: + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character '%c' [0x%02x]", c, c); + return; + } + if (err_has(&pi->err)) { + return; + } + if (stack_empty(&pi->stack)) { + if (Qundef != pi->proc) { + VALUE args[3]; + long len = pi->rd.pos - start; + + *args = stack_head_val(&pi->stack); + args[1] = LONG2NUM(start); + args[2] = LONG2NUM(len); + + if (Qnil == pi->proc) { + rb_yield_values2(3, args); + } else { + rb_proc_call_with_block(pi->proc, 3, args, Qnil); + } + } else if (!pi->has_callbacks) { + first = 0; + } + start = pi->rd.pos; + // TBD break if option set to allow that + } } } @@ -833,46 +817,46 @@ protect_parse(VALUE pip) { VALUE oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd) { - volatile VALUE input; - volatile VALUE wrapped_stack; - VALUE result = Qnil; - int line = 0; + volatile VALUE input; + volatile VALUE wrapped_stack; + VALUE result = Qnil; + int line = 0; if (argc < 1) { - rb_raise(rb_eArgError, "Wrong number of arguments to parse."); + rb_raise(rb_eArgError, "Wrong number of arguments to parse."); } input = argv[0]; if (2 <= argc) { - if (T_HASH == rb_type(argv[1])) { - oj_parse_options(argv[1], &pi->options); - } else if (3 <= argc && T_HASH == rb_type(argv[2])) { - oj_parse_options(argv[2], &pi->options); - } + if (T_HASH == rb_type(argv[1])) { + oj_parse_options(argv[1], &pi->options); + } else if (3 <= argc && T_HASH == rb_type(argv[2])) { + oj_parse_options(argv[2], &pi->options); + } } if (Qnil == input) { - if (Yes == pi->options.nilnil) { - return Qnil; - } else { - rb_raise(rb_eTypeError, "Nil is not a valid JSON source."); - } + if (Yes == pi->options.nilnil) { + return Qnil; + } else { + rb_raise(rb_eTypeError, "Nil is not a valid JSON source."); + } } else if (CompatMode == pi->options.mode && T_STRING == rb_type(input) && No == pi->options.nilnil && 0 == RSTRING_LEN(input)) { - rb_raise(oj_json_parser_error_class, "An empty string is not a valid JSON string."); + rb_raise(oj_json_parser_error_class, "An empty string is not a valid JSON string."); } if (rb_block_given_p()) { - pi->proc = Qnil; + pi->proc = Qnil; } else { - pi->proc = Qundef; + pi->proc = Qundef; } oj_reader_init(&pi->rd, input, fd, CompatMode == pi->options.mode); pi->json = 0; // indicates reader is in use if (Yes == pi->options.circular) { - pi->circ_array = oj_circ_array_new(); + pi->circ_array = oj_circ_array_new(); } else { - pi->circ_array = 0; + pi->circ_array = 0; } if (No == pi->options.allow_gc) { - rb_gc_disable(); + rb_gc_disable(); } // GC can run at any time. When it runs any Object created by C will be // freed. We protect against this by wrapping the value stack in a ruby @@ -881,81 +865,81 @@ oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd) { wrapped_stack = oj_stack_init(&pi->stack); rb_protect(protect_parse, (VALUE)pi, &line); if (Qundef == pi->stack.head->val && !empty_ok(&pi->options)) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Empty input"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Empty input"); } result = stack_head_val(&pi->stack); DATA_PTR(wrapped_stack) = 0; if (No == pi->options.allow_gc) { - rb_gc_enable(); + rb_gc_enable(); } if (!err_has(&pi->err)) { - // If the stack is not empty then the JSON terminated early. - Val v; - VALUE err_class = oj_parse_error_class; - - if (0 != line) { - VALUE ec = rb_obj_class(rb_errinfo()); - - if (rb_eIOError != ec) { - goto CLEANUP; - } - // Sometimes the class of the error is 0 which seems broken. - if (rb_eArgError != ec && 0 != ec) { - err_class = ec; - } - } - if (0 != (v = stack_peek(&pi->stack))) { - switch (v->next) { - case NEXT_ARRAY_NEW: - case NEXT_ARRAY_ELEMENT: - case NEXT_ARRAY_COMMA: - oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated"); - break; - case NEXT_HASH_NEW: - case NEXT_HASH_KEY: - case NEXT_HASH_COLON: - case NEXT_HASH_VALUE: - case NEXT_HASH_COMMA: - oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Hash/Object not terminated"); - break; - default: - oj_set_error_at(pi, err_class, __FILE__, __LINE__, "not terminated"); - } - } + // If the stack is not empty then the JSON terminated early. + Val v; + VALUE err_class = oj_parse_error_class; + + if (0 != line) { + VALUE ec = rb_obj_class(rb_errinfo()); + + if (rb_eIOError != ec) { + goto CLEANUP; + } + // Sometimes the class of the error is 0 which seems broken. + if (rb_eArgError != ec && 0 != ec) { + err_class = ec; + } + } + if (0 != (v = stack_peek(&pi->stack))) { + switch (v->next) { + case NEXT_ARRAY_NEW: + case NEXT_ARRAY_ELEMENT: + case NEXT_ARRAY_COMMA: + oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated"); + break; + case NEXT_HASH_NEW: + case NEXT_HASH_KEY: + case NEXT_HASH_COLON: + case NEXT_HASH_VALUE: + case NEXT_HASH_COMMA: + oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Hash/Object not terminated"); + break; + default: + oj_set_error_at(pi, err_class, __FILE__, __LINE__, "not terminated"); + } + } } CLEANUP: // proceed with cleanup if (0 != pi->circ_array) { - oj_circ_array_free(pi->circ_array); + oj_circ_array_free(pi->circ_array); } stack_cleanup(&pi->stack); if (0 != fd) { - close(fd); + close(fd); } if (err_has(&pi->err)) { - rb_set_errinfo(Qnil); - if (Qnil != pi->err_class && 0 != pi->err_class) { - pi->err.clas = pi->err_class; - } - if (CompatMode == pi->options.mode && Yes != pi->options.safe) { - // The json gem requires the error message be UTF-8 encoded. In - // additional the complete JSON source should be returned but that - // is not possible without stored all the bytes read and reading - // the remaining bytes on the stream. Both seem like a very bad - // idea. - VALUE args[] = { oj_encode(rb_str_new2(pi->err.msg)) }; - - if (pi->err.clas == oj_parse_error_class) { - // The error was an Oj::ParseError so change to a JSON::ParserError. - pi->err.clas = oj_json_parser_error_class; - } - rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas)); - } else { - oj_err_raise(&pi->err); - } - oj_err_raise(&pi->err); + rb_set_errinfo(Qnil); + if (Qnil != pi->err_class && 0 != pi->err_class) { + pi->err.clas = pi->err_class; + } + if (CompatMode == pi->options.mode && Yes != pi->options.safe) { + // The json gem requires the error message be UTF-8 encoded. In + // additional the complete JSON source should be returned but that + // is not possible without stored all the bytes read and reading + // the remaining bytes on the stream. Both seem like a very bad + // idea. + VALUE args[] = { oj_encode(rb_str_new2(pi->err.msg)) }; + + if (pi->err.clas == oj_parse_error_class) { + // The error was an Oj::ParseError so change to a JSON::ParserError. + pi->err.clas = oj_json_parser_error_class; + } + rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas)); + } else { + oj_err_raise(&pi->err); + } + oj_err_raise(&pi->err); } else if (0 != line) { - rb_jump_tag(line); + rb_jump_tag(line); } return result; } diff --git a/ext/oj/stream_writer.c b/ext/oj/stream_writer.c index 8e7dbb8e..c3a90476 100644 --- a/ext/oj/stream_writer.c +++ b/ext/oj/stream_writer.c @@ -7,14 +7,14 @@ #include "encode.h" -extern VALUE Oj; +extern VALUE Oj; static void stream_writer_free(void *ptr) { - StreamWriter sw; + StreamWriter sw; if (0 == ptr) { - return; + return; } sw = (StreamWriter)ptr; xfree(sw->sw.out.buf); @@ -30,33 +30,33 @@ stream_writer_reset_buf(StreamWriter sw) { static void stream_writer_write(StreamWriter sw) { - ssize_t size = sw->sw.out.cur - sw->sw.out.buf; + ssize_t size = sw->sw.out.cur - sw->sw.out.buf; switch (sw->type) { - case STRING_IO: - case STREAM_IO: { - volatile VALUE rs = rb_str_new(sw->sw.out.buf, size); - - // Oddly enough, when pushing ASCII characters with UTF-8 encoding or - // even ASCII-8BIT does not change the output encoding. Pushing any - // non-ASCII no matter what the encoding changes the output encoding - // to ASCII-8BIT if it the string is not forced to UTF-8 here. - rs = oj_encode(rs); - rb_funcall(sw->stream, oj_write_id, 1, rs); - break; - } - case FILE_IO: - if (size != write(sw->fd, sw->sw.out.buf, size)) { - rb_raise(rb_eIOError, "Write failed. [_%d_:%s]\n", errno, strerror(errno)); - } - break; - default: - rb_raise(rb_eArgError, "expected an IO Object."); + case STRING_IO: + case STREAM_IO: { + volatile VALUE rs = rb_str_new(sw->sw.out.buf, size); + + // Oddly enough, when pushing ASCII characters with UTF-8 encoding or + // even ASCII-8BIT does not change the output encoding. Pushing any + // non-ASCII no matter what the encoding changes the output encoding + // to ASCII-8BIT if it the string is not forced to UTF-8 here. + rs = oj_encode(rs); + rb_funcall(sw->stream, oj_write_id, 1, rs); + break; + } + case FILE_IO: + if (size != write(sw->fd, sw->sw.out.buf, size)) { + rb_raise(rb_eIOError, "Write failed. [_%d_:%s]\n", errno, strerror(errno)); + } + break; + default: + rb_raise(rb_eArgError, "expected an IO Object."); } stream_writer_reset_buf(sw); } -static VALUE buffer_size_sym = Qundef; +static VALUE buffer_size_sym = Qundef; /* Document-method: new * call-seq: new(io, options) @@ -76,55 +76,55 @@ static VALUE buffer_size_sym = Qundef; */ static VALUE stream_writer_new(int argc, VALUE *argv, VALUE self) { - StreamWriterType type = STREAM_IO; - int fd = 0; - VALUE stream = argv[0]; - VALUE clas = rb_obj_class(stream); - StreamWriter sw; + StreamWriterType type = STREAM_IO; + int fd = 0; + VALUE stream = argv[0]; + VALUE clas = rb_obj_class(stream); + StreamWriter sw; #if !IS_WINDOWS - VALUE s; + VALUE s; #endif if (oj_stringio_class == clas) { - type = STRING_IO; + type = STRING_IO; #if !IS_WINDOWS } else if (rb_respond_to(stream, oj_fileno_id) && - Qnil != (s = rb_funcall(stream, oj_fileno_id, 0)) && - 0 != (fd = FIX2INT(s))) { - type = FILE_IO; + Qnil != (s = rb_funcall(stream, oj_fileno_id, 0)) && + 0 != (fd = FIX2INT(s))) { + type = FILE_IO; #endif } else if (rb_respond_to(stream, oj_write_id)) { - type = STREAM_IO; + type = STREAM_IO; } else { - rb_raise(rb_eArgError, "expected an IO Object."); + rb_raise(rb_eArgError, "expected an IO Object."); } sw = ALLOC(struct _streamWriter); if (2 == argc && T_HASH == rb_type(argv[1])) { - volatile VALUE v; - int buf_size = 0; - - if (Qundef == buffer_size_sym) { - buffer_size_sym = ID2SYM(rb_intern("buffer_size")); - rb_gc_register_address(&buffer_size_sym); - } - if (Qnil != (v = rb_hash_lookup(argv[1], buffer_size_sym))) { + volatile VALUE v; + int buf_size = 0; + + if (Qundef == buffer_size_sym) { + buffer_size_sym = ID2SYM(rb_intern("buffer_size")); rb_gc_register_address(&buffer_size_sym); + + } + if (Qnil != (v = rb_hash_lookup(argv[1], buffer_size_sym))) { #ifdef RUBY_INTEGER_UNIFICATION - if (rb_cInteger != rb_obj_class(v)) { - rb_raise(rb_eArgError, ":buffer size must be a Integer."); - } + if (rb_cInteger != rb_obj_class(v)) { + rb_raise(rb_eArgError, ":buffer size must be a Integer."); + } #else - if (T_FIXNUM != rb_type(v)) { - rb_raise(rb_eArgError, ":buffer size must be a Integer."); - } + if (T_FIXNUM != rb_type(v)) { + rb_raise(rb_eArgError, ":buffer size must be a Integer."); + } #endif - buf_size = FIX2INT(v); - } - oj_str_writer_init(&sw->sw, buf_size); - oj_parse_options(argv[1], &sw->sw.opts); - sw->flush_limit = buf_size; + buf_size = FIX2INT(v); + } + oj_str_writer_init(&sw->sw, buf_size); + oj_parse_options(argv[1], &sw->sw.opts); + sw->flush_limit = buf_size; } else { - oj_str_writer_init(&sw->sw, 4096); - sw->flush_limit = 0; + oj_str_writer_init(&sw->sw, 4096); + sw->flush_limit = 0; } sw->sw.out.indent = sw->sw.opts.indent; sw->stream = stream; @@ -145,12 +145,12 @@ stream_writer_new(int argc, VALUE *argv, VALUE self) { */ static VALUE stream_writer_push_key(VALUE self, VALUE key) { - StreamWriter sw = (StreamWriter)DATA_PTR(self); + StreamWriter sw = (StreamWriter)DATA_PTR(self); rb_check_type(key, T_STRING); oj_str_writer_push_key(&sw->sw, StringValuePtr(key)); if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) { - stream_writer_write(sw); + stream_writer_write(sw); } return Qnil; } @@ -165,26 +165,26 @@ stream_writer_push_key(VALUE self, VALUE key) { */ static VALUE stream_writer_push_object(int argc, VALUE *argv, VALUE self) { - StreamWriter sw = (StreamWriter)DATA_PTR(self); + StreamWriter sw = (StreamWriter)DATA_PTR(self); switch (argc) { - case 0: - oj_str_writer_push_object(&sw->sw, 0); - break; - case 1: - if (Qnil == argv[0]) { - oj_str_writer_push_object(&sw->sw, 0); - } else { - rb_check_type(argv[0], T_STRING); - oj_str_writer_push_object(&sw->sw, StringValuePtr(argv[0])); - } - break; - default: - rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'."); - break; + case 0: + oj_str_writer_push_object(&sw->sw, 0); + break; + case 1: + if (Qnil == argv[0]) { + oj_str_writer_push_object(&sw->sw, 0); + } else { + rb_check_type(argv[0], T_STRING); + oj_str_writer_push_object(&sw->sw, StringValuePtr(argv[0])); + } + break; + default: + rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'."); + break; } if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) { - stream_writer_write(sw); + stream_writer_write(sw); } return Qnil; } @@ -199,26 +199,26 @@ stream_writer_push_object(int argc, VALUE *argv, VALUE self) { */ static VALUE stream_writer_push_array(int argc, VALUE *argv, VALUE self) { - StreamWriter sw = (StreamWriter)DATA_PTR(self); + StreamWriter sw = (StreamWriter)DATA_PTR(self); switch (argc) { - case 0: - oj_str_writer_push_array(&sw->sw, 0); - break; - case 1: - if (Qnil == argv[0]) { - oj_str_writer_push_array(&sw->sw, 0); - } else { - rb_check_type(argv[0], T_STRING); - oj_str_writer_push_array(&sw->sw, StringValuePtr(argv[0])); - } - break; - default: - rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'."); - break; + case 0: + oj_str_writer_push_array(&sw->sw, 0); + break; + case 1: + if (Qnil == argv[0]) { + oj_str_writer_push_array(&sw->sw, 0); + } else { + rb_check_type(argv[0], T_STRING); + oj_str_writer_push_array(&sw->sw, StringValuePtr(argv[0])); + } + break; + default: + rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'."); + break; } if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) { - stream_writer_write(sw); + stream_writer_write(sw); } return Qnil; } @@ -232,26 +232,26 @@ stream_writer_push_array(int argc, VALUE *argv, VALUE self) { */ static VALUE stream_writer_push_value(int argc, VALUE *argv, VALUE self) { - StreamWriter sw = (StreamWriter)DATA_PTR(self); + StreamWriter sw = (StreamWriter)DATA_PTR(self); switch (argc) { - case 1: - oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0); - break; - case 2: - if (Qnil == argv[1]) { - oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0); - } else { - rb_check_type(argv[1], T_STRING); - oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1])); - } - break; - default: - rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'."); - break; + case 1: + oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0); + break; + case 2: + if (Qnil == argv[1]) { + oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0); + } else { + rb_check_type(argv[1], T_STRING); + oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1])); + } + break; + default: + rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'."); + break; } if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) { - stream_writer_write(sw); + stream_writer_write(sw); } return Qnil; } @@ -267,27 +267,27 @@ stream_writer_push_value(int argc, VALUE *argv, VALUE self) { */ static VALUE stream_writer_push_json(int argc, VALUE *argv, VALUE self) { - StreamWriter sw = (StreamWriter)DATA_PTR(self); + StreamWriter sw = (StreamWriter)DATA_PTR(self); rb_check_type(argv[0], T_STRING); switch (argc) { - case 1: - oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0); - break; - case 2: - if (Qnil == argv[1]) { - oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0); - } else { - rb_check_type(argv[1], T_STRING); - oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), StringValuePtr(argv[1])); - } - break; - default: - rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'."); - break; + case 1: + oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0); + break; + case 2: + if (Qnil == argv[1]) { + oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0); + } else { + rb_check_type(argv[1], T_STRING); + oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), StringValuePtr(argv[1])); + } + break; + default: + rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'."); + break; } if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) { - stream_writer_write(sw); + stream_writer_write(sw); } return Qnil; } @@ -300,11 +300,11 @@ stream_writer_push_json(int argc, VALUE *argv, VALUE self) { */ static VALUE stream_writer_pop(VALUE self) { - StreamWriter sw = (StreamWriter)DATA_PTR(self); + StreamWriter sw = (StreamWriter)DATA_PTR(self); oj_str_writer_pop(&sw->sw); if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) { - stream_writer_write(sw); + stream_writer_write(sw); } return Qnil; } @@ -317,7 +317,7 @@ stream_writer_pop(VALUE self) { */ static VALUE stream_writer_pop_all(VALUE self) { - StreamWriter sw = (StreamWriter)DATA_PTR(self); + StreamWriter sw = (StreamWriter)DATA_PTR(self); oj_str_writer_pop_all(&sw->sw); stream_writer_write(sw); diff --git a/ext/oj/strict.c b/ext/oj/strict.c index 49fab764..c67bc819 100644 --- a/ext/oj/strict.c +++ b/ext/oj/strict.c @@ -1,28 +1,28 @@ // Copyright (c) 2012 Peter Ohler. All rights reserved. // Licensed under the MIT License. See LICENSE file in the project root for license details. -#include #include +#include #include #include -#include "encode.h" -#include "err.h" #include "oj.h" +#include "err.h" #include "parse.h" +#include "encode.h" #include "trace.h" static void hash_end(ParseInfo pi) { if (Yes == pi->options.trace) { - oj_trace_parse_hash_end(pi, __FILE__, __LINE__); + oj_trace_parse_hash_end(pi, __FILE__, __LINE__); } } static void array_end(ParseInfo pi) { if (Yes == pi->options.trace) { - oj_trace_parse_array_end(pi, __FILE__, __LINE__); + oj_trace_parse_array_end(pi, __FILE__, __LINE__); } } @@ -34,80 +34,80 @@ noop_hash_key(ParseInfo pi, const char *key, size_t klen) { static void add_value(ParseInfo pi, VALUE val) { if (Yes == pi->options.trace) { - oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val); + oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val); } pi->stack.head->val = val; } static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { - volatile VALUE rstr = rb_str_new(str, len); + volatile VALUE rstr = rb_str_new(str, len); rstr = oj_encode(rstr); pi->stack.head->val = rstr; if (Yes == pi->options.trace) { - oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr); + oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr); } } static void add_num(ParseInfo pi, NumInfo ni) { if (ni->infinity || ni->nan) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); } pi->stack.head->val = oj_num_as_value(ni); if (Yes == pi->options.trace) { - oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val); + oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val); } } static VALUE start_hash(ParseInfo pi) { if (Qnil != pi->options.hash_class) { - return rb_class_new_instance(0, NULL, pi->options.hash_class); + return rb_class_new_instance(0, NULL, pi->options.hash_class); } if (Yes == pi->options.trace) { - oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__); + oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__); } return rb_hash_new(); } static VALUE calc_hash_key(ParseInfo pi, Val parent) { - volatile VALUE rkey = parent->key_val; + volatile VALUE rkey = parent->key_val; if (Qundef == rkey) { - rkey = rb_str_new(parent->key, parent->klen); + rkey = rb_str_new(parent->key, parent->klen); } rkey = oj_encode(rkey); if (Yes == pi->options.sym_key) { - rkey = rb_str_intern(rkey); + rkey = rb_str_intern(rkey); } return rkey; } static void hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) { - volatile VALUE rstr = rb_str_new(str, len); + volatile VALUE rstr = rb_str_new(str, len); rstr = oj_encode(rstr); rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rstr); if (Yes == pi->options.trace) { - oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr); + oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr); } } static void hash_set_num(ParseInfo pi, Val parent, NumInfo ni) { - volatile VALUE v; + volatile VALUE v; if (ni->infinity || ni->nan) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); } v = oj_num_as_value(ni); rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), v); if (Yes == pi->options.trace) { - oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, v); + oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, v); } } @@ -115,40 +115,40 @@ static void hash_set_value(ParseInfo pi, Val parent, VALUE value) { rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value); if (Yes == pi->options.trace) { - oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value); + oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value); } } static VALUE start_array(ParseInfo pi) { if (Yes == pi->options.trace) { - oj_trace_parse_in("start_array", pi, __FILE__, __LINE__); + oj_trace_parse_in("start_array", pi, __FILE__, __LINE__); } return rb_ary_new(); } static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { - volatile VALUE rstr = rb_str_new(str, len); + volatile VALUE rstr = rb_str_new(str, len); rstr = oj_encode(rstr); rb_ary_push(stack_peek(&pi->stack)->val, rstr); if (Yes == pi->options.trace) { - oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr); + oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr); } } static void array_append_num(ParseInfo pi, NumInfo ni) { - volatile VALUE v; + volatile VALUE v; if (ni->infinity || ni->nan) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); } v = oj_num_as_value(ni); rb_ary_push(stack_peek(&pi->stack)->val, v); if (Yes == pi->options.trace) { - oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, v); + oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, v); } } @@ -156,7 +156,7 @@ static void array_append_value(ParseInfo pi, VALUE value) { rb_ary_push(stack_peek(&pi->stack)->val, value); if (Yes == pi->options.trace) { - oj_trace_parse_call("append_value", pi, __FILE__, __LINE__, value); + oj_trace_parse_call("append_value", pi, __FILE__, __LINE__, value); } } @@ -181,7 +181,7 @@ oj_set_strict_callbacks(ParseInfo pi) { VALUE oj_strict_parse(int argc, VALUE *argv, VALUE self) { - struct _parseInfo pi; + struct _parseInfo pi; parse_info_init(&pi); pi.options = oj_default_options; @@ -190,15 +190,15 @@ oj_strict_parse(int argc, VALUE *argv, VALUE self) { oj_set_strict_callbacks(&pi); if (T_STRING == rb_type(*argv)) { - return oj_pi_parse(argc, argv, &pi, 0, 0, true); + return oj_pi_parse(argc, argv, &pi, 0, 0, true); } else { - return oj_pi_sparse(argc, argv, &pi, 0); + return oj_pi_sparse(argc, argv, &pi, 0); } } VALUE oj_strict_parse_cstr(int argc, VALUE *argv, char *json, size_t len) { - struct _parseInfo pi; + struct _parseInfo pi; parse_info_init(&pi); pi.options = oj_default_options; diff --git a/ext/oj/string_writer.c b/ext/oj/string_writer.c index 44cef46d..8fd89b65 100644 --- a/ext/oj/string_writer.c +++ b/ext/oj/string_writer.c @@ -4,26 +4,26 @@ #include "dump.h" #include "encode.h" -extern VALUE Oj; +extern VALUE Oj; -bool string_writer_optimized = false; +bool string_writer_optimized = false; static void key_check(StrWriter sw, const char *key) { - DumpType type = sw->types[sw->depth]; + DumpType type = sw->types[sw->depth]; if (0 == key && (ObjectNew == type || ObjectType == type)) { - rb_raise(rb_eStandardError, "Can not push onto an Object without a key."); + rb_raise(rb_eStandardError, "Can not push onto an Object without a key."); } } static void push_type(StrWriter sw, DumpType type) { if (sw->types_end <= sw->types + sw->depth + 1) { - size_t size = (sw->types_end - sw->types) * 2; + size_t size = (sw->types_end - sw->types) * 2; - REALLOC_N(sw->types, char, size); - sw->types_end = sw->types + size; + REALLOC_N(sw->types, char, size); + sw->types_end = sw->types + size; } sw->depth++; sw->types[sw->depth] = type; @@ -32,17 +32,17 @@ push_type(StrWriter sw, DumpType type) { static void maybe_comma(StrWriter sw) { switch (sw->types[sw->depth]) { - case ObjectNew: - sw->types[sw->depth] = ObjectType; - break; - case ArrayNew: - sw->types[sw->depth] = ArrayType; - break; - case ObjectType: - case ArrayType: - // Always have a few characters available in the out.buf. - *sw->out.cur++ = ','; - break; + case ObjectNew: + sw->types[sw->depth] = ObjectType; + break; + case ArrayNew: + sw->types[sw->depth] = ArrayType; + break; + case ObjectType: + case ArrayType: + // Always have a few characters available in the out.buf. + *sw->out.cur++ = ','; + break; } } @@ -57,9 +57,9 @@ oj_str_writer_init(StrWriter sw, int buf_size) { sw->keyWritten = 0; if (0 == buf_size) { - buf_size = 4096; + buf_size = 4096; } else if (buf_size < 1024) { - buf_size = 1024; + buf_size = 1024; } sw->out.buf = ALLOC_N(char, buf_size); sw->out.end = sw->out.buf + buf_size - 10; @@ -81,20 +81,20 @@ oj_str_writer_init(StrWriter sw, int buf_size) { void oj_str_writer_push_key(StrWriter sw, const char *key) { - DumpType type = sw->types[sw->depth]; - long size; + DumpType type = sw->types[sw->depth]; + long size; if (sw->keyWritten) { - rb_raise(rb_eStandardError, "Can not push more than one key before pushing a non-key."); + rb_raise(rb_eStandardError, "Can not push more than one key before pushing a non-key."); } if (ObjectNew != type && ObjectType != type) { - rb_raise(rb_eStandardError, "Can only push a key onto an Object."); + rb_raise(rb_eStandardError, "Can only push a key onto an Object."); } size = sw->depth * sw->out.indent + 3; assure_size(&sw->out, size); maybe_comma(sw); if (0 < sw->depth) { - fill_indent(&sw->out, sw->depth); + fill_indent(&sw->out, sw->depth); } oj_dump_cstr(key, strlen(key), 0, 0, &sw->out); *sw->out.cur++ = ':'; @@ -104,22 +104,22 @@ oj_str_writer_push_key(StrWriter sw, const char *key) { void oj_str_writer_push_object(StrWriter sw, const char *key) { if (sw->keyWritten) { - sw->keyWritten = 0; - assure_size(&sw->out, 1); + sw->keyWritten = 0; + assure_size(&sw->out, 1); } else { - long size; - - key_check(sw, key); - size = sw->depth * sw->out.indent + 3; - assure_size(&sw->out, size); - maybe_comma(sw); - if (0 < sw->depth) { - fill_indent(&sw->out, sw->depth); - } - if (0 != key) { - oj_dump_cstr(key, strlen(key), 0, 0, &sw->out); - *sw->out.cur++ = ':'; - } + long size; + + key_check(sw, key); + size = sw->depth * sw->out.indent + 3; + assure_size(&sw->out, size); + maybe_comma(sw); + if (0 < sw->depth) { + fill_indent(&sw->out, sw->depth); + } + if (0 != key) { + oj_dump_cstr(key, strlen(key), 0, 0, &sw->out); + *sw->out.cur++ = ':'; + } } *sw->out.cur++ = '{'; push_type(sw, ObjectNew); @@ -128,22 +128,22 @@ oj_str_writer_push_object(StrWriter sw, const char *key) { void oj_str_writer_push_array(StrWriter sw, const char *key) { if (sw->keyWritten) { - sw->keyWritten = 0; - assure_size(&sw->out, 1); + sw->keyWritten = 0; + assure_size(&sw->out, 1); } else { - long size; - - key_check(sw, key); - size = sw->depth * sw->out.indent + 3; - assure_size(&sw->out, size); - maybe_comma(sw); - if (0 < sw->depth) { - fill_indent(&sw->out, sw->depth); - } - if (0 != key) { - oj_dump_cstr(key, strlen(key), 0, 0, &sw->out); - *sw->out.cur++ = ':'; - } + long size; + + key_check(sw, key); + size = sw->depth * sw->out.indent + 3; + assure_size(&sw->out, size); + maybe_comma(sw); + if (0 < sw->depth) { + fill_indent(&sw->out, sw->depth); + } + if (0 != key) { + oj_dump_cstr(key, strlen(key), 0, 0, &sw->out); + *sw->out.cur++ = ':'; + } } *sw->out.cur++ = '['; push_type(sw, ArrayNew); @@ -151,116 +151,102 @@ oj_str_writer_push_array(StrWriter sw, const char *key) { void oj_str_writer_push_value(StrWriter sw, VALUE val, const char *key) { - Out out = &sw->out; + Out out = &sw->out; if (sw->keyWritten) { - sw->keyWritten = 0; + sw->keyWritten = 0; } else { - long size; - - key_check(sw, key); - size = sw->depth * out->indent + 3; - assure_size(out, size); - maybe_comma(sw); - if (0 < sw->depth) { - fill_indent(&sw->out, sw->depth); - } - if (0 != key) { - oj_dump_cstr(key, strlen(key), 0, 0, out); - *out->cur++ = ':'; - } + long size; + + key_check(sw, key); + size = sw->depth * out->indent + 3; + assure_size(out, size); + maybe_comma(sw); + if (0 < sw->depth) { + fill_indent(&sw->out, sw->depth); + } + if (0 != key) { + oj_dump_cstr(key, strlen(key), 0, 0, out); + *out->cur++ = ':'; + } } switch (out->opts->mode) { - case StrictMode: - oj_dump_strict_val(val, sw->depth, out); - break; - case NullMode: - oj_dump_null_val(val, sw->depth, out); - break; - case ObjectMode: - oj_dump_obj_val(val, sw->depth, out); - break; - case CompatMode: - oj_dump_compat_val(val, sw->depth, out, Yes == out->opts->to_json); - break; - case RailsMode: - oj_dump_rails_val(val, sw->depth, out); - break; - case CustomMode: - oj_dump_custom_val(val, sw->depth, out, true); - break; - default: - oj_dump_custom_val(val, sw->depth, out, true); - break; + case StrictMode: oj_dump_strict_val(val, sw->depth, out); break; + case NullMode: oj_dump_null_val(val, sw->depth, out); break; + case ObjectMode: oj_dump_obj_val(val, sw->depth, out); break; + case CompatMode: oj_dump_compat_val(val, sw->depth, out, Yes == out->opts->to_json); break; + case RailsMode: oj_dump_rails_val(val, sw->depth, out); break; + case CustomMode: oj_dump_custom_val(val, sw->depth, out, true); break; + default: oj_dump_custom_val(val, sw->depth, out, true); break; } } void oj_str_writer_push_json(StrWriter sw, const char *json, const char *key) { if (sw->keyWritten) { - sw->keyWritten = 0; + sw->keyWritten = 0; } else { - long size; - - key_check(sw, key); - size = sw->depth * sw->out.indent + 3; - assure_size(&sw->out, size); - maybe_comma(sw); - if (0 < sw->depth) { - fill_indent(&sw->out, sw->depth); - } - if (0 != key) { - oj_dump_cstr(key, strlen(key), 0, 0, &sw->out); - *sw->out.cur++ = ':'; - } + long size; + + key_check(sw, key); + size = sw->depth * sw->out.indent + 3; + assure_size(&sw->out, size); + maybe_comma(sw); + if (0 < sw->depth) { + fill_indent(&sw->out, sw->depth); + } + if (0 != key) { + oj_dump_cstr(key, strlen(key), 0, 0, &sw->out); + *sw->out.cur++ = ':'; + } } oj_dump_raw(json, strlen(json), &sw->out); } void oj_str_writer_pop(StrWriter sw) { - long size; - DumpType type = sw->types[sw->depth]; + long size; + DumpType type = sw->types[sw->depth]; if (sw->keyWritten) { - sw->keyWritten = 0; - rb_raise(rb_eStandardError, "Can not pop after writing a key but no value."); + sw->keyWritten = 0; + rb_raise(rb_eStandardError, "Can not pop after writing a key but no value."); } sw->depth--; if (0 > sw->depth) { - rb_raise(rb_eStandardError, "Can not pop with no open array or object."); + rb_raise(rb_eStandardError, "Can not pop with no open array or object."); } size = sw->depth * sw->out.indent + 2; assure_size(&sw->out, size); fill_indent(&sw->out, sw->depth); switch (type) { - case ObjectNew: - case ObjectType: - *sw->out.cur++ = '}'; - break; - case ArrayNew: - case ArrayType: - *sw->out.cur++ = ']'; - break; + case ObjectNew: + case ObjectType: + *sw->out.cur++ = '}'; + break; + case ArrayNew: + case ArrayType: + *sw->out.cur++ = ']'; + break; } if (0 == sw->depth && 0 <= sw->out.indent) { - *sw->out.cur++ = '\n'; + *sw->out.cur++ = '\n'; } } void oj_str_writer_pop_all(StrWriter sw) { while (0 < sw->depth) { - oj_str_writer_pop(sw); + oj_str_writer_pop(sw); } } static void str_writer_free(void *ptr) { - StrWriter sw; + StrWriter sw; if (0 == ptr) { - return; + return; } sw = (StrWriter)ptr; xfree(sw->out.buf); @@ -286,11 +272,11 @@ str_writer_free(void *ptr) { */ static VALUE str_writer_new(int argc, VALUE *argv, VALUE self) { - StrWriter sw = ALLOC(struct _strWriter); + StrWriter sw = ALLOC(struct _strWriter); oj_str_writer_init(sw, 0); if (1 == argc) { - oj_parse_options(argv[0], &sw->opts); + oj_parse_options(argv[0], &sw->opts); } sw->out.argc = argc - 1; sw->out.argv = argv + 1; @@ -309,7 +295,7 @@ str_writer_new(int argc, VALUE *argv, VALUE self) { */ static VALUE str_writer_push_key(VALUE self, VALUE key) { - StrWriter sw = (StrWriter)DATA_PTR(self); + StrWriter sw = (StrWriter)DATA_PTR(self); rb_check_type(key, T_STRING); oj_str_writer_push_key(sw, StringValuePtr(key)); @@ -326,27 +312,27 @@ str_writer_push_key(VALUE self, VALUE key) { */ static VALUE str_writer_push_object(int argc, VALUE *argv, VALUE self) { - StrWriter sw = (StrWriter)DATA_PTR(self); + StrWriter sw = (StrWriter)DATA_PTR(self); switch (argc) { - case 0: - oj_str_writer_push_object(sw, 0); - break; - case 1: - if (Qnil == argv[0]) { - oj_str_writer_push_object(sw, 0); - } else { - rb_check_type(argv[0], T_STRING); - oj_str_writer_push_object(sw, StringValuePtr(argv[0])); - } - break; - default: - rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'."); - break; + case 0: + oj_str_writer_push_object(sw, 0); + break; + case 1: + if (Qnil == argv[0]) { + oj_str_writer_push_object(sw, 0); + } else { + rb_check_type(argv[0], T_STRING); + oj_str_writer_push_object(sw, StringValuePtr(argv[0])); + } + break; + default: + rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'."); + break; } if (rb_block_given_p()) { - rb_yield(Qnil); - oj_str_writer_pop(sw); + rb_yield(Qnil); + oj_str_writer_pop(sw); } return Qnil; } @@ -360,27 +346,27 @@ str_writer_push_object(int argc, VALUE *argv, VALUE self) { */ static VALUE str_writer_push_array(int argc, VALUE *argv, VALUE self) { - StrWriter sw = (StrWriter)DATA_PTR(self); + StrWriter sw = (StrWriter)DATA_PTR(self); switch (argc) { - case 0: - oj_str_writer_push_array(sw, 0); - break; - case 1: - if (Qnil == argv[0]) { - oj_str_writer_push_array(sw, 0); - } else { - rb_check_type(argv[0], T_STRING); - oj_str_writer_push_array(sw, StringValuePtr(argv[0])); - } - break; - default: - rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'."); - break; + case 0: + oj_str_writer_push_array(sw, 0); + break; + case 1: + if (Qnil == argv[0]) { + oj_str_writer_push_array(sw, 0); + } else { + rb_check_type(argv[0], T_STRING); + oj_str_writer_push_array(sw, StringValuePtr(argv[0])); + } + break; + default: + rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'."); + break; } if (rb_block_given_p()) { - rb_yield(Qnil); - oj_str_writer_pop(sw); + rb_yield(Qnil); + oj_str_writer_pop(sw); } return Qnil; } @@ -395,20 +381,20 @@ str_writer_push_array(int argc, VALUE *argv, VALUE self) { static VALUE str_writer_push_value(int argc, VALUE *argv, VALUE self) { switch (argc) { - case 1: - oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0); - break; - case 2: - if (Qnil == argv[1]) { - oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0); - } else { - rb_check_type(argv[1], T_STRING); - oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1])); - } - break; - default: - rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'."); - break; + case 1: + oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0); + break; + case 2: + if (Qnil == argv[1]) { + oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0); + } else { + rb_check_type(argv[1], T_STRING); + oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1])); + } + break; + default: + rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'."); + break; } return Qnil; } @@ -426,20 +412,20 @@ static VALUE str_writer_push_json(int argc, VALUE *argv, VALUE self) { rb_check_type(argv[0], T_STRING); switch (argc) { - case 1: - oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0); - break; - case 2: - if (Qnil == argv[1]) { - oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0); - } else { - rb_check_type(argv[1], T_STRING); - oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), StringValuePtr(argv[1])); - } - break; - default: - rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'."); - break; + case 1: + oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0); + break; + case 2: + if (Qnil == argv[1]) { + oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0); + } else { + rb_check_type(argv[1], T_STRING); + oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), StringValuePtr(argv[1])); + } + break; + default: + rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'."); + break; } return Qnil; } @@ -475,7 +461,7 @@ str_writer_pop_all(VALUE self) { */ static VALUE str_writer_reset(VALUE self) { - StrWriter sw = (StrWriter)DATA_PTR(self); + StrWriter sw = (StrWriter)DATA_PTR(self); sw->depth = 0; *sw->types = '\0'; @@ -495,8 +481,8 @@ str_writer_reset(VALUE self) { */ static VALUE str_writer_to_s(VALUE self) { - StrWriter sw = (StrWriter)DATA_PTR(self); - VALUE rstr = rb_str_new(sw->out.buf, sw->out.cur - sw->out.buf); + StrWriter sw = (StrWriter)DATA_PTR(self); + VALUE rstr = rb_str_new(sw->out.buf, sw->out.cur - sw->out.buf); return oj_encode(rstr); } @@ -514,7 +500,7 @@ str_writer_to_s(VALUE self) { static VALUE str_writer_as_json(VALUE self) { if (string_writer_optimized) { - return self; + return self; } return rb_hash_new(); } diff --git a/ext/oj/trace.c b/ext/oj/trace.c index 194402c2..8ad41ace 100644 --- a/ext/oj/trace.c +++ b/ext/oj/trace.c @@ -1,28 +1,28 @@ // Copyright (c) 2018 Peter Ohler. All rights reserved. // Licensed under the MIT License. See LICENSE file in the project root for license details. -#include "trace.h" #include "parse.h" +#include "trace.h" -#define MAX_INDENT 256 +#define MAX_INDENT 256 static void fill_indent(char *indent, int depth) { if (MAX_INDENT <= depth) { - depth = MAX_INDENT - 1; + depth = MAX_INDENT - 1; } else if (depth < 0) { - depth = 0; + depth = 0; } if (0 < depth) { - memset(indent, ' ', depth); + memset(indent, ' ', depth); } indent[depth] = '\0'; } void oj_trace(const char *func, VALUE obj, const char *file, int line, int depth, TraceWhere where) { - char fmt[64]; - char indent[MAX_INDENT]; + char fmt[64]; + char indent[MAX_INDENT]; depth *= 2; fill_indent(indent, depth); @@ -32,9 +32,9 @@ oj_trace(const char *func, VALUE obj, const char *file, int line, int depth, Tra void oj_trace_parse_call(const char *func, ParseInfo pi, const char *file, int line, VALUE obj) { - char fmt[64]; - char indent[MAX_INDENT]; - int depth = (int)(stack_size(&pi->stack) * 2); + char fmt[64]; + char indent[MAX_INDENT]; + int depth = (int)(stack_size(&pi->stack) * 2); fill_indent(indent, depth); sprintf(fmt, "#0:%%13s:%%3d:Oj:-:%%%ds %%s %%s\n", depth); @@ -43,9 +43,9 @@ oj_trace_parse_call(const char *func, ParseInfo pi, const char *file, int line, void oj_trace_parse_in(const char *func, ParseInfo pi, const char *file, int line) { - char fmt[64]; - char indent[MAX_INDENT]; - int depth = (int)(stack_size(&pi->stack) * 2); + char fmt[64]; + char indent[MAX_INDENT]; + int depth = (int)(stack_size(&pi->stack) * 2); fill_indent(indent, depth); sprintf(fmt, "#0:%%13s:%%3d:Oj:}:%%%ds %%s\n", depth); @@ -54,11 +54,11 @@ oj_trace_parse_in(const char *func, ParseInfo pi, const char *file, int line) { void oj_trace_parse_hash_end(ParseInfo pi, const char *file, int line) { - char fmt[64]; - char indent[MAX_INDENT]; - int depth = (int)(stack_size(&pi->stack) * 2 - 2); - Val v = stack_peek(&pi->stack); - VALUE obj = v->val; + char fmt[64]; + char indent[MAX_INDENT]; + int depth = (int)(stack_size(&pi->stack) * 2 - 2); + Val v = stack_peek(&pi->stack); + VALUE obj = v->val; fill_indent(indent, depth); sprintf(fmt, "#0:%%13s:%%3d:Oj:{:%%%ds hash_end %%s\n", depth); @@ -67,9 +67,9 @@ oj_trace_parse_hash_end(ParseInfo pi, const char *file, int line) { void oj_trace_parse_array_end(ParseInfo pi, const char *file, int line) { - char fmt[64]; - char indent[MAX_INDENT]; - int depth = (int)(stack_size(&pi->stack) * 2); + char fmt[64]; + char indent[MAX_INDENT]; + int depth = (int)(stack_size(&pi->stack) * 2); fill_indent(indent, depth); sprintf(fmt, "#0:%%13s:%%3d:Oj:{:%%%ds array_ned\n", depth); diff --git a/ext/oj/trace.h b/ext/oj/trace.h index ef2b846b..e73ea819 100644 --- a/ext/oj/trace.h +++ b/ext/oj/trace.h @@ -4,23 +4,23 @@ #ifndef OJ_TRACE_H #define OJ_TRACE_H -#include #include +#include typedef enum { - TraceIn = '}', - TraceOut = '{', - TraceCall = '-', - TraceRubyIn = '>', - TraceRubyOut = '<', + TraceIn = '}', + TraceOut = '{', + TraceCall = '-', + TraceRubyIn = '>', + TraceRubyOut = '<', } TraceWhere; struct _parseInfo; -extern void oj_trace(const char *func, VALUE obj, const char *file, int line, int depth, TraceWhere where); -extern void oj_trace_parse_in(const char *func, struct _parseInfo *pi, const char *file, int line); -extern void oj_trace_parse_call(const char *func, struct _parseInfo *pi, const char *file, int line, VALUE obj); -extern void oj_trace_parse_hash_end(struct _parseInfo *pi, const char *file, int line); -extern void oj_trace_parse_array_end(struct _parseInfo *pi, const char *file, int line); +extern void oj_trace(const char *func, VALUE obj, const char *file, int line, int depth, TraceWhere where); +extern void oj_trace_parse_in(const char *func, struct _parseInfo *pi, const char *file, int line); +extern void oj_trace_parse_call(const char *func, struct _parseInfo *pi, const char *file, int line, VALUE obj); +extern void oj_trace_parse_hash_end(struct _parseInfo *pi, const char *file, int line); +extern void oj_trace_parse_array_end(struct _parseInfo *pi, const char *file, int line); #endif /* OJ_TRACE_H */ diff --git a/ext/oj/util.c b/ext/oj/util.c index 057dfdc9..08742a2b 100644 --- a/ext/oj/util.c +++ b/ext/oj/util.c @@ -9,15 +9,15 @@ #include #include -#define SECS_PER_DAY 86400LL -#define SECS_PER_YEAR 31536000LL -#define SECS_PER_LEAP 31622400LL -#define SECS_PER_QUAD_YEAR (SECS_PER_YEAR * 3 + SECS_PER_LEAP) -#define SECS_PER_CENT (SECS_PER_QUAD_YEAR * 24 + SECS_PER_YEAR * 4) -#define SECS_PER_LEAP_CENT (SECS_PER_CENT + SECS_PER_DAY) -#define SECS_PER_QUAD_CENT (SECS_PER_CENT * 4 + SECS_PER_DAY) +#define SECS_PER_DAY 86400LL +#define SECS_PER_YEAR 31536000LL +#define SECS_PER_LEAP 31622400LL +#define SECS_PER_QUAD_YEAR (SECS_PER_YEAR * 3 + SECS_PER_LEAP) +#define SECS_PER_CENT (SECS_PER_QUAD_YEAR * 24 + SECS_PER_YEAR * 4) +#define SECS_PER_LEAP_CENT (SECS_PER_CENT + SECS_PER_DAY) +#define SECS_PER_QUAD_CENT (SECS_PER_CENT * 4 + SECS_PER_DAY) -static int64_t eom_secs[] = { +static int64_t eom_secs[] = { 2678400, // January (31) 5097600, // February (28) 2419200 2505600 7776000, // March (31) @@ -32,7 +32,7 @@ static int64_t eom_secs[] = { 31536000, // December (31) }; -static int64_t eom_leap_secs[] = { +static int64_t eom_leap_secs[] = { 2678400, // January (31) 5184000, // February (28) 2419200 2505600 7862400, // March (31) @@ -47,83 +47,84 @@ static int64_t eom_leap_secs[] = { 31622400, // December (31) }; + void sec_as_time(int64_t secs, TimeInfo ti) { - int64_t qc = 0; - int64_t c = 0; - int64_t qy = 0; - int64_t y = 0; - bool leap = false; - int64_t *ms; - int m; - int shift = 0; + int64_t qc = 0; + int64_t c = 0; + int64_t qy = 0; + int64_t y = 0; + bool leap = false; + int64_t *ms; + int m; + int shift = 0; secs += 62167219200LL; // normalize to first day of the year 0 if (secs < 0) { - shift = -secs / SECS_PER_QUAD_CENT; - shift++; - secs += shift * SECS_PER_QUAD_CENT; + shift = -secs / SECS_PER_QUAD_CENT; + shift++; + secs += shift * SECS_PER_QUAD_CENT; } qc = secs / SECS_PER_QUAD_CENT; secs = secs - qc * SECS_PER_QUAD_CENT; if (secs < SECS_PER_LEAP) { - leap = true; + leap = true; } else if (secs < SECS_PER_QUAD_YEAR) { - if (SECS_PER_LEAP <= secs) { - secs -= SECS_PER_LEAP; - y = secs / SECS_PER_YEAR; - secs = secs - y * SECS_PER_YEAR; - y++; - leap = false; - } + if (SECS_PER_LEAP <= secs) { + secs -= SECS_PER_LEAP; + y = secs / SECS_PER_YEAR; + secs = secs - y * SECS_PER_YEAR; + y++; + leap = false; + } } else if (secs < SECS_PER_LEAP_CENT) { // first century in 400 years is a leap century (one extra day) - qy = secs / SECS_PER_QUAD_YEAR; - secs = secs - qy * SECS_PER_QUAD_YEAR; - if (secs < SECS_PER_LEAP) { - leap = true; - } else { - secs -= SECS_PER_LEAP; - y = secs / SECS_PER_YEAR; - secs = secs - y * SECS_PER_YEAR; - y++; - } + qy = secs / SECS_PER_QUAD_YEAR; + secs = secs - qy * SECS_PER_QUAD_YEAR; + if (secs < SECS_PER_LEAP) { + leap = true; + } else { + secs -= SECS_PER_LEAP; + y = secs / SECS_PER_YEAR; + secs = secs - y * SECS_PER_YEAR; + y++; + } } else { - secs -= SECS_PER_LEAP_CENT; - c = secs / SECS_PER_CENT; - secs = secs - c * SECS_PER_CENT; - c++; - if (secs < SECS_PER_YEAR * 4) { - y = secs / SECS_PER_YEAR; - secs = secs - y * SECS_PER_YEAR; - } else { - secs -= SECS_PER_YEAR * 4; - qy = secs / SECS_PER_QUAD_YEAR; - secs = secs - qy * SECS_PER_QUAD_YEAR; - qy++; - if (secs < SECS_PER_LEAP) { - leap = true; - } else { - secs -= SECS_PER_LEAP; - y = secs / SECS_PER_YEAR; - secs = secs - y * SECS_PER_YEAR; - y++; - } - } + secs -= SECS_PER_LEAP_CENT; + c = secs / SECS_PER_CENT; + secs = secs - c * SECS_PER_CENT; + c++; + if (secs < SECS_PER_YEAR * 4) { + y = secs / SECS_PER_YEAR; + secs = secs - y * SECS_PER_YEAR; + } else { + secs -= SECS_PER_YEAR * 4; + qy = secs / SECS_PER_QUAD_YEAR; + secs = secs - qy * SECS_PER_QUAD_YEAR; + qy++; + if (secs < SECS_PER_LEAP) { + leap = true; + } else { + secs -= SECS_PER_LEAP; + y = secs / SECS_PER_YEAR; + secs = secs - y * SECS_PER_YEAR; + y++; + } + } } ti->year = (int)((qc - (int64_t)shift) * 400 + c * 100 + qy * 4 + y); if (leap) { - ms = eom_leap_secs; + ms = eom_leap_secs; } else { - ms = eom_secs; + ms = eom_secs; } for (m = 1; m <= 12; m++, ms++) { - if (secs < *ms) { - if (1 < m) { - secs -= *(ms - 1); - } - ti->mon = m; - break; - } + if (secs < *ms) { + if (1 < m) { + secs -= *(ms - 1); + } + ti->mon = m; + break; + } } ti->day = (int)(secs / 86400LL); secs = secs - (int64_t)ti->day * 86400LL; diff --git a/ext/oj/util.h b/ext/oj/util.h index 147d99ca..fff9eb6b 100644 --- a/ext/oj/util.h +++ b/ext/oj/util.h @@ -13,8 +13,8 @@ typedef struct _timeInfo { int day; int mon; int year; -} * TimeInfo; +} *TimeInfo; -extern void sec_as_time(int64_t secs, TimeInfo ti); +extern void sec_as_time(int64_t secs, TimeInfo ti); #endif /* OJ_UTIL_H */ diff --git a/ext/oj/val_stack.c b/ext/oj/val_stack.c index 5c2613d8..624db0d0 100644 --- a/ext/oj/val_stack.c +++ b/ext/oj/val_stack.c @@ -3,17 +3,17 @@ #include -#include "odd.h" #include "oj.h" +#include "odd.h" #include "val_stack.h" static void mark(void *ptr) { - ValStack stack = (ValStack)ptr; - Val v; + ValStack stack = (ValStack)ptr; + Val v; if (0 == ptr) { - return; + return; } #ifdef HAVE_PTHREAD_MUTEX_INIT pthread_mutex_lock(&stack->mutex); @@ -22,22 +22,22 @@ mark(void *ptr) { rb_gc_mark(stack->mutex); #endif for (v = stack->head; v < stack->tail; v++) { - if (Qnil != v->val && Qundef != v->val) { - rb_gc_mark(v->val); - } - if (Qnil != v->key_val && Qundef != v->key_val) { - rb_gc_mark(v->key_val); - } - if (NULL != v->odd_args) { - VALUE *a; - int i; + if (Qnil != v->val && Qundef != v->val) { + rb_gc_mark(v->val); + } + if (Qnil != v->key_val && Qundef != v->key_val) { + rb_gc_mark(v->key_val); + } + if (NULL != v->odd_args) { + VALUE *a; + int i; - for (i = v->odd_args->odd->attr_cnt, a = v->odd_args->args; 0 < i; i--, a++) { - if (Qnil != *a) { - rb_gc_mark(*a); - } - } - } + for (i = v->odd_args->odd->attr_cnt, a = v->odd_args->args; 0 < i; i--, a++) { + if (Qnil != *a) { + rb_gc_mark(*a); + } + } + } } #ifdef HAVE_PTHREAD_MUTEX_INIT pthread_mutex_unlock(&stack->mutex); @@ -49,10 +49,10 @@ mark(void *ptr) { VALUE oj_stack_init(ValStack stack) { #ifdef HAVE_PTHREAD_MUTEX_INIT - int err; + int err; if (0 != (err = pthread_mutex_init(&stack->mutex, 0))) { - rb_raise(rb_eException, "failed to initialize a mutex. %s", strerror(err)); + rb_raise(rb_eException, "failed to initialize a mutex. %s", strerror(err)); } #else stack->mutex = rb_mutex_new(); @@ -73,29 +73,19 @@ oj_stack_init(ValStack stack) { return Data_Wrap_Struct(oj_cstack_class, mark, 0, stack); } -const char * +const char* oj_stack_next_string(ValNext n) { switch (n) { - case NEXT_ARRAY_NEW: - return "array element or close"; - case NEXT_ARRAY_ELEMENT: - return "array element"; - case NEXT_ARRAY_COMMA: - return "comma"; - case NEXT_HASH_NEW: - return "hash pair or close"; - case NEXT_HASH_KEY: - return "hash key"; - case NEXT_HASH_COLON: - return "colon"; - case NEXT_HASH_VALUE: - return "hash value"; - case NEXT_HASH_COMMA: - return "comma"; - case NEXT_NONE: - break; - default: - break; + case NEXT_ARRAY_NEW: return "array element or close"; + case NEXT_ARRAY_ELEMENT: return "array element"; + case NEXT_ARRAY_COMMA: return "comma"; + case NEXT_HASH_NEW: return "hash pair or close"; + case NEXT_HASH_KEY: return "hash key"; + case NEXT_HASH_COLON: return "colon"; + case NEXT_HASH_VALUE: return "hash value"; + case NEXT_HASH_COMMA: return "comma"; + case NEXT_NONE: break; + default: break; } return "nothing"; } diff --git a/ext/oj/val_stack.h b/ext/oj/val_stack.h index ef12df99..2df8fa99 100644 --- a/ext/oj/val_stack.h +++ b/ext/oj/val_stack.h @@ -4,56 +4,56 @@ #ifndef OJ_VAL_STACK_H #define OJ_VAL_STACK_H -#include "odd.h" #include "ruby.h" +#include "odd.h" #include #ifdef HAVE_PTHREAD_MUTEX_INIT #include #endif -#define STACK_INC 64 +#define STACK_INC 64 typedef enum { - NEXT_NONE = 0, - NEXT_ARRAY_NEW = 'a', - NEXT_ARRAY_ELEMENT = 'e', - NEXT_ARRAY_COMMA = ',', - NEXT_HASH_NEW = 'h', - NEXT_HASH_KEY = 'k', - NEXT_HASH_COLON = ':', - NEXT_HASH_VALUE = 'v', - NEXT_HASH_COMMA = 'n', + NEXT_NONE = 0, + NEXT_ARRAY_NEW = 'a', + NEXT_ARRAY_ELEMENT = 'e', + NEXT_ARRAY_COMMA = ',', + NEXT_HASH_NEW = 'h', + NEXT_HASH_KEY = 'k', + NEXT_HASH_COLON = ':', + NEXT_HASH_VALUE = 'v', + NEXT_HASH_COMMA = 'n', } ValNext; typedef struct _val { - volatile VALUE val; - const char *key; - char karray[32]; - volatile VALUE key_val; - const char *classname; - VALUE clas; - OddArgs odd_args; - uint16_t klen; - uint16_t clen; - char next; // ValNext - char k1; // first original character in the key - char kalloc; -} * Val; + volatile VALUE val; + const char *key; + char karray[32]; + volatile VALUE key_val; + const char *classname; + VALUE clas; + OddArgs odd_args; + uint16_t klen; + uint16_t clen; + char next; // ValNext + char k1; // first original character in the key + char kalloc; +} *Val; typedef struct _valStack { - struct _val base[STACK_INC]; - Val head; // current stack - Val end; // stack end - Val tail; // pointer to one past last element name on stack + struct _val base[STACK_INC]; + Val head; // current stack + Val end; // stack end + Val tail; // pointer to one past last element name on stack #ifdef HAVE_PTHREAD_MUTEX_INIT - pthread_mutex_t mutex; + pthread_mutex_t mutex; #else - VALUE mutex; + VALUE mutex; #endif -} * ValStack; +} *ValStack; -extern VALUE oj_stack_init(ValStack stack); +extern VALUE oj_stack_init(ValStack stack); inline static int stack_empty(ValStack stack) { @@ -64,37 +64,37 @@ inline static void stack_cleanup(ValStack stack) { if (stack->base != stack->head) { xfree(stack->head); - stack->head = NULL; + stack->head = NULL; } } inline static void stack_push(ValStack stack, VALUE val, ValNext next) { if (stack->end <= stack->tail) { - size_t len = stack->end - stack->head; - size_t toff = stack->tail - stack->head; - Val head = stack->head; - - // A realloc can trigger a GC so make sure it happens outside the lock - // but lock before changing pointers. - if (stack->base == stack->head) { - head = ALLOC_N(struct _val, len + STACK_INC); - memcpy(head, stack->base, sizeof(struct _val) * len); - } else { - REALLOC_N(head, struct _val, len + STACK_INC); - } + size_t len = stack->end - stack->head; + size_t toff = stack->tail - stack->head; + Val head = stack->head; + + // A realloc can trigger a GC so make sure it happens outside the lock + // but lock before changing pointers. + if (stack->base == stack->head) { + head = ALLOC_N(struct _val, len + STACK_INC); + memcpy(head, stack->base, sizeof(struct _val) * len); + } else { + REALLOC_N(head, struct _val, len + STACK_INC); + } #ifdef HAVE_PTHREAD_MUTEX_INIT - pthread_mutex_lock(&stack->mutex); + pthread_mutex_lock(&stack->mutex); #else - rb_mutex_lock(stack->mutex); + rb_mutex_lock(stack->mutex); #endif - stack->head = head; - stack->tail = stack->head + toff; - stack->end = stack->head + len + STACK_INC; + stack->head = head; + stack->tail = stack->head + toff; + stack->end = stack->head + len + STACK_INC; #ifdef HAVE_PTHREAD_MUTEX_INIT - pthread_mutex_unlock(&stack->mutex); + pthread_mutex_unlock(&stack->mutex); #else - rb_mutex_unlock(stack->mutex); + rb_mutex_unlock(stack->mutex); #endif } stack->tail->val = val; @@ -118,7 +118,7 @@ stack_size(ValStack stack) { inline static Val stack_peek(ValStack stack) { if (stack->head < stack->tail) { - return stack->tail - 1; + return stack->tail - 1; } return 0; } @@ -126,7 +126,7 @@ stack_peek(ValStack stack) { inline static Val stack_peek_up(ValStack stack) { if (stack->head < stack->tail - 1) { - return stack->tail - 2; + return stack->tail - 2; } return 0; } @@ -139,7 +139,7 @@ stack_prev(ValStack stack) { inline static VALUE stack_head_val(ValStack stack) { if (Qundef != stack->head->val) { - return stack->head->val; + return stack->head->val; } return Qnil; } @@ -147,12 +147,12 @@ stack_head_val(ValStack stack) { inline static Val stack_pop(ValStack stack) { if (stack->head < stack->tail) { - stack->tail--; - return stack->tail; + stack->tail--; + return stack->tail; } return 0; } -extern const char *oj_stack_next_string(ValNext n); +extern const char* oj_stack_next_string(ValNext n); #endif /* OJ_VAL_STACK_H */ diff --git a/ext/oj/wab.c b/ext/oj/wab.c index 20f1ffc1..931e8562 100644 --- a/ext/oj/wab.c +++ b/ext/oj/wab.c @@ -1,24 +1,24 @@ // Copyright (c) 2012 Peter Ohler. All rights reserved. // Licensed under the MIT License. See LICENSE file in the project root for license details. -#include #include +#include #include #include #include -#include "dump.h" -#include "encode.h" -#include "err.h" #include "oj.h" +#include "err.h" #include "parse.h" +#include "encode.h" +#include "dump.h" #include "trace.h" #include "util.h" // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS -#define OJ_INFINITY (1.0 / 0.0) +#define OJ_INFINITY (1.0/0.0) -static char hex_chars[256] = "\ +static char hex_chars[256] = "\ ................................\ ................xxxxxxxxxx......\ .xxxxxx.........................\ @@ -28,24 +28,24 @@ static char hex_chars[256] = "\ ................................\ ................................"; -static VALUE wab_uuid_clas = Qundef; -static VALUE uri_clas = Qundef; -static VALUE uri_http_clas = Qundef; +static VALUE wab_uuid_clas = Qundef; +static VALUE uri_clas = Qundef; +static VALUE uri_http_clas = Qundef; ///// dump functions ///// static VALUE resolve_wab_uuid_class() { if (Qundef == wab_uuid_clas) { - volatile VALUE wab_module; + volatile VALUE wab_module; - wab_uuid_clas = Qnil; - if (rb_const_defined_at(rb_cObject, rb_intern("WAB"))) { - wab_module = rb_const_get_at(rb_cObject, rb_intern("WAB")); - if (rb_const_defined_at(wab_module, rb_intern("UUID"))) { - wab_uuid_clas = rb_const_get(wab_module, rb_intern("UUID")); - } - } + wab_uuid_clas = Qnil; + if (rb_const_defined_at(rb_cObject, rb_intern("WAB"))) { + wab_module = rb_const_get_at(rb_cObject, rb_intern("WAB")); + if (rb_const_defined_at(wab_module, rb_intern("UUID"))) { + wab_uuid_clas = rb_const_get(wab_module, rb_intern("UUID")); + } + } } return wab_uuid_clas; } @@ -54,10 +54,10 @@ static VALUE resolve_uri_class() { if (Qundef == uri_clas) { - uri_clas = Qnil; - if (rb_const_defined_at(rb_cObject, rb_intern("URI"))) { - uri_clas = rb_const_get_at(rb_cObject, rb_intern("URI")); - } + uri_clas = Qnil; + if (rb_const_defined_at(rb_cObject, rb_intern("URI"))) { + uri_clas = rb_const_get_at(rb_cObject, rb_intern("URI")); + } } return uri_clas; } @@ -65,15 +65,15 @@ resolve_uri_class() { static VALUE resolve_uri_http_class() { if (Qundef == uri_http_clas) { - volatile VALUE uri_module; + volatile VALUE uri_module; - uri_http_clas = Qnil; - if (rb_const_defined_at(rb_cObject, rb_intern("URI"))) { - uri_module = rb_const_get_at(rb_cObject, rb_intern("URI")); - if (rb_const_defined_at(uri_module, rb_intern("HTTP"))) { - uri_http_clas = rb_const_get(uri_module, rb_intern("HTTP")); - } - } + uri_http_clas = Qnil; + if (rb_const_defined_at(rb_cObject, rb_intern("URI"))) { + uri_module = rb_const_get_at(rb_cObject, rb_intern("URI")); + if (rb_const_defined_at(uri_module, rb_intern("HTTP"))) { + uri_http_clas = rb_const_get(uri_module, rb_intern("HTTP")); + } + } } return uri_http_clas; } @@ -86,74 +86,74 @@ raise_wab(VALUE obj) { // Removed dependencies on math due to problems with CentOS 5.4. static void dump_float(VALUE obj, int depth, Out out, bool as_ok) { - char buf[64]; - char *b; - double d = rb_num2dbl(obj); - int cnt = 0; + char buf[64]; + char *b; + double d = rb_num2dbl(obj); + int cnt = 0; if (0.0 == d) { - b = buf; - *b++ = '0'; - *b++ = '.'; - *b++ = '0'; - *b++ = '\0'; - cnt = 3; + b = buf; + *b++ = '0'; + *b++ = '.'; + *b++ = '0'; + *b++ = '\0'; + cnt = 3; } else { - if (OJ_INFINITY == d || -OJ_INFINITY == d || isnan(d)) { - raise_wab(obj); - } else if (d == (double)(long long int)d) { - cnt = snprintf(buf, sizeof(buf), "%.1f", d); - } else { - cnt = snprintf(buf, sizeof(buf), "%0.16g", d); - } + if (OJ_INFINITY == d || -OJ_INFINITY == d || isnan(d)) { + raise_wab(obj); + } else if (d == (double)(long long int)d) { + cnt = snprintf(buf, sizeof(buf), "%.1f", d); + } else { + cnt = snprintf(buf, sizeof(buf), "%0.16g", d); + } } assure_size(out, cnt); for (b = buf; '\0' != *b; b++) { - *out->cur++ = *b; + *out->cur++ = *b; } *out->cur = '\0'; } static void dump_array(VALUE a, int depth, Out out, bool as_ok) { - size_t size; - int i, cnt; - int d2 = depth + 1; + size_t size; + int i, cnt; + int d2 = depth + 1; cnt = (int)RARRAY_LEN(a); *out->cur++ = '['; size = 2; assure_size(out, size); if (0 == cnt) { - *out->cur++ = ']'; + *out->cur++ = ']'; } else { - size = d2 * out->indent + 2; - cnt--; - for (i = 0; i <= cnt; i++) { - assure_size(out, size); - fill_indent(out, d2); - oj_dump_wab_val(rb_ary_entry(a, i), d2, out); - if (i < cnt) { - *out->cur++ = ','; - } - } - size = depth * out->indent + 1; - assure_size(out, size); - fill_indent(out, depth); - *out->cur++ = ']'; + size = d2 * out->indent + 2; + cnt--; + for (i = 0; i <= cnt; i++) { + assure_size(out, size); + fill_indent(out, d2); + oj_dump_wab_val(rb_ary_entry(a, i), d2, out); + if (i < cnt) { + *out->cur++ = ','; + } + } + size = depth * out->indent + 1; + assure_size(out, size); + fill_indent(out, depth); + *out->cur++ = ']'; } *out->cur = '\0'; } static int hash_cb(VALUE key, VALUE value, VALUE ov) { - Out out = (Out)ov; - int depth = out->depth; - long size; - int rtype = rb_type(key); + Out out = (Out)ov; + int depth = out->depth; + long size; + int rtype = rb_type(key); if (rtype != T_SYMBOL) { - rb_raise(rb_eTypeError, "In :wab mode all Hash keys must be Symbols, not %s.\n", rb_class2name(rb_obj_class(key))); + rb_raise(rb_eTypeError, "In :wab mode all Hash keys must be Symbols, not %s.\n", rb_class2name(rb_obj_class(key))); } size = depth * out->indent + 1; assure_size(out, size); @@ -169,45 +169,45 @@ hash_cb(VALUE key, VALUE value, VALUE ov) { static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) { - int cnt; - size_t size; + int cnt; + size_t size; cnt = (int)RHASH_SIZE(obj); size = depth * out->indent + 2; assure_size(out, 2); *out->cur++ = '{'; if (0 == cnt) { - *out->cur++ = '}'; + *out->cur++ = '}'; } else { - out->depth = depth + 1; - rb_hash_foreach(obj, hash_cb, (VALUE)out); - if (',' == *(out->cur - 1)) { - out->cur--; // backup to overwrite last comma - } - assure_size(out, size); - fill_indent(out, depth); - *out->cur++ = '}'; + out->depth = depth + 1; + rb_hash_foreach(obj, hash_cb, (VALUE)out); + if (',' == *(out->cur - 1)) { + out->cur--; // backup to overwrite last comma + } + assure_size(out, size); + fill_indent(out, depth); + *out->cur++ = '}'; } *out->cur = '\0'; } static void dump_time(VALUE obj, Out out) { - char buf[64]; - struct _timeInfo ti; - int len; - time_t sec; - long long nsec; + char buf[64]; + struct _timeInfo ti; + int len; + time_t sec; + long long nsec; #ifdef HAVE_RB_TIME_TIMESPEC if (16 <= sizeof(struct timespec)) { - struct timespec ts = rb_time_timespec(obj); + struct timespec ts = rb_time_timespec(obj); - sec = ts.tv_sec; - nsec = ts.tv_nsec; + sec = ts.tv_sec; + nsec = ts.tv_nsec; } else { - sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0)); - nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0)); + sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0)); + nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0)); } #else sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0)); @@ -224,68 +224,68 @@ dump_time(VALUE obj, Out out) { static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) { - volatile VALUE clas = rb_obj_class(obj); + volatile VALUE clas = rb_obj_class(obj); if (rb_cTime == clas) { - dump_time(obj, out); + dump_time(obj, out); } else if (oj_bigdecimal_class == clas) { - volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); + volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0); - oj_dump_raw(rb_string_value_ptr((VALUE *)&rstr), (int)RSTRING_LEN(rstr), out); + oj_dump_raw(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), out); } else if (resolve_wab_uuid_class() == clas) { - oj_dump_str(rb_funcall(obj, oj_to_s_id, 0), depth, out, false); + oj_dump_str(rb_funcall(obj, oj_to_s_id, 0), depth, out, false); } else if (resolve_uri_http_class() == clas) { - oj_dump_str(rb_funcall(obj, oj_to_s_id, 0), depth, out, false); + oj_dump_str(rb_funcall(obj, oj_to_s_id, 0), depth, out, false); } else { - raise_wab(obj); - } -} - -static DumpFunc wab_funcs[] = { - NULL, // RUBY_T_NONE = 0x00, - dump_obj, // RUBY_T_OBJECT = 0x01, - NULL, // RUBY_T_CLASS = 0x02, - NULL, // RUBY_T_MODULE = 0x03, - dump_float, // RUBY_T_FLOAT = 0x04, - oj_dump_str, // RUBY_T_STRING = 0x05, - NULL, // RUBY_T_REGEXP = 0x06, - dump_array, // RUBY_T_ARRAY = 0x07, - dump_hash, // RUBY_T_HASH = 0x08, - NULL, // RUBY_T_STRUCT = 0x09, - oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a, - NULL, // RUBY_T_FILE = 0x0b, - dump_obj, // RUBY_T_DATA = 0x0c, - NULL, // RUBY_T_MATCH = 0x0d, - NULL, // RUBY_T_COMPLEX = 0x0e, - NULL, // RUBY_T_RATIONAL = 0x0f, - NULL, // 0x10 - oj_dump_nil, // RUBY_T_NIL = 0x11, - oj_dump_true, // RUBY_T_TRUE = 0x12, - oj_dump_false, // RUBY_T_FALSE = 0x13, - oj_dump_sym, // RUBY_T_SYMBOL = 0x14, - oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15, + raise_wab(obj); + } +} + +static DumpFunc wab_funcs[] = { + NULL, // RUBY_T_NONE = 0x00, + dump_obj, // RUBY_T_OBJECT = 0x01, + NULL, // RUBY_T_CLASS = 0x02, + NULL, // RUBY_T_MODULE = 0x03, + dump_float, // RUBY_T_FLOAT = 0x04, + oj_dump_str, // RUBY_T_STRING = 0x05, + NULL, // RUBY_T_REGEXP = 0x06, + dump_array, // RUBY_T_ARRAY = 0x07, + dump_hash, // RUBY_T_HASH = 0x08, + NULL, // RUBY_T_STRUCT = 0x09, + oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a, + NULL, // RUBY_T_FILE = 0x0b, + dump_obj, // RUBY_T_DATA = 0x0c, + NULL, // RUBY_T_MATCH = 0x0d, + NULL, // RUBY_T_COMPLEX = 0x0e, + NULL, // RUBY_T_RATIONAL = 0x0f, + NULL, // 0x10 + oj_dump_nil, // RUBY_T_NIL = 0x11, + oj_dump_true, // RUBY_T_TRUE = 0x12, + oj_dump_false, // RUBY_T_FALSE = 0x13, + oj_dump_sym, // RUBY_T_SYMBOL = 0x14, + oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15, }; void oj_dump_wab_val(VALUE obj, int depth, Out out) { - int type = rb_type(obj); + int type = rb_type(obj); if (Yes == out->opts->trace) { - oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn); + oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn); } if (MAX_DEPTH < depth) { - rb_raise(rb_eNoMemError, "Too deeply nested.\n"); + rb_raise(rb_eNoMemError, "Too deeply nested.\n"); } if (0 < type && type <= RUBY_T_FIXNUM) { - DumpFunc f = wab_funcs[type]; + DumpFunc f = wab_funcs[type]; - if (NULL != f) { - f(obj, depth, out, false); - if (Yes == out->opts->trace) { - oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut); - } - return; - } + if (NULL != f) { + f(obj, depth, out, false); + if (Yes == out->opts->trace) { + oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut); + } + return; + } } raise_wab(obj); } @@ -295,14 +295,14 @@ oj_dump_wab_val(VALUE obj, int depth, Out out) { static void hash_end(ParseInfo pi) { if (Yes == pi->options.trace) { - oj_trace_parse_hash_end(pi, __FILE__, __LINE__); + oj_trace_parse_hash_end(pi, __FILE__, __LINE__); } } static void array_end(ParseInfo pi) { if (Yes == pi->options.trace) { - oj_trace_parse_array_end(pi, __FILE__, __LINE__); + oj_trace_parse_array_end(pi, __FILE__, __LINE__); } } @@ -314,7 +314,7 @@ noop_hash_key(ParseInfo pi, const char *key, size_t klen) { static void add_value(ParseInfo pi, VALUE val) { if (Yes == pi->options.trace) { - oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val); + oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val); } pi->stack.head->val = val; } @@ -322,50 +322,50 @@ add_value(ParseInfo pi, VALUE val) { // 123e4567-e89b-12d3-a456-426655440000 static bool uuid_check(const char *str, int len) { - int i; + int i; for (i = 0; i < 8; i++, str++) { - if ('x' != hex_chars[*(uint8_t *)str]) { - return false; - } + if ('x' != hex_chars[*(uint8_t*)str]) { + return false; + } } str++; for (i = 0; i < 4; i++, str++) { - if ('x' != hex_chars[*(uint8_t *)str]) { - return false; - } + if ('x' != hex_chars[*(uint8_t*)str]) { + return false; + } } str++; for (i = 0; i < 4; i++, str++) { - if ('x' != hex_chars[*(uint8_t *)str]) { - return false; - } + if ('x' != hex_chars[*(uint8_t*)str]) { + return false; + } } str++; for (i = 0; i < 4; i++, str++) { - if ('x' != hex_chars[*(uint8_t *)str]) { - return false; - } + if ('x' != hex_chars[*(uint8_t*)str]) { + return false; + } } str++; for (i = 0; i < 12; i++, str++) { - if ('x' != hex_chars[*(uint8_t *)str]) { - return false; - } + if ('x' != hex_chars[*(uint8_t*)str]) { + return false; + } } return true; } -static const char * +static const char* read_num(const char *s, int len, int *vp) { - uint32_t v = 0; + uint32_t v = 0; for (; 0 < len; len--, s++) { - if ('0' <= *s && *s <= '9') { - v = v * 10 + *s - '0'; - } else { - return NULL; - } + if ('0' <= *s && *s <= '9') { + v = v * 10 + *s - '0'; + } else { + return NULL; + } } *vp = (int)v; @@ -374,54 +374,54 @@ read_num(const char *s, int len, int *vp) { static VALUE time_parse(const char *s, int len) { - struct tm tm; - bool neg = false; - long nsecs = 0; - int i; - time_t secs; + struct tm tm; + bool neg = false; + long nsecs = 0; + int i; + time_t secs; memset(&tm, 0, sizeof(tm)); if ('-' == *s) { - s++; - neg = true; + s++; + neg = true; } if (NULL == (s = read_num(s, 4, &tm.tm_year))) { - return Qnil; + return Qnil; } if (neg) { - tm.tm_year = -tm.tm_year; - neg = false; + tm.tm_year = -tm.tm_year; + neg = false; } tm.tm_year -= 1900; s++; if (NULL == (s = read_num(s, 2, &tm.tm_mon))) { - return Qnil; + return Qnil; } tm.tm_mon--; s++; if (NULL == (s = read_num(s, 2, &tm.tm_mday))) { - return Qnil; + return Qnil; } s++; if (NULL == (s = read_num(s, 2, &tm.tm_hour))) { - return Qnil; + return Qnil; } s++; if (NULL == (s = read_num(s, 2, &tm.tm_min))) { - return Qnil; + return Qnil; } s++; if (NULL == (s = read_num(s, 2, &tm.tm_sec))) { - return Qnil; + return Qnil; } s++; for (i = 9; 0 < i; i--, s++) { - if ('0' <= *s && *s <= '9') { - nsecs = nsecs * 10 + *s - '0'; - } else { - return Qnil; - } + if ('0' <= *s && *s <= '9') { + nsecs = nsecs * 10 + *s - '0'; + } else { + return Qnil; + } } #if IS_WINDOWS secs = (time_t)mktime(&tm); @@ -442,24 +442,24 @@ protect_uri(VALUE rstr) { static VALUE cstr_to_rstr(const char *str, size_t len) { - volatile VALUE v = Qnil; + volatile VALUE v = Qnil; - if (30 == len && '-' == str[4] && '-' == str[7] && 'T' == str[10] && ':' == str[13] && ':' == str[16] && '.' == str[19] && 'Z' == str[29]) { - if (Qnil != (v = time_parse(str, (int)len))) { - return v; - } + if (30 == len && '-' == str[4] && '-' == str[7] && 'T' == str[10] && ':' == str[13] && ':' == str[16] && '.' == str[19] && 'Z' == str[29]) { + if (Qnil != (v = time_parse(str, (int)len))) { + return v; + } } if (36 == len && '-' == str[8] && '-' == str[13] && '-' == str[18] && '-' == str[23] && uuid_check(str, (int)len) && Qnil != resolve_wab_uuid_class()) { - return rb_funcall(wab_uuid_clas, oj_new_id, 1, rb_str_new(str, len)); + return rb_funcall(wab_uuid_clas, oj_new_id, 1, rb_str_new(str, len)); } v = rb_str_new(str, len); if (7 < len && 0 == strncasecmp("http://", str, 7)) { - int err = 0; - volatile VALUE uri = rb_protect(protect_uri, v, &err); + int err = 0; + volatile VALUE uri = rb_protect(protect_uri, v, &err); - if (0 == err) { - return uri; - } + if (0 == err) { + return uri; + } } return oj_encode(v); } @@ -468,38 +468,38 @@ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { pi->stack.head->val = cstr_to_rstr(str, len); if (Yes == pi->options.trace) { - oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val); + oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val); } } static void add_num(ParseInfo pi, NumInfo ni) { if (ni->infinity || ni->nan) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); } pi->stack.head->val = oj_num_as_value(ni); if (Yes == pi->options.trace) { - oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val); + oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val); } } static VALUE start_hash(ParseInfo pi) { if (Yes == pi->options.trace) { - oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__); + oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__); } if (Qnil != pi->options.hash_class) { - return rb_class_new_instance(0, NULL, pi->options.hash_class); + return rb_class_new_instance(0, NULL, pi->options.hash_class); } return rb_hash_new(); } static VALUE calc_hash_key(ParseInfo pi, Val parent) { - volatile VALUE rkey = parent->key_val; + volatile VALUE rkey = parent->key_val; if (Qundef == rkey) { - rkey = rb_str_new(parent->key, parent->klen); + rkey = rb_str_new(parent->key, parent->klen); } rkey = oj_encode(rkey); rkey = rb_str_intern(rkey); @@ -509,25 +509,25 @@ calc_hash_key(ParseInfo pi, Val parent) { static void hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) { - volatile VALUE rval = cstr_to_rstr(str, len); + volatile VALUE rval = cstr_to_rstr(str, len); rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval); if (Yes == pi->options.trace) { - oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval); + oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval); } } static void hash_set_num(ParseInfo pi, Val parent, NumInfo ni) { - volatile VALUE rval = Qnil; + volatile VALUE rval = Qnil; if (ni->infinity || ni->nan) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); } rval = oj_num_as_value(ni); rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval); if (Yes == pi->options.trace) { - oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval); + oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval); } } @@ -535,39 +535,39 @@ static void hash_set_value(ParseInfo pi, Val parent, VALUE value) { rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value); if (Yes == pi->options.trace) { - oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value); + oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value); } } static VALUE start_array(ParseInfo pi) { if (Yes == pi->options.trace) { - oj_trace_parse_in("start_array", pi, __FILE__, __LINE__); + oj_trace_parse_in("start_array", pi, __FILE__, __LINE__); } return rb_ary_new(); } static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { - volatile VALUE rval = cstr_to_rstr(str, len); + volatile VALUE rval = cstr_to_rstr(str, len); rb_ary_push(stack_peek(&pi->stack)->val, rval); if (Yes == pi->options.trace) { - oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, rval); + oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, rval); } } static void array_append_num(ParseInfo pi, NumInfo ni) { - volatile VALUE rval = Qnil; + volatile VALUE rval = Qnil; if (ni->infinity || ni->nan) { - oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); + oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value"); } rval = oj_num_as_value(ni); rb_ary_push(stack_peek(&pi->stack)->val, rval); if (Yes == pi->options.trace) { - oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval); + oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval); } } @@ -575,7 +575,7 @@ static void array_append_value(ParseInfo pi, VALUE value) { rb_ary_push(stack_peek(&pi->stack)->val, value); if (Yes == pi->options.trace) { - oj_trace_parse_call("append_value", pi, __FILE__, __LINE__, value); + oj_trace_parse_call("append_value", pi, __FILE__, __LINE__, value); } } @@ -600,7 +600,7 @@ oj_set_wab_callbacks(ParseInfo pi) { VALUE oj_wab_parse(int argc, VALUE *argv, VALUE self) { - struct _parseInfo pi; + struct _parseInfo pi; parse_info_init(&pi); pi.options = oj_default_options; @@ -609,15 +609,15 @@ oj_wab_parse(int argc, VALUE *argv, VALUE self) { oj_set_wab_callbacks(&pi); if (T_STRING == rb_type(*argv)) { - return oj_pi_parse(argc, argv, &pi, 0, 0, true); + return oj_pi_parse(argc, argv, &pi, 0, 0, true); } else { - return oj_pi_sparse(argc, argv, &pi, 0); + return oj_pi_sparse(argc, argv, &pi, 0); } } VALUE oj_wab_parse_cstr(int argc, VALUE *argv, char *json, size_t len) { - struct _parseInfo pi; + struct _parseInfo pi; parse_info_init(&pi); pi.options = oj_default_options; diff --git a/lib/oj/bag.rb b/lib/oj/bag.rb index 0791630c..528ccb54 100644 --- a/lib/oj/bag.rb +++ b/lib/oj/bag.rb @@ -1,4 +1,3 @@ -# frozen_string_literal: true module Oj