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 32package proto 33 34// Functions for parsing the Text protocol buffer format. 35// TODO: message sets. 36 37import ( 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 48const anyRepeatedlyUnpacked = "Any message unpacked multiple times, or %q already set" 49 50type 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 56func (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 64type 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 72func (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 79type 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 87func 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 95func (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] 103func 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 117func isWhitespace(c byte) bool { 118 switch c { 119 case ' ', '\t', '\n', '\r': 120 return true 121 } 122 return false 123} 124 125func isQuote(c byte) bool { 126 switch c { 127 case '"', '\'': 128 return true 129 } 130 return false 131} 132 133func (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 157func (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 207var ( 208 errBadUTF8 = errors.New("proto: bad UTF-8") 209 errBadHex = errors.New("proto: bad hexadecimal") 210) 211 212func unquoteC(s string, quote rune) (string, error) { 213 // This is based on C++'s tokenizer.cc. 214 // Despite its name, this is *not* parsing C syntax. 215 // For instance, "\0" is an invalid quoted string. 216 217 // Avoid allocation in trivial cases. 218 simple := true 219 for _, r := range s { 220 if r == '\\' || r == quote { 221 simple = false 222 break 223 } 224 } 225 if simple { 226 return s, nil 227 } 228 229 buf := make([]byte, 0, 3*len(s)/2) 230 for len(s) > 0 { 231 r, n := utf8.DecodeRuneInString(s) 232 if r == utf8.RuneError && n == 1 { 233 return "", errBadUTF8 234 } 235 s = s[n:] 236 if r != '\\' { 237 if r < utf8.RuneSelf { 238 buf = append(buf, byte(r)) 239 } else { 240 buf = append(buf, string(r)...) 241 } 242 continue 243 } 244 245 ch, tail, err := unescape(s) 246 if err != nil { 247 return "", err 248 } 249 buf = append(buf, ch...) 250 s = tail 251 } 252 return string(buf), nil 253} 254 255func unescape(s string) (ch string, tail string, err error) { 256 r, n := utf8.DecodeRuneInString(s) 257 if r == utf8.RuneError && n == 1 { 258 return "", "", errBadUTF8 259 } 260 s = s[n:] 261 switch r { 262 case 'a': 263 return "\a", s, nil 264 case 'b': 265 return "\b", s, nil 266 case 'f': 267 return "\f", s, nil 268 case 'n': 269 return "\n", s, nil 270 case 'r': 271 return "\r", s, nil 272 case 't': 273 return "\t", s, nil 274 case 'v': 275 return "\v", s, nil 276 case '?': 277 return "?", s, nil // trigraph workaround 278 case '\'', '"', '\\': 279 return string(r), s, nil 280 case '0', '1', '2', '3', '4', '5', '6', '7', 'x', 'X': 281 if len(s) < 2 { 282 return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) 283 } 284 base := 8 285 ss := s[:2] 286 s = s[2:] 287 if r == 'x' || r == 'X' { 288 base = 16 289 } else { 290 ss = string(r) + ss 291 } 292 i, err := strconv.ParseUint(ss, base, 8) 293 if err != nil { 294 return "", "", err 295 } 296 return string([]byte{byte(i)}), s, nil 297 case 'u', 'U': 298 n := 4 299 if r == 'U' { 300 n = 8 301 } 302 if len(s) < n { 303 return "", "", fmt.Errorf(`\%c requires %d digits`, r, n) 304 } 305 306 bs := make([]byte, n/2) 307 for i := 0; i < n; i += 2 { 308 a, ok1 := unhex(s[i]) 309 b, ok2 := unhex(s[i+1]) 310 if !ok1 || !ok2 { 311 return "", "", errBadHex 312 } 313 bs[i/2] = a<<4 | b 314 } 315 s = s[n:] 316 return string(bs), s, nil 317 } 318 return "", "", fmt.Errorf(`unknown escape \%c`, r) 319} 320 321// Adapted from src/pkg/strconv/quote.go. 322func unhex(b byte) (v byte, ok bool) { 323 switch { 324 case '0' <= b && b <= '9': 325 return b - '0', true 326 case 'a' <= b && b <= 'f': 327 return b - 'a' + 10, true 328 case 'A' <= b && b <= 'F': 329 return b - 'A' + 10, true 330 } 331 return 0, false 332} 333 334// Back off the parser by one token. Can only be done between calls to next(). 335// It makes the next advance() a no-op. 336func (p *textParser) back() { p.backed = true } 337 338// Advances the parser and returns the new current token. 339func (p *textParser) next() *token { 340 if p.backed || p.done { 341 p.backed = false 342 return &p.cur 343 } 344 p.advance() 345 if p.done { 346 p.cur.value = "" 347 } else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) { 348 // Look for multiple quoted strings separated by whitespace, 349 // and concatenate them. 350 cat := p.cur 351 for { 352 p.skipWhitespace() 353 if p.done || !isQuote(p.s[0]) { 354 break 355 } 356 p.advance() 357 if p.cur.err != nil { 358 return &p.cur 359 } 360 cat.value += " " + p.cur.value 361 cat.unquoted += p.cur.unquoted 362 } 363 p.done = false // parser may have seen EOF, but we want to return cat 364 p.cur = cat 365 } 366 return &p.cur 367} 368 369func (p *textParser) consumeToken(s string) error { 370 tok := p.next() 371 if tok.err != nil { 372 return tok.err 373 } 374 if tok.value != s { 375 p.back() 376 return p.errorf("expected %q, found %q", s, tok.value) 377 } 378 return nil 379} 380 381// Return a RequiredNotSetError indicating which required field was not set. 382func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSetError { 383 st := sv.Type() 384 sprops := GetProperties(st) 385 for i := 0; i < st.NumField(); i++ { 386 if !isNil(sv.Field(i)) { 387 continue 388 } 389 390 props := sprops.Prop[i] 391 if props.Required { 392 return &RequiredNotSetError{fmt.Sprintf("%v.%v", st, props.OrigName)} 393 } 394 } 395 return &RequiredNotSetError{fmt.Sprintf("%v.<unknown field name>", st)} // should not happen 396} 397 398// Returns the index in the struct for the named field, as well as the parsed tag properties. 399func structFieldByName(sprops *StructProperties, name string) (int, *Properties, bool) { 400 i, ok := sprops.decoderOrigNames[name] 401 if ok { 402 return i, sprops.Prop[i], true 403 } 404 return -1, nil, false 405} 406 407// Consume a ':' from the input stream (if the next token is a colon), 408// returning an error if a colon is needed but not present. 409func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError { 410 tok := p.next() 411 if tok.err != nil { 412 return tok.err 413 } 414 if tok.value != ":" { 415 // Colon is optional when the field is a group or message. 416 needColon := true 417 switch props.Wire { 418 case "group": 419 needColon = false 420 case "bytes": 421 // A "bytes" field is either a message, a string, or a repeated field; 422 // those three become *T, *string and []T respectively, so we can check for 423 // this field being a pointer to a non-string. 424 if typ.Kind() == reflect.Ptr { 425 // *T or *string 426 if typ.Elem().Kind() == reflect.String { 427 break 428 } 429 } else if typ.Kind() == reflect.Slice { 430 // []T or []*T 431 if typ.Elem().Kind() != reflect.Ptr { 432 break 433 } 434 } else if typ.Kind() == reflect.String { 435 // The proto3 exception is for a string field, 436 // which requires a colon. 437 break 438 } 439 needColon = false 440 } 441 if needColon { 442 return p.errorf("expected ':', found %q", tok.value) 443 } 444 p.back() 445 } 446 return nil 447} 448 449func (p *textParser) readStruct(sv reflect.Value, terminator string) error { 450 st := sv.Type() 451 sprops := GetProperties(st) 452 reqCount := sprops.reqCount 453 var reqFieldErr error 454 fieldSet := make(map[string]bool) 455 // A struct is a sequence of "name: value", terminated by one of 456 // '>' or '}', or the end of the input. A name may also be 457 // "[extension]" or "[type/url]". 458 // 459 // The whole struct can also be an expanded Any message, like: 460 // [type/url] < ... struct contents ... > 461 for { 462 tok := p.next() 463 if tok.err != nil { 464 return tok.err 465 } 466 if tok.value == terminator { 467 break 468 } 469 if tok.value == "[" { 470 // Looks like an extension or an Any. 471 // 472 // TODO: Check whether we need to handle 473 // namespace rooted names (e.g. ".something.Foo"). 474 extName, err := p.consumeExtName() 475 if err != nil { 476 return err 477 } 478 479 if s := strings.LastIndex(extName, "/"); s >= 0 { 480 // If it contains a slash, it's an Any type URL. 481 messageName := extName[s+1:] 482 mt := MessageType(messageName) 483 if mt == nil { 484 return p.errorf("unrecognized message %q in google.protobuf.Any", messageName) 485 } 486 tok = p.next() 487 if tok.err != nil { 488 return tok.err 489 } 490 // consume an optional colon 491 if tok.value == ":" { 492 tok = p.next() 493 if tok.err != nil { 494 return tok.err 495 } 496 } 497 var terminator string 498 switch tok.value { 499 case "<": 500 terminator = ">" 501 case "{": 502 terminator = "}" 503 default: 504 return p.errorf("expected '{' or '<', found %q", tok.value) 505 } 506 v := reflect.New(mt.Elem()) 507 if pe := p.readStruct(v.Elem(), terminator); pe != nil { 508 return pe 509 } 510 b, err := Marshal(v.Interface().(Message)) 511 if err != nil { 512 return p.errorf("failed to marshal message of type %q: %v", messageName, err) 513 } 514 if fieldSet["type_url"] { 515 return p.errorf(anyRepeatedlyUnpacked, "type_url") 516 } 517 if fieldSet["value"] { 518 return p.errorf(anyRepeatedlyUnpacked, "value") 519 } 520 sv.FieldByName("TypeUrl").SetString(extName) 521 sv.FieldByName("Value").SetBytes(b) 522 fieldSet["type_url"] = true 523 fieldSet["value"] = true 524 continue 525 } 526 527 var desc *ExtensionDesc 528 // This could be faster, but it's functional. 529 // TODO: Do something smarter than a linear scan. 530 for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) { 531 if d.Name == extName { 532 desc = d 533 break 534 } 535 } 536 if desc == nil { 537 return p.errorf("unrecognized extension %q", extName) 538 } 539 540 props := &Properties{} 541 props.Parse(desc.Tag) 542 543 typ := reflect.TypeOf(desc.ExtensionType) 544 if err := p.checkForColon(props, typ); err != nil { 545 return err 546 } 547 548 rep := desc.repeated() 549 550 // Read the extension structure, and set it in 551 // the value we're constructing. 552 var ext reflect.Value 553 if !rep { 554 ext = reflect.New(typ).Elem() 555 } else { 556 ext = reflect.New(typ.Elem()).Elem() 557 } 558 if err := p.readAny(ext, props); err != nil { 559 if _, ok := err.(*RequiredNotSetError); !ok { 560 return err 561 } 562 reqFieldErr = err 563 } 564 ep := sv.Addr().Interface().(Message) 565 if !rep { 566 SetExtension(ep, desc, ext.Interface()) 567 } else { 568 old, err := GetExtension(ep, desc) 569 var sl reflect.Value 570 if err == nil { 571 sl = reflect.ValueOf(old) // existing slice 572 } else { 573 sl = reflect.MakeSlice(typ, 0, 1) 574 } 575 sl = reflect.Append(sl, ext) 576 SetExtension(ep, desc, sl.Interface()) 577 } 578 if err := p.consumeOptionalSeparator(); err != nil { 579 return err 580 } 581 continue 582 } 583 584 // This is a normal, non-extension field. 585 name := tok.value 586 var dst reflect.Value 587 fi, props, ok := structFieldByName(sprops, name) 588 if ok { 589 dst = sv.Field(fi) 590 } else if oop, ok := sprops.OneofTypes[name]; ok { 591 // It is a oneof. 592 props = oop.Prop 593 nv := reflect.New(oop.Type.Elem()) 594 dst = nv.Elem().Field(0) 595 field := sv.Field(oop.Field) 596 if !field.IsNil() { 597 return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, sv.Type().Field(oop.Field).Name) 598 } 599 field.Set(nv) 600 } 601 if !dst.IsValid() { 602 return p.errorf("unknown field name %q in %v", name, st) 603 } 604 605 if dst.Kind() == reflect.Map { 606 // Consume any colon. 607 if err := p.checkForColon(props, dst.Type()); err != nil { 608 return err 609 } 610 611 // Construct the map if it doesn't already exist. 612 if dst.IsNil() { 613 dst.Set(reflect.MakeMap(dst.Type())) 614 } 615 key := reflect.New(dst.Type().Key()).Elem() 616 val := reflect.New(dst.Type().Elem()).Elem() 617 618 // The map entry should be this sequence of tokens: 619 // < key : KEY value : VALUE > 620 // However, implementations may omit key or value, and technically 621 // we should support them in any order. See b/28924776 for a time 622 // this went wrong. 623 624 tok := p.next() 625 var terminator string 626 switch tok.value { 627 case "<": 628 terminator = ">" 629 case "{": 630 terminator = "}" 631 default: 632 return p.errorf("expected '{' or '<', found %q", tok.value) 633 } 634 for { 635 tok := p.next() 636 if tok.err != nil { 637 return tok.err 638 } 639 if tok.value == terminator { 640 break 641 } 642 switch tok.value { 643 case "key": 644 if err := p.consumeToken(":"); err != nil { 645 return err 646 } 647 if err := p.readAny(key, props.mkeyprop); err != nil { 648 return err 649 } 650 if err := p.consumeOptionalSeparator(); err != nil { 651 return err 652 } 653 case "value": 654 if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil { 655 return err 656 } 657 if err := p.readAny(val, props.mvalprop); err != nil { 658 return err 659 } 660 if err := p.consumeOptionalSeparator(); err != nil { 661 return err 662 } 663 default: 664 p.back() 665 return p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value) 666 } 667 } 668 669 dst.SetMapIndex(key, val) 670 continue 671 } 672 673 // Check that it's not already set if it's not a repeated field. 674 if !props.Repeated && fieldSet[name] { 675 return p.errorf("non-repeated field %q was repeated", name) 676 } 677 678 if err := p.checkForColon(props, dst.Type()); err != nil { 679 return err 680 } 681 682 // Parse into the field. 683 fieldSet[name] = true 684 if err := p.readAny(dst, props); err != nil { 685 if _, ok := err.(*RequiredNotSetError); !ok { 686 return err 687 } 688 reqFieldErr = err 689 } 690 if props.Required { 691 reqCount-- 692 } 693 694 if err := p.consumeOptionalSeparator(); err != nil { 695 return err 696 } 697 698 } 699 700 if reqCount > 0 { 701 return p.missingRequiredFieldError(sv) 702 } 703 return reqFieldErr 704} 705 706// consumeExtName consumes extension name or expanded Any type URL and the 707// following ']'. It returns the name or URL consumed. 708func (p *textParser) consumeExtName() (string, error) { 709 tok := p.next() 710 if tok.err != nil { 711 return "", tok.err 712 } 713 714 // If extension name or type url is quoted, it's a single token. 715 if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] { 716 name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0])) 717 if err != nil { 718 return "", err 719 } 720 return name, p.consumeToken("]") 721 } 722 723 // Consume everything up to "]" 724 var parts []string 725 for tok.value != "]" { 726 parts = append(parts, tok.value) 727 tok = p.next() 728 if tok.err != nil { 729 return "", p.errorf("unrecognized type_url or extension name: %s", tok.err) 730 } 731 } 732 return strings.Join(parts, ""), nil 733} 734 735// consumeOptionalSeparator consumes an optional semicolon or comma. 736// It is used in readStruct to provide backward compatibility. 737func (p *textParser) consumeOptionalSeparator() error { 738 tok := p.next() 739 if tok.err != nil { 740 return tok.err 741 } 742 if tok.value != ";" && tok.value != "," { 743 p.back() 744 } 745 return nil 746} 747 748func (p *textParser) readAny(v reflect.Value, props *Properties) error { 749 tok := p.next() 750 if tok.err != nil { 751 return tok.err 752 } 753 if tok.value == "" { 754 return p.errorf("unexpected EOF") 755 } 756 757 switch fv := v; fv.Kind() { 758 case reflect.Slice: 759 at := v.Type() 760 if at.Elem().Kind() == reflect.Uint8 { 761 // Special case for []byte 762 if tok.value[0] != '"' && tok.value[0] != '\'' { 763 // Deliberately written out here, as the error after 764 // this switch statement would write "invalid []byte: ...", 765 // which is not as user-friendly. 766 return p.errorf("invalid string: %v", tok.value) 767 } 768 bytes := []byte(tok.unquoted) 769 fv.Set(reflect.ValueOf(bytes)) 770 return nil 771 } 772 // Repeated field. 773 if tok.value == "[" { 774 // Repeated field with list notation, like [1,2,3]. 775 for { 776 fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) 777 err := p.readAny(fv.Index(fv.Len()-1), props) 778 if err != nil { 779 return err 780 } 781 tok := p.next() 782 if tok.err != nil { 783 return tok.err 784 } 785 if tok.value == "]" { 786 break 787 } 788 if tok.value != "," { 789 return p.errorf("Expected ']' or ',' found %q", tok.value) 790 } 791 } 792 return nil 793 } 794 // One value of the repeated field. 795 p.back() 796 fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) 797 return p.readAny(fv.Index(fv.Len()-1), props) 798 case reflect.Bool: 799 // true/1/t/True or false/f/0/False. 800 switch tok.value { 801 case "true", "1", "t", "True": 802 fv.SetBool(true) 803 return nil 804 case "false", "0", "f", "False": 805 fv.SetBool(false) 806 return nil 807 } 808 case reflect.Float32, reflect.Float64: 809 v := tok.value 810 // Ignore 'f' for compatibility with output generated by C++, but don't 811 // remove 'f' when the value is "-inf" or "inf". 812 if strings.HasSuffix(v, "f") && tok.value != "-inf" && tok.value != "inf" { 813 v = v[:len(v)-1] 814 } 815 if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil { 816 fv.SetFloat(f) 817 return nil 818 } 819 case reflect.Int32: 820 if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil { 821 fv.SetInt(x) 822 return nil 823 } 824 825 if len(props.Enum) == 0 { 826 break 827 } 828 m, ok := enumValueMaps[props.Enum] 829 if !ok { 830 break 831 } 832 x, ok := m[tok.value] 833 if !ok { 834 break 835 } 836 fv.SetInt(int64(x)) 837 return nil 838 case reflect.Int64: 839 if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil { 840 fv.SetInt(x) 841 return nil 842 } 843 844 case reflect.Ptr: 845 // A basic field (indirected through pointer), or a repeated message/group 846 p.back() 847 fv.Set(reflect.New(fv.Type().Elem())) 848 return p.readAny(fv.Elem(), props) 849 case reflect.String: 850 if tok.value[0] == '"' || tok.value[0] == '\'' { 851 fv.SetString(tok.unquoted) 852 return nil 853 } 854 case reflect.Struct: 855 var terminator string 856 switch tok.value { 857 case "{": 858 terminator = "}" 859 case "<": 860 terminator = ">" 861 default: 862 return p.errorf("expected '{' or '<', found %q", tok.value) 863 } 864 // TODO: Handle nested messages which implement encoding.TextUnmarshaler. 865 return p.readStruct(fv, terminator) 866 case reflect.Uint32: 867 if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { 868 fv.SetUint(x) 869 return nil 870 } 871 case reflect.Uint64: 872 if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil { 873 fv.SetUint(x) 874 return nil 875 } 876 } 877 return p.errorf("invalid %v: %v", v.Type(), tok.value) 878} 879 880// UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb 881// before starting to unmarshal, so any existing data in pb is always removed. 882// If a required field is not set and no other error occurs, 883// UnmarshalText returns *RequiredNotSetError. 884func UnmarshalText(s string, pb Message) error { 885 if um, ok := pb.(encoding.TextUnmarshaler); ok { 886 err := um.UnmarshalText([]byte(s)) 887 return err 888 } 889 pb.Reset() 890 v := reflect.ValueOf(pb) 891 if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil { 892 return pe 893 } 894 return nil 895} 896