summaryrefslogtreecommitdiff
path: root/lib/json/pure.rb
blob: b86d905523315cfd0d27a71dda305ba0af0af1d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
require 'json/common'
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|
      break unless string[2 * i + 1]
      string[2 * i], string[2 * i + 1] = string[2 * i + 1], string[2 * i]
    end
    string
  end

  # This module holds all the modules/classes that implement JSON's
  # functionality in pure ruby.
  module Pure
    $DEBUG and warn "Using pure library for JSON."
    JSON.parser = Parser
    JSON.generator = Generator
  end
end