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