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
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	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
71type writer interface {
72	io.Writer
73	WriteByte(byte) error
74}
75
76// textWriter is an io.Writer that tracks its indentation level.
77type 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
84func (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
98func (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
147func (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
159func (w *textWriter) indent() { w.ind++ }
160
161func (w *textWriter) unindent() {
162	if w.ind == 0 {
163		log.Print("proto: textWriter unindented too far")
164		return
165	}
166	w.ind--
167}
168
169func 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
179func 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
199func 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.
214func (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
260func (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
479var textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
480
481// writeAny writes an arbitrary field.
482func (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.
622func 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.
631func 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
667func 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
734func 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
743type int32Slice []int32
744
745func (s int32Slice) Len() int           { return len(s) }
746func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] }
747func (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.
751func (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
821func (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
839func (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.
856type 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.
863func (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.
906func (tm *TextMarshaler) Text(pb Message) string {
907	var buf bytes.Buffer
908	tm.Marshal(&buf, pb)
909	return buf.String()
910}
911
912var (
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.
921func 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.
924func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) }
925
926// CompactText writes a given protocol buffer in compact text format (one line).
927func 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.
930func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) }
931