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 writing the text protocol buffer format. 35 36 import ( 37 "bufio" 38 "bytes" 39 "encoding" 40 "errors" 41 "fmt" 42 "io" 43 "log" 44 "math" 45 "reflect" 46 "sort" 47 "strings" 48 ) 49 50 var ( 51 newline = []byte("\n") 52 spaces = []byte(" ") 53 gtNewline = []byte(">\n") 54 endBraceNewline = []byte("}\n") 55 backslashN = []byte{'\\', 'n'} 56 backslashR = []byte{'\\', 'r'} 57 backslashT = []byte{'\\', 't'} 58 backslashDQ = []byte{'\\', '"'} 59 backslashBS = []byte{'\\', '\\'} 60 posInf = []byte("inf") 61 negInf = []byte("-inf") 62 nan = []byte("nan") 63 ) 64 65 type writer interface { 66 io.Writer 67 WriteByte(byte) error 68 } 69 70 // textWriter is an io.Writer that tracks its indentation level. 71 type textWriter struct { 72 ind int 73 complete bool // if the current position is a complete line 74 compact bool // whether to write out as a one-liner 75 w writer 76 } 77 78 func (w *textWriter) WriteString(s string) (n int, err error) { 79 if !strings.Contains(s, "\n") { 80 if !w.compact && w.complete { 81 w.writeIndent() 82 } 83 w.complete = false 84 return io.WriteString(w.w, s) 85 } 86 // WriteString is typically called without newlines, so this 87 // codepath and its copy are rare. We copy to avoid 88 // duplicating all of Write's logic here. 89 return w.Write([]byte(s)) 90 } 91 92 func (w *textWriter) Write(p []byte) (n int, err error) { 93 newlines := bytes.Count(p, newline) 94 if newlines == 0 { 95 if !w.compact && w.complete { 96 w.writeIndent() 97 } 98 n, err = w.w.Write(p) 99 w.complete = false 100 return n, err 101 } 102 103 frags := bytes.SplitN(p, newline, newlines+1) 104 if w.compact { 105 for i, frag := range frags { 106 if i > 0 { 107 if err := w.w.WriteByte(' '); err != nil { 108 return n, err 109 } 110 n++ 111 } 112 nn, err := w.w.Write(frag) 113 n += nn 114 if err != nil { 115 return n, err 116 } 117 } 118 return n, nil 119 } 120 121 for i, frag := range frags { 122 if w.complete { 123 w.writeIndent() 124 } 125 nn, err := w.w.Write(frag) 126 n += nn 127 if err != nil { 128 return n, err 129 } 130 if i+1 < len(frags) { 131 if err := w.w.WriteByte('\n'); err != nil { 132 return n, err 133 } 134 n++ 135 } 136 } 137 w.complete = len(frags[len(frags)-1]) == 0 138 return n, nil 139 } 140 141 func (w *textWriter) WriteByte(c byte) error { 142 if w.compact && c == '\n' { 143 c = ' ' 144 } 145 if !w.compact && w.complete { 146 w.writeIndent() 147 } 148 err := w.w.WriteByte(c) 149 w.complete = c == '\n' 150 return err 151 } 152 153 func (w *textWriter) indent() { w.ind++ } 154 155 func (w *textWriter) unindent() { 156 if w.ind == 0 { 157 log.Print("proto: textWriter unindented too far") 158 return 159 } 160 w.ind-- 161 } 162 163 func writeName(w *textWriter, props *Properties) error { 164 if _, err := w.WriteString(props.OrigName); err != nil { 165 return err 166 } 167 if props.Wire != "group" { 168 return w.WriteByte(':') 169 } 170 return nil 171 } 172 173 // raw is the interface satisfied by RawMessage. 174 type raw interface { 175 Bytes() []byte 176 } 177 178 func requiresQuotes(u string) bool { 179 // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted. 180 for _, ch := range u { 181 switch { 182 case ch == '.' || ch == '/' || ch == '_': 183 continue 184 case '0' <= ch && ch <= '9': 185 continue 186 case 'A' <= ch && ch <= 'Z': 187 continue 188 case 'a' <= ch && ch <= 'z': 189 continue 190 default: 191 return true 192 } 193 } 194 return false 195 } 196 197 // isAny reports whether sv is a google.protobuf.Any message 198 func isAny(sv reflect.Value) bool { 199 type wkt interface { 200 XXX_WellKnownType() string 201 } 202 t, ok := sv.Addr().Interface().(wkt) 203 return ok && t.XXX_WellKnownType() == "Any" 204 } 205 206 // writeProto3Any writes an expanded google.protobuf.Any message. 207 // 208 // It returns (false, nil) if sv value can't be unmarshaled (e.g. because 209 // required messages are not linked in). 210 // 211 // It returns (true, error) when sv was written in expanded format or an error 212 // was encountered. 213 func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) { 214 turl := sv.FieldByName("TypeUrl") 215 val := sv.FieldByName("Value") 216 if !turl.IsValid() || !val.IsValid() { 217 return true, errors.New("proto: invalid google.protobuf.Any message") 218 } 219 220 b, ok := val.Interface().([]byte) 221 if !ok { 222 return true, errors.New("proto: invalid google.protobuf.Any message") 223 } 224 225 parts := strings.Split(turl.String(), "/") 226 mt := MessageType(parts[len(parts)-1]) 227 if mt == nil { 228 return false, nil 229 } 230 m := reflect.New(mt.Elem()) 231 if err := Unmarshal(b, m.Interface().(Message)); err != nil { 232 return false, nil 233 } 234 w.Write([]byte("[")) 235 u := turl.String() 236 if requiresQuotes(u) { 237 writeString(w, u) 238 } else { 239 w.Write([]byte(u)) 240 } 241 if w.compact { 242 w.Write([]byte("]:<")) 243 } else { 244 w.Write([]byte("]: <\n")) 245 w.ind++ 246 } 247 if err := tm.writeStruct(w, m.Elem()); err != nil { 248 return true, err 249 } 250 if w.compact { 251 w.Write([]byte("> ")) 252 } else { 253 w.ind-- 254 w.Write([]byte(">\n")) 255 } 256 return true, nil 257 } 258 259 func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { 260 if tm.ExpandAny && isAny(sv) { 261 if canExpand, err := tm.writeProto3Any(w, sv); canExpand { 262 return err 263 } 264 } 265 st := sv.Type() 266 sprops := GetProperties(st) 267 for i := 0; i < sv.NumField(); i++ { 268 fv := sv.Field(i) 269 props := sprops.Prop[i] 270 name := st.Field(i).Name 271 272 if strings.HasPrefix(name, "XXX_") { 273 // There are two XXX_ fields: 274 // XXX_unrecognized []byte 275 // XXX_extensions map[int32]proto.Extension 276 // The first is handled here; 277 // the second is handled at the bottom of this function. 278 if name == "XXX_unrecognized" && !fv.IsNil() { 279 if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil { 280 return err 281 } 282 } 283 continue 284 } 285 if fv.Kind() == reflect.Ptr && fv.IsNil() { 286 // Field not filled in. This could be an optional field or 287 // a required field that wasn't filled in. Either way, there 288 // isn't anything we can show for it. 289 continue 290 } 291 if fv.Kind() == reflect.Slice && fv.IsNil() { 292 // Repeated field that is empty, or a bytes field that is unused. 293 continue 294 } 295 296 if props.Repeated && fv.Kind() == reflect.Slice { 297 // Repeated field. 298 for j := 0; j < fv.Len(); j++ { 299 if err := writeName(w, props); err != nil { 300 return err 301 } 302 if !w.compact { 303 if err := w.WriteByte(' '); err != nil { 304 return err 305 } 306 } 307 v := fv.Index(j) 308 if v.Kind() == reflect.Ptr && v.IsNil() { 309 // A nil message in a repeated field is not valid, 310 // but we can handle that more gracefully than panicking. 311 if _, err := w.Write([]byte("<nil>\n")); err != nil { 312 return err 313 } 314 continue 315 } 316 if err := tm.writeAny(w, v, props); err != nil { 317 return err 318 } 319 if err := w.WriteByte('\n'); err != nil { 320 return err 321 } 322 } 323 continue 324 } 325 if fv.Kind() == reflect.Map { 326 // Map fields are rendered as a repeated struct with key/value fields. 327 keys := fv.MapKeys() 328 sort.Sort(mapKeys(keys)) 329 for _, key := range keys { 330 val := fv.MapIndex(key) 331 if err := writeName(w, props); err != nil { 332 return err 333 } 334 if !w.compact { 335 if err := w.WriteByte(' '); err != nil { 336 return err 337 } 338 } 339 // open struct 340 if err := w.WriteByte('<'); err != nil { 341 return err 342 } 343 if !w.compact { 344 if err := w.WriteByte('\n'); err != nil { 345 return err 346 } 347 } 348 w.indent() 349 // key 350 if _, err := w.WriteString("key:"); err != nil { 351 return err 352 } 353 if !w.compact { 354 if err := w.WriteByte(' '); err != nil { 355 return err 356 } 357 } 358 if err := tm.writeAny(w, key, props.mkeyprop); err != nil { 359 return err 360 } 361 if err := w.WriteByte('\n'); err != nil { 362 return err 363 } 364 // nil values aren't legal, but we can avoid panicking because of them. 365 if val.Kind() != reflect.Ptr || !val.IsNil() { 366 // value 367 if _, err := w.WriteString("value:"); err != nil { 368 return err 369 } 370 if !w.compact { 371 if err := w.WriteByte(' '); err != nil { 372 return err 373 } 374 } 375 if err := tm.writeAny(w, val, props.mvalprop); err != nil { 376 return err 377 } 378 if err := w.WriteByte('\n'); err != nil { 379 return err 380 } 381 } 382 // close struct 383 w.unindent() 384 if err := w.WriteByte('>'); err != nil { 385 return err 386 } 387 if err := w.WriteByte('\n'); err != nil { 388 return err 389 } 390 } 391 continue 392 } 393 if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 { 394 // empty bytes field 395 continue 396 } 397 if fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice { 398 // proto3 non-repeated scalar field; skip if zero value 399 if isProto3Zero(fv) { 400 continue 401 } 402 } 403 404 if fv.Kind() == reflect.Interface { 405 // Check if it is a oneof. 406 if st.Field(i).Tag.Get("protobuf_oneof") != "" { 407 // fv is nil, or holds a pointer to generated struct. 408 // That generated struct has exactly one field, 409 // which has a protobuf struct tag. 410 if fv.IsNil() { 411 continue 412 } 413 inner := fv.Elem().Elem() // interface -> *T -> T 414 tag := inner.Type().Field(0).Tag.Get("protobuf") 415 props = new(Properties) // Overwrite the outer props var, but not its pointee. 416 props.Parse(tag) 417 // Write the value in the oneof, not the oneof itself. 418 fv = inner.Field(0) 419 420 // Special case to cope with malformed messages gracefully: 421 // If the value in the oneof is a nil pointer, don't panic 422 // in writeAny. 423 if fv.Kind() == reflect.Ptr && fv.IsNil() { 424 // Use errors.New so writeAny won't render quotes. 425 msg := errors.New("/* nil */") 426 fv = reflect.ValueOf(&msg).Elem() 427 } 428 } 429 } 430 431 if err := writeName(w, props); err != nil { 432 return err 433 } 434 if !w.compact { 435 if err := w.WriteByte(' '); err != nil { 436 return err 437 } 438 } 439 if b, ok := fv.Interface().(raw); ok { 440 if err := writeRaw(w, b.Bytes()); err != nil { 441 return err 442 } 443 continue 444 } 445 446 // Enums have a String method, so writeAny will work fine. 447 if err := tm.writeAny(w, fv, props); err != nil { 448 return err 449 } 450 451 if err := w.WriteByte('\n'); err != nil { 452 return err 453 } 454 } 455 456 // Extensions (the XXX_extensions field). 457 pv := sv.Addr() 458 if _, ok := extendable(pv.Interface()); ok { 459 if err := tm.writeExtensions(w, pv); err != nil { 460 return err 461 } 462 } 463 464 return nil 465 } 466 467 // writeRaw writes an uninterpreted raw message. 468 func writeRaw(w *textWriter, b []byte) error { 469 if err := w.WriteByte('<'); err != nil { 470 return err 471 } 472 if !w.compact { 473 if err := w.WriteByte('\n'); err != nil { 474 return err 475 } 476 } 477 w.indent() 478 if err := writeUnknownStruct(w, b); err != nil { 479 return err 480 } 481 w.unindent() 482 if err := w.WriteByte('>'); err != nil { 483 return err 484 } 485 return nil 486 } 487 488 // writeAny writes an arbitrary field. 489 func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error { 490 v = reflect.Indirect(v) 491 492 // Floats have special cases. 493 if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 { 494 x := v.Float() 495 var b []byte 496 switch { 497 case math.IsInf(x, 1): 498 b = posInf 499 case math.IsInf(x, -1): 500 b = negInf 501 case math.IsNaN(x): 502 b = nan 503 } 504 if b != nil { 505 _, err := w.Write(b) 506 return err 507 } 508 // Other values are handled below. 509 } 510 511 // We don't attempt to serialise every possible value type; only those 512 // that can occur in protocol buffers. 513 switch v.Kind() { 514 case reflect.Slice: 515 // Should only be a []byte; repeated fields are handled in writeStruct. 516 if err := writeString(w, string(v.Bytes())); err != nil { 517 return err 518 } 519 case reflect.String: 520 if err := writeString(w, v.String()); err != nil { 521 return err 522 } 523 case reflect.Struct: 524 // Required/optional group/message. 525 var bra, ket byte = '<', '>' 526 if props != nil && props.Wire == "group" { 527 bra, ket = '{', '}' 528 } 529 if err := w.WriteByte(bra); err != nil { 530 return err 531 } 532 if !w.compact { 533 if err := w.WriteByte('\n'); err != nil { 534 return err 535 } 536 } 537 w.indent() 538 if etm, ok := v.Interface().(encoding.TextMarshaler); ok { 539 text, err := etm.MarshalText() 540 if err != nil { 541 return err 542 } 543 if _, err = w.Write(text); err != nil { 544 return err 545 } 546 } else if err := tm.writeStruct(w, v); err != nil { 547 return err 548 } 549 w.unindent() 550 if err := w.WriteByte(ket); err != nil { 551 return err 552 } 553 default: 554 _, err := fmt.Fprint(w, v.Interface()) 555 return err 556 } 557 return nil 558 } 559 560 // equivalent to C's isprint. 561 func isprint(c byte) bool { 562 return c >= 0x20 && c < 0x7f 563 } 564 565 // writeString writes a string in the protocol buffer text format. 566 // It is similar to strconv.Quote except we don't use Go escape sequences, 567 // we treat the string as a byte sequence, and we use octal escapes. 568 // These differences are to maintain interoperability with the other 569 // languages' implementations of the text format. 570 func writeString(w *textWriter, s string) error { 571 // use WriteByte here to get any needed indent 572 if err := w.WriteByte('"'); err != nil { 573 return err 574 } 575 // Loop over the bytes, not the runes. 576 for i := 0; i < len(s); i++ { 577 var err error 578 // Divergence from C++: we don't escape apostrophes. 579 // There's no need to escape them, and the C++ parser 580 // copes with a naked apostrophe. 581 switch c := s[i]; c { 582 case '\n': 583 _, err = w.w.Write(backslashN) 584 case '\r': 585 _, err = w.w.Write(backslashR) 586 case '\t': 587 _, err = w.w.Write(backslashT) 588 case '"': 589 _, err = w.w.Write(backslashDQ) 590 case '\\': 591 _, err = w.w.Write(backslashBS) 592 default: 593 if isprint(c) { 594 err = w.w.WriteByte(c) 595 } else { 596 _, err = fmt.Fprintf(w.w, "\\%03o", c) 597 } 598 } 599 if err != nil { 600 return err 601 } 602 } 603 return w.WriteByte('"') 604 } 605 606 func writeUnknownStruct(w *textWriter, data []byte) (err error) { 607 if !w.compact { 608 if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil { 609 return err 610 } 611 } 612 b := NewBuffer(data) 613 for b.index < len(b.buf) { 614 x, err := b.DecodeVarint() 615 if err != nil { 616 _, err := fmt.Fprintf(w, "/* %v */\n", err) 617 return err 618 } 619 wire, tag := x&7, x>>3 620 if wire == WireEndGroup { 621 w.unindent() 622 if _, err := w.Write(endBraceNewline); err != nil { 623 return err 624 } 625 continue 626 } 627 if _, err := fmt.Fprint(w, tag); err != nil { 628 return err 629 } 630 if wire != WireStartGroup { 631 if err := w.WriteByte(':'); err != nil { 632 return err 633 } 634 } 635 if !w.compact || wire == WireStartGroup { 636 if err := w.WriteByte(' '); err != nil { 637 return err 638 } 639 } 640 switch wire { 641 case WireBytes: 642 buf, e := b.DecodeRawBytes(false) 643 if e == nil { 644 _, err = fmt.Fprintf(w, "%q", buf) 645 } else { 646 _, err = fmt.Fprintf(w, "/* %v */", e) 647 } 648 case WireFixed32: 649 x, err = b.DecodeFixed32() 650 err = writeUnknownInt(w, x, err) 651 case WireFixed64: 652 x, err = b.DecodeFixed64() 653 err = writeUnknownInt(w, x, err) 654 case WireStartGroup: 655 err = w.WriteByte('{') 656 w.indent() 657 case WireVarint: 658 x, err = b.DecodeVarint() 659 err = writeUnknownInt(w, x, err) 660 default: 661 _, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire) 662 } 663 if err != nil { 664 return err 665 } 666 if err = w.WriteByte('\n'); err != nil { 667 return err 668 } 669 } 670 return nil 671 } 672 673 func writeUnknownInt(w *textWriter, x uint64, err error) error { 674 if err == nil { 675 _, err = fmt.Fprint(w, x) 676 } else { 677 _, err = fmt.Fprintf(w, "/* %v */", err) 678 } 679 return err 680 } 681 682 type int32Slice []int32 683 684 func (s int32Slice) Len() int { return len(s) } 685 func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] } 686 func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 687 688 // writeExtensions writes all the extensions in pv. 689 // pv is assumed to be a pointer to a protocol message struct that is extendable. 690 func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error { 691 emap := extensionMaps[pv.Type().Elem()] 692 ep, _ := extendable(pv.Interface()) 693 694 // Order the extensions by ID. 695 // This isn't strictly necessary, but it will give us 696 // canonical output, which will also make testing easier. 697 m, mu := ep.extensionsRead() 698 if m == nil { 699 return nil 700 } 701 mu.Lock() 702 ids := make([]int32, 0, len(m)) 703 for id := range m { 704 ids = append(ids, id) 705 } 706 sort.Sort(int32Slice(ids)) 707 mu.Unlock() 708 709 for _, extNum := range ids { 710 ext := m[extNum] 711 var desc *ExtensionDesc 712 if emap != nil { 713 desc = emap[extNum] 714 } 715 if desc == nil { 716 // Unknown extension. 717 if err := writeUnknownStruct(w, ext.enc); err != nil { 718 return err 719 } 720 continue 721 } 722 723 pb, err := GetExtension(ep, desc) 724 if err != nil { 725 return fmt.Errorf("failed getting extension: %v", err) 726 } 727 728 // Repeated extensions will appear as a slice. 729 if !desc.repeated() { 730 if err := tm.writeExtension(w, desc.Name, pb); err != nil { 731 return err 732 } 733 } else { 734 v := reflect.ValueOf(pb) 735 for i := 0; i < v.Len(); i++ { 736 if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil { 737 return err 738 } 739 } 740 } 741 } 742 return nil 743 } 744 745 func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error { 746 if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil { 747 return err 748 } 749 if !w.compact { 750 if err := w.WriteByte(' '); err != nil { 751 return err 752 } 753 } 754 if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil { 755 return err 756 } 757 if err := w.WriteByte('\n'); err != nil { 758 return err 759 } 760 return nil 761 } 762 763 func (w *textWriter) writeIndent() { 764 if !w.complete { 765 return 766 } 767 remain := w.ind * 2 768 for remain > 0 { 769 n := remain 770 if n > len(spaces) { 771 n = len(spaces) 772 } 773 w.w.Write(spaces[:n]) 774 remain -= n 775 } 776 w.complete = false 777 } 778 779 // TextMarshaler is a configurable text format marshaler. 780 type TextMarshaler struct { 781 Compact bool // use compact text format (one line). 782 ExpandAny bool // expand google.protobuf.Any messages of known types 783 } 784 785 // Marshal writes a given protocol buffer in text format. 786 // The only errors returned are from w. 787 func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error { 788 val := reflect.ValueOf(pb) 789 if pb == nil || val.IsNil() { 790 w.Write([]byte("<nil>")) 791 return nil 792 } 793 var bw *bufio.Writer 794 ww, ok := w.(writer) 795 if !ok { 796 bw = bufio.NewWriter(w) 797 ww = bw 798 } 799 aw := &textWriter{ 800 w: ww, 801 complete: true, 802 compact: tm.Compact, 803 } 804 805 if etm, ok := pb.(encoding.TextMarshaler); ok { 806 text, err := etm.MarshalText() 807 if err != nil { 808 return err 809 } 810 if _, err = aw.Write(text); err != nil { 811 return err 812 } 813 if bw != nil { 814 return bw.Flush() 815 } 816 return nil 817 } 818 // Dereference the received pointer so we don't have outer < and >. 819 v := reflect.Indirect(val) 820 if err := tm.writeStruct(aw, v); err != nil { 821 return err 822 } 823 if bw != nil { 824 return bw.Flush() 825 } 826 return nil 827 } 828 829 // Text is the same as Marshal, but returns the string directly. 830 func (tm *TextMarshaler) Text(pb Message) string { 831 var buf bytes.Buffer 832 tm.Marshal(&buf, pb) 833 return buf.String() 834 } 835 836 var ( 837 defaultTextMarshaler = TextMarshaler{} 838 compactTextMarshaler = TextMarshaler{Compact: true} 839 ) 840 841 // TODO: consider removing some of the Marshal functions below. 842 843 // MarshalText writes a given protocol buffer in text format. 844 // The only errors returned are from w. 845 func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) } 846 847 // MarshalTextString is the same as MarshalText, but returns the string directly. 848 func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) } 849 850 // CompactText writes a given protocol buffer in compact text format (one line). 851 func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) } 852 853 // CompactTextString is the same as CompactText, but returns the string directly. 854 func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) } 855