blob: 4d4167c738a1c3a5c427bfa3fe00144cf8a897fd [file] [log] [blame]
Rob Pikeaaa3a622010-03-20 22:32:34 -07001// Go support for Protocol Buffers - Google's data interchange format
2//
David Symondsee6e9c52012-11-29 08:51:07 +11003// Copyright 2010 The Go Authors. All rights reserved.
Rob Pikeaaa3a622010-03-20 22:32:34 -07004// http://code.google.com/p/goprotobuf/
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
32package proto
33
34// Functions for parsing the Text protocol buffer format.
David Symonds54531052011-12-08 12:00:31 +110035// TODO: message sets.
Rob Pikeaaa3a622010-03-20 22:32:34 -070036
37import (
David Symondsfa94a1e2012-09-24 13:21:49 +100038 "errors"
Rob Pikeaaa3a622010-03-20 22:32:34 -070039 "fmt"
Rob Pikeaaa3a622010-03-20 22:32:34 -070040 "reflect"
41 "strconv"
David Symonds183124e2012-03-23 13:20:23 +110042 "strings"
David Symondsfa94a1e2012-09-24 13:21:49 +100043 "unicode/utf8"
Rob Pikeaaa3a622010-03-20 22:32:34 -070044)
45
David Symonds267e8052014-02-19 14:50:51 +110046// textUnmarshaler is implemented by Messages that can unmarshal themsleves.
47// It is identical to encoding.TextUnmarshaler, introduced in go 1.2,
48// which will eventually replace it.
49type textUnmarshaler interface {
50 UnmarshalText(text []byte) error
51}
52
Rob Pikeaaa3a622010-03-20 22:32:34 -070053type ParseError struct {
54 Message string
55 Line int // 1-based line number
56 Offset int // 0-based byte offset from start of input
57}
58
Rob Pikea17fdd92011-11-02 12:43:05 -070059func (p *ParseError) Error() string {
Rob Pikeaaa3a622010-03-20 22:32:34 -070060 if p.Line == 1 {
61 // show offset only for first line
62 return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message)
63 }
64 return fmt.Sprintf("line %d: %v", p.Line, p.Message)
65}
66
67type token struct {
68 value string
69 err *ParseError
70 line int // line number
71 offset int // byte number from start of input, not start of line
72 unquoted string // the unquoted version of value, if it was a quoted string
73}
74
75func (t *token) String() string {
76 if t.err == nil {
77 return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset)
78 }
79 return fmt.Sprintf("parse error: %v", t.err)
80}
81
82type textParser struct {
83 s string // remaining input
84 done bool // whether the parsing is finished (success or error)
85 backed bool // whether back() was called
86 offset, line int
87 cur token
88}
89
90func newTextParser(s string) *textParser {
91 p := new(textParser)
92 p.s = s
93 p.line = 1
94 p.cur.line = 1
95 return p
96}
97
Rob Piked6420b82011-04-13 16:37:04 -070098func (p *textParser) errorf(format string, a ...interface{}) *ParseError {
Rob Pikead7cac72010-09-29 12:29:26 -070099 pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset}
Rob Pikeaaa3a622010-03-20 22:32:34 -0700100 p.cur.err = pe
101 p.done = true
102 return pe
103}
104
105// Numbers and identifiers are matched by [-+._A-Za-z0-9]
106func isIdentOrNumberChar(c byte) bool {
107 switch {
108 case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z':
109 return true
110 case '0' <= c && c <= '9':
111 return true
112 }
113 switch c {
114 case '-', '+', '.', '_':
115 return true
116 }
117 return false
118}
119
120func isWhitespace(c byte) bool {
121 switch c {
122 case ' ', '\t', '\n', '\r':
123 return true
124 }
125 return false
126}
127
128func (p *textParser) skipWhitespace() {
129 i := 0
130 for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') {
131 if p.s[i] == '#' {
132 // comment; skip to end of line or input
133 for i < len(p.s) && p.s[i] != '\n' {
134 i++
135 }
136 if i == len(p.s) {
137 break
138 }
139 }
140 if p.s[i] == '\n' {
141 p.line++
142 }
143 i++
144 }
145 p.offset += i
146 p.s = p.s[i:len(p.s)]
147 if len(p.s) == 0 {
148 p.done = true
149 }
150}
151
152func (p *textParser) advance() {
153 // Skip whitespace
154 p.skipWhitespace()
155 if p.done {
156 return
157 }
158
159 // Start of non-whitespace
160 p.cur.err = nil
161 p.cur.offset, p.cur.line = p.offset, p.line
162 p.cur.unquoted = ""
163 switch p.s[0] {
David Symondsbe02a4a2012-12-06 15:20:41 +1100164 case '<', '>', '{', '}', ':', '[', ']', ';', ',':
Rob Pikeaaa3a622010-03-20 22:32:34 -0700165 // Single symbol
166 p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)]
David Symonds162d0032012-06-28 09:44:46 -0700167 case '"', '\'':
Rob Pikeaaa3a622010-03-20 22:32:34 -0700168 // Quoted string
169 i := 1
David Symonds162d0032012-06-28 09:44:46 -0700170 for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700171 if p.s[i] == '\\' && i+1 < len(p.s) {
172 // skip escaped char
173 i++
174 }
175 i++
176 }
David Symonds162d0032012-06-28 09:44:46 -0700177 if i >= len(p.s) || p.s[i] != p.s[0] {
Rob Piked6420b82011-04-13 16:37:04 -0700178 p.errorf("unmatched quote")
Rob Pikeaaa3a622010-03-20 22:32:34 -0700179 return
180 }
David Symondsfa94a1e2012-09-24 13:21:49 +1000181 unq, err := unquoteC(p.s[1:i], rune(p.s[0]))
Rob Pikeaaa3a622010-03-20 22:32:34 -0700182 if err != nil {
Rob Piked6420b82011-04-13 16:37:04 -0700183 p.errorf("invalid quoted string %v", p.s[0:i+1])
Rob Pikeaaa3a622010-03-20 22:32:34 -0700184 return
185 }
186 p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)]
187 p.cur.unquoted = unq
188 default:
189 i := 0
190 for i < len(p.s) && isIdentOrNumberChar(p.s[i]) {
191 i++
192 }
193 if i == 0 {
Rob Piked6420b82011-04-13 16:37:04 -0700194 p.errorf("unexpected byte %#x", p.s[0])
Rob Pikeaaa3a622010-03-20 22:32:34 -0700195 return
196 }
197 p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)]
198 }
199 p.offset += len(p.cur.value)
200}
201
David Symondsfa94a1e2012-09-24 13:21:49 +1000202var (
David Symondsa7f3a0f2013-09-09 13:32:33 +1000203 errBadUTF8 = errors.New("proto: bad UTF-8")
204 errBadHex = errors.New("proto: bad hexadecimal")
David Symondsfa94a1e2012-09-24 13:21:49 +1000205)
206
207func unquoteC(s string, quote rune) (string, error) {
208 // This is based on C++'s tokenizer.cc.
209 // Despite its name, this is *not* parsing C syntax.
210 // For instance, "\0" is an invalid quoted string.
211
212 // Avoid allocation in trivial cases.
213 simple := true
214 for _, r := range s {
215 if r == '\\' || r == quote {
216 simple = false
217 break
218 }
David Symonds162d0032012-06-28 09:44:46 -0700219 }
David Symondsfa94a1e2012-09-24 13:21:49 +1000220 if simple {
221 return s, nil
222 }
223
224 buf := make([]byte, 0, 3*len(s)/2)
225 for len(s) > 0 {
226 r, n := utf8.DecodeRuneInString(s)
227 if r == utf8.RuneError && n == 1 {
228 return "", errBadUTF8
229 }
230 s = s[n:]
231 if r != '\\' {
232 if r < utf8.RuneSelf {
233 buf = append(buf, byte(r))
234 } else {
235 buf = append(buf, string(r)...)
236 }
237 continue
238 }
239
240 ch, tail, err := unescape(s)
241 if err != nil {
242 return "", err
243 }
244 buf = append(buf, ch...)
245 s = tail
246 }
247 return string(buf), nil
David Symonds162d0032012-06-28 09:44:46 -0700248}
249
David Symondsfa94a1e2012-09-24 13:21:49 +1000250func unescape(s string) (ch string, tail string, err error) {
251 r, n := utf8.DecodeRuneInString(s)
252 if r == utf8.RuneError && n == 1 {
253 return "", "", errBadUTF8
David Symonds162d0032012-06-28 09:44:46 -0700254 }
David Symondsfa94a1e2012-09-24 13:21:49 +1000255 s = s[n:]
256 switch r {
257 case 'a':
258 return "\a", s, nil
259 case 'b':
260 return "\b", s, nil
261 case 'f':
262 return "\f", s, nil
263 case 'n':
264 return "\n", s, nil
265 case 'r':
266 return "\r", s, nil
267 case 't':
268 return "\t", s, nil
269 case 'v':
270 return "\v", s, nil
271 case '?':
272 return "?", s, nil // trigraph workaround
273 case '\'', '"', '\\':
274 return string(r), s, nil
275 case '0', '1', '2', '3', '4', '5', '6', '7', 'x', 'X':
276 if len(s) < 2 {
277 return "", "", fmt.Errorf(`\%c requires 2 following digits`, r)
278 }
279 base := 8
280 ss := s[:2]
281 s = s[2:]
282 if r == 'x' || r == 'X' {
283 base = 16
284 } else {
285 ss = string(r) + ss
286 }
287 i, err := strconv.ParseUint(ss, base, 8)
288 if err != nil {
289 return "", "", err
290 }
291 return string([]byte{byte(i)}), s, nil
292 case 'u', 'U':
293 n := 4
294 if r == 'U' {
295 n = 8
296 }
297 if len(s) < n {
298 return "", "", fmt.Errorf(`\%c requires %d digits`, r, n)
299 }
David Symonds162d0032012-06-28 09:44:46 -0700300
David Symondsfa94a1e2012-09-24 13:21:49 +1000301 bs := make([]byte, n/2)
302 for i := 0; i < n; i += 2 {
303 a, ok1 := unhex(s[i])
304 b, ok2 := unhex(s[i+1])
305 if !ok1 || !ok2 {
306 return "", "", errBadHex
307 }
308 bs[i/2] = a<<4 | b
309 }
310 s = s[n:]
311 return string(bs), s, nil
312 }
313 return "", "", fmt.Errorf(`unknown escape \%c`, r)
314}
315
316// Adapted from src/pkg/strconv/quote.go.
317func unhex(b byte) (v byte, ok bool) {
318 switch {
319 case '0' <= b && b <= '9':
320 return b - '0', true
321 case 'a' <= b && b <= 'f':
322 return b - 'a' + 10, true
323 case 'A' <= b && b <= 'F':
324 return b - 'A' + 10, true
325 }
326 return 0, false
David Symonds183124e2012-03-23 13:20:23 +1100327}
328
Rob Pikeaaa3a622010-03-20 22:32:34 -0700329// Back off the parser by one token. Can only be done between calls to next().
330// It makes the next advance() a no-op.
331func (p *textParser) back() { p.backed = true }
332
333// Advances the parser and returns the new current token.
334func (p *textParser) next() *token {
335 if p.backed || p.done {
336 p.backed = false
337 return &p.cur
338 }
339 p.advance()
340 if p.done {
341 p.cur.value = ""
342 } else if len(p.cur.value) > 0 && p.cur.value[0] == '"' {
343 // Look for multiple quoted strings separated by whitespace,
344 // and concatenate them.
345 cat := p.cur
346 for {
347 p.skipWhitespace()
348 if p.done || p.s[0] != '"' {
349 break
350 }
351 p.advance()
352 if p.cur.err != nil {
353 return &p.cur
354 }
355 cat.value += " " + p.cur.value
356 cat.unquoted += p.cur.unquoted
357 }
358 p.done = false // parser may have seen EOF, but we want to return cat
359 p.cur = cat
360 }
361 return &p.cur
362}
363
Rob Pikeaaa3a622010-03-20 22:32:34 -0700364// Return an error indicating which required field was not set.
Rob Pike97e934d2011-04-11 12:52:49 -0700365func (p *textParser) missingRequiredFieldError(sv reflect.Value) *ParseError {
366 st := sv.Type()
Rob Pikeaaa3a622010-03-20 22:32:34 -0700367 sprops := GetProperties(st)
368 for i := 0; i < st.NumField(); i++ {
Rob Pike97e934d2011-04-11 12:52:49 -0700369 if !isNil(sv.Field(i)) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700370 continue
371 }
372
373 props := sprops.Prop[i]
374 if props.Required {
Rob Piked6420b82011-04-13 16:37:04 -0700375 return p.errorf("message %v missing required field %q", st, props.OrigName)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700376 }
377 }
Rob Piked6420b82011-04-13 16:37:04 -0700378 return p.errorf("message %v missing required field", st) // should not happen
Rob Pikeaaa3a622010-03-20 22:32:34 -0700379}
380
381// Returns the index in the struct for the named field, as well as the parsed tag properties.
Rob Pike97e934d2011-04-11 12:52:49 -0700382func structFieldByName(st reflect.Type, name string) (int, *Properties, bool) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700383 sprops := GetProperties(st)
David Symonds2bba1b22012-09-26 14:53:08 +1000384 i, ok := sprops.decoderOrigNames[name]
David Symonds79eae332010-10-16 11:33:20 +1100385 if ok {
386 return i, sprops.Prop[i], true
Rob Pikeaaa3a622010-03-20 22:32:34 -0700387 }
388 return -1, nil, false
389}
390
David Symonds54531052011-12-08 12:00:31 +1100391// Consume a ':' from the input stream (if the next token is a colon),
392// returning an error if a colon is needed but not present.
393func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError {
394 tok := p.next()
395 if tok.err != nil {
396 return tok.err
397 }
398 if tok.value != ":" {
399 // Colon is optional when the field is a group or message.
400 needColon := true
401 switch props.Wire {
402 case "group":
403 needColon = false
404 case "bytes":
405 // A "bytes" field is either a message, a string, or a repeated field;
406 // those three become *T, *string and []T respectively, so we can check for
407 // this field being a pointer to a non-string.
408 if typ.Kind() == reflect.Ptr {
409 // *T or *string
410 if typ.Elem().Kind() == reflect.String {
411 break
412 }
413 } else if typ.Kind() == reflect.Slice {
414 // []T or []*T
415 if typ.Elem().Kind() != reflect.Ptr {
416 break
417 }
418 }
419 needColon = false
420 }
421 if needColon {
422 return p.errorf("expected ':', found %q", tok.value)
423 }
424 p.back()
425 }
426 return nil
427}
428
Rob Pike97e934d2011-04-11 12:52:49 -0700429func (p *textParser) readStruct(sv reflect.Value, terminator string) *ParseError {
430 st := sv.Type()
Rob Pikeaaa3a622010-03-20 22:32:34 -0700431 reqCount := GetProperties(st).reqCount
432 // A struct is a sequence of "name: value", terminated by one of
David Symonds54531052011-12-08 12:00:31 +1100433 // '>' or '}', or the end of the input. A name may also be
434 // "[extension]".
Rob Pikeaaa3a622010-03-20 22:32:34 -0700435 for {
436 tok := p.next()
437 if tok.err != nil {
438 return tok.err
439 }
440 if tok.value == terminator {
441 break
442 }
David Symonds54531052011-12-08 12:00:31 +1100443 if tok.value == "[" {
444 // Looks like an extension.
445 //
446 // TODO: Check whether we need to handle
447 // namespace rooted names (e.g. ".something.Foo").
448 tok = p.next()
449 if tok.err != nil {
450 return tok.err
451 }
452 var desc *ExtensionDesc
453 // This could be faster, but it's functional.
454 // TODO: Do something smarter than a linear scan.
David Symonds9f60f432012-06-14 09:45:25 +1000455 for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) {
David Symonds54531052011-12-08 12:00:31 +1100456 if d.Name == tok.value {
457 desc = d
458 break
Rob Pikeaaa3a622010-03-20 22:32:34 -0700459 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700460 }
David Symonds54531052011-12-08 12:00:31 +1100461 if desc == nil {
462 return p.errorf("unrecognized extension %q", tok.value)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700463 }
David Symonds54531052011-12-08 12:00:31 +1100464 // Check the extension terminator.
465 tok = p.next()
466 if tok.err != nil {
467 return tok.err
468 }
469 if tok.value != "]" {
470 return p.errorf("unrecognized extension terminator %q", tok.value)
471 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700472
David Symonds54531052011-12-08 12:00:31 +1100473 props := &Properties{}
474 props.Parse(desc.Tag)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700475
David Symonds54531052011-12-08 12:00:31 +1100476 typ := reflect.TypeOf(desc.ExtensionType)
477 if err := p.checkForColon(props, typ); err != nil {
478 return err
479 }
480
David Symonds61826da2012-05-05 09:31:28 +1000481 rep := desc.repeated()
482
David Symonds54531052011-12-08 12:00:31 +1100483 // Read the extension structure, and set it in
484 // the value we're constructing.
David Symonds61826da2012-05-05 09:31:28 +1000485 var ext reflect.Value
486 if !rep {
487 ext = reflect.New(typ).Elem()
488 } else {
489 ext = reflect.New(typ.Elem()).Elem()
490 }
David Symonds54531052011-12-08 12:00:31 +1100491 if err := p.readAny(ext, props); err != nil {
492 return err
493 }
David Symonds61826da2012-05-05 09:31:28 +1000494 ep := sv.Addr().Interface().(extendableProto)
495 if !rep {
496 SetExtension(ep, desc, ext.Interface())
497 } else {
498 old, err := GetExtension(ep, desc)
499 var sl reflect.Value
500 if err == nil {
501 sl = reflect.ValueOf(old) // existing slice
502 } else {
503 sl = reflect.MakeSlice(typ, 0, 1)
504 }
505 sl = reflect.Append(sl, ext)
506 SetExtension(ep, desc, sl.Interface())
507 }
David Symonds54531052011-12-08 12:00:31 +1100508 } else {
509 // This is a normal, non-extension field.
510 fi, props, ok := structFieldByName(st, tok.value)
511 if !ok {
512 return p.errorf("unknown field name %q in %v", tok.value, st)
513 }
514
David Symonds20370902013-03-23 17:20:01 +1100515 dst := sv.Field(fi)
516 isDstNil := isNil(dst)
517
David Symonds54531052011-12-08 12:00:31 +1100518 // Check that it's not already set if it's not a repeated field.
David Symonds20370902013-03-23 17:20:01 +1100519 if !props.Repeated && !isDstNil {
David Symonds54531052011-12-08 12:00:31 +1100520 return p.errorf("non-repeated field %q was repeated", tok.value)
521 }
522
523 if err := p.checkForColon(props, st.Field(fi).Type); err != nil {
524 return err
525 }
526
527 // Parse into the field.
David Symonds007ed9d2012-07-24 10:59:36 +1000528 if err := p.readAny(dst, props); err != nil {
David Symonds54531052011-12-08 12:00:31 +1100529 return err
530 }
531
532 if props.Required {
533 reqCount--
534 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700535 }
David Symondsbe02a4a2012-12-06 15:20:41 +1100536
537 // For backward compatibility, permit a semicolon or comma after a field.
538 tok = p.next()
539 if tok.err != nil {
540 return tok.err
541 }
542 if tok.value != ";" && tok.value != "," {
543 p.back()
544 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700545 }
546
547 if reqCount > 0 {
548 return p.missingRequiredFieldError(sv)
549 }
550 return nil
551}
552
Rob Pikeaaa3a622010-03-20 22:32:34 -0700553func (p *textParser) readAny(v reflect.Value, props *Properties) *ParseError {
554 tok := p.next()
555 if tok.err != nil {
556 return tok.err
557 }
558 if tok.value == "" {
Rob Piked6420b82011-04-13 16:37:04 -0700559 return p.errorf("unexpected EOF")
Rob Pikeaaa3a622010-03-20 22:32:34 -0700560 }
561
Rob Pike97e934d2011-04-11 12:52:49 -0700562 switch fv := v; fv.Kind() {
563 case reflect.Slice:
564 at := v.Type()
Rob Pikeab5b8022010-06-21 17:47:58 -0700565 if at.Elem().Kind() == reflect.Uint8 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700566 // Special case for []byte
David Symonds162d0032012-06-28 09:44:46 -0700567 if tok.value[0] != '"' && tok.value[0] != '\'' {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700568 // Deliberately written out here, as the error after
569 // this switch statement would write "invalid []byte: ...",
570 // which is not as user-friendly.
Rob Piked6420b82011-04-13 16:37:04 -0700571 return p.errorf("invalid string: %v", tok.value)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700572 }
573 bytes := []byte(tok.unquoted)
Nigel Tao4ede8452011-04-28 11:27:25 +1000574 fv.Set(reflect.ValueOf(bytes))
Rob Pikeaaa3a622010-03-20 22:32:34 -0700575 return nil
576 }
577 // Repeated field. May already exist.
David Symonds79eae332010-10-16 11:33:20 +1100578 flen := fv.Len()
579 if flen == fv.Cap() {
580 nav := reflect.MakeSlice(at, flen, 2*flen+1)
Rob Pike48fd4a42010-12-14 23:40:41 -0800581 reflect.Copy(nav, fv)
David Symonds79eae332010-10-16 11:33:20 +1100582 fv.Set(nav)
583 }
584 fv.SetLen(flen + 1)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700585
586 // Read one.
587 p.back()
David Symondsef8f0e82011-10-13 12:57:34 +1100588 return p.readAny(fv.Index(flen), props)
Rob Pike97e934d2011-04-11 12:52:49 -0700589 case reflect.Bool:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700590 // Either "true", "false", 1 or 0.
591 switch tok.value {
592 case "true", "1":
Rob Pike97e934d2011-04-11 12:52:49 -0700593 fv.SetBool(true)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700594 return nil
595 case "false", "0":
Rob Pike97e934d2011-04-11 12:52:49 -0700596 fv.SetBool(false)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700597 return nil
598 }
Rob Pike97e934d2011-04-11 12:52:49 -0700599 case reflect.Float32, reflect.Float64:
David Symonds6bd081e2012-06-28 10:46:25 -0700600 v := tok.value
David Symondsbe02a4a2012-12-06 15:20:41 +1100601 // Ignore 'f' for compatibility with output generated by C++, but don't
602 // remove 'f' when the value is "-inf" or "inf".
603 if strings.HasSuffix(v, "f") && tok.value != "-inf" && tok.value != "inf" {
David Symonds6bd081e2012-06-28 10:46:25 -0700604 v = v[:len(v)-1]
605 }
606 if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil {
Rob Pike97e934d2011-04-11 12:52:49 -0700607 fv.SetFloat(f)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700608 return nil
609 }
Rob Pike19b2dbb2011-04-11 16:49:15 -0700610 case reflect.Int32:
David Symonds32612dd2012-06-15 07:59:05 -0700611 if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil {
Rob Pike19b2dbb2011-04-11 16:49:15 -0700612 fv.SetInt(x)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700613 return nil
Rob Pike19b2dbb2011-04-11 16:49:15 -0700614 }
615 if len(props.Enum) == 0 {
616 break
617 }
618 m, ok := enumValueMaps[props.Enum]
619 if !ok {
620 break
621 }
622 x, ok := m[tok.value]
623 if !ok {
624 break
625 }
626 fv.SetInt(int64(x))
627 return nil
628 case reflect.Int64:
David Symonds32612dd2012-06-15 07:59:05 -0700629 if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil {
Rob Pike19b2dbb2011-04-11 16:49:15 -0700630 fv.SetInt(x)
631 return nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700632 }
Rob Pike97e934d2011-04-11 12:52:49 -0700633 case reflect.Ptr:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700634 // A basic field (indirected through pointer), or a repeated message/group
635 p.back()
Rob Pikeccd260c2011-04-18 13:13:04 -0700636 fv.Set(reflect.New(fv.Type().Elem()))
Rob Pikeaaa3a622010-03-20 22:32:34 -0700637 return p.readAny(fv.Elem(), props)
Rob Pike97e934d2011-04-11 12:52:49 -0700638 case reflect.String:
David Symonds162d0032012-06-28 09:44:46 -0700639 if tok.value[0] == '"' || tok.value[0] == '\'' {
Rob Pike97e934d2011-04-11 12:52:49 -0700640 fv.SetString(tok.unquoted)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700641 return nil
642 }
Rob Pike97e934d2011-04-11 12:52:49 -0700643 case reflect.Struct:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700644 var terminator string
645 switch tok.value {
646 case "{":
647 terminator = "}"
648 case "<":
649 terminator = ">"
650 default:
Rob Piked6420b82011-04-13 16:37:04 -0700651 return p.errorf("expected '{' or '<', found %q", tok.value)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700652 }
David Symonds267e8052014-02-19 14:50:51 +1100653 // TODO: Handle nested messages which implement textUnmarshaler.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700654 return p.readStruct(fv, terminator)
Rob Pike19b2dbb2011-04-11 16:49:15 -0700655 case reflect.Uint32:
David Symonds32612dd2012-06-15 07:59:05 -0700656 if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil {
Rob Pike19b2dbb2011-04-11 16:49:15 -0700657 fv.SetUint(uint64(x))
658 return nil
659 }
660 case reflect.Uint64:
David Symonds32612dd2012-06-15 07:59:05 -0700661 if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil {
Rob Pike19b2dbb2011-04-11 16:49:15 -0700662 fv.SetUint(x)
663 return nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700664 }
665 }
Rob Piked6420b82011-04-13 16:37:04 -0700666 return p.errorf("invalid %v: %v", v.Type(), tok.value)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700667}
668
David Symonds501f7db2013-08-05 13:53:28 +1000669// UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb
670// before starting to unmarshal, so any existing data in pb is always removed.
David Symonds9f60f432012-06-14 09:45:25 +1000671func UnmarshalText(s string, pb Message) error {
David Symonds267e8052014-02-19 14:50:51 +1100672 if um, ok := pb.(textUnmarshaler); ok {
673 err := um.UnmarshalText([]byte(s))
674 return err
675 }
David Symonds501f7db2013-08-05 13:53:28 +1000676 pb.Reset()
Nigel Tao4ede8452011-04-28 11:27:25 +1000677 v := reflect.ValueOf(pb)
David Symondsa9cda212011-04-15 01:23:17 -0700678 if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700679 return pe
680 }
681 return nil
682}