ext/oj/object.c in oj-3.11.3 vs ext/oj/object.c in oj-3.11.4

- old
+ new

@@ -1,772 +1,803 @@ // Copyright (c) 2012 Peter Ohler. All rights reserved. +// Licensed under the MIT License. See LICENSE file in the project root for license details. #include <stdint.h> #include <stdio.h> #include <time.h> -#include "oj.h" +#include "encode.h" #include "err.h" -#include "parse.h" -#include "resolve.h" #include "hash.h" #include "odd.h" -#include "encode.h" +#include "oj.h" +#include "parse.h" +#include "resolve.h" #include "trace.h" #include "util.h" -inline static long -read_long(const char *str, size_t len) { - long n = 0; +inline static long read_long(const char *str, size_t len) { + 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; +static VALUE calc_hash_key(ParseInfo pi, Val kval, char k1) { + 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; +static VALUE str_to_value(ParseInfo pi, const char *str, size_t len, const char *orig) { + 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; } #if (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8) -static VALUE -oj_parse_xml_time(const char *str, int len) { +static VALUE oj_parse_xml_time(const char *str, int len) { return rb_funcall(rb_cTime, oj_parse_id, 1, rb_str_new(str, len)); } #else // 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; +static int parse_num(const char *str, const char *end, int cnt) { + 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++; + char c = *str++; - if ('.' == c) { - long long nsec = 0; + 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; + 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 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); - } - } + 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); } #endif -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; +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; 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); + 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 (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 (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 + 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; } -static int -hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) { +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; + 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]; + 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 + 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; } -static int -hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, volatile VALUE value) { +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); + int len = (int)RARRAY_LEN(value); - if (2 == klen && 'u' == key[1]) { - volatile VALUE sc; - volatile VALUE e1; - int slen; + 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); + 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); - } + 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); -#endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT + 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; +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; #ifdef HAVE_PTHREAD_MUTEX_INIT pthread_mutex_lock(&oj_cache_mutex); #else rb_mutex_lock(oj_cache_mutex); #endif if (0 == (var_id = oj_attr_hash_get(key, klen, &slot))) { - char attr[256]; + char attr[256]; - if ((int)sizeof(attr) <= klen + 2) { - char *buf = ALLOC_N(char, klen + 2); + 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; + 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); #else rb_mutex_unlock(oj_cache_mutex); #endif rb_ivar_set(parent->val, var_id, 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; +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; - 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; + 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; + 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; + 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; + 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 (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; + 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; + 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; +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; - 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; + 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; + 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; + 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 (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; + 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; + 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); +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); - 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; + 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 (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; + 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; + 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 (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; + 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; + 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) { +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); +static void end_hash(ParseInfo pi) { + 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; +static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { + 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 (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 (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); +static void array_append_num(ParseInfo pi, NumInfo 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); } } -static void -add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) { +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); } } -static void -add_num(ParseInfo pi, NumInfo ni) { +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); } } -void -oj_set_object_callbacks(ParseInfo pi) { +void oj_set_object_callbacks(ParseInfo pi) { oj_set_strict_callbacks(pi); - pi->end_hash = end_hash; - pi->start_hash = start_hash; - pi->hash_set_cstr = hash_set_cstr; - pi->hash_set_num = hash_set_num; - pi->hash_set_value = hash_set_value; - pi->add_cstr = add_cstr; - pi->add_num = add_num; + pi->end_hash = end_hash; + pi->start_hash = start_hash; + pi->hash_set_cstr = hash_set_cstr; + pi->hash_set_num = hash_set_num; + pi->hash_set_value = hash_set_value; + pi->add_cstr = add_cstr; + pi->add_num = add_num; pi->array_append_cstr = array_append_cstr; - pi->array_append_num = array_append_num; + pi->array_append_num = array_append_num; } 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; - pi.handler = Qnil; + pi.options = oj_default_options; + pi.handler = Qnil; pi.err_class = Qnil; 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; - pi.handler = Qnil; + pi.options = oj_default_options; + pi.handler = Qnil; pi.err_class = Qnil; oj_set_strict_callbacks(&pi); - pi.end_hash = end_hash; - pi.start_hash = start_hash; - pi.hash_set_cstr = hash_set_cstr; - pi.hash_set_num = hash_set_num; - pi.hash_set_value = hash_set_value; - pi.add_cstr = add_cstr; - pi.add_num = add_num; + pi.end_hash = end_hash; + pi.start_hash = start_hash; + pi.hash_set_cstr = hash_set_cstr; + pi.hash_set_num = hash_set_num; + pi.hash_set_value = hash_set_value; + pi.add_cstr = add_cstr; + pi.add_num = add_num; pi.array_append_cstr = array_append_cstr; - pi.array_append_num = array_append_num; + pi.array_append_num = array_append_num; return oj_pi_parse(argc, argv, &pi, json, len, 1); }