punycode.go (4720B)
1 // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. 2 3 // Copyright 2016 The Go Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file. 6 7 package idna 8 9 // This file implements the Punycode algorithm from RFC 3492. 10 11 import ( 12 "math" 13 "strings" 14 "unicode/utf8" 15 ) 16 17 // These parameter values are specified in section 5. 18 // 19 // All computation is done with int32s, so that overflow behavior is identical 20 // regardless of whether int is 32-bit or 64-bit. 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, "A3"} } 32 33 // decode decodes a string as specified in section 6.2. 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 // encode encodes a string as specified in section 6.3 and prepends prefix to 101 // the result. 102 // 103 // The "while h < length(input)" line in the specification becomes "for 104 // remaining != 0" in the Go code, because len(s) in Go is in bytes, not runes. 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 r < 0x80 { 112 b++ 113 output = append(output, byte(r)) 114 } else { 115 remaining++ 116 } 117 } 118 h := b 119 if b > 0 { 120 output = append(output, '-') 121 } 122 overflow := false 123 for remaining != 0 { 124 m := int32(0x7fffffff) 125 for _, r := range s { 126 if m > r && r >= n { 127 m = r 128 } 129 } 130 delta, overflow = madd(delta, m-n, h+1) 131 if overflow { 132 return "", punyError(s) 133 } 134 n = m 135 for _, r := range s { 136 if r < n { 137 delta++ 138 if delta < 0 { 139 return "", punyError(s) 140 } 141 continue 142 } 143 if r > n { 144 continue 145 } 146 q := delta 147 for k := base; ; k += base { 148 t := k - bias 149 if k <= bias { 150 t = tmin 151 } else if k >= bias+tmax { 152 t = tmax 153 } 154 if q < t { 155 break 156 } 157 output = append(output, encodeDigit(t+(q-t)%(base-t))) 158 q = (q - t) / (base - t) 159 } 160 output = append(output, encodeDigit(q)) 161 bias = adapt(delta, h+1, h == b) 162 delta = 0 163 h++ 164 remaining-- 165 } 166 delta++ 167 n++ 168 } 169 return string(output), nil 170 } 171 172 // madd computes a + (b * c), detecting overflow. 173 func madd(a, b, c int32) (next int32, overflow bool) { 174 p := int64(b) * int64(c) 175 if p > math.MaxInt32-int64(a) { 176 return 0, true 177 } 178 return a + int32(p), false 179 } 180 181 func decodeDigit(x byte) (digit int32, ok bool) { 182 switch { 183 case '0' <= x && x <= '9': 184 return int32(x - ('0' - 26)), true 185 case 'A' <= x && x <= 'Z': 186 return int32(x - 'A'), true 187 case 'a' <= x && x <= 'z': 188 return int32(x - 'a'), true 189 } 190 return 0, false 191 } 192 193 func encodeDigit(digit int32) byte { 194 switch { 195 case 0 <= digit && digit < 26: 196 return byte(digit + 'a') 197 case 26 <= digit && digit < 36: 198 return byte(digit + ('0' - 26)) 199 } 200 panic("idna: internal error in punycode encoding") 201 } 202 203 // adapt is the bias adaptation function specified in section 6.1. 204 func adapt(delta, numPoints int32, firstTime bool) int32 { 205 if firstTime { 206 delta /= damp 207 } else { 208 delta /= 2 209 } 210 delta += delta / numPoints 211 k := int32(0) 212 for delta > ((base-tmin)*tmax)/2 { 213 delta /= base - tmin 214 k += base 215 } 216 return k + (base-tmin+1)*delta/(delta+skew) 217 }