diff --git a/ChangeLog b/ChangeLog index ddc55e1076..38e0c1cc4a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Mon May 7 21:19:17 2012 NARUSE, Yui + + * ext/json: Merge JSON 1.7.1. + https://github.com/flori/json/commit/e5b9a9465c1159fae533bca320d950b772bcb4ac + Mon May 07 22:54:22 2012 Martin Bosslet * ext/openssl/ossl_ssl.c: add support for option flags diff --git a/ext/json/fbuffer/fbuffer.h b/ext/json/fbuffer/fbuffer.h index 47e0c07004..f7c2b034b7 100644 --- a/ext/json/fbuffer/fbuffer.h +++ b/ext/json/fbuffer/fbuffer.h @@ -35,10 +35,14 @@ static FBuffer *fbuffer_alloc(unsigned long initial_length); static void fbuffer_free(FBuffer *fb); static void fbuffer_clear(FBuffer *fb); static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len); +#ifdef JSON_GENERATOR static void fbuffer_append_long(FBuffer *fb, long number); +#endif static void fbuffer_append_char(FBuffer *fb, char newchr); +#ifdef JSON_GENERATOR static FBuffer *fbuffer_dup(FBuffer *fb); static VALUE fbuffer_to_s(FBuffer *fb); +#endif static FBuffer *fbuffer_alloc(unsigned long initial_length) { @@ -68,7 +72,6 @@ static void fbuffer_inc_capa(FBuffer *fb, unsigned long requested) if (!fb->ptr) { fb->ptr = ALLOC_N(char, fb->initial_length); fb->capa = fb->initial_length; - fb->len = 0; } for (required = fb->capa; requested > required - fb->len; required <<= 1); @@ -88,15 +91,17 @@ static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len) } } +#ifdef JSON_GENERATOR static void fbuffer_append_str(FBuffer *fb, VALUE str) { const char *newstr = StringValuePtr(str); unsigned long len = RSTRING_LEN(str); - fbuffer_append(fb, newstr, len); - RB_GC_GUARD(str); + + fbuffer_append(fb, newstr, len); } +#endif static void fbuffer_append_char(FBuffer *fb, char newchr) { @@ -105,6 +110,7 @@ static void fbuffer_append_char(FBuffer *fb, char newchr) fb->len++; } +#ifdef JSON_GENERATOR static void freverse(char *start, char *end) { char c; @@ -155,3 +161,4 @@ static VALUE fbuffer_to_s(FBuffer *fb) return result; } #endif +#endif diff --git a/ext/json/generator/depend b/ext/json/generator/depend index bb76ad6400..1a042a2501 100644 --- a/ext/json/generator/depend +++ b/ext/json/generator/depend @@ -1 +1 @@ -generator.o: generator.c generator.h +generator.o: generator.c generator.h $(srcdir)/../fbuffer/fbuffer.h diff --git a/ext/json/generator/extconf.rb b/ext/json/generator/extconf.rb index 75c76ce15b..8627c5f4bd 100644 --- a/ext/json/generator/extconf.rb +++ b/ext/json/generator/extconf.rb @@ -1,3 +1,4 @@ require 'mkmf' +$defs << "-DJSON_GENERATOR" create_makefile 'json/ext/generator' diff --git a/ext/json/generator/generator.c b/ext/json/generator/generator.c index 6eea7ff148..b1babb15f3 100644 --- a/ext/json/generator/generator.c +++ b/ext/json/generator/generator.c @@ -762,7 +762,6 @@ static void generate_json_bignum(FBuffer *buffer, VALUE Vstate, JSON_Generator_S { VALUE tmp = rb_funcall(obj, i_to_s, 0); fbuffer_append_str(buffer, tmp); - RB_GC_GUARD(tmp); } static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj) @@ -853,6 +852,21 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj) return fbuffer_to_s(buffer); } +/* + * This function returns true if string is either a JSON array or JSON object. + * It might suffer from false positives, e. g. syntactically incorrect JSON in + * the string or certain UTF-8 characters on the right hand side. + */ +static int isArrayOrObject(VALUE string) +{ + long string_len = RSTRING_LEN(string); + char *p = RSTRING_PTR(string), *q = p + string_len - 1; + if (string_len < 2) return 0; + for (; p < q && isspace(*p); p++); + for (; q > p && isspace(*q); q--); + return *p == '[' && *q == ']' || *p == '{' && *q == '}'; +} + /* * call-seq: generate(obj) * @@ -863,15 +877,9 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj) static VALUE cState_generate(VALUE self, VALUE obj) { VALUE result = cState_partial_generate(self, obj); - VALUE re, args[2]; GET_STATE(self); - if (!state->quirks_mode) { - args[0] = rb_str_new2("\\A\\s*(?:\\[.*\\]|\\{.*\\})\\s*\\Z"); - args[1] = CRegexp_MULTILINE; - re = rb_class_new_instance(2, args, rb_cRegexp); - if (NIL_P(rb_funcall(re, i_match, 1, result))) { - rb_raise(eGeneratorError, "only generation of JSON objects or arrays allowed"); - } + if (!state->quirks_mode && !isArrayOrObject(result)) { + rb_raise(eGeneratorError, "only generation of JSON objects or arrays allowed"); } return result; } diff --git a/ext/json/generator/generator.h b/ext/json/generator/generator.h index 4958cf094d..901b62c251 100644 --- a/ext/json/generator/generator.h +++ b/ext/json/generator/generator.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "ruby.h" @@ -105,7 +106,6 @@ typedef struct JSON_Generator_StateStruct { Data_Get_Struct(Vstate, JSON_Generator_State, state); \ buffer = cState_prepare_buffer(Vstate); \ generate_json_##type(buffer, Vstate, state, self); \ - RB_GC_GUARD(Vstate); \ return fbuffer_to_s(buffer) static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self); diff --git a/ext/json/lib/json/common.rb b/ext/json/lib/json/common.rb index cf7a8b9003..a30e4ce136 100644 --- a/ext/json/lib/json/common.rb +++ b/ext/json/lib/json/common.rb @@ -1,4 +1,5 @@ require 'json/version' +require 'json/generic_object' module JSON class << self diff --git a/ext/json/lib/json/version.rb b/ext/json/lib/json/version.rb index 63ebcf3195..b1cf47f295 100644 --- a/ext/json/lib/json/version.rb +++ b/ext/json/lib/json/version.rb @@ -1,6 +1,6 @@ module JSON # JSON version - VERSION = '1.6.6' + VERSION = '1.7.1' VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc: VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc: VERSION_MINOR = VERSION_ARRAY[1] # :nodoc: diff --git a/ext/json/parser/depend b/ext/json/parser/depend index 5eaf6dd040..498ffa964c 100644 --- a/ext/json/parser/depend +++ b/ext/json/parser/depend @@ -1 +1 @@ -parser.o: parser.c parser.h +parser.o: parser.c parser.h $(srcdir)/../fbuffer/fbuffer.h diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c index d4adb8e620..c140fdb2fe 100644 --- a/ext/json/parser/parser.c +++ b/ext/json/parser/parser.c @@ -1721,6 +1721,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) source = convert_encoding(StringValue(source)); } json->current_nesting = 0; + StringValue(source); json->len = RSTRING_LEN(source); json->source = RSTRING_PTR(source);; json->Vsource = source; @@ -1728,7 +1729,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) } -#line 1732 "parser.c" +#line 1733 "parser.c" static const int JSON_start = 1; static const int JSON_first_final = 10; static const int JSON_error = 0; @@ -1736,7 +1737,7 @@ static const int JSON_error = 0; static const int JSON_en_main = 1; -#line 739 "parser.rl" +#line 740 "parser.rl" static VALUE cParser_parse_strict(VALUE self) @@ -1747,16 +1748,16 @@ static VALUE cParser_parse_strict(VALUE self) GET_PARSER; -#line 1751 "parser.c" +#line 1752 "parser.c" { cs = JSON_start; } -#line 749 "parser.rl" +#line 750 "parser.rl" p = json->source; pe = p + json->len; -#line 1760 "parser.c" +#line 1761 "parser.c" { if ( p == pe ) goto _test_eof; @@ -1812,7 +1813,7 @@ case 5: goto st1; goto st5; tr3: -#line 728 "parser.rl" +#line 729 "parser.rl" { char *np; json->current_nesting = 1; @@ -1821,7 +1822,7 @@ tr3: } goto st10; tr4: -#line 721 "parser.rl" +#line 722 "parser.rl" { char *np; json->current_nesting = 1; @@ -1833,7 +1834,7 @@ st10: if ( ++p == pe ) goto _test_eof10; case 10: -#line 1837 "parser.c" +#line 1838 "parser.c" switch( (*p) ) { case 13: goto st10; case 32: goto st10; @@ -1890,7 +1891,7 @@ case 9: _out: {} } -#line 752 "parser.rl" +#line 753 "parser.rl" if (cs >= JSON_first_final && p == pe) { return result; @@ -1902,7 +1903,7 @@ case 9: -#line 1906 "parser.c" +#line 1907 "parser.c" static const int JSON_quirks_mode_start = 1; static const int JSON_quirks_mode_first_final = 10; static const int JSON_quirks_mode_error = 0; @@ -1910,7 +1911,7 @@ static const int JSON_quirks_mode_error = 0; static const int JSON_quirks_mode_en_main = 1; -#line 777 "parser.rl" +#line 778 "parser.rl" static VALUE cParser_parse_quirks_mode(VALUE self) @@ -1921,16 +1922,16 @@ static VALUE cParser_parse_quirks_mode(VALUE self) GET_PARSER; -#line 1925 "parser.c" +#line 1926 "parser.c" { cs = JSON_quirks_mode_start; } -#line 787 "parser.rl" +#line 788 "parser.rl" p = json->source; pe = p + json->len; -#line 1934 "parser.c" +#line 1935 "parser.c" { if ( p == pe ) goto _test_eof; @@ -1964,7 +1965,7 @@ st0: cs = 0; goto _out; tr2: -#line 769 "parser.rl" +#line 770 "parser.rl" { char *np = JSON_parse_value(json, p, pe, &result); if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;} @@ -1974,7 +1975,7 @@ st10: if ( ++p == pe ) goto _test_eof10; case 10: -#line 1978 "parser.c" +#line 1979 "parser.c" switch( (*p) ) { case 13: goto st10; case 32: goto st10; @@ -2063,7 +2064,7 @@ case 9: _out: {} } -#line 790 "parser.rl" +#line 791 "parser.rl" if (cs >= JSON_quirks_mode_first_final && p == pe) { return result; diff --git a/ext/json/parser/parser.rl b/ext/json/parser/parser.rl index c96b0a8225..20ecc486e1 100644 --- a/ext/json/parser/parser.rl +++ b/ext/json/parser/parser.rl @@ -705,6 +705,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) source = convert_encoding(StringValue(source)); } json->current_nesting = 0; + StringValue(source); json->len = RSTRING_LEN(source); json->source = RSTRING_PTR(source);; json->Vsource = source; diff --git a/test/json/test_json.rb b/test/json/test_json.rb index 1b39360b33..22cd5ee5a5 100755 --- a/test/json/test_json.rb +++ b/test/json/test_json.rb @@ -21,7 +21,7 @@ unless Array.method_defined?(:permutation) end end -class TC_JSON < Test::Unit::TestCase +class TestJSON < Test::Unit::TestCase include JSON def setup @@ -109,6 +109,8 @@ class TC_JSON < Test::Unit::TestCase def test_parse_json_primitive_values assert_raise(JSON::ParserError) { JSON.parse('') } assert_raise(JSON::ParserError) { JSON.parse('', :quirks_mode => true) } + assert_raise(TypeError) { JSON::Parser.new(nil).parse } + assert_raise(TypeError) { JSON::Parser.new(nil, :quirks_mode => true).parse } assert_raise(TypeError) { JSON.parse(nil) } assert_raise(TypeError) { JSON.parse(nil, :quirks_mode => true) } assert_raise(JSON::ParserError) { JSON.parse(' /* foo */ ') } @@ -314,6 +316,16 @@ class TC_JSON < Test::Unit::TestCase assert res.item_set? end + def test_parse_generic_object + res = parse('{"foo":"bar", "baz":{}}', :object_class => JSON::GenericObject) + assert_equal(JSON::GenericObject, res.class) + assert_equal "bar", res.foo + assert_equal "bar", res["foo"] + assert_equal "bar", res[:foo] + assert_equal "bar", res.to_hash[:foo] + assert_equal(JSON::GenericObject, res.baz.class) + end + def test_generate_core_subclasses_with_new_to_json obj = SubHash2["foo" => SubHash2["bar" => true]] obj_json = JSON(obj) diff --git a/test/json/test_json_addition.rb b/test/json/test_json_addition.rb index e262e25953..cf808668b8 100755 --- a/test/json/test_json_addition.rb +++ b/test/json/test_json_addition.rb @@ -10,7 +10,7 @@ require 'json/add/bigdecimal' require 'json/add/ostruct' require 'date' -class TC_JSONAddition < Test::Unit::TestCase +class TestJSONAddition < Test::Unit::TestCase include JSON class A @@ -64,7 +64,7 @@ class TC_JSONAddition < Test::Unit::TestCase def to_json(*args) { - 'json_class' => 'TC_JSONAddition::Nix', + 'json_class' => 'TestJSONAddition::Nix', }.to_json(*args) end end @@ -88,7 +88,7 @@ class TC_JSONAddition < Test::Unit::TestCase a_hash = JSON.parse(json, :create_additions => false) assert_kind_of Hash, a_hash assert_equal( - {"args"=>[666], "json_class"=>"TC_JSONAddition::A"}.sort_by { |k,| k }, + {"args"=>[666], "json_class"=>"TestJSONAddition::A"}.sort_by { |k,| k }, a_hash.sort_by { |k,| k } ) end @@ -97,7 +97,7 @@ class TC_JSONAddition < Test::Unit::TestCase b = B.new assert !B.json_creatable? json = generate(b) - assert_equal({ "json_class"=>"TC_JSONAddition::B" }, JSON.parse(json)) + assert_equal({ "json_class"=>"TestJSONAddition::B" }, JSON.parse(json)) end def test_extended_json_fail2 diff --git a/test/json/test_json_encoding.rb b/test/json/test_json_encoding.rb index 7af5e63a73..caa0c6c50e 100644 --- a/test/json/test_json_encoding.rb +++ b/test/json/test_json_encoding.rb @@ -4,7 +4,7 @@ require 'test/unit' require File.join(File.dirname(__FILE__), 'setup_variant') -class TC_JSONEncoding < Test::Unit::TestCase +class TestJSONEncoding < Test::Unit::TestCase include JSON def setup diff --git a/test/json/test_json_fixtures.rb b/test/json/test_json_fixtures.rb index e9df8f5b1c..37e51457d4 100755 --- a/test/json/test_json_fixtures.rb +++ b/test/json/test_json_fixtures.rb @@ -4,7 +4,7 @@ require 'test/unit' require File.join(File.dirname(__FILE__), 'setup_variant') -class TC_JSONFixtures < Test::Unit::TestCase +class TestJSONFixtures < Test::Unit::TestCase def setup fixtures = File.join(File.dirname(__FILE__), 'fixtures/*.json') passed, failed = Dir[fixtures].partition { |f| f['pass'] } diff --git a/test/json/test_json_generate.rb b/test/json/test_json_generate.rb index 8d06cec10e..04368a4c8b 100755 --- a/test/json/test_json_generate.rb +++ b/test/json/test_json_generate.rb @@ -4,7 +4,7 @@ require 'test/unit' require File.join(File.dirname(__FILE__), 'setup_variant') -class TC_JSONGenerate < Test::Unit::TestCase +class TestJSONGenerate < Test::Unit::TestCase include JSON def setup diff --git a/test/json/test_json_string_matching.rb b/test/json/test_json_string_matching.rb index df26a68a4d..b8a7169490 100644 --- a/test/json/test_json_string_matching.rb +++ b/test/json/test_json_string_matching.rb @@ -6,7 +6,7 @@ require File.join(File.dirname(__FILE__), 'setup_variant') require 'stringio' require 'time' -class TestJsonStringMatching < Test::Unit::TestCase +class TestJSONStringMatching < Test::Unit::TestCase include JSON class TestTime < ::Time diff --git a/test/json/test_json_unicode.rb b/test/json/test_json_unicode.rb index ace56cae36..c328811106 100755 --- a/test/json/test_json_unicode.rb +++ b/test/json/test_json_unicode.rb @@ -4,7 +4,7 @@ require 'test/unit' require File.join(File.dirname(__FILE__), 'setup_variant') -class TC_JSONUnicode < Test::Unit::TestCase +class TestJSONUnicode < Test::Unit::TestCase include JSON def test_unicode