You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
203 lines
4.3 KiB
203 lines
4.3 KiB
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. |
|
|
|
// Copyright 2016 The Go Authors. All rights reserved. |
|
// Use of this source code is governed by a BSD-style |
|
// license that can be found in the LICENSE file. |
|
|
|
package idna |
|
|
|
// This file implements the Punycode algorithm from RFC 3492. |
|
|
|
import ( |
|
"math" |
|
"strings" |
|
"unicode/utf8" |
|
) |
|
|
|
// These parameter values are specified in section 5. |
|
// |
|
// All computation is done with int32s, so that overflow behavior is identical |
|
// regardless of whether int is 32-bit or 64-bit. |
|
const ( |
|
base int32 = 36 |
|
damp int32 = 700 |
|
initialBias int32 = 72 |
|
initialN int32 = 128 |
|
skew int32 = 38 |
|
tmax int32 = 26 |
|
tmin int32 = 1 |
|
) |
|
|
|
func punyError(s string) error { return &labelError{s, "A3"} } |
|
|
|
// decode decodes a string as specified in section 6.2. |
|
func decode(encoded string) (string, error) { |
|
if encoded == "" { |
|
return "", nil |
|
} |
|
pos := 1 + strings.LastIndex(encoded, "-") |
|
if pos == 1 { |
|
return "", punyError(encoded) |
|
} |
|
if pos == len(encoded) { |
|
return encoded[:len(encoded)-1], nil |
|
} |
|
output := make([]rune, 0, len(encoded)) |
|
if pos != 0 { |
|
for _, r := range encoded[:pos-1] { |
|
output = append(output, r) |
|
} |
|
} |
|
i, n, bias := int32(0), initialN, initialBias |
|
for pos < len(encoded) { |
|
oldI, w := i, int32(1) |
|
for k := base; ; k += base { |
|
if pos == len(encoded) { |
|
return "", punyError(encoded) |
|
} |
|
digit, ok := decodeDigit(encoded[pos]) |
|
if !ok { |
|
return "", punyError(encoded) |
|
} |
|
pos++ |
|
i += digit * w |
|
if i < 0 { |
|
return "", punyError(encoded) |
|
} |
|
t := k - bias |
|
if t < tmin { |
|
t = tmin |
|
} else if t > tmax { |
|
t = tmax |
|
} |
|
if digit < t { |
|
break |
|
} |
|
w *= base - t |
|
if w >= math.MaxInt32/base { |
|
return "", punyError(encoded) |
|
} |
|
} |
|
x := int32(len(output) + 1) |
|
bias = adapt(i-oldI, x, oldI == 0) |
|
n += i / x |
|
i %= x |
|
if n > utf8.MaxRune || len(output) >= 1024 { |
|
return "", punyError(encoded) |
|
} |
|
output = append(output, 0) |
|
copy(output[i+1:], output[i:]) |
|
output[i] = n |
|
i++ |
|
} |
|
return string(output), nil |
|
} |
|
|
|
// encode encodes a string as specified in section 6.3 and prepends prefix to |
|
// the result. |
|
// |
|
// The "while h < length(input)" line in the specification becomes "for |
|
// remaining != 0" in the Go code, because len(s) in Go is in bytes, not runes. |
|
func encode(prefix, s string) (string, error) { |
|
output := make([]byte, len(prefix), len(prefix)+1+2*len(s)) |
|
copy(output, prefix) |
|
delta, n, bias := int32(0), initialN, initialBias |
|
b, remaining := int32(0), int32(0) |
|
for _, r := range s { |
|
if r < 0x80 { |
|
b++ |
|
output = append(output, byte(r)) |
|
} else { |
|
remaining++ |
|
} |
|
} |
|
h := b |
|
if b > 0 { |
|
output = append(output, '-') |
|
} |
|
for remaining != 0 { |
|
m := int32(0x7fffffff) |
|
for _, r := range s { |
|
if m > r && r >= n { |
|
m = r |
|
} |
|
} |
|
delta += (m - n) * (h + 1) |
|
if delta < 0 { |
|
return "", punyError(s) |
|
} |
|
n = m |
|
for _, r := range s { |
|
if r < n { |
|
delta++ |
|
if delta < 0 { |
|
return "", punyError(s) |
|
} |
|
continue |
|
} |
|
if r > n { |
|
continue |
|
} |
|
q := delta |
|
for k := base; ; k += base { |
|
t := k - bias |
|
if t < tmin { |
|
t = tmin |
|
} else if t > tmax { |
|
t = tmax |
|
} |
|
if q < t { |
|
break |
|
} |
|
output = append(output, encodeDigit(t+(q-t)%(base-t))) |
|
q = (q - t) / (base - t) |
|
} |
|
output = append(output, encodeDigit(q)) |
|
bias = adapt(delta, h+1, h == b) |
|
delta = 0 |
|
h++ |
|
remaining-- |
|
} |
|
delta++ |
|
n++ |
|
} |
|
return string(output), nil |
|
} |
|
|
|
func decodeDigit(x byte) (digit int32, ok bool) { |
|
switch { |
|
case '0' <= x && x <= '9': |
|
return int32(x - ('0' - 26)), true |
|
case 'A' <= x && x <= 'Z': |
|
return int32(x - 'A'), true |
|
case 'a' <= x && x <= 'z': |
|
return int32(x - 'a'), true |
|
} |
|
return 0, false |
|
} |
|
|
|
func encodeDigit(digit int32) byte { |
|
switch { |
|
case 0 <= digit && digit < 26: |
|
return byte(digit + 'a') |
|
case 26 <= digit && digit < 36: |
|
return byte(digit + ('0' - 26)) |
|
} |
|
panic("idna: internal error in punycode encoding") |
|
} |
|
|
|
// adapt is the bias adaptation function specified in section 6.1. |
|
func adapt(delta, numPoints int32, firstTime bool) int32 { |
|
if firstTime { |
|
delta /= damp |
|
} else { |
|
delta /= 2 |
|
} |
|
delta += delta / numPoints |
|
k := int32(0) |
|
for delta > ((base-tmin)*tmax)/2 { |
|
delta /= base - tmin |
|
k += base |
|
} |
|
return k + (base-tmin+1)*delta/(delta+skew) |
|
}
|
|
|