diff options
-rw-r--r-- | ext/json/ext/generator/generator.c | 108 | ||||
-rw-r--r-- | ext/json/ext/parser/parser.c | 22 | ||||
-rw-r--r-- | ext/json/ext/parser/parser.rl | 6 | ||||
-rw-r--r-- | tests/json_common_interface_test.rb | 2 |
4 files changed, 90 insertions, 48 deletions
diff --git a/ext/json/ext/generator/generator.c b/ext/json/ext/generator/generator.c index 6b3cdd7..73a7eb3 100644 --- a/ext/json/ext/generator/generator.c +++ b/ext/json/ext/generator/generator.c @@ -237,6 +237,7 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string) int escape_len; unsigned char c; char buf[6] = { '\\', 'u' }; + int ascii_only = rb_enc_str_asciionly_p(string); for (start = 0, end = 0; end < len;) { p = ptr + end; @@ -281,14 +282,17 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string) break; default: { - unsigned short clen = trailingBytesForUTF8[c] + 1; - if (end + clen > len) { - rb_raise(rb_path2class("JSON::GeneratorError"), - "partial character in source, but hit end"); - } - if (!isLegalUTF8((UTF8 *) p, clen)) { - rb_raise(rb_path2class("JSON::GeneratorError"), - "source sequence is illegal/malformed utf-8"); + unsigned short clen = 1; + if (!ascii_only) { + clen += trailingBytesForUTF8[c]; + if (end + clen > len) { + rb_raise(rb_path2class("JSON::GeneratorError"), + "partial character in source, but hit end"); + } + if (!isLegalUTF8((UTF8 *) p, clen)) { + rb_raise(rb_path2class("JSON::GeneratorError"), + "source sequence is illegal/malformed utf-8"); + } } end += clen; } @@ -715,43 +719,83 @@ static VALUE cState_aset(VALUE self, VALUE name, VALUE value) return Qnil; } -static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj) +struct hash_foreach_arg { + FBuffer *buffer; + JSON_Generator_State *state; + VALUE Vstate; + int iter; +}; + +static int +json_object_i(VALUE key, VALUE val, VALUE _arg) { + struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg; + FBuffer *buffer = arg->buffer; + JSON_Generator_State *state = arg->state; + VALUE Vstate = arg->Vstate; + char *object_nl = state->object_nl; long object_nl_len = state->object_nl_len; char *indent = state->indent; long indent_len = state->indent_len; - long max_nesting = state->max_nesting; char *delim = FBUFFER_PTR(state->object_delim); long delim_len = FBUFFER_LEN(state->object_delim); char *delim2 = FBUFFER_PTR(state->object_delim2); long delim2_len = FBUFFER_LEN(state->object_delim2); + long depth = state->depth; + int j; + VALUE klass, key_to_s; + + if (arg->iter > 0) fbuffer_append(buffer, delim, delim_len); + if (object_nl) { + fbuffer_append(buffer, object_nl, object_nl_len); + } + if (indent) { + for (j = 0; j < depth; j++) { + fbuffer_append(buffer, indent, indent_len); + } + } + + klass = CLASS_OF(key); + if (klass == rb_cString) { + key_to_s = key; + } else if (klass == rb_cSymbol) { + key_to_s = rb_id2str(SYM2ID(key)); + } else { + key_to_s = rb_funcall(key, i_to_s, 0); + } + Check_Type(key_to_s, T_STRING); + generate_json(buffer, Vstate, state, key_to_s); + fbuffer_append(buffer, delim2, delim2_len); + generate_json(buffer, Vstate, state, val); + + arg->iter++; + return ST_CONTINUE; +} + +static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj) +{ + char *object_nl = state->object_nl; + long object_nl_len = state->object_nl_len; + char *indent = state->indent; + long indent_len = state->indent_len; + long max_nesting = state->max_nesting; long depth = ++state->depth; - int i, j; - VALUE key, key_to_s, keys; + int j; + struct hash_foreach_arg arg; + if (max_nesting != 0 && depth > max_nesting) { fbuffer_free(buffer); rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth); } fbuffer_append_char(buffer, '{'); - keys = rb_funcall(obj, i_keys, 0); - for(i = 0; i < RARRAY_LEN(keys); i++) { - if (i > 0) fbuffer_append(buffer, delim, delim_len); - if (object_nl) { - fbuffer_append(buffer, object_nl, object_nl_len); - } - if (indent) { - for (j = 0; j < depth; j++) { - fbuffer_append(buffer, indent, indent_len); - } - } - key = rb_ary_entry(keys, i); - key_to_s = rb_funcall(key, i_to_s, 0); - Check_Type(key_to_s, T_STRING); - generate_json(buffer, Vstate, state, key_to_s); - fbuffer_append(buffer, delim2, delim2_len); - generate_json(buffer, Vstate, state, rb_hash_aref(obj, key)); - } + + arg.buffer = buffer; + arg.state = state; + arg.Vstate = Vstate; + arg.iter = 0; + rb_hash_foreach(obj, json_object_i, (VALUE)&arg); + depth = --state->depth; if (object_nl) { fbuffer_append(buffer, object_nl, object_nl_len); @@ -806,7 +850,9 @@ static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_S { fbuffer_append_char(buffer, '"'); #ifdef HAVE_RUBY_ENCODING_H - obj = rb_funcall(obj, i_encode, 1, CEncoding_UTF_8); + if (!rb_enc_str_asciicompat_p(obj)) { + obj = rb_str_encode(obj, CEncoding_UTF_8, 0, Qnil); + } #endif if (state->ascii_only) { convert_UTF8_to_JSON_ASCII(buffer, obj); diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c index f686768..63b895e 100644 --- a/ext/json/ext/parser/parser.c +++ b/ext/json/ext/parser/parser.c @@ -1676,10 +1676,8 @@ case 7: if (json->symbolize_names && json->parsing_name) { *result = rb_str_intern(*result); - } else { - if (RB_TYPE_P(*result, T_STRING)) { - rb_str_resize(*result, RSTRING_LEN(*result)); - } + } else if (RB_TYPE_P(*result, T_STRING)) { + rb_str_resize(*result, RSTRING_LEN(*result)); } if (cs >= JSON_string_first_final) { return p + 1; @@ -1850,7 +1848,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) } -#line 1854 "parser.c" +#line 1852 "parser.c" enum {JSON_start = 1}; enum {JSON_first_final = 10}; enum {JSON_error = 0}; @@ -1858,7 +1856,7 @@ enum {JSON_error = 0}; enum {JSON_en_main = 1}; -#line 762 "parser.rl" +#line 760 "parser.rl" /* @@ -1875,16 +1873,16 @@ static VALUE cParser_parse(VALUE self) GET_PARSER; -#line 1879 "parser.c" +#line 1877 "parser.c" { cs = JSON_start; } -#line 778 "parser.rl" +#line 776 "parser.rl" p = json->source; pe = p + json->len; -#line 1888 "parser.c" +#line 1886 "parser.c" { if ( p == pe ) goto _test_eof; @@ -1918,7 +1916,7 @@ st0: cs = 0; goto _out; tr2: -#line 754 "parser.rl" +#line 752 "parser.rl" { char *np = JSON_parse_value(json, p, pe, &result, 0); if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;} @@ -1928,7 +1926,7 @@ st10: if ( ++p == pe ) goto _test_eof10; case 10: -#line 1932 "parser.c" +#line 1930 "parser.c" switch( (*p) ) { case 13: goto st10; case 32: goto st10; @@ -2017,7 +2015,7 @@ case 9: _out: {} } -#line 781 "parser.rl" +#line 779 "parser.rl" if (cs >= JSON_first_final && p == pe) { return result; diff --git a/ext/json/ext/parser/parser.rl b/ext/json/ext/parser/parser.rl index d4e7a60..e7738d6 100644 --- a/ext/json/ext/parser/parser.rl +++ b/ext/json/ext/parser/parser.rl @@ -571,10 +571,8 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu if (json->symbolize_names && json->parsing_name) { *result = rb_str_intern(*result); - } else { - if (RB_TYPE_P(*result, T_STRING)) { - rb_str_resize(*result, RSTRING_LEN(*result)); - } + } else if (RB_TYPE_P(*result, T_STRING)) { + rb_str_resize(*result, RSTRING_LEN(*result)); } if (cs >= JSON_string_first_final) { return p + 1; diff --git a/tests/json_common_interface_test.rb b/tests/json_common_interface_test.rb index 29b4a5b..de88c6e 100644 --- a/tests/json_common_interface_test.rb +++ b/tests/json_common_interface_test.rb @@ -56,7 +56,7 @@ class JSONCommonInterfaceTest < Test::Unit::TestCase end def test_parse_bang - assert_equal [ 1, NaN, 3, ], JSON.parse!('[ 1, NaN, 3 ]') + assert_equal [ 1, Infinity, 3, ], JSON.parse!('[ 1, Infinity, 3 ]') end def test_generate |