blob: 3bbf9aa5e1dc0520386a4e358441b945b026cce4 [file] [log] [blame]
Rob Pikeaaa3a622010-03-20 22:32:34 -07001// Go support for Protocol Buffers - Google's data interchange format
2//
3// Copyright 2010 Google Inc. All rights reserved.
4// 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 (
37 "bytes"
38 "fmt"
39 "io"
David Symondse37856c2011-06-22 12:52:53 +100040 "log"
Rob Pikeaaa3a622010-03-20 22:32:34 -070041 "os"
42 "reflect"
David Symonds1d72f7a2011-08-19 18:28:52 +100043 "sort"
Rob Pikeaaa3a622010-03-20 22:32:34 -070044 "strings"
45)
46
David Symondse37856c2011-06-22 12:52:53 +100047// textWriter is an io.Writer that tracks its indentation level.
Rob Pikeaaa3a622010-03-20 22:32:34 -070048type textWriter struct {
David Symondse37856c2011-06-22 12:52:53 +100049 ind int
50 complete bool // if the current position is a complete line
51 compact bool // whether to write out as a one-liner
52 writer io.Writer
David Symonds9f402812011-04-28 18:08:44 +100053
54 c [1]byte // scratch
Rob Pikeaaa3a622010-03-20 22:32:34 -070055}
56
Rob Pikea17fdd92011-11-02 12:43:05 -070057func (w *textWriter) Write(p []byte) (n int, err error) {
Rob Pikeaaa3a622010-03-20 22:32:34 -070058 n, err = len(p), nil
59
David Symonds8935abf2011-07-04 15:53:16 +100060 frags := strings.Split(string(p), "\n")
Rob Pikeaaa3a622010-03-20 22:32:34 -070061 if w.compact {
62 w.writer.Write([]byte(strings.Join(frags, " ")))
63 return
64 }
65
David Symondse37856c2011-06-22 12:52:53 +100066 for i, frag := range frags {
Rob Pikeaaa3a622010-03-20 22:32:34 -070067 if w.complete {
David Symondse37856c2011-06-22 12:52:53 +100068 for j := 0; j < w.ind; j++ {
Rob Pikeaaa3a622010-03-20 22:32:34 -070069 w.writer.Write([]byte{' ', ' '})
70 }
71 w.complete = false
72 }
73
David Symondse37856c2011-06-22 12:52:53 +100074 w.writer.Write([]byte(frag))
Rob Pikeaaa3a622010-03-20 22:32:34 -070075 if i+1 < len(frags) {
76 w.writer.Write([]byte{'\n'})
77 }
78 }
79 w.complete = len(frags[len(frags)-1]) == 0
80
81 return
82}
83
Rob Pikea17fdd92011-11-02 12:43:05 -070084func (w *textWriter) WriteByte(c byte) error {
David Symonds9f402812011-04-28 18:08:44 +100085 w.c[0] = c
86 _, err := w.Write(w.c[:])
87 return err
88}
89
David Symondse37856c2011-06-22 12:52:53 +100090func (w *textWriter) indent() { w.ind++ }
Rob Pikeaaa3a622010-03-20 22:32:34 -070091
92func (w *textWriter) unindent() {
David Symondse37856c2011-06-22 12:52:53 +100093 if w.ind == 0 {
David Symondsd4661c52012-08-30 15:17:53 +100094 log.Printf("proto: textWriter unindented too far")
David Symondse37856c2011-06-22 12:52:53 +100095 return
Rob Pikeaaa3a622010-03-20 22:32:34 -070096 }
David Symondse37856c2011-06-22 12:52:53 +100097 w.ind--
Rob Pikeaaa3a622010-03-20 22:32:34 -070098}
99
David Symonds9f402812011-04-28 18:08:44 +1000100func writeName(w *textWriter, props *Properties) {
101 io.WriteString(w, props.OrigName)
102 if props.Wire != "group" {
103 w.WriteByte(':')
104 }
105}
106
David Symonds1d72f7a2011-08-19 18:28:52 +1000107var (
Russ Coxd4ce3f12012-09-12 10:36:26 +1000108 messageSetType = reflect.TypeOf((*MessageSet)(nil)).Elem()
David Symonds1d72f7a2011-08-19 18:28:52 +1000109)
David Symondse37856c2011-06-22 12:52:53 +1000110
David Symondse9e7aaf2012-03-23 13:12:33 +1100111// raw is the interface satisfied by RawMessage.
112type raw interface {
113 Bytes() []byte
114}
115
Rob Pike97e934d2011-04-11 12:52:49 -0700116func writeStruct(w *textWriter, sv reflect.Value) {
David Symonds1d72f7a2011-08-19 18:28:52 +1000117 if sv.Type() == messageSetType {
118 writeMessageSet(w, sv.Addr().Interface().(*MessageSet))
119 return
120 }
121
Rob Pike97e934d2011-04-11 12:52:49 -0700122 st := sv.Type()
Rob Pikeaaa3a622010-03-20 22:32:34 -0700123 sprops := GetProperties(st)
124 for i := 0; i < sv.NumField(); i++ {
David Symonds1d72f7a2011-08-19 18:28:52 +1000125 fv := sv.Field(i)
126 if name := st.Field(i).Name; strings.HasPrefix(name, "XXX_") {
127 // There's only two XXX_ fields:
128 // XXX_unrecognized []byte
129 // XXX_extensions map[int32]proto.Extension
130 // The first is handled here;
131 // the second is handled at the bottom of this function.
132 if name == "XXX_unrecognized" && !fv.IsNil() {
133 writeUnknownStruct(w, fv.Interface().([]byte))
134 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700135 continue
136 }
137 props := sprops.Prop[i]
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700138 if fv.Kind() == reflect.Ptr && fv.IsNil() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700139 // Field not filled in. This could be an optional field or
140 // a required field that wasn't filled in. Either way, there
141 // isn't anything we can show for it.
142 continue
143 }
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700144 if fv.Kind() == reflect.Slice && fv.IsNil() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700145 // Repeated field that is empty, or a bytes field that is unused.
146 continue
147 }
148
David Symondsaa922ff2011-07-19 14:58:06 +1000149 if props.Repeated && fv.Kind() == reflect.Slice {
150 // Repeated field.
151 for j := 0; j < fv.Len(); j++ {
152 writeName(w, props)
153 if !w.compact {
154 w.WriteByte(' ')
Rob Pikeaaa3a622010-03-20 22:32:34 -0700155 }
David Symondsaa922ff2011-07-19 14:58:06 +1000156 writeAny(w, fv.Index(j), props)
157 w.WriteByte('\n')
Rob Pikeaaa3a622010-03-20 22:32:34 -0700158 }
David Symondsaa922ff2011-07-19 14:58:06 +1000159 continue
Rob Pikeaaa3a622010-03-20 22:32:34 -0700160 }
161
David Symonds9f402812011-04-28 18:08:44 +1000162 writeName(w, props)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700163 if !w.compact {
David Symonds9f402812011-04-28 18:08:44 +1000164 w.WriteByte(' ')
Rob Pikeaaa3a622010-03-20 22:32:34 -0700165 }
David Symondse9e7aaf2012-03-23 13:12:33 +1100166 if b, ok := fv.Interface().(raw); ok {
167 writeRaw(w, b.Bytes())
168 continue
169 }
David Symondse37856c2011-06-22 12:52:53 +1000170 if props.Enum != "" && tryWriteEnum(w, props.Enum, fv) {
171 // Enum written.
172 } else {
David Symonds9f402812011-04-28 18:08:44 +1000173 writeAny(w, fv, props)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700174 }
David Symondse37856c2011-06-22 12:52:53 +1000175 w.WriteByte('\n')
176 }
177
David Symonds1d72f7a2011-08-19 18:28:52 +1000178 // Extensions (the XXX_extensions field).
David Symondse37856c2011-06-22 12:52:53 +1000179 pv := sv.Addr()
180 if pv.Type().Implements(extendableProtoType) {
181 writeExtensions(w, pv)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700182 }
183}
184
David Symondse9e7aaf2012-03-23 13:12:33 +1100185// writeRaw writes an uninterpreted raw message.
186func writeRaw(w *textWriter, b []byte) {
187 w.WriteByte('<')
188 if !w.compact {
189 w.WriteByte('\n')
190 }
191 w.indent()
192 writeUnknownStruct(w, b)
193 w.unindent()
194 w.WriteByte('>')
195}
196
David Symondse37856c2011-06-22 12:52:53 +1000197// tryWriteEnum attempts to write an enum value as a symbolic constant.
198// If the enum is unregistered, nothing is written and false is returned.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700199func tryWriteEnum(w *textWriter, enum string, v reflect.Value) bool {
Rob Pikeab5b8022010-06-21 17:47:58 -0700200 v = reflect.Indirect(v)
201 if v.Type().Kind() != reflect.Int32 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700202 return false
203 }
204 m, ok := enumNameMaps[enum]
205 if !ok {
206 return false
207 }
Rob Pike97e934d2011-04-11 12:52:49 -0700208 str, ok := m[int32(v.Int())]
Rob Pikeaaa3a622010-03-20 22:32:34 -0700209 if !ok {
210 return false
211 }
212 fmt.Fprintf(w, str)
213 return true
214}
215
David Symondse37856c2011-06-22 12:52:53 +1000216// writeAny writes an arbitrary field.
David Symonds9f402812011-04-28 18:08:44 +1000217func writeAny(w *textWriter, v reflect.Value, props *Properties) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700218 v = reflect.Indirect(v)
219
220 // We don't attempt to serialise every possible value type; only those
221 // that can occur in protocol buffers, plus a few extra that were easy.
David Symondse37856c2011-06-22 12:52:53 +1000222 switch v.Kind() {
Rob Pike97e934d2011-04-11 12:52:49 -0700223 case reflect.Slice:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700224 // Should only be a []byte; repeated fields are handled in writeStruct.
David Symonds4c95bfe2011-09-13 14:43:27 +1000225 writeString(w, string(v.Interface().([]byte)))
Rob Pike97e934d2011-04-11 12:52:49 -0700226 case reflect.String:
David Symonds4c95bfe2011-09-13 14:43:27 +1000227 writeString(w, v.String())
Rob Pike97e934d2011-04-11 12:52:49 -0700228 case reflect.Struct:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700229 // Required/optional group/message.
David Symonds9f402812011-04-28 18:08:44 +1000230 var bra, ket byte = '<', '>'
231 if props != nil && props.Wire == "group" {
232 bra, ket = '{', '}'
233 }
234 w.WriteByte(bra)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700235 if !w.compact {
David Symonds9f402812011-04-28 18:08:44 +1000236 w.WriteByte('\n')
Rob Pikeaaa3a622010-03-20 22:32:34 -0700237 }
238 w.indent()
David Symondse37856c2011-06-22 12:52:53 +1000239 writeStruct(w, v)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700240 w.unindent()
David Symonds9f402812011-04-28 18:08:44 +1000241 w.WriteByte(ket)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700242 default:
David Symondse37856c2011-06-22 12:52:53 +1000243 fmt.Fprint(w, v.Interface())
244 }
245}
246
David Symonds4c95bfe2011-09-13 14:43:27 +1000247// equivalent to C's isprint.
248func isprint(c byte) bool {
249 return c >= 0x20 && c < 0x7f
250}
251
252// writeString writes a string in the protocol buffer text format.
253// It is similar to strconv.Quote except we don't use Go escape sequences,
254// we treat the string as a byte sequence, and we use octal escapes.
255// These differences are to maintain interoperability with the other
256// languages' implementations of the text format.
257func writeString(w *textWriter, s string) {
258 w.WriteByte('"')
259
260 // Loop over the bytes, not the runes.
261 for i := 0; i < len(s); i++ {
262 // Divergence from C++: we don't escape apostrophes.
263 // There's no need to escape them, and the C++ parser
264 // copes with a naked apostrophe.
265 switch c := s[i]; c {
266 case '\n':
267 w.Write([]byte{'\\', 'n'})
268 case '\r':
269 w.Write([]byte{'\\', 'r'})
270 case '\t':
271 w.Write([]byte{'\\', 't'})
272 case '"':
273 w.Write([]byte{'\\', '"'})
274 case '\\':
275 w.Write([]byte{'\\', '\\'})
276 default:
277 if isprint(c) {
278 w.WriteByte(c)
279 } else {
280 fmt.Fprintf(w, "\\%03o", c)
281 }
282 }
283 }
284
285 w.WriteByte('"')
286}
287
David Symonds1d72f7a2011-08-19 18:28:52 +1000288func writeMessageSet(w *textWriter, ms *MessageSet) {
289 for _, item := range ms.Item {
290 id := *item.TypeId
291 if msd, ok := messageSetMap[id]; ok {
292 // Known message set type.
293 fmt.Fprintf(w, "[%s]: <\n", msd.name)
294 w.indent()
295
296 pb := reflect.New(msd.t.Elem())
David Symonds9f60f432012-06-14 09:45:25 +1000297 if err := Unmarshal(item.Message, pb.Interface().(Message)); err != nil {
David Symonds1d72f7a2011-08-19 18:28:52 +1000298 fmt.Fprintf(w, "/* bad message: %v */\n", err)
299 } else {
300 writeStruct(w, pb.Elem())
301 }
302 } else {
303 // Unknown type.
304 fmt.Fprintf(w, "[%d]: <\n", id)
305 w.indent()
306 writeUnknownStruct(w, item.Message)
307 }
308 w.unindent()
309 w.Write([]byte(">\n"))
310 }
311}
312
313func writeUnknownStruct(w *textWriter, data []byte) {
314 if !w.compact {
315 fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data))
316 }
317 b := NewBuffer(data)
318 for b.index < len(b.buf) {
319 x, err := b.DecodeVarint()
320 if err != nil {
321 fmt.Fprintf(w, "/* %v */\n", err)
322 return
323 }
324 wire, tag := x&7, x>>3
325 if wire == WireEndGroup {
326 w.unindent()
327 w.Write([]byte("}\n"))
328 continue
329 }
330 fmt.Fprintf(w, "tag%d", tag)
331 if wire != WireStartGroup {
332 w.WriteByte(':')
333 }
334 if !w.compact || wire == WireStartGroup {
335 w.WriteByte(' ')
336 }
337 switch wire {
338 case WireBytes:
339 buf, err := b.DecodeRawBytes(false)
340 if err == nil {
341 fmt.Fprintf(w, "%q", buf)
342 } else {
343 fmt.Fprintf(w, "/* %v */", err)
344 }
345 case WireFixed32:
346 x, err := b.DecodeFixed32()
347 writeUnknownInt(w, x, err)
348 case WireFixed64:
349 x, err := b.DecodeFixed64()
350 writeUnknownInt(w, x, err)
351 case WireStartGroup:
352 fmt.Fprint(w, "{")
353 w.indent()
354 case WireVarint:
355 x, err := b.DecodeVarint()
356 writeUnknownInt(w, x, err)
357 default:
358 fmt.Fprintf(w, "/* unknown wire type %d */", wire)
359 }
360 w.WriteByte('\n')
361 }
362}
363
Rob Pikea17fdd92011-11-02 12:43:05 -0700364func writeUnknownInt(w *textWriter, x uint64, err error) {
David Symonds1d72f7a2011-08-19 18:28:52 +1000365 if err == nil {
366 fmt.Fprint(w, x)
367 } else {
368 fmt.Fprintf(w, "/* %v */", err)
369 }
370}
371
372type int32Slice []int32
373
374func (s int32Slice) Len() int { return len(s) }
375func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] }
376func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
377
David Symondse37856c2011-06-22 12:52:53 +1000378// writeExtensions writes all the extensions in pv.
379// pv is assumed to be a pointer to a protocol message struct that is extendable.
380func writeExtensions(w *textWriter, pv reflect.Value) {
381 emap := extensionMaps[pv.Type().Elem()]
382 ep := pv.Interface().(extendableProto)
David Symonds1d72f7a2011-08-19 18:28:52 +1000383
384 // Order the extensions by ID.
385 // This isn't strictly necessary, but it will give us
386 // canonical output, which will also make testing easier.
387 m := ep.ExtensionMap()
388 ids := make([]int32, 0, len(m))
389 for id := range m {
390 ids = append(ids, id)
391 }
392 sort.Sort(int32Slice(ids))
393
394 for _, extNum := range ids {
395 ext := m[extNum]
David Symondse37856c2011-06-22 12:52:53 +1000396 var desc *ExtensionDesc
397 if emap != nil {
398 desc = emap[extNum]
399 }
400 if desc == nil {
David Symonds1d72f7a2011-08-19 18:28:52 +1000401 // Unknown extension.
402 writeUnknownStruct(w, ext.enc)
David Symondse37856c2011-06-22 12:52:53 +1000403 continue
404 }
405
406 pb, err := GetExtension(ep, desc)
407 if err != nil {
408 fmt.Fprintln(os.Stderr, "proto: failed getting extension: ", err)
409 continue
410 }
411
David Symonds61826da2012-05-05 09:31:28 +1000412 // Repeated extensions will appear as a slice.
413 if !desc.repeated() {
414 writeExtension(w, desc.Name, pb)
415 } else {
416 v := reflect.ValueOf(pb)
417 for i := 0; i < v.Len(); i++ {
418 writeExtension(w, desc.Name, v.Index(i).Interface())
419 }
David Symondse37856c2011-06-22 12:52:53 +1000420 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700421 }
422}
423
David Symonds61826da2012-05-05 09:31:28 +1000424func writeExtension(w *textWriter, name string, pb interface{}) {
425 fmt.Fprintf(w, "[%s]:", name)
426 if !w.compact {
427 w.WriteByte(' ')
428 }
429 writeAny(w, reflect.ValueOf(pb), nil)
430 w.WriteByte('\n')
431}
432
David Symonds9f60f432012-06-14 09:45:25 +1000433func marshalText(w io.Writer, pb Message, compact bool) {
David Symonds03c9d412010-08-26 14:23:18 +1000434 if pb == nil {
435 w.Write([]byte("<nil>"))
436 return
437 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700438 aw := new(textWriter)
439 aw.writer = w
440 aw.complete = true
441 aw.compact = compact
442
David Symonds92dd6c12012-03-23 10:59:49 +1100443 // Dereference the received pointer so we don't have outer < and >.
David Symonds9f60f432012-06-14 09:45:25 +1000444 v := reflect.Indirect(reflect.ValueOf(pb))
445 writeStruct(aw, v)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700446}
447
David Symondse37856c2011-06-22 12:52:53 +1000448// MarshalText writes a given protocol buffer in text format.
David Symonds9f60f432012-06-14 09:45:25 +1000449func MarshalText(w io.Writer, pb Message) { marshalText(w, pb, false) }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700450
David Symondsd2bff3c2012-03-14 10:45:25 +1100451// MarshalTextString is the same as MarshalText, but returns the string directly.
David Symonds9f60f432012-06-14 09:45:25 +1000452func MarshalTextString(pb Message) string {
David Symondsd2bff3c2012-03-14 10:45:25 +1100453 var buf bytes.Buffer
454 marshalText(&buf, pb, false)
455 return buf.String()
456}
457
David Symondsd4661c52012-08-30 15:17:53 +1000458// CompactText writes a given protocol buffer in compact text format (one line).
David Symonds9f60f432012-06-14 09:45:25 +1000459func CompactText(w io.Writer, pb Message) { marshalText(w, pb, true) }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700460
461// CompactTextString is the same as CompactText, but returns the string directly.
David Symonds9f60f432012-06-14 09:45:25 +1000462func CompactTextString(pb Message) string {
David Symonds183124e2012-03-23 13:20:23 +1100463 var buf bytes.Buffer
464 marshalText(&buf, pb, true)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700465 return buf.String()
466}