lib/json.rb in json-0.4.1 vs lib/json.rb in json-0.4.2

- old
+ new

@@ -138,28 +138,82 @@ def support_unicode=(enable) @support_unicode = enable end # Returns _true_ if JSON supports unicode, otherwise _false_ is returned. + # + # If loading of the iconv library fails, or it doesn't support utf8/utf16 + # encoding, this will be set to false, as a fallback. def support_unicode? !!@support_unicode end end - JSON.support_unicode = true # default, hower it's possible to switch off full - # unicode support, if non-ascii bytes should be + JSON.support_unicode = true # default, however it's possible to switch off + # full unicode support, if non-ascii bytes should be # just passed through. begin require 'iconv' # An iconv instance to convert from UTF8 to UTF16 Big Endian. UTF16toUTF8 = Iconv.new('utf-8', 'utf-16be') # An iconv instance to convert from UTF16 Big Endian to UTF8. UTF8toUTF16 = Iconv.new('utf-16be', 'utf-8'); UTF8toUTF16.iconv('no bom') + rescue Errno::EINVAL + begin + old_verbose = $VERBOSE + $VERBOSE = nil + # An iconv instance to convert from UTF8 to UTF16 Big Endian. + UTF16toUTF8 = Iconv.new('utf-8', 'utf-16') + # An iconv instance to convert from UTF16 Big Endian to UTF8. + UTF8toUTF16 = Iconv.new('utf-16', 'utf-8'); UTF8toUTF16.iconv('no bom') + if UTF8toUTF16.iconv("\xe2\x82\xac") == "\xac\x20" + swapper = Class.new do + def initialize(iconv) + @iconv = iconv + end + + def iconv(string) + result = @iconv.iconv(string) + JSON.swap!(result) + end + end + UTF8toUTF16 = swapper.new(UTF8toUTF16) + end + if UTF16toUTF8.iconv("\xac\x20") == "\xe2\x82\xac" + swapper = Class.new do + def initialize(iconv) + @iconv = iconv + end + + def iconv(string) + string = JSON.swap!(string.dup) + @iconv.iconv(string) + end + end + UTF16toUTF8 = swapper.new(UTF16toUTF8) + end + rescue Errno::EINVAL + # Enforce disabling of unicode support, if iconv doesn't support + # UTF8/UTF16 at all. + JSON.support_unicode = false + ensure + $VERBOSE = old_verbose + end rescue LoadError - JSON.support_unicode = false # enforce disabling of unicode support + # Enforce disabling of unicode support, if iconv doesn't exist. + JSON.support_unicode = false end + # Swap consecutive bytes in string in place. + def self.swap!(string) + 0.upto(string.size / 2) do |i| + break unless string[2 * i + 1] + string[2 * i], string[2 * i + 1] = string[2 * i + 1], string[2 * i] + end + string + end + # This class implements the JSON parser that is used to parse a JSON string # into a Ruby data structure. class Parser < StringScanner STRING = /"((?:[^"\\]|\\.)*)"/ INTEGER = /-?\d+/ @@ -213,19 +267,20 @@ private def parse_string if scan(STRING) return '' if self[1].empty? - self[1].gsub(/\\(?:[\\bfnrt"]|u([A-Fa-f\d]{4}))/) do + self[1].gsub(%r(\\(?:[\\bfnrt"/]|u([A-Fa-f\d]{4})))) do case $~[0] when '\\\\' then '\\' when '\\b' then "\b" when '\\f' then "\f" when '\\n' then "\n" when '\\r' then "\r" when '\\t' then "\t" when '\\"' then '"' + when '\\/' then '/' else if JSON.support_unicode? and $KCODE == 'UTF8' JSON.utf16_to_utf8($~[1]) else # if utf8 mode is switched off or unicode not supported, try to @@ -406,9 +461,10 @@ when char == ?\n then result << '\n' when char == ?\f then result << '\f' when char == ?\r then result << '\r' when char == ?" then result << '\"' when char == ?\\ then result << '\\\\' + when char == ?/ then result << '\/' when char.between?(0x0, 0x1f) then result << "\\u%04x" % char when char.between?(0x20, 0x7f) then result << char when !(JSON.support_unicode? && $KCODE == 'UTF8') # if utf8 mode is switched off or unicode not supported, just pass # bytes through: