blob: 5063009c27cca67358d21fd7c84f5f713acf6c61 [file] [log] [blame]
Rob Pikeaaa3a622010-03-20 22:32:34 -07001// Go support for Protocol Buffers - Google's data interchange format
2//
David Symondsee6e9c52012-11-29 08:51:07 +11003// Copyright 2010 The Go Authors. All rights reserved.
Rob Pikeaaa3a622010-03-20 22:32:34 -07004// http://code.google.com/p/goprotobuf/
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
David Symondse37856c2011-06-22 12:52:53 +100034// Functions for writing the text protocol buffer format.
Rob Pikeaaa3a622010-03-20 22:32:34 -070035
36import (
David Symonds4dc589e2012-12-06 14:05:48 +110037 "bufio"
Rob Pikeaaa3a622010-03-20 22:32:34 -070038 "bytes"
39 "fmt"
40 "io"
David Symondse37856c2011-06-22 12:52:53 +100041 "log"
David Symonds9cc87e32013-06-08 12:27:15 +100042 "math"
Rob Pikeaaa3a622010-03-20 22:32:34 -070043 "os"
44 "reflect"
David Symonds1d72f7a2011-08-19 18:28:52 +100045 "sort"
Rob Pikeaaa3a622010-03-20 22:32:34 -070046 "strings"
47)
48
David Symondsdbdc4212012-11-08 08:20:35 +110049var (
50 newline = []byte("\n")
51 spaces = []byte(" ")
52 gtNewline = []byte(">\n")
53 endBraceNewline = []byte("}\n")
54 backslashN = []byte{'\\', 'n'}
55 backslashR = []byte{'\\', 'r'}
56 backslashT = []byte{'\\', 't'}
57 backslashDQ = []byte{'\\', '"'}
58 backslashBS = []byte{'\\', '\\'}
David Symonds9cc87e32013-06-08 12:27:15 +100059 posInf = []byte("inf")
60 negInf = []byte("-inf")
61 nan = []byte("nan")
David Symondsdbdc4212012-11-08 08:20:35 +110062)
63
David Symonds4dc589e2012-12-06 14:05:48 +110064type writer interface {
65 io.Writer
66 WriteByte(byte) error
67}
68
David Symondse37856c2011-06-22 12:52:53 +100069// textWriter is an io.Writer that tracks its indentation level.
Rob Pikeaaa3a622010-03-20 22:32:34 -070070type textWriter struct {
David Symonds4dc589e2012-12-06 14:05:48 +110071 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
David Symondsdbdc4212012-11-08 08:20:35 +110075}
David Symonds9f402812011-04-28 18:08:44 +100076
David Symonds267e8052014-02-19 14:50:51 +110077// textMarshaler is implemented by Messages that can marshal themsleves.
78// It is identical to encoding.TextMarshaler, introduced in go 1.2,
79// which will eventually replace it.
80type textMarshaler interface {
81 MarshalText() (text []byte, err error)
82}
83
David Symondsdbdc4212012-11-08 08:20:35 +110084func (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
David Symonds4dc589e2012-12-06 14:05:48 +110090 return io.WriteString(w.w, s)
David Symondsdbdc4212012-11-08 08:20:35 +110091 }
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))
Rob Pikeaaa3a622010-03-20 22:32:34 -070096}
97
Rob Pikea17fdd92011-11-02 12:43:05 -070098func (w *textWriter) Write(p []byte) (n int, err error) {
David Symondsdbdc4212012-11-08 08:20:35 +110099 newlines := bytes.Count(p, newline)
100 if newlines == 0 {
101 if !w.compact && w.complete {
102 w.writeIndent()
103 }
David Symonds4dc589e2012-12-06 14:05:48 +1100104 n, err = w.w.Write(p)
David Symondsdbdc4212012-11-08 08:20:35 +1100105 w.complete = false
David Symonds4dc589e2012-12-06 14:05:48 +1100106 return n, err
David Symondsdbdc4212012-11-08 08:20:35 +1100107 }
108
109 frags := bytes.SplitN(p, newline, newlines+1)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700110 if w.compact {
David Symondsdbdc4212012-11-08 08:20:35 +1100111 for i, frag := range frags {
112 if i > 0 {
David Symonds4dc589e2012-12-06 14:05:48 +1100113 if err := w.w.WriteByte(' '); err != nil {
114 return n, err
115 }
116 n++
David Symondsdbdc4212012-11-08 08:20:35 +1100117 }
David Symonds4dc589e2012-12-06 14:05:48 +1100118 nn, err := w.w.Write(frag)
119 n += nn
120 if err != nil {
121 return n, err
122 }
David Symondsdbdc4212012-11-08 08:20:35 +1100123 }
David Symonds4dc589e2012-12-06 14:05:48 +1100124 return n, nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700125 }
126
David Symondse37856c2011-06-22 12:52:53 +1000127 for i, frag := range frags {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700128 if w.complete {
David Symondsdbdc4212012-11-08 08:20:35 +1100129 w.writeIndent()
Rob Pikeaaa3a622010-03-20 22:32:34 -0700130 }
David Symonds4dc589e2012-12-06 14:05:48 +1100131 nn, err := w.w.Write(frag)
132 n += nn
133 if err != nil {
134 return n, err
135 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700136 if i+1 < len(frags) {
David Symonds4dc589e2012-12-06 14:05:48 +1100137 if err := w.w.WriteByte('\n'); err != nil {
138 return n, err
139 }
140 n++
Rob Pikeaaa3a622010-03-20 22:32:34 -0700141 }
142 }
143 w.complete = len(frags[len(frags)-1]) == 0
David Symonds4dc589e2012-12-06 14:05:48 +1100144 return n, nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700145}
146
Rob Pikea17fdd92011-11-02 12:43:05 -0700147func (w *textWriter) WriteByte(c byte) error {
David Symondsdbdc4212012-11-08 08:20:35 +1100148 if w.compact && c == '\n' {
149 c = ' '
150 }
151 if !w.compact && w.complete {
152 w.writeIndent()
153 }
David Symonds4dc589e2012-12-06 14:05:48 +1100154 err := w.w.WriteByte(c)
David Symondsdbdc4212012-11-08 08:20:35 +1100155 w.complete = c == '\n'
David Symonds9f402812011-04-28 18:08:44 +1000156 return err
157}
158
David Symondse37856c2011-06-22 12:52:53 +1000159func (w *textWriter) indent() { w.ind++ }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700160
161func (w *textWriter) unindent() {
David Symondse37856c2011-06-22 12:52:53 +1000162 if w.ind == 0 {
David Symondsd4661c52012-08-30 15:17:53 +1000163 log.Printf("proto: textWriter unindented too far")
David Symondse37856c2011-06-22 12:52:53 +1000164 return
Rob Pikeaaa3a622010-03-20 22:32:34 -0700165 }
David Symondse37856c2011-06-22 12:52:53 +1000166 w.ind--
Rob Pikeaaa3a622010-03-20 22:32:34 -0700167}
168
David Symonds4dc589e2012-12-06 14:05:48 +1100169func writeName(w *textWriter, props *Properties) error {
170 if _, err := w.WriteString(props.OrigName); err != nil {
171 return err
David Symonds9f402812011-04-28 18:08:44 +1000172 }
David Symonds4dc589e2012-12-06 14:05:48 +1100173 if props.Wire != "group" {
174 return w.WriteByte(':')
175 }
176 return nil
David Symonds9f402812011-04-28 18:08:44 +1000177}
178
David Symonds1d72f7a2011-08-19 18:28:52 +1000179var (
Russ Coxd4ce3f12012-09-12 10:36:26 +1000180 messageSetType = reflect.TypeOf((*MessageSet)(nil)).Elem()
David Symonds1d72f7a2011-08-19 18:28:52 +1000181)
David Symondse37856c2011-06-22 12:52:53 +1000182
David Symondse9e7aaf2012-03-23 13:12:33 +1100183// raw is the interface satisfied by RawMessage.
184type raw interface {
185 Bytes() []byte
186}
187
David Symonds4dc589e2012-12-06 14:05:48 +1100188func writeStruct(w *textWriter, sv reflect.Value) error {
David Symonds1d72f7a2011-08-19 18:28:52 +1000189 if sv.Type() == messageSetType {
David Symonds4dc589e2012-12-06 14:05:48 +1100190 return writeMessageSet(w, sv.Addr().Interface().(*MessageSet))
David Symonds1d72f7a2011-08-19 18:28:52 +1000191 }
192
Rob Pike97e934d2011-04-11 12:52:49 -0700193 st := sv.Type()
Rob Pikeaaa3a622010-03-20 22:32:34 -0700194 sprops := GetProperties(st)
195 for i := 0; i < sv.NumField(); i++ {
David Symonds1d72f7a2011-08-19 18:28:52 +1000196 fv := sv.Field(i)
David Symonds20370902013-03-23 17:20:01 +1100197 props := sprops.Prop[i]
198 name := st.Field(i).Name
199
200 if strings.HasPrefix(name, "XXX_") {
201 // There are two XXX_ fields:
David Symonds1d72f7a2011-08-19 18:28:52 +1000202 // XXX_unrecognized []byte
203 // XXX_extensions map[int32]proto.Extension
204 // The first is handled here;
205 // the second is handled at the bottom of this function.
206 if name == "XXX_unrecognized" && !fv.IsNil() {
David Symonds4dc589e2012-12-06 14:05:48 +1100207 if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil {
208 return err
209 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000210 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700211 continue
212 }
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700213 if fv.Kind() == reflect.Ptr && fv.IsNil() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700214 // Field not filled in. This could be an optional field or
215 // a required field that wasn't filled in. Either way, there
216 // isn't anything we can show for it.
217 continue
218 }
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700219 if fv.Kind() == reflect.Slice && fv.IsNil() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700220 // Repeated field that is empty, or a bytes field that is unused.
221 continue
222 }
223
David Symondsaa922ff2011-07-19 14:58:06 +1000224 if props.Repeated && fv.Kind() == reflect.Slice {
225 // Repeated field.
226 for j := 0; j < fv.Len(); j++ {
David Symonds4dc589e2012-12-06 14:05:48 +1100227 if err := writeName(w, props); err != nil {
228 return err
Rob Pikeaaa3a622010-03-20 22:32:34 -0700229 }
David Symonds4dc589e2012-12-06 14:05:48 +1100230 if !w.compact {
231 if err := w.WriteByte(' '); err != nil {
232 return err
233 }
234 }
David Symonds4b9d2e12014-04-15 18:22:22 +1000235 v := fv.Index(j)
236 if v.Kind() == reflect.Ptr && v.IsNil() {
237 // A nil message in a repeated field is not valid,
238 // but we can handle that more gracefully than panicking.
239 if _, err := w.Write([]byte("<nil>\n")); err != nil {
240 return err
241 }
242 continue
243 }
244 if err := writeAny(w, v, props); err != nil {
David Symonds4dc589e2012-12-06 14:05:48 +1100245 return err
246 }
247 if err := w.WriteByte('\n'); err != nil {
248 return err
249 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700250 }
David Symondsaa922ff2011-07-19 14:58:06 +1000251 continue
Rob Pikeaaa3a622010-03-20 22:32:34 -0700252 }
253
David Symonds4dc589e2012-12-06 14:05:48 +1100254 if err := writeName(w, props); err != nil {
255 return err
256 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700257 if !w.compact {
David Symonds4dc589e2012-12-06 14:05:48 +1100258 if err := w.WriteByte(' '); err != nil {
259 return err
260 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700261 }
David Symondse9e7aaf2012-03-23 13:12:33 +1100262 if b, ok := fv.Interface().(raw); ok {
David Symonds4dc589e2012-12-06 14:05:48 +1100263 if err := writeRaw(w, b.Bytes()); err != nil {
264 return err
265 }
David Symondse9e7aaf2012-03-23 13:12:33 +1100266 continue
267 }
David Symonds4dc589e2012-12-06 14:05:48 +1100268
David Symondsf8a1fcc2013-05-03 08:51:23 +1000269 // Enums have a String method, so writeAny will work fine.
270 if err := writeAny(w, fv, props); err != nil {
271 return err
David Symonds4dc589e2012-12-06 14:05:48 +1100272 }
273
274 if err := w.WriteByte('\n'); err != nil {
275 return err
276 }
David Symondse37856c2011-06-22 12:52:53 +1000277 }
278
David Symonds1d72f7a2011-08-19 18:28:52 +1000279 // Extensions (the XXX_extensions field).
David Symondse37856c2011-06-22 12:52:53 +1000280 pv := sv.Addr()
281 if pv.Type().Implements(extendableProtoType) {
David Symonds4dc589e2012-12-06 14:05:48 +1100282 if err := writeExtensions(w, pv); err != nil {
283 return err
284 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700285 }
David Symonds4dc589e2012-12-06 14:05:48 +1100286
287 return nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700288}
289
David Symondse9e7aaf2012-03-23 13:12:33 +1100290// writeRaw writes an uninterpreted raw message.
David Symonds4dc589e2012-12-06 14:05:48 +1100291func writeRaw(w *textWriter, b []byte) error {
292 if err := w.WriteByte('<'); err != nil {
293 return err
294 }
David Symondse9e7aaf2012-03-23 13:12:33 +1100295 if !w.compact {
David Symonds4dc589e2012-12-06 14:05:48 +1100296 if err := w.WriteByte('\n'); err != nil {
297 return err
298 }
David Symondse9e7aaf2012-03-23 13:12:33 +1100299 }
300 w.indent()
David Symonds4dc589e2012-12-06 14:05:48 +1100301 if err := writeUnknownStruct(w, b); err != nil {
302 return err
303 }
David Symondse9e7aaf2012-03-23 13:12:33 +1100304 w.unindent()
David Symonds4dc589e2012-12-06 14:05:48 +1100305 if err := w.WriteByte('>'); err != nil {
306 return err
307 }
308 return nil
David Symondse9e7aaf2012-03-23 13:12:33 +1100309}
310
David Symondse37856c2011-06-22 12:52:53 +1000311// writeAny writes an arbitrary field.
David Symonds4dc589e2012-12-06 14:05:48 +1100312func writeAny(w *textWriter, v reflect.Value, props *Properties) error {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700313 v = reflect.Indirect(v)
314
David Symonds9cc87e32013-06-08 12:27:15 +1000315 // Floats have special cases.
316 if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 {
317 x := v.Float()
318 var b []byte
319 switch {
320 case math.IsInf(x, 1):
321 b = posInf
322 case math.IsInf(x, -1):
323 b = negInf
324 case math.IsNaN(x):
325 b = nan
326 }
327 if b != nil {
328 _, err := w.Write(b)
329 return err
330 }
331 // Other values are handled below.
332 }
333
Rob Pikeaaa3a622010-03-20 22:32:34 -0700334 // We don't attempt to serialise every possible value type; only those
David Symonds9cc87e32013-06-08 12:27:15 +1000335 // that can occur in protocol buffers.
David Symondse37856c2011-06-22 12:52:53 +1000336 switch v.Kind() {
Rob Pike97e934d2011-04-11 12:52:49 -0700337 case reflect.Slice:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700338 // Should only be a []byte; repeated fields are handled in writeStruct.
David Symonds4dc589e2012-12-06 14:05:48 +1100339 if err := writeString(w, string(v.Interface().([]byte))); err != nil {
340 return err
341 }
Rob Pike97e934d2011-04-11 12:52:49 -0700342 case reflect.String:
David Symonds4dc589e2012-12-06 14:05:48 +1100343 if err := writeString(w, v.String()); err != nil {
344 return err
345 }
Rob Pike97e934d2011-04-11 12:52:49 -0700346 case reflect.Struct:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700347 // Required/optional group/message.
David Symonds9f402812011-04-28 18:08:44 +1000348 var bra, ket byte = '<', '>'
349 if props != nil && props.Wire == "group" {
350 bra, ket = '{', '}'
351 }
David Symonds4dc589e2012-12-06 14:05:48 +1100352 if err := w.WriteByte(bra); err != nil {
353 return err
354 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700355 if !w.compact {
David Symonds4dc589e2012-12-06 14:05:48 +1100356 if err := w.WriteByte('\n'); err != nil {
357 return err
358 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700359 }
360 w.indent()
David Symonds267e8052014-02-19 14:50:51 +1100361 if tm, ok := v.Interface().(textMarshaler); ok {
362 text, err := tm.MarshalText()
363 if err != nil {
364 return err
365 }
366 if _, err = w.Write(text); err != nil {
367 return err
368 }
369 } else if err := writeStruct(w, v); err != nil {
David Symonds4dc589e2012-12-06 14:05:48 +1100370 return err
371 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700372 w.unindent()
David Symonds4dc589e2012-12-06 14:05:48 +1100373 if err := w.WriteByte(ket); err != nil {
374 return err
375 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700376 default:
David Symonds4dc589e2012-12-06 14:05:48 +1100377 _, err := fmt.Fprint(w, v.Interface())
378 return err
David Symondse37856c2011-06-22 12:52:53 +1000379 }
David Symonds4dc589e2012-12-06 14:05:48 +1100380 return nil
David Symondse37856c2011-06-22 12:52:53 +1000381}
382
David Symonds4c95bfe2011-09-13 14:43:27 +1000383// equivalent to C's isprint.
384func isprint(c byte) bool {
385 return c >= 0x20 && c < 0x7f
386}
387
388// writeString writes a string in the protocol buffer text format.
389// It is similar to strconv.Quote except we don't use Go escape sequences,
390// we treat the string as a byte sequence, and we use octal escapes.
391// These differences are to maintain interoperability with the other
392// languages' implementations of the text format.
David Symonds4dc589e2012-12-06 14:05:48 +1100393func writeString(w *textWriter, s string) error {
394 // use WriteByte here to get any needed indent
395 if err := w.WriteByte('"'); err != nil {
396 return err
397 }
David Symonds4c95bfe2011-09-13 14:43:27 +1000398 // Loop over the bytes, not the runes.
399 for i := 0; i < len(s); i++ {
David Symonds4dc589e2012-12-06 14:05:48 +1100400 var err error
David Symonds4c95bfe2011-09-13 14:43:27 +1000401 // Divergence from C++: we don't escape apostrophes.
402 // There's no need to escape them, and the C++ parser
403 // copes with a naked apostrophe.
404 switch c := s[i]; c {
405 case '\n':
David Symonds4dc589e2012-12-06 14:05:48 +1100406 _, err = w.w.Write(backslashN)
David Symonds4c95bfe2011-09-13 14:43:27 +1000407 case '\r':
David Symonds4dc589e2012-12-06 14:05:48 +1100408 _, err = w.w.Write(backslashR)
David Symonds4c95bfe2011-09-13 14:43:27 +1000409 case '\t':
David Symonds4dc589e2012-12-06 14:05:48 +1100410 _, err = w.w.Write(backslashT)
David Symonds4c95bfe2011-09-13 14:43:27 +1000411 case '"':
David Symonds4dc589e2012-12-06 14:05:48 +1100412 _, err = w.w.Write(backslashDQ)
David Symonds4c95bfe2011-09-13 14:43:27 +1000413 case '\\':
David Symonds4dc589e2012-12-06 14:05:48 +1100414 _, err = w.w.Write(backslashBS)
David Symonds4c95bfe2011-09-13 14:43:27 +1000415 default:
416 if isprint(c) {
David Symonds4dc589e2012-12-06 14:05:48 +1100417 err = w.w.WriteByte(c)
David Symonds4c95bfe2011-09-13 14:43:27 +1000418 } else {
David Symonds4dc589e2012-12-06 14:05:48 +1100419 _, err = fmt.Fprintf(w.w, "\\%03o", c)
David Symonds4c95bfe2011-09-13 14:43:27 +1000420 }
421 }
David Symonds4dc589e2012-12-06 14:05:48 +1100422 if err != nil {
423 return err
424 }
David Symonds4c95bfe2011-09-13 14:43:27 +1000425 }
David Symonds4dc589e2012-12-06 14:05:48 +1100426 return w.WriteByte('"')
David Symonds4c95bfe2011-09-13 14:43:27 +1000427}
428
David Symonds4dc589e2012-12-06 14:05:48 +1100429func writeMessageSet(w *textWriter, ms *MessageSet) error {
David Symonds1d72f7a2011-08-19 18:28:52 +1000430 for _, item := range ms.Item {
431 id := *item.TypeId
432 if msd, ok := messageSetMap[id]; ok {
433 // Known message set type.
David Symonds4dc589e2012-12-06 14:05:48 +1100434 if _, err := fmt.Fprintf(w, "[%s]: <\n", msd.name); err != nil {
435 return err
436 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000437 w.indent()
438
439 pb := reflect.New(msd.t.Elem())
David Symonds9f60f432012-06-14 09:45:25 +1000440 if err := Unmarshal(item.Message, pb.Interface().(Message)); err != nil {
David Symonds4dc589e2012-12-06 14:05:48 +1100441 if _, err := fmt.Fprintf(w, "/* bad message: %v */\n", err); err != nil {
442 return err
443 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000444 } else {
David Symonds4dc589e2012-12-06 14:05:48 +1100445 if err := writeStruct(w, pb.Elem()); err != nil {
446 return err
447 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000448 }
449 } else {
450 // Unknown type.
David Symonds4dc589e2012-12-06 14:05:48 +1100451 if _, err := fmt.Fprintf(w, "[%d]: <\n", id); err != nil {
452 return err
453 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000454 w.indent()
David Symonds4dc589e2012-12-06 14:05:48 +1100455 if err := writeUnknownStruct(w, item.Message); err != nil {
456 return err
457 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000458 }
459 w.unindent()
David Symonds4dc589e2012-12-06 14:05:48 +1100460 if _, err := w.Write(gtNewline); err != nil {
461 return err
462 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000463 }
David Symonds4dc589e2012-12-06 14:05:48 +1100464 return nil
David Symonds1d72f7a2011-08-19 18:28:52 +1000465}
466
David Symonds4dc589e2012-12-06 14:05:48 +1100467func writeUnknownStruct(w *textWriter, data []byte) (err error) {
David Symonds1d72f7a2011-08-19 18:28:52 +1000468 if !w.compact {
David Symonds4dc589e2012-12-06 14:05:48 +1100469 if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil {
470 return err
471 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000472 }
473 b := NewBuffer(data)
474 for b.index < len(b.buf) {
475 x, err := b.DecodeVarint()
476 if err != nil {
David Symonds4dc589e2012-12-06 14:05:48 +1100477 _, err := fmt.Fprintf(w, "/* %v */\n", err)
478 return err
David Symonds1d72f7a2011-08-19 18:28:52 +1000479 }
480 wire, tag := x&7, x>>3
481 if wire == WireEndGroup {
482 w.unindent()
David Symonds4dc589e2012-12-06 14:05:48 +1100483 if _, err := w.Write(endBraceNewline); err != nil {
484 return err
485 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000486 continue
487 }
David Symonds20370902013-03-23 17:20:01 +1100488 if _, err := fmt.Fprint(w, tag); err != nil {
David Symonds4dc589e2012-12-06 14:05:48 +1100489 return err
490 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000491 if wire != WireStartGroup {
David Symonds4dc589e2012-12-06 14:05:48 +1100492 if err := w.WriteByte(':'); err != nil {
493 return err
494 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000495 }
496 if !w.compact || wire == WireStartGroup {
David Symonds4dc589e2012-12-06 14:05:48 +1100497 if err := w.WriteByte(' '); err != nil {
498 return err
499 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000500 }
501 switch wire {
502 case WireBytes:
David Symonds4dc589e2012-12-06 14:05:48 +1100503 buf, e := b.DecodeRawBytes(false)
David Symonds0bf1ad52013-10-11 09:07:50 +1100504 if e == nil {
David Symonds4dc589e2012-12-06 14:05:48 +1100505 _, err = fmt.Fprintf(w, "%q", buf)
David Symonds1d72f7a2011-08-19 18:28:52 +1000506 } else {
David Symonds4dc589e2012-12-06 14:05:48 +1100507 _, err = fmt.Fprintf(w, "/* %v */", e)
David Symonds1d72f7a2011-08-19 18:28:52 +1000508 }
509 case WireFixed32:
David Symonds4dc589e2012-12-06 14:05:48 +1100510 x, err = b.DecodeFixed32()
511 err = writeUnknownInt(w, x, err)
David Symonds1d72f7a2011-08-19 18:28:52 +1000512 case WireFixed64:
David Symonds4dc589e2012-12-06 14:05:48 +1100513 x, err = b.DecodeFixed64()
514 err = writeUnknownInt(w, x, err)
David Symonds1d72f7a2011-08-19 18:28:52 +1000515 case WireStartGroup:
David Symonds4dc589e2012-12-06 14:05:48 +1100516 err = w.WriteByte('{')
David Symonds1d72f7a2011-08-19 18:28:52 +1000517 w.indent()
518 case WireVarint:
David Symonds4dc589e2012-12-06 14:05:48 +1100519 x, err = b.DecodeVarint()
520 err = writeUnknownInt(w, x, err)
David Symonds1d72f7a2011-08-19 18:28:52 +1000521 default:
David Symonds4dc589e2012-12-06 14:05:48 +1100522 _, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire)
David Symonds1d72f7a2011-08-19 18:28:52 +1000523 }
David Symonds4dc589e2012-12-06 14:05:48 +1100524 if err != nil {
525 return err
526 }
527 if err = w.WriteByte('\n'); err != nil {
528 return err
529 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000530 }
David Symonds4dc589e2012-12-06 14:05:48 +1100531 return nil
David Symonds1d72f7a2011-08-19 18:28:52 +1000532}
533
David Symonds4dc589e2012-12-06 14:05:48 +1100534func writeUnknownInt(w *textWriter, x uint64, err error) error {
David Symonds1d72f7a2011-08-19 18:28:52 +1000535 if err == nil {
David Symonds4dc589e2012-12-06 14:05:48 +1100536 _, err = fmt.Fprint(w, x)
David Symonds1d72f7a2011-08-19 18:28:52 +1000537 } else {
David Symonds4dc589e2012-12-06 14:05:48 +1100538 _, err = fmt.Fprintf(w, "/* %v */", err)
David Symonds1d72f7a2011-08-19 18:28:52 +1000539 }
David Symonds4dc589e2012-12-06 14:05:48 +1100540 return err
David Symonds1d72f7a2011-08-19 18:28:52 +1000541}
542
543type int32Slice []int32
544
545func (s int32Slice) Len() int { return len(s) }
546func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] }
547func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
548
David Symondse37856c2011-06-22 12:52:53 +1000549// writeExtensions writes all the extensions in pv.
550// pv is assumed to be a pointer to a protocol message struct that is extendable.
David Symonds4dc589e2012-12-06 14:05:48 +1100551func writeExtensions(w *textWriter, pv reflect.Value) error {
David Symondse37856c2011-06-22 12:52:53 +1000552 emap := extensionMaps[pv.Type().Elem()]
553 ep := pv.Interface().(extendableProto)
David Symonds1d72f7a2011-08-19 18:28:52 +1000554
555 // Order the extensions by ID.
556 // This isn't strictly necessary, but it will give us
557 // canonical output, which will also make testing easier.
558 m := ep.ExtensionMap()
559 ids := make([]int32, 0, len(m))
560 for id := range m {
561 ids = append(ids, id)
562 }
563 sort.Sort(int32Slice(ids))
564
565 for _, extNum := range ids {
566 ext := m[extNum]
David Symondse37856c2011-06-22 12:52:53 +1000567 var desc *ExtensionDesc
568 if emap != nil {
569 desc = emap[extNum]
570 }
571 if desc == nil {
David Symonds1d72f7a2011-08-19 18:28:52 +1000572 // Unknown extension.
David Symonds4dc589e2012-12-06 14:05:48 +1100573 if err := writeUnknownStruct(w, ext.enc); err != nil {
574 return err
575 }
David Symondse37856c2011-06-22 12:52:53 +1000576 continue
577 }
578
579 pb, err := GetExtension(ep, desc)
580 if err != nil {
David Symonds4dc589e2012-12-06 14:05:48 +1100581 if _, err := fmt.Fprintln(os.Stderr, "proto: failed getting extension: ", err); err != nil {
582 return err
583 }
David Symondse37856c2011-06-22 12:52:53 +1000584 continue
585 }
586
David Symonds61826da2012-05-05 09:31:28 +1000587 // Repeated extensions will appear as a slice.
588 if !desc.repeated() {
David Symonds4dc589e2012-12-06 14:05:48 +1100589 if err := writeExtension(w, desc.Name, pb); err != nil {
590 return err
591 }
David Symonds61826da2012-05-05 09:31:28 +1000592 } else {
593 v := reflect.ValueOf(pb)
594 for i := 0; i < v.Len(); i++ {
David Symonds4dc589e2012-12-06 14:05:48 +1100595 if err := writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil {
596 return err
597 }
David Symonds61826da2012-05-05 09:31:28 +1000598 }
David Symondse37856c2011-06-22 12:52:53 +1000599 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700600 }
David Symonds4dc589e2012-12-06 14:05:48 +1100601 return nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700602}
603
David Symonds4dc589e2012-12-06 14:05:48 +1100604func writeExtension(w *textWriter, name string, pb interface{}) error {
605 if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil {
606 return err
David Symonds61826da2012-05-05 09:31:28 +1000607 }
David Symonds4dc589e2012-12-06 14:05:48 +1100608 if !w.compact {
609 if err := w.WriteByte(' '); err != nil {
610 return err
611 }
612 }
613 if err := writeAny(w, reflect.ValueOf(pb), nil); err != nil {
614 return err
615 }
616 if err := w.WriteByte('\n'); err != nil {
617 return err
618 }
619 return nil
David Symonds61826da2012-05-05 09:31:28 +1000620}
621
David Symondsdbdc4212012-11-08 08:20:35 +1100622func (w *textWriter) writeIndent() {
623 if !w.complete {
624 return
625 }
626 remain := w.ind * 2
627 for remain > 0 {
628 n := remain
629 if n > len(spaces) {
630 n = len(spaces)
631 }
David Symonds4dc589e2012-12-06 14:05:48 +1100632 w.w.Write(spaces[:n])
David Symondsdbdc4212012-11-08 08:20:35 +1100633 remain -= n
634 }
635 w.complete = false
636}
637
David Symonds4dc589e2012-12-06 14:05:48 +1100638func marshalText(w io.Writer, pb Message, compact bool) error {
David Symonds6e8ab872013-01-30 17:07:26 +1100639 val := reflect.ValueOf(pb)
640 if pb == nil || val.IsNil() {
David Symonds03c9d412010-08-26 14:23:18 +1000641 w.Write([]byte("<nil>"))
David Symonds4dc589e2012-12-06 14:05:48 +1100642 return nil
David Symonds03c9d412010-08-26 14:23:18 +1000643 }
David Symonds4dc589e2012-12-06 14:05:48 +1100644 var bw *bufio.Writer
645 ww, ok := w.(writer)
646 if !ok {
647 bw = bufio.NewWriter(w)
648 ww = bw
649 }
650 aw := &textWriter{
651 w: ww,
652 complete: true,
653 compact: compact,
David Symondsdbdc4212012-11-08 08:20:35 +1100654 }
655
David Symonds267e8052014-02-19 14:50:51 +1100656 if tm, ok := pb.(textMarshaler); ok {
657 text, err := tm.MarshalText()
658 if err != nil {
659 return err
660 }
661 if _, err = aw.Write(text); err != nil {
662 return err
663 }
664 if bw != nil {
665 return bw.Flush()
666 }
667 return nil
668 }
David Symonds92dd6c12012-03-23 10:59:49 +1100669 // Dereference the received pointer so we don't have outer < and >.
David Symonds6e8ab872013-01-30 17:07:26 +1100670 v := reflect.Indirect(val)
David Symonds4dc589e2012-12-06 14:05:48 +1100671 if err := writeStruct(aw, v); err != nil {
672 return err
673 }
674 if bw != nil {
675 return bw.Flush()
676 }
677 return nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700678}
679
David Symondse37856c2011-06-22 12:52:53 +1000680// MarshalText writes a given protocol buffer in text format.
David Symonds4dc589e2012-12-06 14:05:48 +1100681// The only errors returned are from w.
David Symonds267e8052014-02-19 14:50:51 +1100682func MarshalText(w io.Writer, pb Message) error {
683 return marshalText(w, pb, false)
684}
Rob Pikeaaa3a622010-03-20 22:32:34 -0700685
David Symondsd2bff3c2012-03-14 10:45:25 +1100686// MarshalTextString is the same as MarshalText, but returns the string directly.
David Symonds9f60f432012-06-14 09:45:25 +1000687func MarshalTextString(pb Message) string {
David Symondsd2bff3c2012-03-14 10:45:25 +1100688 var buf bytes.Buffer
689 marshalText(&buf, pb, false)
690 return buf.String()
691}
692
David Symondsd4661c52012-08-30 15:17:53 +1000693// CompactText writes a given protocol buffer in compact text format (one line).
David Symonds4dc589e2012-12-06 14:05:48 +1100694func CompactText(w io.Writer, pb Message) error { return marshalText(w, pb, true) }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700695
696// CompactTextString is the same as CompactText, but returns the string directly.
David Symonds9f60f432012-06-14 09:45:25 +1000697func CompactTextString(pb Message) string {
David Symonds183124e2012-03-23 13:20:23 +1100698 var buf bytes.Buffer
699 marshalText(&buf, pb, true)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700700 return buf.String()
701}