blob: 1f170bfb2b02e51addd8898cb9ec644a2cf66063 [file] [log] [blame]
Rob Pikeaaa3a622010-03-20 22:32:34 -07001// Go support for Protocol Buffers - Google's data interchange format
2//
3// Copyright 2010 Google Inc. All rights reserved.
4// 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
Rob Pikeaaa3a622010-03-20 22:32:34 -070046type ParseError struct {
47 Message string
48 Line int // 1-based line number
49 Offset int // 0-based byte offset from start of input
50}
51
Rob Pikea17fdd92011-11-02 12:43:05 -070052func (p *ParseError) Error() string {
Rob Pikeaaa3a622010-03-20 22:32:34 -070053 if p.Line == 1 {
54 // show offset only for first line
55 return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message)
56 }
57 return fmt.Sprintf("line %d: %v", p.Line, p.Message)
58}
59
60type token struct {
61 value string
62 err *ParseError
63 line int // line number
64 offset int // byte number from start of input, not start of line
65 unquoted string // the unquoted version of value, if it was a quoted string
66}
67
68func (t *token) String() string {
69 if t.err == nil {
70 return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset)
71 }
72 return fmt.Sprintf("parse error: %v", t.err)
73}
74
75type textParser struct {
76 s string // remaining input
77 done bool // whether the parsing is finished (success or error)
78 backed bool // whether back() was called
79 offset, line int
80 cur token
81}
82
83func newTextParser(s string) *textParser {
84 p := new(textParser)
85 p.s = s
86 p.line = 1
87 p.cur.line = 1
88 return p
89}
90
Rob Piked6420b82011-04-13 16:37:04 -070091func (p *textParser) errorf(format string, a ...interface{}) *ParseError {
Rob Pikead7cac72010-09-29 12:29:26 -070092 pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset}
Rob Pikeaaa3a622010-03-20 22:32:34 -070093 p.cur.err = pe
94 p.done = true
95 return pe
96}
97
98// Numbers and identifiers are matched by [-+._A-Za-z0-9]
99func isIdentOrNumberChar(c byte) bool {
100 switch {
101 case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z':
102 return true
103 case '0' <= c && c <= '9':
104 return true
105 }
106 switch c {
107 case '-', '+', '.', '_':
108 return true
109 }
110 return false
111}
112
113func isWhitespace(c byte) bool {
114 switch c {
115 case ' ', '\t', '\n', '\r':
116 return true
117 }
118 return false
119}
120
121func (p *textParser) skipWhitespace() {
122 i := 0
123 for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') {
124 if p.s[i] == '#' {
125 // comment; skip to end of line or input
126 for i < len(p.s) && p.s[i] != '\n' {
127 i++
128 }
129 if i == len(p.s) {
130 break
131 }
132 }
133 if p.s[i] == '\n' {
134 p.line++
135 }
136 i++
137 }
138 p.offset += i
139 p.s = p.s[i:len(p.s)]
140 if len(p.s) == 0 {
141 p.done = true
142 }
143}
144
145func (p *textParser) advance() {
146 // Skip whitespace
147 p.skipWhitespace()
148 if p.done {
149 return
150 }
151
152 // Start of non-whitespace
153 p.cur.err = nil
154 p.cur.offset, p.cur.line = p.offset, p.line
155 p.cur.unquoted = ""
156 switch p.s[0] {
David Symonds54531052011-12-08 12:00:31 +1100157 case '<', '>', '{', '}', ':', '[', ']':
Rob Pikeaaa3a622010-03-20 22:32:34 -0700158 // Single symbol
159 p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)]
David Symonds162d0032012-06-28 09:44:46 -0700160 case '"', '\'':
Rob Pikeaaa3a622010-03-20 22:32:34 -0700161 // Quoted string
162 i := 1
David Symonds162d0032012-06-28 09:44:46 -0700163 for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700164 if p.s[i] == '\\' && i+1 < len(p.s) {
165 // skip escaped char
166 i++
167 }
168 i++
169 }
David Symonds162d0032012-06-28 09:44:46 -0700170 if i >= len(p.s) || p.s[i] != p.s[0] {
Rob Piked6420b82011-04-13 16:37:04 -0700171 p.errorf("unmatched quote")
Rob Pikeaaa3a622010-03-20 22:32:34 -0700172 return
173 }
David Symondsfa94a1e2012-09-24 13:21:49 +1000174 unq, err := unquoteC(p.s[1:i], rune(p.s[0]))
Rob Pikeaaa3a622010-03-20 22:32:34 -0700175 if err != nil {
Rob Piked6420b82011-04-13 16:37:04 -0700176 p.errorf("invalid quoted string %v", p.s[0:i+1])
Rob Pikeaaa3a622010-03-20 22:32:34 -0700177 return
178 }
179 p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)]
180 p.cur.unquoted = unq
181 default:
182 i := 0
183 for i < len(p.s) && isIdentOrNumberChar(p.s[i]) {
184 i++
185 }
186 if i == 0 {
Rob Piked6420b82011-04-13 16:37:04 -0700187 p.errorf("unexpected byte %#x", p.s[0])
Rob Pikeaaa3a622010-03-20 22:32:34 -0700188 return
189 }
190 p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)]
191 }
192 p.offset += len(p.cur.value)
193}
194
David Symondsfa94a1e2012-09-24 13:21:49 +1000195var (
196 errBadUTF8 = errors.New("bad UTF-8")
197 errBadHex = errors.New("bad hexadecimal")
198)
199
200func unquoteC(s string, quote rune) (string, error) {
201 // This is based on C++'s tokenizer.cc.
202 // Despite its name, this is *not* parsing C syntax.
203 // For instance, "\0" is an invalid quoted string.
204
205 // Avoid allocation in trivial cases.
206 simple := true
207 for _, r := range s {
208 if r == '\\' || r == quote {
209 simple = false
210 break
211 }
David Symonds162d0032012-06-28 09:44:46 -0700212 }
David Symondsfa94a1e2012-09-24 13:21:49 +1000213 if simple {
214 return s, nil
215 }
216
217 buf := make([]byte, 0, 3*len(s)/2)
218 for len(s) > 0 {
219 r, n := utf8.DecodeRuneInString(s)
220 if r == utf8.RuneError && n == 1 {
221 return "", errBadUTF8
222 }
223 s = s[n:]
224 if r != '\\' {
225 if r < utf8.RuneSelf {
226 buf = append(buf, byte(r))
227 } else {
228 buf = append(buf, string(r)...)
229 }
230 continue
231 }
232
233 ch, tail, err := unescape(s)
234 if err != nil {
235 return "", err
236 }
237 buf = append(buf, ch...)
238 s = tail
239 }
240 return string(buf), nil
David Symonds162d0032012-06-28 09:44:46 -0700241}
242
David Symondsfa94a1e2012-09-24 13:21:49 +1000243func unescape(s string) (ch string, tail string, err error) {
244 r, n := utf8.DecodeRuneInString(s)
245 if r == utf8.RuneError && n == 1 {
246 return "", "", errBadUTF8
David Symonds162d0032012-06-28 09:44:46 -0700247 }
David Symondsfa94a1e2012-09-24 13:21:49 +1000248 s = s[n:]
249 switch r {
250 case 'a':
251 return "\a", s, nil
252 case 'b':
253 return "\b", s, nil
254 case 'f':
255 return "\f", s, nil
256 case 'n':
257 return "\n", s, nil
258 case 'r':
259 return "\r", s, nil
260 case 't':
261 return "\t", s, nil
262 case 'v':
263 return "\v", s, nil
264 case '?':
265 return "?", s, nil // trigraph workaround
266 case '\'', '"', '\\':
267 return string(r), s, nil
268 case '0', '1', '2', '3', '4', '5', '6', '7', 'x', 'X':
269 if len(s) < 2 {
270 return "", "", fmt.Errorf(`\%c requires 2 following digits`, r)
271 }
272 base := 8
273 ss := s[:2]
274 s = s[2:]
275 if r == 'x' || r == 'X' {
276 base = 16
277 } else {
278 ss = string(r) + ss
279 }
280 i, err := strconv.ParseUint(ss, base, 8)
281 if err != nil {
282 return "", "", err
283 }
284 return string([]byte{byte(i)}), s, nil
285 case 'u', 'U':
286 n := 4
287 if r == 'U' {
288 n = 8
289 }
290 if len(s) < n {
291 return "", "", fmt.Errorf(`\%c requires %d digits`, r, n)
292 }
David Symonds162d0032012-06-28 09:44:46 -0700293
David Symondsfa94a1e2012-09-24 13:21:49 +1000294 bs := make([]byte, n/2)
295 for i := 0; i < n; i += 2 {
296 a, ok1 := unhex(s[i])
297 b, ok2 := unhex(s[i+1])
298 if !ok1 || !ok2 {
299 return "", "", errBadHex
300 }
301 bs[i/2] = a<<4 | b
302 }
303 s = s[n:]
304 return string(bs), s, nil
305 }
306 return "", "", fmt.Errorf(`unknown escape \%c`, r)
307}
308
309// Adapted from src/pkg/strconv/quote.go.
310func unhex(b byte) (v byte, ok bool) {
311 switch {
312 case '0' <= b && b <= '9':
313 return b - '0', true
314 case 'a' <= b && b <= 'f':
315 return b - 'a' + 10, true
316 case 'A' <= b && b <= 'F':
317 return b - 'A' + 10, true
318 }
319 return 0, false
David Symonds183124e2012-03-23 13:20:23 +1100320}
321
Rob Pikeaaa3a622010-03-20 22:32:34 -0700322// Back off the parser by one token. Can only be done between calls to next().
323// It makes the next advance() a no-op.
324func (p *textParser) back() { p.backed = true }
325
326// Advances the parser and returns the new current token.
327func (p *textParser) next() *token {
328 if p.backed || p.done {
329 p.backed = false
330 return &p.cur
331 }
332 p.advance()
333 if p.done {
334 p.cur.value = ""
335 } else if len(p.cur.value) > 0 && p.cur.value[0] == '"' {
336 // Look for multiple quoted strings separated by whitespace,
337 // and concatenate them.
338 cat := p.cur
339 for {
340 p.skipWhitespace()
341 if p.done || p.s[0] != '"' {
342 break
343 }
344 p.advance()
345 if p.cur.err != nil {
346 return &p.cur
347 }
348 cat.value += " " + p.cur.value
349 cat.unquoted += p.cur.unquoted
350 }
351 p.done = false // parser may have seen EOF, but we want to return cat
352 p.cur = cat
353 }
354 return &p.cur
355}
356
Rob Pikeaaa3a622010-03-20 22:32:34 -0700357// Return an error indicating which required field was not set.
Rob Pike97e934d2011-04-11 12:52:49 -0700358func (p *textParser) missingRequiredFieldError(sv reflect.Value) *ParseError {
359 st := sv.Type()
Rob Pikeaaa3a622010-03-20 22:32:34 -0700360 sprops := GetProperties(st)
361 for i := 0; i < st.NumField(); i++ {
Rob Pike97e934d2011-04-11 12:52:49 -0700362 if !isNil(sv.Field(i)) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700363 continue
364 }
365
366 props := sprops.Prop[i]
367 if props.Required {
Rob Piked6420b82011-04-13 16:37:04 -0700368 return p.errorf("message %v missing required field %q", st, props.OrigName)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700369 }
370 }
Rob Piked6420b82011-04-13 16:37:04 -0700371 return p.errorf("message %v missing required field", st) // should not happen
Rob Pikeaaa3a622010-03-20 22:32:34 -0700372}
373
374// Returns the index in the struct for the named field, as well as the parsed tag properties.
Rob Pike97e934d2011-04-11 12:52:49 -0700375func structFieldByName(st reflect.Type, name string) (int, *Properties, bool) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700376 sprops := GetProperties(st)
David Symonds2bba1b22012-09-26 14:53:08 +1000377 i, ok := sprops.decoderOrigNames[name]
David Symonds79eae332010-10-16 11:33:20 +1100378 if ok {
379 return i, sprops.Prop[i], true
Rob Pikeaaa3a622010-03-20 22:32:34 -0700380 }
381 return -1, nil, false
382}
383
David Symonds54531052011-12-08 12:00:31 +1100384// Consume a ':' from the input stream (if the next token is a colon),
385// returning an error if a colon is needed but not present.
386func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError {
387 tok := p.next()
388 if tok.err != nil {
389 return tok.err
390 }
391 if tok.value != ":" {
392 // Colon is optional when the field is a group or message.
393 needColon := true
394 switch props.Wire {
395 case "group":
396 needColon = false
397 case "bytes":
398 // A "bytes" field is either a message, a string, or a repeated field;
399 // those three become *T, *string and []T respectively, so we can check for
400 // this field being a pointer to a non-string.
401 if typ.Kind() == reflect.Ptr {
402 // *T or *string
403 if typ.Elem().Kind() == reflect.String {
404 break
405 }
406 } else if typ.Kind() == reflect.Slice {
407 // []T or []*T
408 if typ.Elem().Kind() != reflect.Ptr {
409 break
410 }
411 }
412 needColon = false
413 }
414 if needColon {
415 return p.errorf("expected ':', found %q", tok.value)
416 }
417 p.back()
418 }
419 return nil
420}
421
Rob Pike97e934d2011-04-11 12:52:49 -0700422func (p *textParser) readStruct(sv reflect.Value, terminator string) *ParseError {
423 st := sv.Type()
Rob Pikeaaa3a622010-03-20 22:32:34 -0700424 reqCount := GetProperties(st).reqCount
425 // A struct is a sequence of "name: value", terminated by one of
David Symonds54531052011-12-08 12:00:31 +1100426 // '>' or '}', or the end of the input. A name may also be
427 // "[extension]".
Rob Pikeaaa3a622010-03-20 22:32:34 -0700428 for {
429 tok := p.next()
430 if tok.err != nil {
431 return tok.err
432 }
433 if tok.value == terminator {
434 break
435 }
David Symonds54531052011-12-08 12:00:31 +1100436 if tok.value == "[" {
437 // Looks like an extension.
438 //
439 // TODO: Check whether we need to handle
440 // namespace rooted names (e.g. ".something.Foo").
441 tok = p.next()
442 if tok.err != nil {
443 return tok.err
444 }
445 var desc *ExtensionDesc
446 // This could be faster, but it's functional.
447 // TODO: Do something smarter than a linear scan.
David Symonds9f60f432012-06-14 09:45:25 +1000448 for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) {
David Symonds54531052011-12-08 12:00:31 +1100449 if d.Name == tok.value {
450 desc = d
451 break
Rob Pikeaaa3a622010-03-20 22:32:34 -0700452 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700453 }
David Symonds54531052011-12-08 12:00:31 +1100454 if desc == nil {
455 return p.errorf("unrecognized extension %q", tok.value)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700456 }
David Symonds54531052011-12-08 12:00:31 +1100457 // Check the extension terminator.
458 tok = p.next()
459 if tok.err != nil {
460 return tok.err
461 }
462 if tok.value != "]" {
463 return p.errorf("unrecognized extension terminator %q", tok.value)
464 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700465
David Symonds54531052011-12-08 12:00:31 +1100466 props := &Properties{}
467 props.Parse(desc.Tag)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700468
David Symonds54531052011-12-08 12:00:31 +1100469 typ := reflect.TypeOf(desc.ExtensionType)
470 if err := p.checkForColon(props, typ); err != nil {
471 return err
472 }
473
David Symonds61826da2012-05-05 09:31:28 +1000474 rep := desc.repeated()
475
David Symonds54531052011-12-08 12:00:31 +1100476 // Read the extension structure, and set it in
477 // the value we're constructing.
David Symonds61826da2012-05-05 09:31:28 +1000478 var ext reflect.Value
479 if !rep {
480 ext = reflect.New(typ).Elem()
481 } else {
482 ext = reflect.New(typ.Elem()).Elem()
483 }
David Symonds54531052011-12-08 12:00:31 +1100484 if err := p.readAny(ext, props); err != nil {
485 return err
486 }
David Symonds61826da2012-05-05 09:31:28 +1000487 ep := sv.Addr().Interface().(extendableProto)
488 if !rep {
489 SetExtension(ep, desc, ext.Interface())
490 } else {
491 old, err := GetExtension(ep, desc)
492 var sl reflect.Value
493 if err == nil {
494 sl = reflect.ValueOf(old) // existing slice
495 } else {
496 sl = reflect.MakeSlice(typ, 0, 1)
497 }
498 sl = reflect.Append(sl, ext)
499 SetExtension(ep, desc, sl.Interface())
500 }
David Symonds54531052011-12-08 12:00:31 +1100501 } else {
502 // This is a normal, non-extension field.
503 fi, props, ok := structFieldByName(st, tok.value)
504 if !ok {
505 return p.errorf("unknown field name %q in %v", tok.value, st)
506 }
507
508 // Check that it's not already set if it's not a repeated field.
509 if !props.Repeated && !isNil(sv.Field(fi)) {
510 return p.errorf("non-repeated field %q was repeated", tok.value)
511 }
512
513 if err := p.checkForColon(props, st.Field(fi).Type); err != nil {
514 return err
515 }
516
David Symonds007ed9d2012-07-24 10:59:36 +1000517 dst := sv.Field(fi)
518
David Symonds54531052011-12-08 12:00:31 +1100519 // Parse into the field.
David Symonds007ed9d2012-07-24 10:59:36 +1000520 if err := p.readAny(dst, props); err != nil {
David Symonds54531052011-12-08 12:00:31 +1100521 return err
522 }
523
524 if props.Required {
525 reqCount--
526 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700527 }
528 }
529
530 if reqCount > 0 {
531 return p.missingRequiredFieldError(sv)
532 }
533 return nil
534}
535
Rob Pikeaaa3a622010-03-20 22:32:34 -0700536func (p *textParser) readAny(v reflect.Value, props *Properties) *ParseError {
537 tok := p.next()
538 if tok.err != nil {
539 return tok.err
540 }
541 if tok.value == "" {
Rob Piked6420b82011-04-13 16:37:04 -0700542 return p.errorf("unexpected EOF")
Rob Pikeaaa3a622010-03-20 22:32:34 -0700543 }
544
Rob Pike97e934d2011-04-11 12:52:49 -0700545 switch fv := v; fv.Kind() {
546 case reflect.Slice:
547 at := v.Type()
Rob Pikeab5b8022010-06-21 17:47:58 -0700548 if at.Elem().Kind() == reflect.Uint8 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700549 // Special case for []byte
David Symonds162d0032012-06-28 09:44:46 -0700550 if tok.value[0] != '"' && tok.value[0] != '\'' {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700551 // Deliberately written out here, as the error after
552 // this switch statement would write "invalid []byte: ...",
553 // which is not as user-friendly.
Rob Piked6420b82011-04-13 16:37:04 -0700554 return p.errorf("invalid string: %v", tok.value)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700555 }
556 bytes := []byte(tok.unquoted)
Nigel Tao4ede8452011-04-28 11:27:25 +1000557 fv.Set(reflect.ValueOf(bytes))
Rob Pikeaaa3a622010-03-20 22:32:34 -0700558 return nil
559 }
560 // Repeated field. May already exist.
David Symonds79eae332010-10-16 11:33:20 +1100561 flen := fv.Len()
562 if flen == fv.Cap() {
563 nav := reflect.MakeSlice(at, flen, 2*flen+1)
Rob Pike48fd4a42010-12-14 23:40:41 -0800564 reflect.Copy(nav, fv)
David Symonds79eae332010-10-16 11:33:20 +1100565 fv.Set(nav)
566 }
567 fv.SetLen(flen + 1)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700568
569 // Read one.
570 p.back()
David Symondsef8f0e82011-10-13 12:57:34 +1100571 return p.readAny(fv.Index(flen), props)
Rob Pike97e934d2011-04-11 12:52:49 -0700572 case reflect.Bool:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700573 // Either "true", "false", 1 or 0.
574 switch tok.value {
575 case "true", "1":
Rob Pike97e934d2011-04-11 12:52:49 -0700576 fv.SetBool(true)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700577 return nil
578 case "false", "0":
Rob Pike97e934d2011-04-11 12:52:49 -0700579 fv.SetBool(false)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700580 return nil
581 }
Rob Pike97e934d2011-04-11 12:52:49 -0700582 case reflect.Float32, reflect.Float64:
David Symonds6bd081e2012-06-28 10:46:25 -0700583 v := tok.value
584 if strings.HasSuffix(v, "f") {
585 // Ignore 'f' for compatibility with output generated by C++.
586 v = v[:len(v)-1]
587 }
588 if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil {
Rob Pike97e934d2011-04-11 12:52:49 -0700589 fv.SetFloat(f)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700590 return nil
591 }
Rob Pike19b2dbb2011-04-11 16:49:15 -0700592 case reflect.Int32:
David Symonds32612dd2012-06-15 07:59:05 -0700593 if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil {
Rob Pike19b2dbb2011-04-11 16:49:15 -0700594 fv.SetInt(x)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700595 return nil
Rob Pike19b2dbb2011-04-11 16:49:15 -0700596 }
597 if len(props.Enum) == 0 {
598 break
599 }
600 m, ok := enumValueMaps[props.Enum]
601 if !ok {
602 break
603 }
604 x, ok := m[tok.value]
605 if !ok {
606 break
607 }
608 fv.SetInt(int64(x))
609 return nil
610 case reflect.Int64:
David Symonds32612dd2012-06-15 07:59:05 -0700611 if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil {
Rob Pike19b2dbb2011-04-11 16:49:15 -0700612 fv.SetInt(x)
613 return nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700614 }
Rob Pike97e934d2011-04-11 12:52:49 -0700615 case reflect.Ptr:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700616 // A basic field (indirected through pointer), or a repeated message/group
617 p.back()
Rob Pikeccd260c2011-04-18 13:13:04 -0700618 fv.Set(reflect.New(fv.Type().Elem()))
Rob Pikeaaa3a622010-03-20 22:32:34 -0700619 return p.readAny(fv.Elem(), props)
Rob Pike97e934d2011-04-11 12:52:49 -0700620 case reflect.String:
David Symonds162d0032012-06-28 09:44:46 -0700621 if tok.value[0] == '"' || tok.value[0] == '\'' {
Rob Pike97e934d2011-04-11 12:52:49 -0700622 fv.SetString(tok.unquoted)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700623 return nil
624 }
Rob Pike97e934d2011-04-11 12:52:49 -0700625 case reflect.Struct:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700626 var terminator string
627 switch tok.value {
628 case "{":
629 terminator = "}"
630 case "<":
631 terminator = ">"
632 default:
Rob Piked6420b82011-04-13 16:37:04 -0700633 return p.errorf("expected '{' or '<', found %q", tok.value)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700634 }
635 return p.readStruct(fv, terminator)
Rob Pike19b2dbb2011-04-11 16:49:15 -0700636 case reflect.Uint32:
David Symonds32612dd2012-06-15 07:59:05 -0700637 if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil {
Rob Pike19b2dbb2011-04-11 16:49:15 -0700638 fv.SetUint(uint64(x))
639 return nil
640 }
641 case reflect.Uint64:
David Symonds32612dd2012-06-15 07:59:05 -0700642 if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil {
Rob Pike19b2dbb2011-04-11 16:49:15 -0700643 fv.SetUint(x)
644 return nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700645 }
646 }
Rob Piked6420b82011-04-13 16:37:04 -0700647 return p.errorf("invalid %v: %v", v.Type(), tok.value)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700648}
649
David Symonds9f60f432012-06-14 09:45:25 +1000650// UnmarshalText reads a protocol buffer in Text format.
651func UnmarshalText(s string, pb Message) error {
Nigel Tao4ede8452011-04-28 11:27:25 +1000652 v := reflect.ValueOf(pb)
David Symondsa9cda212011-04-15 01:23:17 -0700653 if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700654 return pe
655 }
656 return nil
657}