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