xref: /aosp_15_r20/external/golang-protobuf/internal/encoding/text/decode_string.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
1*1c12ee1eSDan Willemsen// Copyright 2018 The Go Authors. All rights reserved.
2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style
3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file.
4*1c12ee1eSDan Willemsen
5*1c12ee1eSDan Willemsenpackage text
6*1c12ee1eSDan Willemsen
7*1c12ee1eSDan Willemsenimport (
8*1c12ee1eSDan Willemsen	"bytes"
9*1c12ee1eSDan Willemsen	"strconv"
10*1c12ee1eSDan Willemsen	"strings"
11*1c12ee1eSDan Willemsen	"unicode"
12*1c12ee1eSDan Willemsen	"unicode/utf16"
13*1c12ee1eSDan Willemsen	"unicode/utf8"
14*1c12ee1eSDan Willemsen
15*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/strs"
16*1c12ee1eSDan Willemsen)
17*1c12ee1eSDan Willemsen
18*1c12ee1eSDan Willemsen// parseStringValue parses string field token.
19*1c12ee1eSDan Willemsen// This differs from parseString since the text format allows
20*1c12ee1eSDan Willemsen// multiple back-to-back string literals where they are semantically treated
21*1c12ee1eSDan Willemsen// as a single large string with all values concatenated.
22*1c12ee1eSDan Willemsen//
23*1c12ee1eSDan Willemsen// E.g., `"foo" "bar" "baz"` => "foobarbaz"
24*1c12ee1eSDan Willemsenfunc (d *Decoder) parseStringValue() (Token, error) {
25*1c12ee1eSDan Willemsen	// Note that the ending quote is sufficient to unambiguously mark the end
26*1c12ee1eSDan Willemsen	// of a string. Thus, the text grammar does not require intervening
27*1c12ee1eSDan Willemsen	// whitespace or control characters in-between strings.
28*1c12ee1eSDan Willemsen	// Thus, the following is valid:
29*1c12ee1eSDan Willemsen	//	`"foo"'bar'"baz"` => "foobarbaz"
30*1c12ee1eSDan Willemsen	in0 := d.in
31*1c12ee1eSDan Willemsen	var ss []string
32*1c12ee1eSDan Willemsen	for len(d.in) > 0 && (d.in[0] == '"' || d.in[0] == '\'') {
33*1c12ee1eSDan Willemsen		s, err := d.parseString()
34*1c12ee1eSDan Willemsen		if err != nil {
35*1c12ee1eSDan Willemsen			return Token{}, err
36*1c12ee1eSDan Willemsen		}
37*1c12ee1eSDan Willemsen		ss = append(ss, s)
38*1c12ee1eSDan Willemsen	}
39*1c12ee1eSDan Willemsen	// d.in already points to the end of the value at this point.
40*1c12ee1eSDan Willemsen	return Token{
41*1c12ee1eSDan Willemsen		kind:  Scalar,
42*1c12ee1eSDan Willemsen		attrs: stringValue,
43*1c12ee1eSDan Willemsen		pos:   len(d.orig) - len(in0),
44*1c12ee1eSDan Willemsen		raw:   in0[:len(in0)-len(d.in)],
45*1c12ee1eSDan Willemsen		str:   strings.Join(ss, ""),
46*1c12ee1eSDan Willemsen	}, nil
47*1c12ee1eSDan Willemsen}
48*1c12ee1eSDan Willemsen
49*1c12ee1eSDan Willemsen// parseString parses a string value enclosed in " or '.
50*1c12ee1eSDan Willemsenfunc (d *Decoder) parseString() (string, error) {
51*1c12ee1eSDan Willemsen	in := d.in
52*1c12ee1eSDan Willemsen	if len(in) == 0 {
53*1c12ee1eSDan Willemsen		return "", ErrUnexpectedEOF
54*1c12ee1eSDan Willemsen	}
55*1c12ee1eSDan Willemsen	quote := in[0]
56*1c12ee1eSDan Willemsen	in = in[1:]
57*1c12ee1eSDan Willemsen	i := indexNeedEscapeInBytes(in)
58*1c12ee1eSDan Willemsen	in, out := in[i:], in[:i:i] // set cap to prevent mutations
59*1c12ee1eSDan Willemsen	for len(in) > 0 {
60*1c12ee1eSDan Willemsen		switch r, n := utf8.DecodeRune(in); {
61*1c12ee1eSDan Willemsen		case r == utf8.RuneError && n == 1:
62*1c12ee1eSDan Willemsen			return "", d.newSyntaxError("invalid UTF-8 detected")
63*1c12ee1eSDan Willemsen		case r == 0 || r == '\n':
64*1c12ee1eSDan Willemsen			return "", d.newSyntaxError("invalid character %q in string", r)
65*1c12ee1eSDan Willemsen		case r == rune(quote):
66*1c12ee1eSDan Willemsen			in = in[1:]
67*1c12ee1eSDan Willemsen			d.consume(len(d.in) - len(in))
68*1c12ee1eSDan Willemsen			return string(out), nil
69*1c12ee1eSDan Willemsen		case r == '\\':
70*1c12ee1eSDan Willemsen			if len(in) < 2 {
71*1c12ee1eSDan Willemsen				return "", ErrUnexpectedEOF
72*1c12ee1eSDan Willemsen			}
73*1c12ee1eSDan Willemsen			switch r := in[1]; r {
74*1c12ee1eSDan Willemsen			case '"', '\'', '\\', '?':
75*1c12ee1eSDan Willemsen				in, out = in[2:], append(out, r)
76*1c12ee1eSDan Willemsen			case 'a':
77*1c12ee1eSDan Willemsen				in, out = in[2:], append(out, '\a')
78*1c12ee1eSDan Willemsen			case 'b':
79*1c12ee1eSDan Willemsen				in, out = in[2:], append(out, '\b')
80*1c12ee1eSDan Willemsen			case 'n':
81*1c12ee1eSDan Willemsen				in, out = in[2:], append(out, '\n')
82*1c12ee1eSDan Willemsen			case 'r':
83*1c12ee1eSDan Willemsen				in, out = in[2:], append(out, '\r')
84*1c12ee1eSDan Willemsen			case 't':
85*1c12ee1eSDan Willemsen				in, out = in[2:], append(out, '\t')
86*1c12ee1eSDan Willemsen			case 'v':
87*1c12ee1eSDan Willemsen				in, out = in[2:], append(out, '\v')
88*1c12ee1eSDan Willemsen			case 'f':
89*1c12ee1eSDan Willemsen				in, out = in[2:], append(out, '\f')
90*1c12ee1eSDan Willemsen			case '0', '1', '2', '3', '4', '5', '6', '7':
91*1c12ee1eSDan Willemsen				// One, two, or three octal characters.
92*1c12ee1eSDan Willemsen				n := len(in[1:]) - len(bytes.TrimLeft(in[1:], "01234567"))
93*1c12ee1eSDan Willemsen				if n > 3 {
94*1c12ee1eSDan Willemsen					n = 3
95*1c12ee1eSDan Willemsen				}
96*1c12ee1eSDan Willemsen				v, err := strconv.ParseUint(string(in[1:1+n]), 8, 8)
97*1c12ee1eSDan Willemsen				if err != nil {
98*1c12ee1eSDan Willemsen					return "", d.newSyntaxError("invalid octal escape code %q in string", in[:1+n])
99*1c12ee1eSDan Willemsen				}
100*1c12ee1eSDan Willemsen				in, out = in[1+n:], append(out, byte(v))
101*1c12ee1eSDan Willemsen			case 'x':
102*1c12ee1eSDan Willemsen				// One or two hexadecimal characters.
103*1c12ee1eSDan Willemsen				n := len(in[2:]) - len(bytes.TrimLeft(in[2:], "0123456789abcdefABCDEF"))
104*1c12ee1eSDan Willemsen				if n > 2 {
105*1c12ee1eSDan Willemsen					n = 2
106*1c12ee1eSDan Willemsen				}
107*1c12ee1eSDan Willemsen				v, err := strconv.ParseUint(string(in[2:2+n]), 16, 8)
108*1c12ee1eSDan Willemsen				if err != nil {
109*1c12ee1eSDan Willemsen					return "", d.newSyntaxError("invalid hex escape code %q in string", in[:2+n])
110*1c12ee1eSDan Willemsen				}
111*1c12ee1eSDan Willemsen				in, out = in[2+n:], append(out, byte(v))
112*1c12ee1eSDan Willemsen			case 'u', 'U':
113*1c12ee1eSDan Willemsen				// Four or eight hexadecimal characters
114*1c12ee1eSDan Willemsen				n := 6
115*1c12ee1eSDan Willemsen				if r == 'U' {
116*1c12ee1eSDan Willemsen					n = 10
117*1c12ee1eSDan Willemsen				}
118*1c12ee1eSDan Willemsen				if len(in) < n {
119*1c12ee1eSDan Willemsen					return "", ErrUnexpectedEOF
120*1c12ee1eSDan Willemsen				}
121*1c12ee1eSDan Willemsen				v, err := strconv.ParseUint(string(in[2:n]), 16, 32)
122*1c12ee1eSDan Willemsen				if utf8.MaxRune < v || err != nil {
123*1c12ee1eSDan Willemsen					return "", d.newSyntaxError("invalid Unicode escape code %q in string", in[:n])
124*1c12ee1eSDan Willemsen				}
125*1c12ee1eSDan Willemsen				in = in[n:]
126*1c12ee1eSDan Willemsen
127*1c12ee1eSDan Willemsen				r := rune(v)
128*1c12ee1eSDan Willemsen				if utf16.IsSurrogate(r) {
129*1c12ee1eSDan Willemsen					if len(in) < 6 {
130*1c12ee1eSDan Willemsen						return "", ErrUnexpectedEOF
131*1c12ee1eSDan Willemsen					}
132*1c12ee1eSDan Willemsen					v, err := strconv.ParseUint(string(in[2:6]), 16, 16)
133*1c12ee1eSDan Willemsen					r = utf16.DecodeRune(r, rune(v))
134*1c12ee1eSDan Willemsen					if in[0] != '\\' || in[1] != 'u' || r == unicode.ReplacementChar || err != nil {
135*1c12ee1eSDan Willemsen						return "", d.newSyntaxError("invalid Unicode escape code %q in string", in[:6])
136*1c12ee1eSDan Willemsen					}
137*1c12ee1eSDan Willemsen					in = in[6:]
138*1c12ee1eSDan Willemsen				}
139*1c12ee1eSDan Willemsen				out = append(out, string(r)...)
140*1c12ee1eSDan Willemsen			default:
141*1c12ee1eSDan Willemsen				return "", d.newSyntaxError("invalid escape code %q in string", in[:2])
142*1c12ee1eSDan Willemsen			}
143*1c12ee1eSDan Willemsen		default:
144*1c12ee1eSDan Willemsen			i := indexNeedEscapeInBytes(in[n:])
145*1c12ee1eSDan Willemsen			in, out = in[n+i:], append(out, in[:n+i]...)
146*1c12ee1eSDan Willemsen		}
147*1c12ee1eSDan Willemsen	}
148*1c12ee1eSDan Willemsen	return "", ErrUnexpectedEOF
149*1c12ee1eSDan Willemsen}
150*1c12ee1eSDan Willemsen
151*1c12ee1eSDan Willemsen// indexNeedEscapeInString returns the index of the character that needs
152*1c12ee1eSDan Willemsen// escaping. If no characters need escaping, this returns the input length.
153*1c12ee1eSDan Willemsenfunc indexNeedEscapeInBytes(b []byte) int { return indexNeedEscapeInString(strs.UnsafeString(b)) }
154*1c12ee1eSDan Willemsen
155*1c12ee1eSDan Willemsen// UnmarshalString returns an unescaped string given a textproto string value.
156*1c12ee1eSDan Willemsen// String value needs to contain single or double quotes. This is only used by
157*1c12ee1eSDan Willemsen// internal/encoding/defval package for unmarshaling bytes.
158*1c12ee1eSDan Willemsenfunc UnmarshalString(s string) (string, error) {
159*1c12ee1eSDan Willemsen	d := NewDecoder([]byte(s))
160*1c12ee1eSDan Willemsen	return d.parseString()
161*1c12ee1eSDan Willemsen}
162