blob: 28a978e1f9e2e75def8f551b3852cd090aa59368 [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"
Rob Pikeaaa3a622010-03-20 22:32:34 -070042 "os"
43 "reflect"
David Symonds1d72f7a2011-08-19 18:28:52 +100044 "sort"
Rob Pikeaaa3a622010-03-20 22:32:34 -070045 "strings"
46)
47
David Symondsdbdc4212012-11-08 08:20:35 +110048var (
49 newline = []byte("\n")
50 spaces = []byte(" ")
51 gtNewline = []byte(">\n")
52 endBraceNewline = []byte("}\n")
53 backslashN = []byte{'\\', 'n'}
54 backslashR = []byte{'\\', 'r'}
55 backslashT = []byte{'\\', 't'}
56 backslashDQ = []byte{'\\', '"'}
57 backslashBS = []byte{'\\', '\\'}
58)
59
David Symonds4dc589e2012-12-06 14:05:48 +110060type writer interface {
61 io.Writer
62 WriteByte(byte) error
63}
64
David Symondse37856c2011-06-22 12:52:53 +100065// textWriter is an io.Writer that tracks its indentation level.
Rob Pikeaaa3a622010-03-20 22:32:34 -070066type textWriter struct {
David Symonds4dc589e2012-12-06 14:05:48 +110067 ind int
68 complete bool // if the current position is a complete line
69 compact bool // whether to write out as a one-liner
70 w writer
David Symondsdbdc4212012-11-08 08:20:35 +110071}
David Symonds9f402812011-04-28 18:08:44 +100072
David Symondsdbdc4212012-11-08 08:20:35 +110073func (w *textWriter) WriteString(s string) (n int, err error) {
74 if !strings.Contains(s, "\n") {
75 if !w.compact && w.complete {
76 w.writeIndent()
77 }
78 w.complete = false
David Symonds4dc589e2012-12-06 14:05:48 +110079 return io.WriteString(w.w, s)
David Symondsdbdc4212012-11-08 08:20:35 +110080 }
81 // WriteString is typically called without newlines, so this
82 // codepath and its copy are rare. We copy to avoid
83 // duplicating all of Write's logic here.
84 return w.Write([]byte(s))
Rob Pikeaaa3a622010-03-20 22:32:34 -070085}
86
Rob Pikea17fdd92011-11-02 12:43:05 -070087func (w *textWriter) Write(p []byte) (n int, err error) {
David Symondsdbdc4212012-11-08 08:20:35 +110088 newlines := bytes.Count(p, newline)
89 if newlines == 0 {
90 if !w.compact && w.complete {
91 w.writeIndent()
92 }
David Symonds4dc589e2012-12-06 14:05:48 +110093 n, err = w.w.Write(p)
David Symondsdbdc4212012-11-08 08:20:35 +110094 w.complete = false
David Symonds4dc589e2012-12-06 14:05:48 +110095 return n, err
David Symondsdbdc4212012-11-08 08:20:35 +110096 }
97
98 frags := bytes.SplitN(p, newline, newlines+1)
Rob Pikeaaa3a622010-03-20 22:32:34 -070099 if w.compact {
David Symondsdbdc4212012-11-08 08:20:35 +1100100 for i, frag := range frags {
101 if i > 0 {
David Symonds4dc589e2012-12-06 14:05:48 +1100102 if err := w.w.WriteByte(' '); err != nil {
103 return n, err
104 }
105 n++
David Symondsdbdc4212012-11-08 08:20:35 +1100106 }
David Symonds4dc589e2012-12-06 14:05:48 +1100107 nn, err := w.w.Write(frag)
108 n += nn
109 if err != nil {
110 return n, err
111 }
David Symondsdbdc4212012-11-08 08:20:35 +1100112 }
David Symonds4dc589e2012-12-06 14:05:48 +1100113 return n, nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700114 }
115
David Symondse37856c2011-06-22 12:52:53 +1000116 for i, frag := range frags {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700117 if w.complete {
David Symondsdbdc4212012-11-08 08:20:35 +1100118 w.writeIndent()
Rob Pikeaaa3a622010-03-20 22:32:34 -0700119 }
David Symonds4dc589e2012-12-06 14:05:48 +1100120 nn, err := w.w.Write(frag)
121 n += nn
122 if err != nil {
123 return n, err
124 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700125 if i+1 < len(frags) {
David Symonds4dc589e2012-12-06 14:05:48 +1100126 if err := w.w.WriteByte('\n'); err != nil {
127 return n, err
128 }
129 n++
Rob Pikeaaa3a622010-03-20 22:32:34 -0700130 }
131 }
132 w.complete = len(frags[len(frags)-1]) == 0
David Symonds4dc589e2012-12-06 14:05:48 +1100133 return n, nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700134}
135
Rob Pikea17fdd92011-11-02 12:43:05 -0700136func (w *textWriter) WriteByte(c byte) error {
David Symondsdbdc4212012-11-08 08:20:35 +1100137 if w.compact && c == '\n' {
138 c = ' '
139 }
140 if !w.compact && w.complete {
141 w.writeIndent()
142 }
David Symonds4dc589e2012-12-06 14:05:48 +1100143 err := w.w.WriteByte(c)
David Symondsdbdc4212012-11-08 08:20:35 +1100144 w.complete = c == '\n'
David Symonds9f402812011-04-28 18:08:44 +1000145 return err
146}
147
David Symondse37856c2011-06-22 12:52:53 +1000148func (w *textWriter) indent() { w.ind++ }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700149
150func (w *textWriter) unindent() {
David Symondse37856c2011-06-22 12:52:53 +1000151 if w.ind == 0 {
David Symondsd4661c52012-08-30 15:17:53 +1000152 log.Printf("proto: textWriter unindented too far")
David Symondse37856c2011-06-22 12:52:53 +1000153 return
Rob Pikeaaa3a622010-03-20 22:32:34 -0700154 }
David Symondse37856c2011-06-22 12:52:53 +1000155 w.ind--
Rob Pikeaaa3a622010-03-20 22:32:34 -0700156}
157
David Symonds4dc589e2012-12-06 14:05:48 +1100158func writeName(w *textWriter, props *Properties) error {
159 if _, err := w.WriteString(props.OrigName); err != nil {
160 return err
David Symonds9f402812011-04-28 18:08:44 +1000161 }
David Symonds4dc589e2012-12-06 14:05:48 +1100162 if props.Wire != "group" {
163 return w.WriteByte(':')
164 }
165 return nil
David Symonds9f402812011-04-28 18:08:44 +1000166}
167
David Symonds1d72f7a2011-08-19 18:28:52 +1000168var (
Russ Coxd4ce3f12012-09-12 10:36:26 +1000169 messageSetType = reflect.TypeOf((*MessageSet)(nil)).Elem()
David Symonds1d72f7a2011-08-19 18:28:52 +1000170)
David Symondse37856c2011-06-22 12:52:53 +1000171
David Symondse9e7aaf2012-03-23 13:12:33 +1100172// raw is the interface satisfied by RawMessage.
173type raw interface {
174 Bytes() []byte
175}
176
David Symonds4dc589e2012-12-06 14:05:48 +1100177func writeStruct(w *textWriter, sv reflect.Value) error {
David Symonds1d72f7a2011-08-19 18:28:52 +1000178 if sv.Type() == messageSetType {
David Symonds4dc589e2012-12-06 14:05:48 +1100179 return writeMessageSet(w, sv.Addr().Interface().(*MessageSet))
David Symonds1d72f7a2011-08-19 18:28:52 +1000180 }
181
Rob Pike97e934d2011-04-11 12:52:49 -0700182 st := sv.Type()
Rob Pikeaaa3a622010-03-20 22:32:34 -0700183 sprops := GetProperties(st)
184 for i := 0; i < sv.NumField(); i++ {
David Symonds1d72f7a2011-08-19 18:28:52 +1000185 fv := sv.Field(i)
David Symonds20370902013-03-23 17:20:01 +1100186 props := sprops.Prop[i]
187 name := st.Field(i).Name
188
189 if strings.HasPrefix(name, "XXX_") {
190 // There are two XXX_ fields:
David Symonds1d72f7a2011-08-19 18:28:52 +1000191 // XXX_unrecognized []byte
192 // XXX_extensions map[int32]proto.Extension
193 // The first is handled here;
194 // the second is handled at the bottom of this function.
195 if name == "XXX_unrecognized" && !fv.IsNil() {
David Symonds4dc589e2012-12-06 14:05:48 +1100196 if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil {
197 return err
198 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000199 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700200 continue
201 }
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700202 if fv.Kind() == reflect.Ptr && fv.IsNil() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700203 // Field not filled in. This could be an optional field or
204 // a required field that wasn't filled in. Either way, there
205 // isn't anything we can show for it.
206 continue
207 }
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700208 if fv.Kind() == reflect.Slice && fv.IsNil() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700209 // Repeated field that is empty, or a bytes field that is unused.
210 continue
211 }
212
David Symondsaa922ff2011-07-19 14:58:06 +1000213 if props.Repeated && fv.Kind() == reflect.Slice {
214 // Repeated field.
215 for j := 0; j < fv.Len(); j++ {
David Symonds4dc589e2012-12-06 14:05:48 +1100216 if err := writeName(w, props); err != nil {
217 return err
Rob Pikeaaa3a622010-03-20 22:32:34 -0700218 }
David Symonds4dc589e2012-12-06 14:05:48 +1100219 if !w.compact {
220 if err := w.WriteByte(' '); err != nil {
221 return err
222 }
223 }
224 if err := writeAny(w, fv.Index(j), props); err != nil {
225 return err
226 }
227 if err := w.WriteByte('\n'); err != nil {
228 return err
229 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700230 }
David Symondsaa922ff2011-07-19 14:58:06 +1000231 continue
Rob Pikeaaa3a622010-03-20 22:32:34 -0700232 }
233
David Symonds4dc589e2012-12-06 14:05:48 +1100234 if err := writeName(w, props); err != nil {
235 return err
236 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700237 if !w.compact {
David Symonds4dc589e2012-12-06 14:05:48 +1100238 if err := w.WriteByte(' '); err != nil {
239 return err
240 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700241 }
David Symondse9e7aaf2012-03-23 13:12:33 +1100242 if b, ok := fv.Interface().(raw); ok {
David Symonds4dc589e2012-12-06 14:05:48 +1100243 if err := writeRaw(w, b.Bytes()); err != nil {
244 return err
245 }
David Symondse9e7aaf2012-03-23 13:12:33 +1100246 continue
247 }
David Symonds4dc589e2012-12-06 14:05:48 +1100248
249 var written bool
250 var err error
251 if props.Enum != "" {
252 written, err = tryWriteEnum(w, props.Enum, fv)
253 if err != nil {
254 return err
255 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700256 }
David Symonds4dc589e2012-12-06 14:05:48 +1100257 if !written {
258 if err := writeAny(w, fv, props); err != nil {
259 return err
260 }
261 }
262
263 if err := w.WriteByte('\n'); err != nil {
264 return err
265 }
David Symondse37856c2011-06-22 12:52:53 +1000266 }
267
David Symonds1d72f7a2011-08-19 18:28:52 +1000268 // Extensions (the XXX_extensions field).
David Symondse37856c2011-06-22 12:52:53 +1000269 pv := sv.Addr()
270 if pv.Type().Implements(extendableProtoType) {
David Symonds4dc589e2012-12-06 14:05:48 +1100271 if err := writeExtensions(w, pv); err != nil {
272 return err
273 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700274 }
David Symonds4dc589e2012-12-06 14:05:48 +1100275
276 return nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700277}
278
David Symondse9e7aaf2012-03-23 13:12:33 +1100279// writeRaw writes an uninterpreted raw message.
David Symonds4dc589e2012-12-06 14:05:48 +1100280func writeRaw(w *textWriter, b []byte) error {
281 if err := w.WriteByte('<'); err != nil {
282 return err
283 }
David Symondse9e7aaf2012-03-23 13:12:33 +1100284 if !w.compact {
David Symonds4dc589e2012-12-06 14:05:48 +1100285 if err := w.WriteByte('\n'); err != nil {
286 return err
287 }
David Symondse9e7aaf2012-03-23 13:12:33 +1100288 }
289 w.indent()
David Symonds4dc589e2012-12-06 14:05:48 +1100290 if err := writeUnknownStruct(w, b); err != nil {
291 return err
292 }
David Symondse9e7aaf2012-03-23 13:12:33 +1100293 w.unindent()
David Symonds4dc589e2012-12-06 14:05:48 +1100294 if err := w.WriteByte('>'); err != nil {
295 return err
296 }
297 return nil
David Symondse9e7aaf2012-03-23 13:12:33 +1100298}
299
David Symondse37856c2011-06-22 12:52:53 +1000300// tryWriteEnum attempts to write an enum value as a symbolic constant.
301// If the enum is unregistered, nothing is written and false is returned.
David Symonds4dc589e2012-12-06 14:05:48 +1100302func tryWriteEnum(w *textWriter, enum string, v reflect.Value) (bool, error) {
Rob Pikeab5b8022010-06-21 17:47:58 -0700303 v = reflect.Indirect(v)
304 if v.Type().Kind() != reflect.Int32 {
David Symonds4dc589e2012-12-06 14:05:48 +1100305 return false, nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700306 }
307 m, ok := enumNameMaps[enum]
308 if !ok {
David Symonds4dc589e2012-12-06 14:05:48 +1100309 return false, nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700310 }
Rob Pike97e934d2011-04-11 12:52:49 -0700311 str, ok := m[int32(v.Int())]
Rob Pikeaaa3a622010-03-20 22:32:34 -0700312 if !ok {
David Symonds4dc589e2012-12-06 14:05:48 +1100313 return false, nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700314 }
David Symonds4dc589e2012-12-06 14:05:48 +1100315 _, err := fmt.Fprintf(w, str)
316 return true, err
Rob Pikeaaa3a622010-03-20 22:32:34 -0700317}
318
David Symondse37856c2011-06-22 12:52:53 +1000319// writeAny writes an arbitrary field.
David Symonds4dc589e2012-12-06 14:05:48 +1100320func writeAny(w *textWriter, v reflect.Value, props *Properties) error {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700321 v = reflect.Indirect(v)
322
323 // We don't attempt to serialise every possible value type; only those
324 // that can occur in protocol buffers, plus a few extra that were easy.
David Symondse37856c2011-06-22 12:52:53 +1000325 switch v.Kind() {
Rob Pike97e934d2011-04-11 12:52:49 -0700326 case reflect.Slice:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700327 // Should only be a []byte; repeated fields are handled in writeStruct.
David Symonds4dc589e2012-12-06 14:05:48 +1100328 if err := writeString(w, string(v.Interface().([]byte))); err != nil {
329 return err
330 }
Rob Pike97e934d2011-04-11 12:52:49 -0700331 case reflect.String:
David Symonds4dc589e2012-12-06 14:05:48 +1100332 if err := writeString(w, v.String()); err != nil {
333 return err
334 }
Rob Pike97e934d2011-04-11 12:52:49 -0700335 case reflect.Struct:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700336 // Required/optional group/message.
David Symonds9f402812011-04-28 18:08:44 +1000337 var bra, ket byte = '<', '>'
338 if props != nil && props.Wire == "group" {
339 bra, ket = '{', '}'
340 }
David Symonds4dc589e2012-12-06 14:05:48 +1100341 if err := w.WriteByte(bra); err != nil {
342 return err
343 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700344 if !w.compact {
David Symonds4dc589e2012-12-06 14:05:48 +1100345 if err := w.WriteByte('\n'); err != nil {
346 return err
347 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700348 }
349 w.indent()
David Symonds4dc589e2012-12-06 14:05:48 +1100350 if err := writeStruct(w, v); err != nil {
351 return err
352 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700353 w.unindent()
David Symonds4dc589e2012-12-06 14:05:48 +1100354 if err := w.WriteByte(ket); err != nil {
355 return err
356 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700357 default:
David Symonds4dc589e2012-12-06 14:05:48 +1100358 _, err := fmt.Fprint(w, v.Interface())
359 return err
David Symondse37856c2011-06-22 12:52:53 +1000360 }
David Symonds4dc589e2012-12-06 14:05:48 +1100361 return nil
David Symondse37856c2011-06-22 12:52:53 +1000362}
363
David Symonds4c95bfe2011-09-13 14:43:27 +1000364// equivalent to C's isprint.
365func isprint(c byte) bool {
366 return c >= 0x20 && c < 0x7f
367}
368
369// writeString writes a string in the protocol buffer text format.
370// It is similar to strconv.Quote except we don't use Go escape sequences,
371// we treat the string as a byte sequence, and we use octal escapes.
372// These differences are to maintain interoperability with the other
373// languages' implementations of the text format.
David Symonds4dc589e2012-12-06 14:05:48 +1100374func writeString(w *textWriter, s string) error {
375 // use WriteByte here to get any needed indent
376 if err := w.WriteByte('"'); err != nil {
377 return err
378 }
David Symonds4c95bfe2011-09-13 14:43:27 +1000379 // Loop over the bytes, not the runes.
380 for i := 0; i < len(s); i++ {
David Symonds4dc589e2012-12-06 14:05:48 +1100381 var err error
David Symonds4c95bfe2011-09-13 14:43:27 +1000382 // Divergence from C++: we don't escape apostrophes.
383 // There's no need to escape them, and the C++ parser
384 // copes with a naked apostrophe.
385 switch c := s[i]; c {
386 case '\n':
David Symonds4dc589e2012-12-06 14:05:48 +1100387 _, err = w.w.Write(backslashN)
David Symonds4c95bfe2011-09-13 14:43:27 +1000388 case '\r':
David Symonds4dc589e2012-12-06 14:05:48 +1100389 _, err = w.w.Write(backslashR)
David Symonds4c95bfe2011-09-13 14:43:27 +1000390 case '\t':
David Symonds4dc589e2012-12-06 14:05:48 +1100391 _, err = w.w.Write(backslashT)
David Symonds4c95bfe2011-09-13 14:43:27 +1000392 case '"':
David Symonds4dc589e2012-12-06 14:05:48 +1100393 _, err = w.w.Write(backslashDQ)
David Symonds4c95bfe2011-09-13 14:43:27 +1000394 case '\\':
David Symonds4dc589e2012-12-06 14:05:48 +1100395 _, err = w.w.Write(backslashBS)
David Symonds4c95bfe2011-09-13 14:43:27 +1000396 default:
397 if isprint(c) {
David Symonds4dc589e2012-12-06 14:05:48 +1100398 err = w.w.WriteByte(c)
David Symonds4c95bfe2011-09-13 14:43:27 +1000399 } else {
David Symonds4dc589e2012-12-06 14:05:48 +1100400 _, err = fmt.Fprintf(w.w, "\\%03o", c)
David Symonds4c95bfe2011-09-13 14:43:27 +1000401 }
402 }
David Symonds4dc589e2012-12-06 14:05:48 +1100403 if err != nil {
404 return err
405 }
David Symonds4c95bfe2011-09-13 14:43:27 +1000406 }
David Symonds4dc589e2012-12-06 14:05:48 +1100407 return w.WriteByte('"')
David Symonds4c95bfe2011-09-13 14:43:27 +1000408}
409
David Symonds4dc589e2012-12-06 14:05:48 +1100410func writeMessageSet(w *textWriter, ms *MessageSet) error {
David Symonds1d72f7a2011-08-19 18:28:52 +1000411 for _, item := range ms.Item {
412 id := *item.TypeId
413 if msd, ok := messageSetMap[id]; ok {
414 // Known message set type.
David Symonds4dc589e2012-12-06 14:05:48 +1100415 if _, err := fmt.Fprintf(w, "[%s]: <\n", msd.name); err != nil {
416 return err
417 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000418 w.indent()
419
420 pb := reflect.New(msd.t.Elem())
David Symonds9f60f432012-06-14 09:45:25 +1000421 if err := Unmarshal(item.Message, pb.Interface().(Message)); err != nil {
David Symonds4dc589e2012-12-06 14:05:48 +1100422 if _, err := fmt.Fprintf(w, "/* bad message: %v */\n", err); err != nil {
423 return err
424 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000425 } else {
David Symonds4dc589e2012-12-06 14:05:48 +1100426 if err := writeStruct(w, pb.Elem()); err != nil {
427 return err
428 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000429 }
430 } else {
431 // Unknown type.
David Symonds4dc589e2012-12-06 14:05:48 +1100432 if _, err := fmt.Fprintf(w, "[%d]: <\n", id); err != nil {
433 return err
434 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000435 w.indent()
David Symonds4dc589e2012-12-06 14:05:48 +1100436 if err := writeUnknownStruct(w, item.Message); err != nil {
437 return err
438 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000439 }
440 w.unindent()
David Symonds4dc589e2012-12-06 14:05:48 +1100441 if _, err := w.Write(gtNewline); err != nil {
442 return err
443 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000444 }
David Symonds4dc589e2012-12-06 14:05:48 +1100445 return nil
David Symonds1d72f7a2011-08-19 18:28:52 +1000446}
447
David Symonds4dc589e2012-12-06 14:05:48 +1100448func writeUnknownStruct(w *textWriter, data []byte) (err error) {
David Symonds1d72f7a2011-08-19 18:28:52 +1000449 if !w.compact {
David Symonds4dc589e2012-12-06 14:05:48 +1100450 if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil {
451 return err
452 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000453 }
454 b := NewBuffer(data)
455 for b.index < len(b.buf) {
456 x, err := b.DecodeVarint()
457 if err != nil {
David Symonds4dc589e2012-12-06 14:05:48 +1100458 _, err := fmt.Fprintf(w, "/* %v */\n", err)
459 return err
David Symonds1d72f7a2011-08-19 18:28:52 +1000460 }
461 wire, tag := x&7, x>>3
462 if wire == WireEndGroup {
463 w.unindent()
David Symonds4dc589e2012-12-06 14:05:48 +1100464 if _, err := w.Write(endBraceNewline); err != nil {
465 return err
466 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000467 continue
468 }
David Symonds20370902013-03-23 17:20:01 +1100469 if _, err := fmt.Fprint(w, tag); err != nil {
David Symonds4dc589e2012-12-06 14:05:48 +1100470 return err
471 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000472 if wire != WireStartGroup {
David Symonds4dc589e2012-12-06 14:05:48 +1100473 if err := w.WriteByte(':'); err != nil {
474 return err
475 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000476 }
477 if !w.compact || wire == WireStartGroup {
David Symonds4dc589e2012-12-06 14:05:48 +1100478 if err := w.WriteByte(' '); err != nil {
479 return err
480 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000481 }
482 switch wire {
483 case WireBytes:
David Symonds4dc589e2012-12-06 14:05:48 +1100484 buf, e := b.DecodeRawBytes(false)
David Symonds1d72f7a2011-08-19 18:28:52 +1000485 if err == nil {
David Symonds4dc589e2012-12-06 14:05:48 +1100486 _, err = fmt.Fprintf(w, "%q", buf)
David Symonds1d72f7a2011-08-19 18:28:52 +1000487 } else {
David Symonds4dc589e2012-12-06 14:05:48 +1100488 _, err = fmt.Fprintf(w, "/* %v */", e)
David Symonds1d72f7a2011-08-19 18:28:52 +1000489 }
490 case WireFixed32:
David Symonds4dc589e2012-12-06 14:05:48 +1100491 x, err = b.DecodeFixed32()
492 err = writeUnknownInt(w, x, err)
David Symonds1d72f7a2011-08-19 18:28:52 +1000493 case WireFixed64:
David Symonds4dc589e2012-12-06 14:05:48 +1100494 x, err = b.DecodeFixed64()
495 err = writeUnknownInt(w, x, err)
David Symonds1d72f7a2011-08-19 18:28:52 +1000496 case WireStartGroup:
David Symonds4dc589e2012-12-06 14:05:48 +1100497 err = w.WriteByte('{')
David Symonds1d72f7a2011-08-19 18:28:52 +1000498 w.indent()
499 case WireVarint:
David Symonds4dc589e2012-12-06 14:05:48 +1100500 x, err = b.DecodeVarint()
501 err = writeUnknownInt(w, x, err)
David Symonds1d72f7a2011-08-19 18:28:52 +1000502 default:
David Symonds4dc589e2012-12-06 14:05:48 +1100503 _, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire)
David Symonds1d72f7a2011-08-19 18:28:52 +1000504 }
David Symonds4dc589e2012-12-06 14:05:48 +1100505 if err != nil {
506 return err
507 }
508 if err = w.WriteByte('\n'); err != nil {
509 return err
510 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000511 }
David Symonds4dc589e2012-12-06 14:05:48 +1100512 return nil
David Symonds1d72f7a2011-08-19 18:28:52 +1000513}
514
David Symonds4dc589e2012-12-06 14:05:48 +1100515func writeUnknownInt(w *textWriter, x uint64, err error) error {
David Symonds1d72f7a2011-08-19 18:28:52 +1000516 if err == nil {
David Symonds4dc589e2012-12-06 14:05:48 +1100517 _, err = fmt.Fprint(w, x)
David Symonds1d72f7a2011-08-19 18:28:52 +1000518 } else {
David Symonds4dc589e2012-12-06 14:05:48 +1100519 _, err = fmt.Fprintf(w, "/* %v */", err)
David Symonds1d72f7a2011-08-19 18:28:52 +1000520 }
David Symonds4dc589e2012-12-06 14:05:48 +1100521 return err
David Symonds1d72f7a2011-08-19 18:28:52 +1000522}
523
524type int32Slice []int32
525
526func (s int32Slice) Len() int { return len(s) }
527func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] }
528func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
529
David Symondse37856c2011-06-22 12:52:53 +1000530// writeExtensions writes all the extensions in pv.
531// pv is assumed to be a pointer to a protocol message struct that is extendable.
David Symonds4dc589e2012-12-06 14:05:48 +1100532func writeExtensions(w *textWriter, pv reflect.Value) error {
David Symondse37856c2011-06-22 12:52:53 +1000533 emap := extensionMaps[pv.Type().Elem()]
534 ep := pv.Interface().(extendableProto)
David Symonds1d72f7a2011-08-19 18:28:52 +1000535
536 // Order the extensions by ID.
537 // This isn't strictly necessary, but it will give us
538 // canonical output, which will also make testing easier.
539 m := ep.ExtensionMap()
540 ids := make([]int32, 0, len(m))
541 for id := range m {
542 ids = append(ids, id)
543 }
544 sort.Sort(int32Slice(ids))
545
546 for _, extNum := range ids {
547 ext := m[extNum]
David Symondse37856c2011-06-22 12:52:53 +1000548 var desc *ExtensionDesc
549 if emap != nil {
550 desc = emap[extNum]
551 }
552 if desc == nil {
David Symonds1d72f7a2011-08-19 18:28:52 +1000553 // Unknown extension.
David Symonds4dc589e2012-12-06 14:05:48 +1100554 if err := writeUnknownStruct(w, ext.enc); err != nil {
555 return err
556 }
David Symondse37856c2011-06-22 12:52:53 +1000557 continue
558 }
559
560 pb, err := GetExtension(ep, desc)
561 if err != nil {
David Symonds4dc589e2012-12-06 14:05:48 +1100562 if _, err := fmt.Fprintln(os.Stderr, "proto: failed getting extension: ", err); err != nil {
563 return err
564 }
David Symondse37856c2011-06-22 12:52:53 +1000565 continue
566 }
567
David Symonds61826da2012-05-05 09:31:28 +1000568 // Repeated extensions will appear as a slice.
569 if !desc.repeated() {
David Symonds4dc589e2012-12-06 14:05:48 +1100570 if err := writeExtension(w, desc.Name, pb); err != nil {
571 return err
572 }
David Symonds61826da2012-05-05 09:31:28 +1000573 } else {
574 v := reflect.ValueOf(pb)
575 for i := 0; i < v.Len(); i++ {
David Symonds4dc589e2012-12-06 14:05:48 +1100576 if err := writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil {
577 return err
578 }
David Symonds61826da2012-05-05 09:31:28 +1000579 }
David Symondse37856c2011-06-22 12:52:53 +1000580 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700581 }
David Symonds4dc589e2012-12-06 14:05:48 +1100582 return nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700583}
584
David Symonds4dc589e2012-12-06 14:05:48 +1100585func writeExtension(w *textWriter, name string, pb interface{}) error {
586 if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil {
587 return err
David Symonds61826da2012-05-05 09:31:28 +1000588 }
David Symonds4dc589e2012-12-06 14:05:48 +1100589 if !w.compact {
590 if err := w.WriteByte(' '); err != nil {
591 return err
592 }
593 }
594 if err := writeAny(w, reflect.ValueOf(pb), nil); err != nil {
595 return err
596 }
597 if err := w.WriteByte('\n'); err != nil {
598 return err
599 }
600 return nil
David Symonds61826da2012-05-05 09:31:28 +1000601}
602
David Symondsdbdc4212012-11-08 08:20:35 +1100603func (w *textWriter) writeIndent() {
604 if !w.complete {
605 return
606 }
607 remain := w.ind * 2
608 for remain > 0 {
609 n := remain
610 if n > len(spaces) {
611 n = len(spaces)
612 }
David Symonds4dc589e2012-12-06 14:05:48 +1100613 w.w.Write(spaces[:n])
David Symondsdbdc4212012-11-08 08:20:35 +1100614 remain -= n
615 }
616 w.complete = false
617}
618
David Symonds4dc589e2012-12-06 14:05:48 +1100619func marshalText(w io.Writer, pb Message, compact bool) error {
David Symonds6e8ab872013-01-30 17:07:26 +1100620 val := reflect.ValueOf(pb)
621 if pb == nil || val.IsNil() {
David Symonds03c9d412010-08-26 14:23:18 +1000622 w.Write([]byte("<nil>"))
David Symonds4dc589e2012-12-06 14:05:48 +1100623 return nil
David Symonds03c9d412010-08-26 14:23:18 +1000624 }
David Symonds4dc589e2012-12-06 14:05:48 +1100625 var bw *bufio.Writer
626 ww, ok := w.(writer)
627 if !ok {
628 bw = bufio.NewWriter(w)
629 ww = bw
630 }
631 aw := &textWriter{
632 w: ww,
633 complete: true,
634 compact: compact,
David Symondsdbdc4212012-11-08 08:20:35 +1100635 }
636
David Symonds92dd6c12012-03-23 10:59:49 +1100637 // Dereference the received pointer so we don't have outer < and >.
David Symonds6e8ab872013-01-30 17:07:26 +1100638 v := reflect.Indirect(val)
David Symonds4dc589e2012-12-06 14:05:48 +1100639 if err := writeStruct(aw, v); err != nil {
640 return err
641 }
642 if bw != nil {
643 return bw.Flush()
644 }
645 return nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700646}
647
David Symondse37856c2011-06-22 12:52:53 +1000648// MarshalText writes a given protocol buffer in text format.
David Symonds4dc589e2012-12-06 14:05:48 +1100649// The only errors returned are from w.
650func MarshalText(w io.Writer, pb Message) error { return marshalText(w, pb, false) }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700651
David Symondsd2bff3c2012-03-14 10:45:25 +1100652// MarshalTextString is the same as MarshalText, but returns the string directly.
David Symonds9f60f432012-06-14 09:45:25 +1000653func MarshalTextString(pb Message) string {
David Symondsd2bff3c2012-03-14 10:45:25 +1100654 var buf bytes.Buffer
655 marshalText(&buf, pb, false)
656 return buf.String()
657}
658
David Symondsd4661c52012-08-30 15:17:53 +1000659// CompactText writes a given protocol buffer in compact text format (one line).
David Symonds4dc589e2012-12-06 14:05:48 +1100660func CompactText(w io.Writer, pb Message) error { return marshalText(w, pb, true) }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700661
662// CompactTextString is the same as CompactText, but returns the string directly.
David Symonds9f60f432012-06-14 09:45:25 +1000663func CompactTextString(pb Message) string {
David Symonds183124e2012-03-23 13:20:23 +1100664 var buf bytes.Buffer
665 marshalText(&buf, pb, true)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700666 return buf.String()
667}