github.com/go-xe2/third@v1.0.3/golang.org/x/text/internal/export/idna/punycode.go (about) 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 }