blob: e1a08a98d8f64cd1a62ff0fa63d55bca7b4ef71a [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 "strconv"
45 "strings"
46)
47
David Symondse37856c2011-06-22 12:52:53 +100048// textWriter is an io.Writer that tracks its indentation level.
Rob Pikeaaa3a622010-03-20 22:32:34 -070049type textWriter struct {
David Symondse37856c2011-06-22 12:52:53 +100050 ind int
51 complete bool // if the current position is a complete line
52 compact bool // whether to write out as a one-liner
53 writer io.Writer
David Symonds9f402812011-04-28 18:08:44 +100054
55 c [1]byte // scratch
Rob Pikeaaa3a622010-03-20 22:32:34 -070056}
57
58func (w *textWriter) Write(p []byte) (n int, err os.Error) {
59 n, err = len(p), nil
60
David Symonds8935abf2011-07-04 15:53:16 +100061 frags := strings.Split(string(p), "\n")
Rob Pikeaaa3a622010-03-20 22:32:34 -070062 if w.compact {
63 w.writer.Write([]byte(strings.Join(frags, " ")))
64 return
65 }
66
David Symondse37856c2011-06-22 12:52:53 +100067 for i, frag := range frags {
Rob Pikeaaa3a622010-03-20 22:32:34 -070068 if w.complete {
David Symondse37856c2011-06-22 12:52:53 +100069 for j := 0; j < w.ind; j++ {
Rob Pikeaaa3a622010-03-20 22:32:34 -070070 w.writer.Write([]byte{' ', ' '})
71 }
72 w.complete = false
73 }
74
David Symondse37856c2011-06-22 12:52:53 +100075 w.writer.Write([]byte(frag))
Rob Pikeaaa3a622010-03-20 22:32:34 -070076 if i+1 < len(frags) {
77 w.writer.Write([]byte{'\n'})
78 }
79 }
80 w.complete = len(frags[len(frags)-1]) == 0
81
82 return
83}
84
David Symonds9f402812011-04-28 18:08:44 +100085func (w *textWriter) WriteByte(c byte) os.Error {
86 w.c[0] = c
87 _, err := w.Write(w.c[:])
88 return err
89}
90
David Symondse37856c2011-06-22 12:52:53 +100091func (w *textWriter) indent() { w.ind++ }
Rob Pikeaaa3a622010-03-20 22:32:34 -070092
93func (w *textWriter) unindent() {
David Symondse37856c2011-06-22 12:52:53 +100094 if w.ind == 0 {
95 log.Printf("proto: textWriter unindented too far!")
96 return
Rob Pikeaaa3a622010-03-20 22:32:34 -070097 }
David Symondse37856c2011-06-22 12:52:53 +100098 w.ind--
Rob Pikeaaa3a622010-03-20 22:32:34 -070099}
100
David Symonds9f402812011-04-28 18:08:44 +1000101func writeName(w *textWriter, props *Properties) {
102 io.WriteString(w, props.OrigName)
103 if props.Wire != "group" {
104 w.WriteByte(':')
105 }
106}
107
David Symonds1d72f7a2011-08-19 18:28:52 +1000108var (
109 messageSetType = reflect.TypeOf((*MessageSet)(nil)).Elem()
110 extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem()
111)
David Symondse37856c2011-06-22 12:52:53 +1000112
Rob Pike97e934d2011-04-11 12:52:49 -0700113func writeStruct(w *textWriter, sv reflect.Value) {
David Symonds1d72f7a2011-08-19 18:28:52 +1000114 if sv.Type() == messageSetType {
115 writeMessageSet(w, sv.Addr().Interface().(*MessageSet))
116 return
117 }
118
Rob Pike97e934d2011-04-11 12:52:49 -0700119 st := sv.Type()
Rob Pikeaaa3a622010-03-20 22:32:34 -0700120 sprops := GetProperties(st)
121 for i := 0; i < sv.NumField(); i++ {
David Symonds1d72f7a2011-08-19 18:28:52 +1000122 fv := sv.Field(i)
123 if name := st.Field(i).Name; strings.HasPrefix(name, "XXX_") {
124 // There's only two XXX_ fields:
125 // XXX_unrecognized []byte
126 // XXX_extensions map[int32]proto.Extension
127 // The first is handled here;
128 // the second is handled at the bottom of this function.
129 if name == "XXX_unrecognized" && !fv.IsNil() {
130 writeUnknownStruct(w, fv.Interface().([]byte))
131 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700132 continue
133 }
134 props := sprops.Prop[i]
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700135 if fv.Kind() == reflect.Ptr && fv.IsNil() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700136 // Field not filled in. This could be an optional field or
137 // a required field that wasn't filled in. Either way, there
138 // isn't anything we can show for it.
139 continue
140 }
Rob Pikeac8b1ce2011-04-11 16:14:54 -0700141 if fv.Kind() == reflect.Slice && fv.IsNil() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700142 // Repeated field that is empty, or a bytes field that is unused.
143 continue
144 }
145
David Symondsaa922ff2011-07-19 14:58:06 +1000146 if props.Repeated && fv.Kind() == reflect.Slice {
147 // Repeated field.
148 for j := 0; j < fv.Len(); j++ {
149 writeName(w, props)
150 if !w.compact {
151 w.WriteByte(' ')
Rob Pikeaaa3a622010-03-20 22:32:34 -0700152 }
David Symondsaa922ff2011-07-19 14:58:06 +1000153 writeAny(w, fv.Index(j), props)
154 w.WriteByte('\n')
Rob Pikeaaa3a622010-03-20 22:32:34 -0700155 }
David Symondsaa922ff2011-07-19 14:58:06 +1000156 continue
Rob Pikeaaa3a622010-03-20 22:32:34 -0700157 }
158
David Symonds9f402812011-04-28 18:08:44 +1000159 writeName(w, props)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700160 if !w.compact {
David Symonds9f402812011-04-28 18:08:44 +1000161 w.WriteByte(' ')
Rob Pikeaaa3a622010-03-20 22:32:34 -0700162 }
David Symondse37856c2011-06-22 12:52:53 +1000163 if props.Enum != "" && tryWriteEnum(w, props.Enum, fv) {
164 // Enum written.
165 } else {
David Symonds9f402812011-04-28 18:08:44 +1000166 writeAny(w, fv, props)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700167 }
David Symondse37856c2011-06-22 12:52:53 +1000168 w.WriteByte('\n')
169 }
170
David Symonds1d72f7a2011-08-19 18:28:52 +1000171 // Extensions (the XXX_extensions field).
David Symondse37856c2011-06-22 12:52:53 +1000172 pv := sv.Addr()
173 if pv.Type().Implements(extendableProtoType) {
174 writeExtensions(w, pv)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700175 }
176}
177
David Symondse37856c2011-06-22 12:52:53 +1000178// tryWriteEnum attempts to write an enum value as a symbolic constant.
179// If the enum is unregistered, nothing is written and false is returned.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700180func tryWriteEnum(w *textWriter, enum string, v reflect.Value) bool {
Rob Pikeab5b8022010-06-21 17:47:58 -0700181 v = reflect.Indirect(v)
182 if v.Type().Kind() != reflect.Int32 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700183 return false
184 }
185 m, ok := enumNameMaps[enum]
186 if !ok {
187 return false
188 }
Rob Pike97e934d2011-04-11 12:52:49 -0700189 str, ok := m[int32(v.Int())]
Rob Pikeaaa3a622010-03-20 22:32:34 -0700190 if !ok {
191 return false
192 }
193 fmt.Fprintf(w, str)
194 return true
195}
196
David Symondse37856c2011-06-22 12:52:53 +1000197// writeAny writes an arbitrary field.
David Symonds9f402812011-04-28 18:08:44 +1000198func writeAny(w *textWriter, v reflect.Value, props *Properties) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700199 v = reflect.Indirect(v)
200
201 // We don't attempt to serialise every possible value type; only those
202 // that can occur in protocol buffers, plus a few extra that were easy.
David Symondse37856c2011-06-22 12:52:53 +1000203 switch v.Kind() {
Rob Pike97e934d2011-04-11 12:52:49 -0700204 case reflect.Slice:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700205 // Should only be a []byte; repeated fields are handled in writeStruct.
David Symondse37856c2011-06-22 12:52:53 +1000206 // TODO: Should be strconv.QuoteToASCII, which should be released after 2011-06-20.
207 fmt.Fprint(w, strconv.Quote(string(v.Interface().([]byte))))
Rob Pike97e934d2011-04-11 12:52:49 -0700208 case reflect.String:
David Symondse37856c2011-06-22 12:52:53 +1000209 // TODO: Should be strconv.QuoteToASCII, which should be released after 2011-06-20.
210 fmt.Fprint(w, strconv.Quote(v.String()))
Rob Pike97e934d2011-04-11 12:52:49 -0700211 case reflect.Struct:
Rob Pikeaaa3a622010-03-20 22:32:34 -0700212 // Required/optional group/message.
David Symonds9f402812011-04-28 18:08:44 +1000213 var bra, ket byte = '<', '>'
214 if props != nil && props.Wire == "group" {
215 bra, ket = '{', '}'
216 }
217 w.WriteByte(bra)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700218 if !w.compact {
David Symonds9f402812011-04-28 18:08:44 +1000219 w.WriteByte('\n')
Rob Pikeaaa3a622010-03-20 22:32:34 -0700220 }
221 w.indent()
David Symondse37856c2011-06-22 12:52:53 +1000222 writeStruct(w, v)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700223 w.unindent()
David Symonds9f402812011-04-28 18:08:44 +1000224 w.WriteByte(ket)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700225 default:
David Symondse37856c2011-06-22 12:52:53 +1000226 fmt.Fprint(w, v.Interface())
227 }
228}
229
David Symonds1d72f7a2011-08-19 18:28:52 +1000230func writeMessageSet(w *textWriter, ms *MessageSet) {
231 for _, item := range ms.Item {
232 id := *item.TypeId
233 if msd, ok := messageSetMap[id]; ok {
234 // Known message set type.
235 fmt.Fprintf(w, "[%s]: <\n", msd.name)
236 w.indent()
237
238 pb := reflect.New(msd.t.Elem())
239 if err := Unmarshal(item.Message, pb.Interface()); err != nil {
240 fmt.Fprintf(w, "/* bad message: %v */\n", err)
241 } else {
242 writeStruct(w, pb.Elem())
243 }
244 } else {
245 // Unknown type.
246 fmt.Fprintf(w, "[%d]: <\n", id)
247 w.indent()
248 writeUnknownStruct(w, item.Message)
249 }
250 w.unindent()
251 w.Write([]byte(">\n"))
252 }
253}
254
255func writeUnknownStruct(w *textWriter, data []byte) {
256 if !w.compact {
257 fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data))
258 }
259 b := NewBuffer(data)
260 for b.index < len(b.buf) {
261 x, err := b.DecodeVarint()
262 if err != nil {
263 fmt.Fprintf(w, "/* %v */\n", err)
264 return
265 }
266 wire, tag := x&7, x>>3
267 if wire == WireEndGroup {
268 w.unindent()
269 w.Write([]byte("}\n"))
270 continue
271 }
272 fmt.Fprintf(w, "tag%d", tag)
273 if wire != WireStartGroup {
274 w.WriteByte(':')
275 }
276 if !w.compact || wire == WireStartGroup {
277 w.WriteByte(' ')
278 }
279 switch wire {
280 case WireBytes:
281 buf, err := b.DecodeRawBytes(false)
282 if err == nil {
283 fmt.Fprintf(w, "%q", buf)
284 } else {
285 fmt.Fprintf(w, "/* %v */", err)
286 }
287 case WireFixed32:
288 x, err := b.DecodeFixed32()
289 writeUnknownInt(w, x, err)
290 case WireFixed64:
291 x, err := b.DecodeFixed64()
292 writeUnknownInt(w, x, err)
293 case WireStartGroup:
294 fmt.Fprint(w, "{")
295 w.indent()
296 case WireVarint:
297 x, err := b.DecodeVarint()
298 writeUnknownInt(w, x, err)
299 default:
300 fmt.Fprintf(w, "/* unknown wire type %d */", wire)
301 }
302 w.WriteByte('\n')
303 }
304}
305
306func writeUnknownInt(w *textWriter, x uint64, err os.Error) {
307 if err == nil {
308 fmt.Fprint(w, x)
309 } else {
310 fmt.Fprintf(w, "/* %v */", err)
311 }
312}
313
314type int32Slice []int32
315
316func (s int32Slice) Len() int { return len(s) }
317func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] }
318func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
319
David Symondse37856c2011-06-22 12:52:53 +1000320// writeExtensions writes all the extensions in pv.
321// pv is assumed to be a pointer to a protocol message struct that is extendable.
322func writeExtensions(w *textWriter, pv reflect.Value) {
323 emap := extensionMaps[pv.Type().Elem()]
324 ep := pv.Interface().(extendableProto)
David Symonds1d72f7a2011-08-19 18:28:52 +1000325
326 // Order the extensions by ID.
327 // This isn't strictly necessary, but it will give us
328 // canonical output, which will also make testing easier.
329 m := ep.ExtensionMap()
330 ids := make([]int32, 0, len(m))
331 for id := range m {
332 ids = append(ids, id)
333 }
334 sort.Sort(int32Slice(ids))
335
336 for _, extNum := range ids {
337 ext := m[extNum]
David Symondse37856c2011-06-22 12:52:53 +1000338 var desc *ExtensionDesc
339 if emap != nil {
340 desc = emap[extNum]
341 }
342 if desc == nil {
David Symonds1d72f7a2011-08-19 18:28:52 +1000343 // Unknown extension.
344 writeUnknownStruct(w, ext.enc)
David Symondse37856c2011-06-22 12:52:53 +1000345 continue
346 }
347
348 pb, err := GetExtension(ep, desc)
349 if err != nil {
350 fmt.Fprintln(os.Stderr, "proto: failed getting extension: ", err)
351 continue
352 }
353
354 fmt.Fprintf(w, "[%s]:", desc.Name)
355 if !w.compact {
356 w.WriteByte(' ')
357 }
358 writeAny(w, reflect.ValueOf(pb), nil)
359 w.WriteByte('\n')
Rob Pikeaaa3a622010-03-20 22:32:34 -0700360 }
361}
362
363func marshalText(w io.Writer, pb interface{}, compact bool) {
David Symonds03c9d412010-08-26 14:23:18 +1000364 if pb == nil {
365 w.Write([]byte("<nil>"))
366 return
367 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700368 aw := new(textWriter)
369 aw.writer = w
370 aw.complete = true
371 aw.compact = compact
372
Nigel Tao4ede8452011-04-28 11:27:25 +1000373 v := reflect.ValueOf(pb)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700374 // We should normally be passed a struct, or a pointer to a struct,
375 // and we don't want the outer < and > in that case.
376 v = reflect.Indirect(v)
David Symondsa9cda212011-04-15 01:23:17 -0700377 if v.Kind() == reflect.Struct {
378 writeStruct(aw, v)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700379 } else {
David Symonds9f402812011-04-28 18:08:44 +1000380 writeAny(aw, v, nil)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700381 }
382}
383
David Symondse37856c2011-06-22 12:52:53 +1000384// MarshalText writes a given protocol buffer in text format.
385// Values that are not protocol buffers can also be written, but their formatting is not guaranteed.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700386func MarshalText(w io.Writer, pb interface{}) { marshalText(w, pb, false) }
387
David Symondse37856c2011-06-22 12:52:53 +1000388// CompactText writes a given protocl buffer in compact text format (one line).
389// Values that are not protocol buffers can also be written, but their formatting is not guaranteed.
Rob Pikeaaa3a622010-03-20 22:32:34 -0700390func CompactText(w io.Writer, pb interface{}) { marshalText(w, pb, true) }
391
392// CompactTextString is the same as CompactText, but returns the string directly.
393func CompactTextString(pb interface{}) string {
394 buf := new(bytes.Buffer)
395 marshalText(buf, pb, true)
396 return buf.String()
397}