1
2
3
4
5 package idna
6
7
8
9 import (
10 "math"
11 "strings"
12 "unicode/utf8"
13 )
14
15
16
17
18
19 const (
20 base int32 = 36
21 damp int32 = 700
22 initialBias int32 = 72
23 initialN int32 = 128
24 skew int32 = 38
25 tmax int32 = 26
26 tmin int32 = 1
27 )
28
29 func punyError(s string) error { return &labelError{s, "A3"} }
30
31
32 func decode(encoded string) (string, error) {
33 if encoded == "" {
34 return "", nil
35 }
36 pos := 1 + strings.LastIndex(encoded, "-")
37 if pos == 1 {
38 return "", punyError(encoded)
39 }
40 if pos == len(encoded) {
41 return encoded[:len(encoded)-1], nil
42 }
43 output := make([]rune, 0, len(encoded))
44 if pos != 0 {
45 for _, r := range encoded[:pos-1] {
46 output = append(output, r)
47 }
48 }
49 i, n, bias := int32(0), initialN, initialBias
50 overflow := false
51 for pos < len(encoded) {
52 oldI, w := i, int32(1)
53 for k := base; ; k += base {
54 if pos == len(encoded) {
55 return "", punyError(encoded)
56 }
57 digit, ok := decodeDigit(encoded[pos])
58 if !ok {
59 return "", punyError(encoded)
60 }
61 pos++
62 i, overflow = madd(i, digit, w)
63 if overflow {
64 return "", punyError(encoded)
65 }
66 t := k - bias
67 if k <= bias {
68 t = tmin
69 } else if k >= bias+tmax {
70 t = tmax
71 }
72 if digit < t {
73 break
74 }
75 w, overflow = madd(0, w, base-t)
76 if overflow {
77 return "", punyError(encoded)
78 }
79 }
80 if len(output) >= 1024 {
81 return "", punyError(encoded)
82 }
83 x := int32(len(output) + 1)
84 bias = adapt(i-oldI, x, oldI == 0)
85 n += i / x
86 i %= x
87 if n < 0 || n > utf8.MaxRune {
88 return "", punyError(encoded)
89 }
90 output = append(output, 0)
91 copy(output[i+1:], output[i:])
92 output[i] = n
93 i++
94 }
95 return string(output), nil
96 }
97
98
99
100
101
102
103 func encode(prefix, s string) (string, error) {
104 output := make([]byte, len(prefix), len(prefix)+1+2*len(s))
105 copy(output, prefix)
106 delta, n, bias := int32(0), initialN, initialBias
107 b, remaining := int32(0), int32(0)
108 for _, r := range s {
109 if r < 0x80 {
110 b++
111 output = append(output, byte(r))
112 } else {
113 remaining++
114 }
115 }
116 h := b
117 if b > 0 {
118 output = append(output, '-')
119 }
120 overflow := false
121 for remaining != 0 {
122 m := int32(0x7fffffff)
123 for _, r := range s {
124 if m > r && r >= n {
125 m = r
126 }
127 }
128 delta, overflow = madd(delta, m-n, h+1)
129 if overflow {
130 return "", punyError(s)
131 }
132 n = m
133 for _, r := range s {
134 if r < n {
135 delta++
136 if delta < 0 {
137 return "", punyError(s)
138 }
139 continue
140 }
141 if r > n {
142 continue
143 }
144 q := delta
145 for k := base; ; k += base {
146 t := k - bias
147 if k <= bias {
148 t = tmin
149 } else if k >= bias+tmax {
150 t = tmax
151 }
152 if q < t {
153 break
154 }
155 output = append(output, encodeDigit(t+(q-t)%(base-t)))
156 q = (q - t) / (base - t)
157 }
158 output = append(output, encodeDigit(q))
159 bias = adapt(delta, h+1, h == b)
160 delta = 0
161 h++
162 remaining--
163 }
164 delta++
165 n++
166 }
167 return string(output), nil
168 }
169
170
171 func madd(a, b, c int32) (next int32, overflow bool) {
172 p := int64(b) * int64(c)
173 if p > math.MaxInt32-int64(a) {
174 return 0, true
175 }
176 return a + int32(p), false
177 }
178
179 func decodeDigit(x byte) (digit int32, ok bool) {
180 switch {
181 case '0' <= x && x <= '9':
182 return int32(x - ('0' - 26)), true
183 case 'A' <= x && x <= 'Z':
184 return int32(x - 'A'), true
185 case 'a' <= x && x <= 'z':
186 return int32(x - 'a'), true
187 }
188 return 0, false
189 }
190
191 func encodeDigit(digit int32) byte {
192 switch {
193 case 0 <= digit && digit < 26:
194 return byte(digit + 'a')
195 case 26 <= digit && digit < 36:
196 return byte(digit + ('0' - 26))
197 }
198 panic("idna: internal error in punycode encoding")
199 }
200
201
202 func adapt(delta, numPoints int32, firstTime bool) int32 {
203 if firstTime {
204 delta /= damp
205 } else {
206 delta /= 2
207 }
208 delta += delta / numPoints
209 k := int32(0)
210 for delta > ((base-tmin)*tmax)/2 {
211 delta /= base - tmin
212 k += base
213 }
214 return k + (base-tmin+1)*delta/(delta+skew)
215 }
216
View as plain text