OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / text / internal / export / idna / punycode.go
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.
4
5 package idna
6
7 // This file implements the Punycode algorithm from RFC 3492.
8
9 import (
10         "math"
11         "strings"
12         "unicode/utf8"
13 )
14
15 // These parameter values are specified in section 5.
16 //
17 // All computation is done with int32s, so that overflow behavior is identical
18 // regardless of whether int is 32-bit or 64-bit.
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 // decode decodes a string as specified in section 6.2.
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         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)
55                         }
56                         digit, ok := decodeDigit(encoded[pos])
57                         if !ok {
58                                 return "", punyError(encoded)
59                         }
60                         pos++
61                         i += digit * w
62                         if i < 0 {
63                                 return "", punyError(encoded)
64                         }
65                         t := k - bias
66                         if t < tmin {
67                                 t = tmin
68                         } else if t > tmax {
69                                 t = tmax
70                         }
71                         if digit < t {
72                                 break
73                         }
74                         w *= base - t
75                         if w >= math.MaxInt32/base {
76                                 return "", punyError(encoded)
77                         }
78                 }
79                 x := int32(len(output) + 1)
80                 bias = adapt(i-oldI, x, oldI == 0)
81                 n += i / x
82                 i %= x
83                 if n > utf8.MaxRune || len(output) >= 1024 {
84                         return "", punyError(encoded)
85                 }
86                 output = append(output, 0)
87                 copy(output[i+1:], output[i:])
88                 output[i] = n
89                 i++
90         }
91         return string(output), nil
92 }
93
94 // encode encodes a string as specified in section 6.3 and prepends prefix to
95 // the result.
96 //
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))
101         copy(output, prefix)
102         delta, n, bias := int32(0), initialN, initialBias
103         b, remaining := int32(0), int32(0)
104         for _, r := range s {
105                 if r < 0x80 {
106                         b++
107                         output = append(output, byte(r))
108                 } else {
109                         remaining++
110                 }
111         }
112         h := b
113         if b > 0 {
114                 output = append(output, '-')
115         }
116         for remaining != 0 {
117                 m := int32(0x7fffffff)
118                 for _, r := range s {
119                         if m > r && r >= n {
120                                 m = r
121                         }
122                 }
123                 delta += (m - n) * (h + 1)
124                 if delta < 0 {
125                         return "", punyError(s)
126                 }
127                 n = m
128                 for _, r := range s {
129                         if r < n {
130                                 delta++
131                                 if delta < 0 {
132                                         return "", punyError(s)
133                                 }
134                                 continue
135                         }
136                         if r > n {
137                                 continue
138                         }
139                         q := delta
140                         for k := base; ; k += base {
141                                 t := k - bias
142                                 if t < tmin {
143                                         t = tmin
144                                 } else if t > tmax {
145                                         t = tmax
146                                 }
147                                 if q < t {
148                                         break
149                                 }
150                                 output = append(output, encodeDigit(t+(q-t)%(base-t)))
151                                 q = (q - t) / (base - t)
152                         }
153                         output = append(output, encodeDigit(q))
154                         bias = adapt(delta, h+1, h == b)
155                         delta = 0
156                         h++
157                         remaining--
158                 }
159                 delta++
160                 n++
161         }
162         return string(output), nil
163 }
164
165 func decodeDigit(x byte) (digit int32, ok bool) {
166         switch {
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
173         }
174         return 0, false
175 }
176
177 func encodeDigit(digit int32) byte {
178         switch {
179         case 0 <= digit && digit < 26:
180                 return byte(digit + 'a')
181         case 26 <= digit && digit < 36:
182                 return byte(digit + ('0' - 26))
183         }
184         panic("idna: internal error in punycode encoding")
185 }
186
187 // adapt is the bias adaptation function specified in section 6.1.
188 func adapt(delta, numPoints int32, firstTime bool) int32 {
189         if firstTime {
190                 delta /= damp
191         } else {
192                 delta /= 2
193         }
194         delta += delta / numPoints
195         k := int32(0)
196         for delta > ((base-tmin)*tmax)/2 {
197                 delta /= base - tmin
198                 k += base
199         }
200         return k + (base-tmin+1)*delta/(delta+skew)
201 }