punycode.go

  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
  7package idna
  8
  9// This file implements the Punycode algorithm from RFC 3492.
 10
 11import (
 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.
 21const (
 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
 31func punyError(s string) error { return &labelError{s, "A3"} }
 32
 33// decode decodes a string as specified in section 6.2.
 34func 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.
105func 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.
173func 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
181func 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
193func 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.
204func 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}