| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788 |
- package utf7
- import (
- "strings"
- "unicode/utf16"
- "unicode/utf8"
- )
- // Encode encodes a string with modified UTF-7.
- func Encode(src string) string {
- var sb strings.Builder
- sb.Grow(len(src))
- for i := 0; i < len(src); {
- ch := src[i]
- if min <= ch && ch <= max {
- sb.WriteByte(ch)
- if ch == '&' {
- sb.WriteByte('-')
- }
- i++
- } else {
- start := i
- // Find the next printable ASCII code point
- i++
- for i < len(src) && (src[i] < min || src[i] > max) {
- i++
- }
- sb.Write(encode([]byte(src[start:i])))
- }
- }
- return sb.String()
- }
- // Converts string s from UTF-8 to UTF-16-BE, encodes the result as base64,
- // removes the padding, and adds UTF-7 shifts.
- func encode(s []byte) []byte {
- // len(s) is sufficient for UTF-8 to UTF-16 conversion if there are no
- // control code points (see table below).
- b := make([]byte, 0, len(s)+4)
- for len(s) > 0 {
- r, size := utf8.DecodeRune(s)
- if r > utf8.MaxRune {
- r, size = utf8.RuneError, 1 // Bug fix (issue 3785)
- }
- s = s[size:]
- if r1, r2 := utf16.EncodeRune(r); r1 != utf8.RuneError {
- b = append(b, byte(r1>>8), byte(r1))
- r = r2
- }
- b = append(b, byte(r>>8), byte(r))
- }
- // Encode as base64
- n := b64Enc.EncodedLen(len(b)) + 2
- b64 := make([]byte, n)
- b64Enc.Encode(b64[1:], b)
- // Strip padding
- n -= 2 - (len(b)+2)%3
- b64 = b64[:n]
- // Add UTF-7 shifts
- b64[0] = '&'
- b64[n-1] = '-'
- return b64
- }
- // Escape passes through raw UTF-8 as-is and escapes the special UTF-7 marker
- // (the ampersand character).
- func Escape(src string) string {
- var sb strings.Builder
- sb.Grow(len(src))
- for _, ch := range src {
- sb.WriteRune(ch)
- if ch == '&' {
- sb.WriteByte('-')
- }
- }
- return sb.String()
- }
|