Method: SimpleIDN::Punycode.decode

Defined in:
lib/simpleidn.rb

.decode(input) ⇒ Object

Main decode



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/simpleidn.rb', line 56

def decode(input)
  input_encoding = input.encoding
  input = input.encode(Encoding::UTF_8).codepoints.to_a
  output = []

  # Initialize the state:
  n = INITIAL_N
  i = 0
  bias = INITIAL_BIAS

  # Handle the basic code points: Let basic be the number of input code
  # points before the last delimiter, or 0 if there is none, then
  # copy the first basic code points to the output.
  basic = input.rindex(DELIMITER) || 0

  input[0, basic].each do |char|
    raise(ConversionError, "Illegal input >= 0x80") if char > ASCII_MAX
    output << char
  end

  # Main decoding loop: Start just after the last delimiter if any
  # basic code points were copied; start at the beginning otherwise.

  ic = basic > 0 ? basic + 1 : 0
  while ic < input.length
    # ic is the index of the next character to be consumed,

    # Decode a generalized variable-length integer into delta,
    # which gets added to i. The overflow checking is easier
    # if we increase i as we go, then subtract off its starting
    # value at the end to obtain delta.
    oldi = i
    w = 1
    k = BASE
    loop do
      raise(ConversionError, "punycode_bad_input(1)") if ic >= input.length

      digit = decode_digit(input[ic])
      ic += 1

      raise(ConversionError, "punycode_bad_input(2)") if digit >= BASE

      raise(ConversionError, "punycode_overflow(1)") if digit > (MAXINT - i) / w

      i += digit * w
      t = k <= bias ? TMIN : k >= bias + TMAX ? TMAX : k - bias
      break if digit < t
      raise(ConversionError, "punycode_overflow(2)") if w > MAXINT / (BASE - t)

      w *= BASE - t
      k += BASE
    end

    out = output.length + 1
    bias = adapt(i - oldi, out, oldi == 0)

    # i was supposed to wrap around from out to 0,
    # incrementing n each time, so we'll fix that now:
    raise(ConversionError, "punycode_overflow(3)") if (i / out) > MAXINT - n

    n += (i / out)
    i %= out

    # Insert n at position i of the output:
    output.insert(i, n)
    i += 1
  end

  output.collect {|c| c.chr(Encoding::UTF_8)}.join(EMPTY).encode(input_encoding)
end