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