diff options
Diffstat (limited to 'vendor/github.com/golang/protobuf/proto/text_parser.go')
-rw-r--r-- | vendor/github.com/golang/protobuf/proto/text_parser.go | 880 |
1 files changed, 880 insertions, 0 deletions
diff --git a/vendor/github.com/golang/protobuf/proto/text_parser.go b/vendor/github.com/golang/protobuf/proto/text_parser.go new file mode 100644 index 0000000..bb55a3a --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/text_parser.go | |||
@@ -0,0 +1,880 @@ | |||
1 | // Go support for Protocol Buffers - Google's data interchange format | ||
2 | // | ||
3 | // Copyright 2010 The Go Authors. All rights reserved. | ||
4 | // https://github.com/golang/protobuf | ||
5 | // | ||
6 | // Redistribution and use in source and binary forms, with or without | ||
7 | // modification, are permitted provided that the following conditions are | ||
8 | // met: | ||
9 | // | ||
10 | // * Redistributions of source code must retain the above copyright | ||
11 | // notice, this list of conditions and the following disclaimer. | ||
12 | // * Redistributions in binary form must reproduce the above | ||
13 | // copyright notice, this list of conditions and the following disclaimer | ||
14 | // in the documentation and/or other materials provided with the | ||
15 | // distribution. | ||
16 | // * Neither the name of Google Inc. nor the names of its | ||
17 | // contributors may be used to endorse or promote products derived from | ||
18 | // this software without specific prior written permission. | ||
19 | // | ||
20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | |||
32 | package proto | ||
33 | |||
34 | // Functions for parsing the Text protocol buffer format. | ||
35 | // TODO: message sets. | ||
36 | |||
37 | import ( | ||
38 | "encoding" | ||
39 | "errors" | ||
40 | "fmt" | ||
41 | "reflect" | ||
42 | "strconv" | ||
43 | "strings" | ||
44 | "unicode/utf8" | ||
45 | ) | ||
46 | |||
47 | // Error string emitted when deserializing Any and fields are already set | ||
48 | const anyRepeatedlyUnpacked = "Any message unpacked multiple times, or %q already set" | ||
49 | |||
50 | type ParseError struct { | ||
51 | Message string | ||
52 | Line int // 1-based line number | ||
53 | Offset int // 0-based byte offset from start of input | ||
54 | } | ||
55 | |||
56 | func (p *ParseError) Error() string { | ||
57 | if p.Line == 1 { | ||
58 | // show offset only for first line | ||
59 | return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message) | ||
60 | } | ||
61 | return fmt.Sprintf("line %d: %v", p.Line, p.Message) | ||
62 | } | ||
63 | |||
64 | type token struct { | ||
65 | value string | ||
66 | err *ParseError | ||
67 | line int // line number | ||
68 | offset int // byte number from start of input, not start of line | ||
69 | unquoted string // the unquoted version of value, if it was a quoted string | ||
70 | } | ||
71 | |||
72 | func (t *token) String() string { | ||
73 | if t.err == nil { | ||
74 | return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset) | ||
75 | } | ||
76 | return fmt.Sprintf("parse error: %v", t.err) | ||
77 | } | ||
78 | |||
79 | type textParser struct { | ||
80 | s string // remaining input | ||
81 | done bool // whether the parsing is finished (success or error) | ||
82 | backed bool // whether back() was called | ||
83 | offset, line int | ||
84 | cur token | ||
85 | } | ||
86 | |||
87 | func newTextParser(s string) *textParser { | ||
88 | p := new(textParser) | ||
89 | p.s = s | ||
90 | p.line = 1 | ||
91 | p.cur.line = 1 | ||
92 | return p | ||
93 | } | ||
94 | |||
95 | func (p *textParser) errorf(format string, a ...interface{}) *ParseError { | ||
96 | pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset} | ||
97 | p.cur.err = pe | ||
98 | p.done = true | ||
99 | return pe | ||
100 | } | ||
101 | |||
102 | // Numbers and identifiers are matched by [-+._A-Za-z0-9] | ||
103 | func isIdentOrNumberChar(c byte) bool { | ||
104 | switch { | ||
105 | case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z': | ||
106 | return true | ||
107 | case '0' <= c && c <= '9': | ||
108 | return true | ||
109 | } | ||
110 | switch c { | ||
111 | case '-', '+', '.', '_': | ||
112 | return true | ||
113 | } | ||
114 | return false | ||
115 | } | ||
116 | |||
117 | func isWhitespace(c byte) bool { | ||
118 | switch c { | ||
119 | case ' ', '\t', '\n', '\r': | ||
120 | return true | ||
121 | } | ||
122 | return false | ||
123 | } | ||
124 | |||
125 | func isQuote(c byte) bool { | ||
126 | switch c { | ||
127 | case '"', '\'': | ||
128 | return true | ||
129 | } | ||
130 | return false | ||
131 | } | ||
132 | |||
133 | func (p *textParser) skipWhitespace() { | ||
134 | i := 0 | ||
135 | for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') { | ||
136 | if p.s[i] == '#' { | ||
137 | // comment; skip to end of line or input | ||
138 | for i < len(p.s) && p.s[i] != '\n' { | ||
139 | i++ | ||
140 | } | ||
141 | if i == len(p.s) { | ||
142 | break | ||
143 | } | ||
144 | } | ||
145 | if p.s[i] == '\n' { | ||
146 | p.line++ | ||
147 | } | ||
148 | i++ | ||
149 | } | ||
150 | p.offset += i | ||
151 | p.s = p.s[i:len(p.s)] | ||
152 | if len(p.s) == 0 { | ||
153 | p.done = true | ||
154 | } | ||
155 | } | ||
156 | |||
157 | func (p *textParser) advance() { | ||
158 | // Skip whitespace | ||
159 | p.skipWhitespace() | ||
160 | if p.done { | ||
161 | return | ||
162 | } | ||
163 | |||
164 | // Start of non-whitespace | ||
165 | p.cur.err = nil | ||
166 | p.cur.offset, p.cur.line = p.offset, p.line | ||
167 | p.cur.unquoted = "" | ||
168 | switch p.s[0] { | ||
169 | case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/': | ||
170 | // Single symbol | ||
171 | p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)] | ||
172 | case '"', '\'': | ||
173 | // Quoted string | ||
174 | i := 1 | ||
175 | for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' { | ||
176 | if p.s[i] == '\\' && i+1 < len(p.s) { | ||
177 | // skip escaped char | ||
178 | i++ | ||
179 | } | ||
180 | i++ | ||
181 | } | ||
182 | if i >= len(p.s) || p.s[i] != p.s[0] { | ||
183 | p.errorf("unmatched quote") | ||
184 | return | ||
185 | } | ||
186 | unq, err := unquoteC(p.s[1:i], rune(p.s[0])) | ||
187 | if err != nil { | ||
188 | p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err) | ||
189 | return | ||
190 | } | ||
191 | p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)] | ||
192 | p.cur.unquoted = unq | ||
193 | default: | ||
194 | i := 0 | ||
195 | for i < len(p.s) && isIdentOrNumberChar(p.s[i]) { | ||
196 | i++ | ||
197 | } | ||
198 | if i == 0 { | ||
199 | p.errorf("unexpected byte %#x", p.s[0]) | ||
200 | return | ||
201 | } | ||
202 | p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)] | ||
203 | } | ||
204 | p.offset += len(p.cur.value) | ||
205 | } | ||
206 | |||
207 | var ( | ||
208 | errBadUTF8 = errors.New("proto: bad UTF-8") | ||
209 | ) | ||
210 | |||
211 | func unquoteC(s string, quote rune) (string, error) { | ||
212 | // This is based on C++'s tokenizer.cc. | ||
213 | // Despite its name, this is *not* parsing C syntax. | ||
214 | // For instance, "\0" is an invalid quoted string. | ||
215 | |||
216 | // Avoid allocation in trivial cases. | ||
217 | simple := true | ||
218 | for _, r := range s { | ||
219 | if r == '\\' || r == quote { | ||
220 | simple = false | ||
221 | break | ||
222 | } | ||
223 | } | ||
224 | if simple { | ||
225 | return s, nil | ||
226 | } | ||
227 | |||
228 | buf := make([]byte, 0, 3*len(s)/2) | ||
229 | for len(s) > 0 { | ||
230 | r, n := utf8.DecodeRuneInString(s) | ||
231 | if r == utf8.RuneError && n == 1 { | ||
232 | return "", errBadUTF8 | ||
233 | } | ||
234 | s = s[n:] | ||
235 | if r != '\\' { | ||
236 | if r < utf8.RuneSelf { | ||
237 | buf = append(buf, byte(r)) | ||
238 | } else { | ||
239 | buf = append(buf, string(r)...) | ||
240 | } | ||
241 | continue | ||
242 | } | ||
243 | |||
244 | ch, tail, err := unescape(s) | ||
245 | if err != nil { | ||
246 | return "", err | ||
247 | } | ||
248 | buf = append(buf, ch...) | ||
249 | s = tail | ||
250 | } | ||
251 | return string(buf), nil | ||
252 | } | ||
253 | |||
254 | func unescape(s string) (ch string, tail string, err error) { | ||
255 | r, n := utf8.DecodeRuneInString(s) | ||
256 | if r == utf8.RuneError && n == 1 { | ||
257 | return "", "", errBadUTF8 | ||
258 | } | ||
259 | s = s[n:] | ||
260 | switch r { | ||
261 | case 'a': | ||
262 | return "\a", s, nil | ||
263 | case 'b': | ||
264 | return "\b", s, nil | ||
265 | case 'f': | ||
266 | return "\f", s, nil | ||
267 | case 'n': | ||
268 | return "\n", s, nil | ||
269 | case 'r': | ||
270 | return "\r", s, nil | ||
271 | case 't': | ||
272 | return "\t", s, nil | ||
273 | case 'v': | ||
274 | return "\v", s, nil | ||
275 | case '?': | ||
276 | return "?", s, nil // trigraph workaround | ||
277 | case '\'', '"', '\\': | ||
278 | return string(r), s, nil | ||
279 | case '0', '1', '2', '3', '4', '5', '6', '7': | ||
280 | if len(s) < 2 { | ||
281 | return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) | ||
282 | } | ||
283 | ss := string(r) + s[:2] | ||
284 | s = s[2:] | ||
285 | i, err := strconv.ParseUint(ss, 8, 8) | ||
286 | if err != nil { | ||
287 | return "", "", fmt.Errorf(`\%s contains non-octal digits`, ss) | ||
288 | } | ||
289 | return string([]byte{byte(i)}), s, nil | ||
290 | case 'x', 'X', 'u', 'U': | ||
291 | var n int | ||
292 | switch r { | ||
293 | case 'x', 'X': | ||
294 | n = 2 | ||
295 | case 'u': | ||
296 | n = 4 | ||
297 | case 'U': | ||
298 | n = 8 | ||
299 | } | ||
300 | if len(s) < n { | ||
301 | return "", "", fmt.Errorf(`\%c requires %d following digits`, r, n) | ||
302 | } | ||
303 | ss := s[:n] | ||
304 | s = s[n:] | ||
305 | i, err := strconv.ParseUint(ss, 16, 64) | ||
306 | if err != nil { | ||
307 | return "", "", fmt.Errorf(`\%c%s contains non-hexadecimal digits`, r, ss) | ||
308 | } | ||
309 | if r == 'x' || r == 'X' { | ||
310 | return string([]byte{byte(i)}), s, nil | ||
311 | } | ||
312 | if i > utf8.MaxRune { | ||
313 | return "", "", fmt.Errorf(`\%c%s is not a valid Unicode code point`, r, ss) | ||
314 | } | ||
315 | return string(i), s, nil | ||
316 | } | ||
317 | return "", "", fmt.Errorf(`unknown escape \%c`, r) | ||
318 | } | ||
319 | |||
320 | // Back off the parser by one token. Can only be done between calls to next(). | ||
321 | // It makes the next advance() a no-op. | ||
322 | func (p *textParser) back() { p.backed = true } | ||
323 | |||
324 | // Advances the parser and returns the new current token. | ||
325 | func (p *textParser) next() *token { | ||
326 | if p.backed || p.done { | ||
327 | p.backed = false | ||
328 | return &p.cur | ||
329 | } | ||
330 | p.advance() | ||
331 | if p.done { | ||
332 | p.cur.value = "" | ||
333 | } else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) { | ||
334 | // Look for multiple quoted strings separated by whitespace, | ||
335 | // and concatenate them. | ||
336 | cat := p.cur | ||
337 | for { | ||
338 | p.skipWhitespace() | ||
339 | if p.done || !isQuote(p.s[0]) { | ||
340 | break | ||
341 | } | ||
342 | p.advance() | ||
343 | if p.cur.err != nil { | ||
344 | return &p.cur | ||
345 | } | ||
346 | cat.value += " " + p.cur.value | ||
347 | cat.unquoted += p.cur.unquoted | ||
348 | } | ||
349 | p.done = false // parser may have seen EOF, but we want to return cat | ||
350 | p.cur = cat | ||
351 | } | ||
352 | return &p.cur | ||
353 | } | ||
354 | |||
355 | func (p *textParser) consumeToken(s string) error { | ||
356 | tok := p.next() | ||
357 | if tok.err != nil { | ||
358 | return tok.err | ||
359 | } | ||
360 | if tok.value != s { | ||
361 | p.back() | ||
362 | return p.errorf("expected %q, found %q", s, tok.value) | ||
363 | } | ||
364 | return nil | ||
365 | } | ||
366 | |||
367 | // Return a RequiredNotSetError indicating which required field was not set. | ||
368 | func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSetError { | ||
369 | st := sv.Type() | ||
370 | sprops := GetProperties(st) | ||
371 | for i := 0; i < st.NumField(); i++ { | ||
372 | if !isNil(sv.Field(i)) { | ||
373 | continue | ||
374 | } | ||
375 | |||
376 | props := sprops.Prop[i] | ||
377 | if props.Required { | ||
378 | return &RequiredNotSetError{fmt.Sprintf("%v.%v", st, props.OrigName)} | ||
379 | } | ||
380 | } | ||
381 | return &RequiredNotSetError{fmt.Sprintf("%v.<unknown field name>", st)} // should not happen | ||
382 | } | ||
383 | |||
384 | // Returns the index in the struct for the named field, as well as the parsed tag properties. | ||
385 | func structFieldByName(sprops *StructProperties, name string) (int, *Properties, bool) { | ||
386 | i, ok := sprops.decoderOrigNames[name] | ||
387 | if ok { | ||
388 | return i, sprops.Prop[i], true | ||
389 | } | ||
390 | return -1, nil, false | ||
391 | } | ||
392 | |||
393 | // Consume a ':' from the input stream (if the next token is a colon), | ||
394 | // returning an error if a colon is needed but not present. | ||
395 | func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError { | ||
396 | tok := p.next() | ||
397 | if tok.err != nil { | ||
398 | return tok.err | ||
399 | } | ||
400 | if tok.value != ":" { | ||
401 | // Colon is optional when the field is a group or message. | ||
402 | needColon := true | ||
403 | switch props.Wire { | ||
404 | case "group": | ||
405 | needColon = false | ||
406 | case "bytes": | ||
407 | // A "bytes" field is either a message, a string, or a repeated field; | ||
408 | // those three become *T, *string and []T respectively, so we can check for | ||
409 | // this field being a pointer to a non-string. | ||
410 | if typ.Kind() == reflect.Ptr { | ||
411 | // *T or *string | ||
412 | if typ.Elem().Kind() == reflect.String { | ||
413 | break | ||
414 | } | ||
415 | } else if typ.Kind() == reflect.Slice { | ||
416 | // []T or []*T | ||
417 | if typ.Elem().Kind() != reflect.Ptr { | ||
418 | break | ||
419 | } | ||
420 | } else if typ.Kind() == reflect.String { | ||
421 | // The proto3 exception is for a string field, | ||
422 | // which requires a colon. | ||
423 | break | ||
424 | } | ||
425 | needColon = false | ||
426 | } | ||
427 | if needColon { | ||
428 | return p.errorf("expected ':', found %q", tok.value) | ||
429 | } | ||
430 | p.back() | ||
431 | } | ||
432 | return nil | ||
433 | } | ||
434 | |||
435 | func (p *textParser) readStruct(sv reflect.Value, terminator string) error { | ||
436 | st := sv.Type() | ||
437 | sprops := GetProperties(st) | ||
438 | reqCount := sprops.reqCount | ||
439 | var reqFieldErr error | ||
440 | fieldSet := make(map[string]bool) | ||
441 | // A struct is a sequence of "name: value", terminated by one of | ||
442 | // '>' or '}', or the end of the input. A name may also be | ||
443 | // "[extension]" or "[type/url]". | ||
444 | // | ||
445 | // The whole struct can also be an expanded Any message, like: | ||
446 | // [type/url] < ... struct contents ... > | ||
447 | for { | ||
448 | tok := p.next() | ||
449 | if tok.err != nil { | ||
450 | return tok.err | ||
451 | } | ||
452 | if tok.value == terminator { | ||
453 | break | ||
454 | } | ||
455 | if tok.value == "[" { | ||
456 | // Looks like an extension or an Any. | ||
457 | // | ||
458 | // TODO: Check whether we need to handle | ||
459 | // namespace rooted names (e.g. ".something.Foo"). | ||
460 | extName, err := p.consumeExtName() | ||
461 | if err != nil { | ||
462 | return err | ||
463 | } | ||
464 | |||
465 | if s := strings.LastIndex(extName, "/"); s >= 0 { | ||
466 | // If it contains a slash, it's an Any type URL. | ||
467 | messageName := extName[s+1:] | ||
468 | mt := MessageType(messageName) | ||
469 | if mt == nil { | ||
470 | return p.errorf("unrecognized message %q in google.protobuf.Any", messageName) | ||
471 | } | ||
472 | tok = p.next() | ||
473 | if tok.err != nil { | ||
474 | return tok.err | ||
475 | } | ||
476 | // consume an optional colon | ||
477 | if tok.value == ":" { | ||
478 | tok = p.next() | ||
479 | if tok.err != nil { | ||
480 | return tok.err | ||
481 | } | ||
482 | } | ||
483 | var terminator string | ||
484 | switch tok.value { | ||
485 | case "<": | ||
486 | terminator = ">" | ||
487 | case "{": | ||
488 | terminator = "}" | ||
489 | default: | ||
490 | return p.errorf("expected '{' or '<', found %q", tok.value) | ||
491 | } | ||
492 | v := reflect.New(mt.Elem()) | ||
493 | if pe := p.readStruct(v.Elem(), terminator); pe != nil { | ||
494 | return pe | ||
495 | } | ||
496 | b, err := Marshal(v.Interface().(Message)) | ||
497 | if err != nil { | ||
498 | return p.errorf("failed to marshal message of type %q: %v", messageName, err) | ||
499 | } | ||
500 | if fieldSet["type_url"] { | ||
501 | return p.errorf(anyRepeatedlyUnpacked, "type_url") | ||
502 | } | ||
503 | if fieldSet["value"] { | ||
504 | return p.errorf(anyRepeatedlyUnpacked, "value") | ||
505 | } | ||
506 | sv.FieldByName("TypeUrl").SetString(extName) | ||
507 | sv.FieldByName("Value").SetBytes(b) | ||
508 | fieldSet["type_url"] = true | ||
509 | fieldSet["value"] = true | ||
510 | continue | ||
511 | } | ||
512 | |||
513 | var desc *ExtensionDesc | ||
514 | // This could be faster, but it's functional. | ||
515 | // TODO: Do something smarter than a linear scan. | ||
516 | for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) { | ||
517 | if d.Name == extName { | ||
518 | desc = d | ||
519 | break | ||
520 | } | ||
521 | } | ||
522 | if desc == nil { | ||
523 | return p.errorf("unrecognized extension %q", extName) | ||
524 | } | ||
525 | |||
526 | props := &Properties{} | ||
527 | props.Parse(desc.Tag) | ||
528 | |||
529 | typ := reflect.TypeOf(desc.ExtensionType) | ||
530 | if err := p.checkForColon(props, typ); err != nil { | ||
531 | return err | ||
532 | } | ||
533 | |||
534 | rep := desc.repeated() | ||
535 | |||
536 | // Read the extension structure, and set it in | ||
537 | // the value we're constructing. | ||
538 | var ext reflect.Value | ||
539 | if !rep { | ||
540 | ext = reflect.New(typ).Elem() | ||
541 | } else { | ||
542 | ext = reflect.New(typ.Elem()).Elem() | ||
543 | } | ||
544 | if err := p.readAny(ext, props); err != nil { | ||
545 | if _, ok := err.(*RequiredNotSetError); !ok { | ||
546 | return err | ||
547 | } | ||
548 | reqFieldErr = err | ||
549 | } | ||
550 | ep := sv.Addr().Interface().(Message) | ||
551 | if !rep { | ||
552 | SetExtension(ep, desc, ext.Interface()) | ||
553 | } else { | ||
554 | old, err := GetExtension(ep, desc) | ||
555 | var sl reflect.Value | ||
556 | if err == nil { | ||
557 | sl = reflect.ValueOf(old) // existing slice | ||
558 | } else { | ||
559 | sl = reflect.MakeSlice(typ, 0, 1) | ||
560 | } | ||
561 | sl = reflect.Append(sl, ext) | ||
562 | SetExtension(ep, desc, sl.Interface()) | ||
563 | } | ||
564 | if err := p.consumeOptionalSeparator(); err != nil { | ||
565 | return err | ||
566 | } | ||
567 | continue | ||
568 | } | ||
569 | |||
570 | // This is a normal, non-extension field. | ||
571 | name := tok.value | ||
572 | var dst reflect.Value | ||
573 | fi, props, ok := structFieldByName(sprops, name) | ||
574 | if ok { | ||
575 | dst = sv.Field(fi) | ||
576 | } else if oop, ok := sprops.OneofTypes[name]; ok { | ||
577 | // It is a oneof. | ||
578 | props = oop.Prop | ||
579 | nv := reflect.New(oop.Type.Elem()) | ||
580 | dst = nv.Elem().Field(0) | ||
581 | field := sv.Field(oop.Field) | ||
582 | if !field.IsNil() { | ||
583 | return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, sv.Type().Field(oop.Field).Name) | ||
584 | } | ||
585 | field.Set(nv) | ||
586 | } | ||
587 | if !dst.IsValid() { | ||
588 | return p.errorf("unknown field name %q in %v", name, st) | ||
589 | } | ||
590 | |||
591 | if dst.Kind() == reflect.Map { | ||
592 | // Consume any colon. | ||
593 | if err := p.checkForColon(props, dst.Type()); err != nil { | ||
594 | return err | ||
595 | } | ||
596 | |||
597 | // Construct the map if it doesn't already exist. | ||
598 | if dst.IsNil() { | ||
599 | dst.Set(reflect.MakeMap(dst.Type())) | ||
600 | } | ||
601 | key := reflect.New(dst.Type().Key()).Elem() | ||
602 | val := reflect.New(dst.Type().Elem()).Elem() | ||
603 | |||
604 | // The map entry should be this sequence of tokens: | ||
605 | // < key : KEY value : VALUE > | ||
606 | // However, implementations may omit key or value, and technically | ||
607 | // we should support them in any order. See b/28924776 for a time | ||
608 | // this went wrong. | ||
609 | |||
610 | tok := p.next() | ||
611 | var terminator string | ||
612 | switch tok.value { | ||
613 | case "<": | ||
614 | terminator = ">" | ||
615 | case "{": | ||
616 | terminator = "}" | ||
617 | default: | ||
618 | return p.errorf("expected '{' or '<', found %q", tok.value) | ||
619 | } | ||
620 | for { | ||
621 | tok := p.next() | ||
622 | if tok.err != nil { | ||
623 | return tok.err | ||
624 | } | ||
625 | if tok.value == terminator { | ||
626 | break | ||
627 | } | ||
628 | switch tok.value { | ||
629 | case "key": | ||
630 | if err := p.consumeToken(":"); err != nil { | ||
631 | return err | ||
632 | } | ||
633 | if err := p.readAny(key, props.MapKeyProp); err != nil { | ||
634 | return err | ||
635 | } | ||
636 | if err := p.consumeOptionalSeparator(); err != nil { | ||
637 | return err | ||
638 | } | ||
639 | case "value": | ||
640 | if err := p.checkForColon(props.MapValProp, dst.Type().Elem()); err != nil { | ||
641 | return err | ||
642 | } | ||
643 | if err := p.readAny(val, props.MapValProp); err != nil { | ||
644 | return err | ||
645 | } | ||
646 | if err := p.consumeOptionalSeparator(); err != nil { | ||
647 | return err | ||
648 | } | ||
649 | default: | ||
650 | p.back() | ||
651 | return p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value) | ||
652 | } | ||
653 | } | ||
654 | |||
655 | dst.SetMapIndex(key, val) | ||
656 | continue | ||
657 | } | ||
658 | |||
659 | // Check that it's not already set if it's not a repeated field. | ||
660 | if !props.Repeated && fieldSet[name] { | ||
661 | return p.errorf("non-repeated field %q was repeated", name) | ||
662 | } | ||
663 | |||
664 | if err := p.checkForColon(props, dst.Type()); err != nil { | ||
665 | return err | ||
666 | } | ||
667 | |||
668 | // Parse into the field. | ||
669 | fieldSet[name] = true | ||
670 | if err := p.readAny(dst, props); err != nil { | ||
671 | if _, ok := err.(*RequiredNotSetError); !ok { | ||
672 | return err | ||
673 | } | ||
674 | reqFieldErr = err | ||
675 | } | ||
676 | if props.Required { | ||
677 | reqCount-- | ||
678 | } | ||
679 | |||
680 | if err := p.consumeOptionalSeparator(); err != nil { | ||
681 | return err | ||
682 | } | ||
683 | |||
684 | } | ||
685 | |||
686 | if reqCount > 0 { | ||
687 | return p.missingRequiredFieldError(sv) | ||
688 | } | ||
689 | return reqFieldErr | ||
690 | } | ||
691 | |||
692 | // consumeExtName consumes extension name or expanded Any type URL and the | ||
693 | // following ']'. It returns the name or URL consumed. | ||
694 | func (p *textParser) consumeExtName() (string, error) { | ||
695 | tok := p.next() | ||
696 | if tok.err != nil { | ||
697 | return "", tok.err | ||
698 | } | ||
699 | |||
700 | // If extension name or type url is quoted, it's a single token. | ||
701 | if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] { | ||
702 | name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0])) | ||
703 | if err != nil { | ||
704 | return "", err | ||
705 | } | ||
706 | return name, p.consumeToken("]") | ||
707 | } | ||
708 | |||
709 | // Consume everything up to "]" | ||
710 | var parts []string | ||
711 | for tok.value != "]" { | ||
712 | parts = append(parts, tok.value) | ||
713 | tok = p.next() | ||
714 | if tok.err != nil { | ||
715 | return "", p.errorf("unrecognized type_url or extension name: %s", tok.err) | ||
716 | } | ||
717 | if p.done && tok.value != "]" { | ||
718 | return "", p.errorf("unclosed type_url or extension name") | ||
719 | } | ||
720 | } | ||
721 | return strings.Join(parts, ""), nil | ||
722 | } | ||
723 | |||
724 | // consumeOptionalSeparator consumes an optional semicolon or comma. | ||
725 | // It is used in readStruct to provide backward compatibility. | ||
726 | func (p *textParser) consumeOptionalSeparator() error { | ||
727 | tok := p.next() | ||
728 | if tok.err != nil { | ||
729 | return tok.err | ||
730 | } | ||
731 | if tok.value != ";" && tok.value != "," { | ||
732 | p.back() | ||
733 | } | ||
734 | return nil | ||
735 | } | ||
736 | |||
737 | func (p *textParser) readAny(v reflect.Value, props *Properties) error { | ||
738 | tok := p.next() | ||
739 | if tok.err != nil { | ||
740 | return tok.err | ||
741 | } | ||
742 | if tok.value == "" { | ||
743 | return p.errorf("unexpected EOF") | ||
744 | } | ||
745 | |||
746 | switch fv := v; fv.Kind() { | ||
747 | case reflect.Slice: | ||
748 | at := v.Type() | ||
749 | if at.Elem().Kind() == reflect.Uint8 { | ||
750 | // Special case for []byte | ||
751 | if tok.value[0] != '"' && tok.value[0] != '\'' { | ||
752 | // Deliberately written out here, as the error after | ||
753 | // this switch statement would write "invalid []byte: ...", | ||
754 | // which is not as user-friendly. | ||
755 | return p.errorf("invalid string: %v", tok.value) | ||
756 | } | ||
757 | bytes := []byte(tok.unquoted) | ||
758 | fv.Set(reflect.ValueOf(bytes)) | ||
759 | return nil | ||
760 | } | ||
761 | // Repeated field. | ||
762 | if tok.value == "[" { | ||
763 | // Repeated field with list notation, like [1,2,3]. | ||
764 | for { | ||
765 | fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) | ||
766 | err := p.readAny(fv.Index(fv.Len()-1), props) | ||
767 | if err != nil { | ||
768 | return err | ||
769 | } | ||
770 | tok := p.next() | ||
771 | if tok.err != nil { | ||
772 | return tok.err | ||
773 | } | ||
774 | if tok.value == "]" { | ||
775 | break | ||
776 | } | ||
777 | if tok.value != "," { | ||
778 | return p.errorf("Expected ']' or ',' found %q", tok.value) | ||
779 | } | ||
780 | } | ||
781 | return nil | ||
782 | } | ||
783 | // One value of the repeated field. | ||
784 | p.back() | ||
785 | fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) | ||
786 | return p.readAny(fv.Index(fv.Len()-1), props) | ||
787 | case reflect.Bool: | ||
788 | // true/1/t/True or false/f/0/False. | ||
789 | switch tok.value { | ||
790 | case "true", "1", "t", "True": | ||
791 | fv.SetBool(true) | ||
792 | return nil | ||
793 | case "false", "0", "f", "False": | ||
794 | fv.SetBool(false) | ||
795 | return nil | ||
796 | } | ||
797 | case reflect.Float32, reflect.Float64: | ||
798 | v := tok.value | ||
799 | // Ignore 'f' for compatibility with output generated by C++, but don't | ||
800 | // remove 'f' when the value is "-inf" or "inf". | ||
801 | if strings.HasSuffix(v, "f") && tok.value != "-inf" && tok.value != "inf" { | ||
802 | v = v[:len(v)-1] | ||
803 | } | ||
804 | if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil { | ||
805 | fv.SetFloat(f) | ||
806 | return nil | ||
807 | } | ||
808 | case reflect.Int32: | ||
809 | if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil { | ||
810 | fv.SetInt(x) | ||
811 | return nil | ||
812 | } | ||
813 | |||
814 | if len(props.Enum) == 0 { | ||
815 | break | ||
816 | } | ||
817 | m, ok := enumValueMaps[props.Enum] | ||
818 | if !ok { | ||
819 | break | ||
820 | } | ||
821 | x, ok := m[tok.value] | ||
822 | if !ok { | ||
823 | break | ||
824 | } | ||
825 | fv.SetInt(int64(x)) | ||
826 | return nil | ||
827 | case reflect.Int64: | ||
828 | if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil { | ||
829 | fv.SetInt(x) | ||
830 | return nil | ||
831 | } | ||
832 | |||
833 | case reflect.Ptr: | ||
834 | // A basic field (indirected through pointer), or a repeated message/group | ||
835 | p.back() | ||
836 | fv.Set(reflect.New(fv.Type().Elem())) | ||
837 | return p.readAny(fv.Elem(), props) | ||
838 | case reflect.String: | ||
839 | if tok.value[0] == '"' || tok.value[0] == '\'' { | ||
840 | fv.SetString(tok.unquoted) | ||
841 | return nil | ||
842 | } | ||
843 | case reflect.Struct: | ||
844 | var terminator string | ||
845 | switch tok.value { | ||
846 | case "{": | ||
847 | terminator = "}" | ||
848 | case "<": | ||
849 | terminator = ">" | ||
850 | default: | ||
851 | return p.errorf("expected '{' or '<', found %q", tok.value) | ||
852 | } | ||
853 | // TODO: Handle nested messages which implement encoding.TextUnmarshaler. | ||
854 | return p.readStruct(fv, terminator) | ||
855 | case reflect.Uint32: | ||
856 | if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { | ||
857 | fv.SetUint(uint64(x)) | ||
858 | return nil | ||
859 | } | ||
860 | case reflect.Uint64: | ||
861 | if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil { | ||
862 | fv.SetUint(x) | ||
863 | return nil | ||
864 | } | ||
865 | } | ||
866 | return p.errorf("invalid %v: %v", v.Type(), tok.value) | ||
867 | } | ||
868 | |||
869 | // UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb | ||
870 | // before starting to unmarshal, so any existing data in pb is always removed. | ||
871 | // If a required field is not set and no other error occurs, | ||
872 | // UnmarshalText returns *RequiredNotSetError. | ||
873 | func UnmarshalText(s string, pb Message) error { | ||
874 | if um, ok := pb.(encoding.TextUnmarshaler); ok { | ||
875 | return um.UnmarshalText([]byte(s)) | ||
876 | } | ||
877 | pb.Reset() | ||
878 | v := reflect.ValueOf(pb) | ||
879 | return newTextParser(s).readStruct(v.Elem(), "") | ||
880 | } | ||