1 // Copyright 2016 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
7 // This file implements the Punycode algorithm from RFC 3492.
15 // These parameter values are specified in section 5.
17 // All computation is done with int32s, so that overflow behavior is identical
18 // regardless of whether int is 32-bit or 64-bit.
22 initialBias int32 = 72
29 func punyError(s string) error { return &labelError{s, "A3"} }
31 // decode decodes a string as specified in section 6.2.
32 func decode(encoded string) (string, error) {
36 pos := 1 + strings.LastIndex(encoded, "-")
38 return "", punyError(encoded)
40 if pos == len(encoded) {
41 return encoded[:len(encoded)-1], nil
43 output := make([]rune, 0, len(encoded))
45 for _, r := range encoded[:pos-1] {
46 output = append(output, r)
49 i, n, bias := int32(0), initialN, initialBias
50 for pos < len(encoded) {
51 oldI, w := i, int32(1)
52 for k := base; ; k += base {
53 if pos == len(encoded) {
54 return "", punyError(encoded)
56 digit, ok := decodeDigit(encoded[pos])
58 return "", punyError(encoded)
63 return "", punyError(encoded)
75 if w >= math.MaxInt32/base {
76 return "", punyError(encoded)
79 x := int32(len(output) + 1)
80 bias = adapt(i-oldI, x, oldI == 0)
83 if n > utf8.MaxRune || len(output) >= 1024 {
84 return "", punyError(encoded)
86 output = append(output, 0)
87 copy(output[i+1:], output[i:])
91 return string(output), nil
94 // encode encodes a string as specified in section 6.3 and prepends prefix to
97 // The "while h < length(input)" line in the specification becomes "for
98 // remaining != 0" in the Go code, because len(s) in Go is in bytes, not runes.
99 func encode(prefix, s string) (string, error) {
100 output := make([]byte, len(prefix), len(prefix)+1+2*len(s))
102 delta, n, bias := int32(0), initialN, initialBias
103 b, remaining := int32(0), int32(0)
104 for _, r := range s {
107 output = append(output, byte(r))
114 output = append(output, '-')
117 m := int32(0x7fffffff)
118 for _, r := range s {
123 delta += (m - n) * (h + 1)
125 return "", punyError(s)
128 for _, r := range s {
132 return "", punyError(s)
140 for k := base; ; k += base {
150 output = append(output, encodeDigit(t+(q-t)%(base-t)))
151 q = (q - t) / (base - t)
153 output = append(output, encodeDigit(q))
154 bias = adapt(delta, h+1, h == b)
162 return string(output), nil
165 func decodeDigit(x byte) (digit int32, ok bool) {
167 case '0' <= x && x <= '9':
168 return int32(x - ('0' - 26)), true
169 case 'A' <= x && x <= 'Z':
170 return int32(x - 'A'), true
171 case 'a' <= x && x <= 'z':
172 return int32(x - 'a'), true
177 func encodeDigit(digit int32) byte {
179 case 0 <= digit && digit < 26:
180 return byte(digit + 'a')
181 case 26 <= digit && digit < 36:
182 return byte(digit + ('0' - 26))
184 panic("idna: internal error in punycode encoding")
187 // adapt is the bias adaptation function specified in section 6.1.
188 func adapt(delta, numPoints int32, firstTime bool) int32 {
194 delta += delta / numPoints
196 for delta > ((base-tmin)*tmax)/2 {
200 return k + (base-tmin+1)*delta/(delta+skew)