From 7bb08fc7dd1fb32baeb2a076a02885231a362fef Mon Sep 17 00:00:00 2001 From: Florian Frank Date: Mon, 19 Oct 2009 23:29:57 +0200 Subject: added conversion to utf8 to generators as well --- ext/json/ext/generator/generator.c | 16 ++++++++++++++++ lib/json/pure/generator.rb | 30 ++++++++++++++++++++++-------- tests/test_json_encoding.rb | 36 +++++++++++++++++++++++------------- 3 files changed, 61 insertions(+), 21 deletions(-) diff --git a/ext/json/ext/generator/generator.c b/ext/json/ext/generator/generator.c index 9bcd580..558f28d 100644 --- a/ext/json/ext/generator/generator.c +++ b/ext/json/ext/generator/generator.c @@ -24,6 +24,8 @@ #ifdef HAVE_RUBY_ENCODING_H #include "ruby/encoding.h" #define FORCE_UTF8(obj) rb_enc_associate((obj), rb_utf8_encoding()) +static VALUE mEncoding_UTF_8; +static ID i_encoding, i_encode; #else #define FORCE_UTF8(obj) #endif @@ -357,7 +359,16 @@ static VALUE mString_to_json(int argc, VALUE *argv, VALUE self) { VALUE result = rb_str_buf_new(RSTRING_LEN(self)); rb_str_buf_cat2(result, "\""); +#ifdef HAVE_RUBY_ENCODING_H + if (rb_funcall(self, i_encoding, 0) == mEncoding_UTF_8) { + JSON_convert_UTF8_to_JSON(result, self, strictConversion); + } else { + VALUE string = rb_funcall(self, i_encode, 1, mEncoding_UTF_8); + JSON_convert_UTF8_to_JSON(result, string, strictConversion); + } +#else JSON_convert_UTF8_to_JSON(result, self, strictConversion); +#endif rb_str_buf_cat2(result, "\""); FORCE_UTF8(result); return result; @@ -916,4 +927,9 @@ void Init_generator() i_unpack = rb_intern("unpack"); i_create_id = rb_intern("create_id"); i_extend = rb_intern("extend"); +#ifdef HAVE_RUBY_ENCODING_H + mEncoding_UTF_8 = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-8")); + i_encoding = rb_intern("encoding"); + i_encode = rb_intern("encode"); +#endif } diff --git a/lib/json/pure/generator.rb b/lib/json/pure/generator.rb index 2b7eeb7..57ef483 100644 --- a/lib/json/pure/generator.rb +++ b/lib/json/pure/generator.rb @@ -38,11 +38,11 @@ module JSON # Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with # UTF16 big endian characters as \u????, and return it. - if String.method_defined?(:force_encoding) + if defined?(::Encoding) def utf8_to_json(string) # :nodoc: string = string.dup string << '' # XXX workaround: avoid buffer sharing - string.force_encoding(Encoding::ASCII_8BIT) + string.force_encoding(::Encoding::ASCII_8BIT) string.gsub!(/["\\\x0-\x1f]/) { MAP[$&] } string.gsub!(/( (?: @@ -56,7 +56,7 @@ module JSON s = JSON::UTF8toUTF16.iconv(c).unpack('H*')[0] s.gsub!(/.{4}/n, '\\\\u\&') } - string.force_encoding(Encoding::UTF_8) + string.force_encoding(::Encoding::UTF_8) string rescue Iconv::Failure => e raise GeneratorError, "Caught #{e.class}: #{e}" @@ -369,11 +369,25 @@ module JSON end module String - # This string should be encoded with UTF-8 A call to this method - # returns a JSON string encoded with UTF16 big endian characters as - # \u????. - def to_json(*) - '"' << JSON.utf8_to_json(self) << '"' + if defined?(::Encoding) + # This string should be encoded with UTF-8 A call to this method + # returns a JSON string encoded with UTF16 big endian characters as + # \u????. + def to_json(*) + if encoding == ::Encoding::UTF_8 + '"' << JSON.utf8_to_json(self) << '"' + else + string = encode(::Encoding::UTF_8) + '"' << JSON.utf8_to_json(string) << '"' + end + end + else + # This string should be encoded with UTF-8 A call to this method + # returns a JSON string encoded with UTF16 big endian characters as + # \u????. + def to_json(*) + '"' << JSON.utf8_to_json(self) << '"' + end end # Module that holds the extinding methods if, the String module is diff --git a/tests/test_json_encoding.rb b/tests/test_json_encoding.rb index f46b476..bfb3e60 100644 --- a/tests/test_json_encoding.rb +++ b/tests/test_json_encoding.rb @@ -14,7 +14,9 @@ class TC_JSONEncoding < Test::Unit::TestCase def setup @utf_8 = '["© ≠ €!"]' - @decoded = [ "© ≠ €!" ] + @parsed = [ "© ≠ €!" ] + @utf_16_data = Iconv.iconv('utf-16be', 'utf-8', @parsed.first) + @generated = '["\u00a9 \u2260 \u20ac!"]' if defined?(::Encoding) @utf_8_ascii_8bit = @utf_8.dup.force_encoding(Encoding::ASCII_8BIT) @utf_16be, = Iconv.iconv('utf-16be', 'utf-8', @utf_8) @@ -38,20 +40,28 @@ class TC_JSONEncoding < Test::Unit::TestCase end end - def test_decode - assert @decoded, JSON.parse(@utf_8) - assert @decoded, JSON.parse(@utf_16be) - assert @decoded, JSON.parse(@utf_16le) - assert @decoded, JSON.parse(@utf_32be) - assert @decoded, JSON.parse(@utf_32le) + def test_parse + assert_equal @parsed, JSON.parse(@utf_8) + assert_equal @parsed, JSON.parse(@utf_16be) + assert_equal @parsed, JSON.parse(@utf_16le) + assert_equal @parsed, JSON.parse(@utf_32be) + assert_equal @parsed, JSON.parse(@utf_32le) end - def test_decode_ascii_8bit - assert @decoded, JSON.parse(@utf_8_ascii_8bit) - assert @decoded, JSON.parse(@utf_16be_ascii_8bit) - assert @decoded, JSON.parse(@utf_16le_ascii_8bit) - assert @decoded, JSON.parse(@utf_32be_ascii_8bit) - assert @decoded, JSON.parse(@utf_32le_ascii_8bit) + def test_parse_ascii_8bit + assert_equal @parsed, JSON.parse(@utf_8_ascii_8bit) + assert_equal @parsed, JSON.parse(@utf_16be_ascii_8bit) + assert_equal @parsed, JSON.parse(@utf_16le_ascii_8bit) + assert_equal @parsed, JSON.parse(@utf_32be_ascii_8bit) + assert_equal @parsed, JSON.parse(@utf_32le_ascii_8bit) end + def test_generate + assert_equal @generated, JSON.generate(@parsed) + if defined?(::Encoding) + assert_equal @generated, JSON.generate(@utf_16_data) + else + assert_raises(JSON::GeneratorError) { JSON.generate(@utf_16_data) } + end + end end -- cgit v1.2.1