diff --git a/ChangeLog b/ChangeLog index 8ba33abd8d..e2d5bae826 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +Fri Oct 3 19:33:21 2008 NARUSE, Yui + + * ext/json/lib/json/pure.rb (module JSON): remove Iconv dependency. + + * ext/json/lib/json/pure/generator.rb (utf8_to_json): process as + binary and remove Iconv dependency. + + * ext/json/lib/json/pure/parser.rb (parse_string): ditto. + Fri Oct 3 14:04:05 2008 NAKAMURA Usaku * win32/{configure.bat,setup.mak,Makefile.sub): add --program-prefix diff --git a/ext/json/lib/json/pure.rb b/ext/json/lib/json/pure.rb index b86d905523..6af8705c5b 100644 --- a/ext/json/lib/json/pure.rb +++ b/ext/json/lib/json/pure.rb @@ -3,59 +3,6 @@ require 'json/pure/parser' require 'json/pure/generator' module JSON - begin - require 'iconv' - # An iconv instance to convert from UTF8 to UTF16 Big Endian. - UTF16toUTF8 = Iconv.new('utf-8', 'utf-16be') # :nodoc: - # An iconv instance to convert from UTF16 Big Endian to UTF8. - UTF8toUTF16 = Iconv.new('utf-16be', 'utf-8') # :nodoc: - UTF8toUTF16.iconv('no bom') - rescue Errno::EINVAL, Iconv::InvalidEncoding - # Iconv doesn't support big endian utf-16. Let's try to hack this manually - # into the converters. - begin - old_verbose, $VERBSOSE = $VERBOSE, nil - # An iconv instance to convert from UTF8 to UTF16 Big Endian. - UTF16toUTF8 = Iconv.new('utf-8', 'utf-16') # :nodoc: - # An iconv instance to convert from UTF16 Big Endian to UTF8. - UTF8toUTF16 = Iconv.new('utf-16', 'utf-8') # :nodoc: - UTF8toUTF16.iconv('no bom') - if UTF8toUTF16.iconv("\xe2\x82\xac") == "\xac\x20" - swapper = Class.new do - def initialize(iconv) # :nodoc: - @iconv = iconv - end - - def iconv(string) # :nodoc: - result = @iconv.iconv(string) - JSON.swap!(result) - end - end - UTF8toUTF16 = swapper.new(UTF8toUTF16) # :nodoc: - end - if UTF16toUTF8.iconv("\xac\x20") == "\xe2\x82\xac" - swapper = Class.new do - def initialize(iconv) # :nodoc: - @iconv = iconv - end - - def iconv(string) # :nodoc: - string = JSON.swap!(string.dup) - @iconv.iconv(string) - end - end - UTF16toUTF8 = swapper.new(UTF16toUTF8) # :nodoc: - end - rescue Errno::EINVAL, Iconv::InvalidEncoding - raise MissingUnicodeSupport, "iconv doesn't seem to support UTF-8/UTF-16 conversions" - ensure - $VERBOSE = old_verbose - end - rescue LoadError - raise MissingUnicodeSupport, - "iconv couldn't be loaded, which is required for UTF-8/UTF-16 conversions" - end - # Swap consecutive bytes of _string_ in place. def self.swap!(string) # :nodoc: 0.upto(string.size / 2) do |i| diff --git a/ext/json/lib/json/pure/generator.rb b/ext/json/lib/json/pure/generator.rb index c8bbfd09ee..91bdc0ff41 100644 --- a/ext/json/lib/json/pure/generator.rb +++ b/ext/json/lib/json/pure/generator.rb @@ -41,6 +41,7 @@ module JSON # UTF16 big endian characters as \u????, and return it. def utf8_to_json(string) # :nodoc: string = string.gsub(/["\\\/\x0-\x1f]/) { MAP[$&] } + string.force_encoding(Encoding::ASCII_8BIT) string.gsub!(/( (?: [\xc2-\xdf][\x80-\xbf] | @@ -50,12 +51,10 @@ module JSON [\x80-\xc1\xf5-\xff] # invalid )/nx) { |c| c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'" - s = JSON::UTF8toUTF16.iconv(c).unpack('H*')[0] - s.gsub!(/.{4}/n, '\\\\u\&') + c = c.unpack("U*")[0] + c > 0xFFFF ? ('\uD%03X\uD%03X' % [0x7C0+c/1024, 0xC00+c%1024]) : ('\u%04X'%c) } string - rescue Iconv::Failure => e - raise GeneratorError, "Caught #{e.class}: #{e}" end module_function :utf8_to_json diff --git a/ext/json/lib/json/pure/parser.rb b/ext/json/lib/json/pure/parser.rb index 9b30f15c07..a0ab3075fe 100644 --- a/ext/json/lib/json/pure/parser.rb +++ b/ext/json/lib/json/pure/parser.rb @@ -126,20 +126,30 @@ module JSON if u = UNESCAPE_MAP[$&[1]] u else # \uXXXX - bytes = '' - i = 0 - while c[6 * i] == ?\\ && c[6 * i + 1] == ?u - bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16) - i += 1 + res = [] + stack = nil + [c.delete!('\\\\u')].pack("H*").unpack("n*").each do |c| + case c + when 0xD800..0xDBFF + raise JSON::ParserError, "partial character in source" if stack + stack = c + when 0xDC00..0xDFFF + raise JSON::ParserError, + "partial character in source" unless (0xD800..0xDBFF).include?(stack) + res << (stack << 10) - 0x35fdc00 + c + stack = nil + else + raise JSON::ParserError, "partial character in source" if stack + res << c + end end - JSON::UTF16toUTF8.iconv(bytes) + raise JSON::ParserError, "partial character in source" if stack + res.pack("U*") end end else UNPARSED end - rescue Iconv::Failure => e - raise GeneratorError, "Caught #{e.class}: #{e}" end def parse_value