blob: ff8a0bb1e8ccaa306829e177fbf95f91d7fb8977 [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 Symondsdbdc4212012-11-08 08:20:35 +110077func (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
David Symonds4dc589e2012-12-06 14:05:48 +110083 return io.WriteString(w.w, s)
David Symondsdbdc4212012-11-08 08:20:35 +110084 }
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))
Rob Pikeaaa3a622010-03-20 22:32:34 -070089}
90
Rob Pikea17fdd92011-11-02 12:43:05 -070091func (w *textWriter) Write(p []byte) (n int, err error) {
David Symondsdbdc4212012-11-08 08:20:35 +110092 newlines := bytes.Count(p, newline)
93 if newlines == 0 {
94 if !w.compact && w.complete {
95 w.writeIndent()
96 }
David Symonds4dc589e2012-12-06 14:05:48 +110097 n, err = w.w.Write(p)
David Symondsdbdc4212012-11-08 08:20:35 +110098 w.complete = false
David Symonds4dc589e2012-12-06 14:05:48 +110099 return n, err
David Symondsdbdc4212012-11-08 08:20:35 +1100100 }
101
102 frags := bytes.SplitN(p, newline, newlines+1)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700103 if w.compact {
David Symondsdbdc4212012-11-08 08:20:35 +1100104 for i, frag := range frags {
105 if i > 0 {
David Symonds4dc589e2012-12-06 14:05:48 +1100106 if err := w.w.WriteByte(' '); err != nil {
107 return n, err
108 }
109 n++
David Symondsdbdc4212012-11-08 08:20:35 +1100110 }
David Symonds4dc589e2012-12-06 14:05:48 +1100111 nn, err := w.w.Write(frag)
112 n += nn
113 if err != nil {
114 return n, err
115 }
David Symondsdbdc4212012-11-08 08:20:35 +1100116 }
David Symonds4dc589e2012-12-06 14:05:48 +1100117 return n, nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700118 }
119
David Symondse37856c2011-06-22 12:52:53 +1000120 for i, frag := range frags {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700121 if w.complete {
David Symondsdbdc4212012-11-08 08:20:35 +1100122 w.writeIndent()
Rob Pikeaaa3a622010-03-20 22:32:34 -0700123 }
David Symonds4dc589e2012-12-06 14:05:48 +1100124 nn, err := w.w.Write(frag)
125 n += nn
126 if err != nil {
127 return n, err
128 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700129 if i+1 < len(frags) {
David Symonds4dc589e2012-12-06 14:05:48 +1100130 if err := w.w.WriteByte('\n'); err != nil {
131 return n, err
132 }
133 n++
Rob Pikeaaa3a622010-03-20 22:32:34 -0700134 }
135 }
136 w.complete = len(frags[len(frags)-1]) == 0
David Symonds4dc589e2012-12-06 14:05:48 +1100137 return n, nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700138}
139
Rob Pikea17fdd92011-11-02 12:43:05 -0700140func (w *textWriter) WriteByte(c byte) error {
David Symondsdbdc4212012-11-08 08:20:35 +1100141 if w.compact && c == '\n' {
142 c = ' '
143 }
144 if !w.compact && w.complete {
145 w.writeIndent()
146 }
David Symonds4dc589e2012-12-06 14:05:48 +1100147 err := w.w.WriteByte(c)
David Symondsdbdc4212012-11-08 08:20:35 +1100148 w.complete = c == '\n'
David Symonds9f402812011-04-28 18:08:44 +1000149 return err
150}
151
David Symondse37856c2011-06-22 12:52:53 +1000152func (w *textWriter) indent() { w.ind++ }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700153
154func (w *textWriter) unindent() {
David Symondse37856c2011-06-22 12:52:53 +1000155 if w.ind == 0 {
David Symondsd4661c52012-08-30 15:17:53 +1000156 log.Printf("proto: textWriter unindented too far")
David Symondse37856c2011-06-22 12:52:53 +1000157 return
Rob Pikeaaa3a622010-03-20 22:32:34 -0700158 }
David Symondse37856c2011-06-22 12:52:53 +1000159 w.ind--
Rob Pikeaaa3a622010-03-20 22:32:34 -0700160}
161
David Symonds4dc589e2012-12-06 14:05:48 +1100162func writeName(w *textWriter, props *Properties) error {
163 if _, err := w.WriteString(props.OrigName); err != nil {
164 return err
David Symonds9f402812011-04-28 18:08:44 +1000165 }
David Symonds4dc589e2012-12-06 14:05:48 +1100166 if props.Wire != "group" {
167 return w.WriteByte(':')
168 }
169 return nil
David Symonds9f402812011-04-28 18:08:44 +1000170}
171
David Symonds1d72f7a2011-08-19 18:28:52 +1000172var (
Russ Coxd4ce3f12012-09-12 10:36:26 +1000173 messageSetType = reflect.TypeOf((*MessageSet)(nil)).Elem()
David Symonds1d72f7a2011-08-19 18:28:52 +1000174)
David Symondse37856c2011-06-22 12:52:53 +1000175
David Symondse9e7aaf2012-03-23 13:12:33 +1100176// raw is the interface satisfied by RawMessage.
177type raw interface {
178 Bytes() []byte
179}
180
David Symonds4dc589e2012-12-06 14:05:48 +1100181func writeStruct(w *textWriter, sv reflect.Value) error {
David Symonds1d72f7a2011-08-19 18:28:52 +1000182 if sv.Type() == messageSetType {
David Symonds4dc589e2012-12-06 14:05:48 +1100183 return writeMessageSet(w, sv.Addr().Interface().(*MessageSet))
David Symonds1d72f7a2011-08-19 18:28:52 +1000184 }
185
Rob Pike97e934d2011-04-11 12:52:49 -0700186 st := sv.Type()
Rob Pikeaaa3a622010-03-20 22:32:34 -0700187 sprops := GetProperties(st)
188 for i := 0; i < sv.NumField(); i++ {
David Symonds1d72f7a2011-08-19 18:28:52 +1000189 fv := sv.Field(i)
David Symonds20370902013-03-23 17:20:01 +1100190 props := sprops.Prop[i]
191 name := st.Field(i).Name
192
193 if strings.HasPrefix(name, "XXX_") {
194 // There are two XXX_ fields:
David Symonds1d72f7a2011-08-19 18:28:52 +1000195 // XXX_unrecognized []byte
196 // XXX_extensions map[int32]proto.Extension
197 // The first is handled here;
198 // the second is handled at the bottom of this function.
199 if name == "XXX_unrecognized" && !fv.IsNil() {
David Symonds4dc589e2012-12-06 14:05:48 +1100200 if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil {
201 return err
202 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000203 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700204 continue
205 }
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700206 if fv.Kind() == reflect.Ptr && fv.IsNil() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700207 // Field not filled in. This could be an optional field or
208 // a required field that wasn't filled in. Either way, there
209 // isn't anything we can show for it.
210 continue
211 }
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700212 if fv.Kind() == reflect.Slice && fv.IsNil() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700213 // Repeated field that is empty, or a bytes field that is unused.
214 continue
215 }
216
David Symondsaa922ff2011-07-19 14:58:06 +1000217 if props.Repeated && fv.Kind() == reflect.Slice {
218 // Repeated field.
219 for j := 0; j < fv.Len(); j++ {
David Symonds4dc589e2012-12-06 14:05:48 +1100220 if err := writeName(w, props); err != nil {
221 return err
Rob Pikeaaa3a622010-03-20 22:32:34 -0700222 }
David Symonds4dc589e2012-12-06 14:05:48 +1100223 if !w.compact {
224 if err := w.WriteByte(' '); err != nil {
225 return err
226 }
227 }
228 if err := writeAny(w, fv.Index(j), props); err != nil {
229 return err
230 }
231 if err := w.WriteByte('\n'); err != nil {
232 return err
233 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700234 }
David Symondsaa922ff2011-07-19 14:58:06 +1000235 continue
Rob Pikeaaa3a622010-03-20 22:32:34 -0700236 }
237
David Symonds4dc589e2012-12-06 14:05:48 +1100238 if err := writeName(w, props); err != nil {
239 return err
240 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700241 if !w.compact {
David Symonds4dc589e2012-12-06 14:05:48 +1100242 if err := w.WriteByte(' '); err != nil {
243 return err
244 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700245 }
David Symondse9e7aaf2012-03-23 13:12:33 +1100246 if b, ok := fv.Interface().(raw); ok {
David Symonds4dc589e2012-12-06 14:05:48 +1100247 if err := writeRaw(w, b.Bytes()); err != nil {
248 return err
249 }
David Symondse9e7aaf2012-03-23 13:12:33 +1100250 continue
251 }
David Symonds4dc589e2012-12-06 14:05:48 +1100252
David Symondsf8a1fcc2013-05-03 08:51:23 +1000253 // Enums have a String method, so writeAny will work fine.
254 if err := writeAny(w, fv, props); err != nil {
255 return err
David Symonds4dc589e2012-12-06 14:05:48 +1100256 }
257
258 if err := w.WriteByte('\n'); err != nil {
259 return err
260 }
David Symondse37856c2011-06-22 12:52:53 +1000261 }
262
David Symonds1d72f7a2011-08-19 18:28:52 +1000263 // Extensions (the XXX_extensions field).
David Symondse37856c2011-06-22 12:52:53 +1000264 pv := sv.Addr()
265 if pv.Type().Implements(extendableProtoType) {
David Symonds4dc589e2012-12-06 14:05:48 +1100266 if err := writeExtensions(w, pv); err != nil {
267 return err
268 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700269 }
David Symonds4dc589e2012-12-06 14:05:48 +1100270
271 return nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700272}
273
David Symondse9e7aaf2012-03-23 13:12:33 +1100274// writeRaw writes an uninterpreted raw message.
David Symonds4dc589e2012-12-06 14:05:48 +1100275func writeRaw(w *textWriter, b []byte) error {
276 if err := w.WriteByte('<'); err != nil {
277 return err
278 }
David Symondse9e7aaf2012-03-23 13:12:33 +1100279 if !w.compact {
David Symonds4dc589e2012-12-06 14:05:48 +1100280 if err := w.WriteByte('\n'); err != nil {
281 return err
282 }
David Symondse9e7aaf2012-03-23 13:12:33 +1100283 }
284 w.indent()
David Symonds4dc589e2012-12-06 14:05:48 +1100285 if err := writeUnknownStruct(w, b); err != nil {
286 return err
287 }
David Symondse9e7aaf2012-03-23 13:12:33 +1100288 w.unindent()
David Symonds4dc589e2012-12-06 14:05:48 +1100289 if err := w.WriteByte('>'); err != nil {
290 return err
291 }
292 return nil
David Symondse9e7aaf2012-03-23 13:12:33 +1100293}
294
David Symondse37856c2011-06-22 12:52:53 +1000295// writeAny writes an arbitrary field.
David Symonds4dc589e2012-12-06 14:05:48 +1100296func writeAny(w *textWriter, v reflect.Value, props *Properties) error {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700297 v = reflect.Indirect(v)
298
David Symonds9cc87e32013-06-08 12:27:15 +1000299 // Floats have special cases.
300 if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 {
301 x := v.Float()
302 var b []byte
303 switch {
304 case math.IsInf(x, 1):
305 b = posInf
306 case math.IsInf(x, -1):
307 b = negInf
308 case math.IsNaN(x):
309 b = nan
310 }
311 if b != nil {
312 _, err := w.Write(b)
313 return err
314 }
315 // Other values are handled below.
316 }
317
Rob Pikeaaa3a622010-03-20 22:32:34 -0700318 // We don't attempt to serialise every possible value type; only those
David Symonds9cc87e32013-06-08 12:27:15 +1000319 // that can occur in protocol buffers.
David Symondse37856c2011-06-22 12:52:53 +1000320 switch v.Kind() {
Rob Pike97e934d2011-04-11 12:52:49 -0700321 case reflect.Slice:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700322 // Should only be a []byte; repeated fields are handled in writeStruct.
David Symonds4dc589e2012-12-06 14:05:48 +1100323 if err := writeString(w, string(v.Interface().([]byte))); err != nil {
324 return err
325 }
Rob Pike97e934d2011-04-11 12:52:49 -0700326 case reflect.String:
David Symonds4dc589e2012-12-06 14:05:48 +1100327 if err := writeString(w, v.String()); err != nil {
328 return err
329 }
Rob Pike97e934d2011-04-11 12:52:49 -0700330 case reflect.Struct:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700331 // Required/optional group/message.
David Symonds9f402812011-04-28 18:08:44 +1000332 var bra, ket byte = '<', '>'
333 if props != nil && props.Wire == "group" {
334 bra, ket = '{', '}'
335 }
David Symonds4dc589e2012-12-06 14:05:48 +1100336 if err := w.WriteByte(bra); err != nil {
337 return err
338 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700339 if !w.compact {
David Symonds4dc589e2012-12-06 14:05:48 +1100340 if err := w.WriteByte('\n'); err != nil {
341 return err
342 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700343 }
344 w.indent()
David Symonds4dc589e2012-12-06 14:05:48 +1100345 if err := writeStruct(w, v); err != nil {
346 return err
347 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700348 w.unindent()
David Symonds4dc589e2012-12-06 14:05:48 +1100349 if err := w.WriteByte(ket); err != nil {
350 return err
351 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700352 default:
David Symonds4dc589e2012-12-06 14:05:48 +1100353 _, err := fmt.Fprint(w, v.Interface())
354 return err
David Symondse37856c2011-06-22 12:52:53 +1000355 }
David Symonds4dc589e2012-12-06 14:05:48 +1100356 return nil
David Symondse37856c2011-06-22 12:52:53 +1000357}
358
David Symonds4c95bfe2011-09-13 14:43:27 +1000359// equivalent to C's isprint.
360func isprint(c byte) bool {
361 return c >= 0x20 && c < 0x7f
362}
363
364// writeString writes a string in the protocol buffer text format.
365// It is similar to strconv.Quote except we don't use Go escape sequences,
366// we treat the string as a byte sequence, and we use octal escapes.
367// These differences are to maintain interoperability with the other
368// languages' implementations of the text format.
David Symonds4dc589e2012-12-06 14:05:48 +1100369func writeString(w *textWriter, s string) error {
370 // use WriteByte here to get any needed indent
371 if err := w.WriteByte('"'); err != nil {
372 return err
373 }
David Symonds4c95bfe2011-09-13 14:43:27 +1000374 // Loop over the bytes, not the runes.
375 for i := 0; i < len(s); i++ {
David Symonds4dc589e2012-12-06 14:05:48 +1100376 var err error
David Symonds4c95bfe2011-09-13 14:43:27 +1000377 // Divergence from C++: we don't escape apostrophes.
378 // There's no need to escape them, and the C++ parser
379 // copes with a naked apostrophe.
380 switch c := s[i]; c {
381 case '\n':
David Symonds4dc589e2012-12-06 14:05:48 +1100382 _, err = w.w.Write(backslashN)
David Symonds4c95bfe2011-09-13 14:43:27 +1000383 case '\r':
David Symonds4dc589e2012-12-06 14:05:48 +1100384 _, err = w.w.Write(backslashR)
David Symonds4c95bfe2011-09-13 14:43:27 +1000385 case '\t':
David Symonds4dc589e2012-12-06 14:05:48 +1100386 _, err = w.w.Write(backslashT)
David Symonds4c95bfe2011-09-13 14:43:27 +1000387 case '"':
David Symonds4dc589e2012-12-06 14:05:48 +1100388 _, err = w.w.Write(backslashDQ)
David Symonds4c95bfe2011-09-13 14:43:27 +1000389 case '\\':
David Symonds4dc589e2012-12-06 14:05:48 +1100390 _, err = w.w.Write(backslashBS)
David Symonds4c95bfe2011-09-13 14:43:27 +1000391 default:
392 if isprint(c) {
David Symonds4dc589e2012-12-06 14:05:48 +1100393 err = w.w.WriteByte(c)
David Symonds4c95bfe2011-09-13 14:43:27 +1000394 } else {
David Symonds4dc589e2012-12-06 14:05:48 +1100395 _, err = fmt.Fprintf(w.w, "\\%03o", c)
David Symonds4c95bfe2011-09-13 14:43:27 +1000396 }
397 }
David Symonds4dc589e2012-12-06 14:05:48 +1100398 if err != nil {
399 return err
400 }
David Symonds4c95bfe2011-09-13 14:43:27 +1000401 }
David Symonds4dc589e2012-12-06 14:05:48 +1100402 return w.WriteByte('"')
David Symonds4c95bfe2011-09-13 14:43:27 +1000403}
404
David Symonds4dc589e2012-12-06 14:05:48 +1100405func writeMessageSet(w *textWriter, ms *MessageSet) error {
David Symonds1d72f7a2011-08-19 18:28:52 +1000406 for _, item := range ms.Item {
407 id := *item.TypeId
408 if msd, ok := messageSetMap[id]; ok {
409 // Known message set type.
David Symonds4dc589e2012-12-06 14:05:48 +1100410 if _, err := fmt.Fprintf(w, "[%s]: <\n", msd.name); err != nil {
411 return err
412 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000413 w.indent()
414
415 pb := reflect.New(msd.t.Elem())
David Symonds9f60f432012-06-14 09:45:25 +1000416 if err := Unmarshal(item.Message, pb.Interface().(Message)); err != nil {
David Symonds4dc589e2012-12-06 14:05:48 +1100417 if _, err := fmt.Fprintf(w, "/* bad message: %v */\n", err); err != nil {
418 return err
419 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000420 } else {
David Symonds4dc589e2012-12-06 14:05:48 +1100421 if err := writeStruct(w, pb.Elem()); err != nil {
422 return err
423 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000424 }
425 } else {
426 // Unknown type.
David Symonds4dc589e2012-12-06 14:05:48 +1100427 if _, err := fmt.Fprintf(w, "[%d]: <\n", id); err != nil {
428 return err
429 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000430 w.indent()
David Symonds4dc589e2012-12-06 14:05:48 +1100431 if err := writeUnknownStruct(w, item.Message); err != nil {
432 return err
433 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000434 }
435 w.unindent()
David Symonds4dc589e2012-12-06 14:05:48 +1100436 if _, err := w.Write(gtNewline); err != nil {
437 return err
438 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000439 }
David Symonds4dc589e2012-12-06 14:05:48 +1100440 return nil
David Symonds1d72f7a2011-08-19 18:28:52 +1000441}
442
David Symonds4dc589e2012-12-06 14:05:48 +1100443func writeUnknownStruct(w *textWriter, data []byte) (err error) {
David Symonds1d72f7a2011-08-19 18:28:52 +1000444 if !w.compact {
David Symonds4dc589e2012-12-06 14:05:48 +1100445 if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil {
446 return err
447 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000448 }
449 b := NewBuffer(data)
450 for b.index < len(b.buf) {
451 x, err := b.DecodeVarint()
452 if err != nil {
David Symonds4dc589e2012-12-06 14:05:48 +1100453 _, err := fmt.Fprintf(w, "/* %v */\n", err)
454 return err
David Symonds1d72f7a2011-08-19 18:28:52 +1000455 }
456 wire, tag := x&7, x>>3
457 if wire == WireEndGroup {
458 w.unindent()
David Symonds4dc589e2012-12-06 14:05:48 +1100459 if _, err := w.Write(endBraceNewline); err != nil {
460 return err
461 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000462 continue
463 }
David Symonds20370902013-03-23 17:20:01 +1100464 if _, err := fmt.Fprint(w, tag); err != nil {
David Symonds4dc589e2012-12-06 14:05:48 +1100465 return err
466 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000467 if wire != WireStartGroup {
David Symonds4dc589e2012-12-06 14:05:48 +1100468 if err := w.WriteByte(':'); err != nil {
469 return err
470 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000471 }
472 if !w.compact || 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 switch wire {
478 case WireBytes:
David Symonds4dc589e2012-12-06 14:05:48 +1100479 buf, e := b.DecodeRawBytes(false)
David Symonds1d72f7a2011-08-19 18:28:52 +1000480 if err == nil {
David Symonds4dc589e2012-12-06 14:05:48 +1100481 _, err = fmt.Fprintf(w, "%q", buf)
David Symonds1d72f7a2011-08-19 18:28:52 +1000482 } else {
David Symonds4dc589e2012-12-06 14:05:48 +1100483 _, err = fmt.Fprintf(w, "/* %v */", e)
David Symonds1d72f7a2011-08-19 18:28:52 +1000484 }
485 case WireFixed32:
David Symonds4dc589e2012-12-06 14:05:48 +1100486 x, err = b.DecodeFixed32()
487 err = writeUnknownInt(w, x, err)
David Symonds1d72f7a2011-08-19 18:28:52 +1000488 case WireFixed64:
David Symonds4dc589e2012-12-06 14:05:48 +1100489 x, err = b.DecodeFixed64()
490 err = writeUnknownInt(w, x, err)
David Symonds1d72f7a2011-08-19 18:28:52 +1000491 case WireStartGroup:
David Symonds4dc589e2012-12-06 14:05:48 +1100492 err = w.WriteByte('{')
David Symonds1d72f7a2011-08-19 18:28:52 +1000493 w.indent()
494 case WireVarint:
David Symonds4dc589e2012-12-06 14:05:48 +1100495 x, err = b.DecodeVarint()
496 err = writeUnknownInt(w, x, err)
David Symonds1d72f7a2011-08-19 18:28:52 +1000497 default:
David Symonds4dc589e2012-12-06 14:05:48 +1100498 _, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire)
David Symonds1d72f7a2011-08-19 18:28:52 +1000499 }
David Symonds4dc589e2012-12-06 14:05:48 +1100500 if err != nil {
501 return err
502 }
503 if err = w.WriteByte('\n'); err != nil {
504 return err
505 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000506 }
David Symonds4dc589e2012-12-06 14:05:48 +1100507 return nil
David Symonds1d72f7a2011-08-19 18:28:52 +1000508}
509
David Symonds4dc589e2012-12-06 14:05:48 +1100510func writeUnknownInt(w *textWriter, x uint64, err error) error {
David Symonds1d72f7a2011-08-19 18:28:52 +1000511 if err == nil {
David Symonds4dc589e2012-12-06 14:05:48 +1100512 _, err = fmt.Fprint(w, x)
David Symonds1d72f7a2011-08-19 18:28:52 +1000513 } else {
David Symonds4dc589e2012-12-06 14:05:48 +1100514 _, err = fmt.Fprintf(w, "/* %v */", err)
David Symonds1d72f7a2011-08-19 18:28:52 +1000515 }
David Symonds4dc589e2012-12-06 14:05:48 +1100516 return err
David Symonds1d72f7a2011-08-19 18:28:52 +1000517}
518
519type int32Slice []int32
520
521func (s int32Slice) Len() int { return len(s) }
522func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] }
523func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
524
David Symondse37856c2011-06-22 12:52:53 +1000525// writeExtensions writes all the extensions in pv.
526// pv is assumed to be a pointer to a protocol message struct that is extendable.
David Symonds4dc589e2012-12-06 14:05:48 +1100527func writeExtensions(w *textWriter, pv reflect.Value) error {
David Symondse37856c2011-06-22 12:52:53 +1000528 emap := extensionMaps[pv.Type().Elem()]
529 ep := pv.Interface().(extendableProto)
David Symonds1d72f7a2011-08-19 18:28:52 +1000530
531 // Order the extensions by ID.
532 // This isn't strictly necessary, but it will give us
533 // canonical output, which will also make testing easier.
534 m := ep.ExtensionMap()
535 ids := make([]int32, 0, len(m))
536 for id := range m {
537 ids = append(ids, id)
538 }
539 sort.Sort(int32Slice(ids))
540
541 for _, extNum := range ids {
542 ext := m[extNum]
David Symondse37856c2011-06-22 12:52:53 +1000543 var desc *ExtensionDesc
544 if emap != nil {
545 desc = emap[extNum]
546 }
547 if desc == nil {
David Symonds1d72f7a2011-08-19 18:28:52 +1000548 // Unknown extension.
David Symonds4dc589e2012-12-06 14:05:48 +1100549 if err := writeUnknownStruct(w, ext.enc); err != nil {
550 return err
551 }
David Symondse37856c2011-06-22 12:52:53 +1000552 continue
553 }
554
555 pb, err := GetExtension(ep, desc)
556 if err != nil {
David Symonds4dc589e2012-12-06 14:05:48 +1100557 if _, err := fmt.Fprintln(os.Stderr, "proto: failed getting extension: ", err); err != nil {
558 return err
559 }
David Symondse37856c2011-06-22 12:52:53 +1000560 continue
561 }
562
David Symonds61826da2012-05-05 09:31:28 +1000563 // Repeated extensions will appear as a slice.
564 if !desc.repeated() {
David Symonds4dc589e2012-12-06 14:05:48 +1100565 if err := writeExtension(w, desc.Name, pb); err != nil {
566 return err
567 }
David Symonds61826da2012-05-05 09:31:28 +1000568 } else {
569 v := reflect.ValueOf(pb)
570 for i := 0; i < v.Len(); i++ {
David Symonds4dc589e2012-12-06 14:05:48 +1100571 if err := writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil {
572 return err
573 }
David Symonds61826da2012-05-05 09:31:28 +1000574 }
David Symondse37856c2011-06-22 12:52:53 +1000575 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700576 }
David Symonds4dc589e2012-12-06 14:05:48 +1100577 return nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700578}
579
David Symonds4dc589e2012-12-06 14:05:48 +1100580func writeExtension(w *textWriter, name string, pb interface{}) error {
581 if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil {
582 return err
David Symonds61826da2012-05-05 09:31:28 +1000583 }
David Symonds4dc589e2012-12-06 14:05:48 +1100584 if !w.compact {
585 if err := w.WriteByte(' '); err != nil {
586 return err
587 }
588 }
589 if err := writeAny(w, reflect.ValueOf(pb), nil); err != nil {
590 return err
591 }
592 if err := w.WriteByte('\n'); err != nil {
593 return err
594 }
595 return nil
David Symonds61826da2012-05-05 09:31:28 +1000596}
597
David Symondsdbdc4212012-11-08 08:20:35 +1100598func (w *textWriter) writeIndent() {
599 if !w.complete {
600 return
601 }
602 remain := w.ind * 2
603 for remain > 0 {
604 n := remain
605 if n > len(spaces) {
606 n = len(spaces)
607 }
David Symonds4dc589e2012-12-06 14:05:48 +1100608 w.w.Write(spaces[:n])
David Symondsdbdc4212012-11-08 08:20:35 +1100609 remain -= n
610 }
611 w.complete = false
612}
613
David Symonds4dc589e2012-12-06 14:05:48 +1100614func marshalText(w io.Writer, pb Message, compact bool) error {
David Symonds6e8ab872013-01-30 17:07:26 +1100615 val := reflect.ValueOf(pb)
616 if pb == nil || val.IsNil() {
David Symonds03c9d412010-08-26 14:23:18 +1000617 w.Write([]byte("<nil>"))
David Symonds4dc589e2012-12-06 14:05:48 +1100618 return nil
David Symonds03c9d412010-08-26 14:23:18 +1000619 }
David Symonds4dc589e2012-12-06 14:05:48 +1100620 var bw *bufio.Writer
621 ww, ok := w.(writer)
622 if !ok {
623 bw = bufio.NewWriter(w)
624 ww = bw
625 }
626 aw := &textWriter{
627 w: ww,
628 complete: true,
629 compact: compact,
David Symondsdbdc4212012-11-08 08:20:35 +1100630 }
631
David Symonds92dd6c12012-03-23 10:59:49 +1100632 // Dereference the received pointer so we don't have outer < and >.
David Symonds6e8ab872013-01-30 17:07:26 +1100633 v := reflect.Indirect(val)
David Symonds4dc589e2012-12-06 14:05:48 +1100634 if err := writeStruct(aw, v); err != nil {
635 return err
636 }
637 if bw != nil {
638 return bw.Flush()
639 }
640 return nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700641}
642
David Symondse37856c2011-06-22 12:52:53 +1000643// MarshalText writes a given protocol buffer in text format.
David Symonds4dc589e2012-12-06 14:05:48 +1100644// The only errors returned are from w.
645func MarshalText(w io.Writer, pb Message) error { return marshalText(w, pb, false) }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700646
David Symondsd2bff3c2012-03-14 10:45:25 +1100647// MarshalTextString is the same as MarshalText, but returns the string directly.
David Symonds9f60f432012-06-14 09:45:25 +1000648func MarshalTextString(pb Message) string {
David Symondsd2bff3c2012-03-14 10:45:25 +1100649 var buf bytes.Buffer
650 marshalText(&buf, pb, false)
651 return buf.String()
652}
653
David Symondsd4661c52012-08-30 15:17:53 +1000654// CompactText writes a given protocol buffer in compact text format (one line).
David Symonds4dc589e2012-12-06 14:05:48 +1100655func CompactText(w io.Writer, pb Message) error { return marshalText(w, pb, true) }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700656
657// CompactTextString is the same as CompactText, but returns the string directly.
David Symonds9f60f432012-06-14 09:45:25 +1000658func CompactTextString(pb Message) string {
David Symonds183124e2012-03-23 13:20:23 +1100659 var buf bytes.Buffer
660 marshalText(&buf, pb, true)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700661 return buf.String()
662}