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