initialise
[debian/goprotobuf.git] / proto / text.go
1 // 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
32 package proto
33
34 // Functions for writing the text protocol buffer format.
35
36 import (
37         "bytes"
38         "fmt"
39         "io"
40         "log"
41         "os"
42         "reflect"
43         "sort"
44         "strings"
45 )
46
47 // textWriter is an io.Writer that tracks its indentation level.
48 type textWriter struct {
49         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
53
54         c [1]byte // scratch
55 }
56
57 func (w *textWriter) Write(p []byte) (n int, err os.Error) {
58         n, err = len(p), nil
59
60         frags := strings.Split(string(p), "\n")
61         if w.compact {
62                 w.writer.Write([]byte(strings.Join(frags, " ")))
63                 return
64         }
65
66         for i, frag := range frags {
67                 if w.complete {
68                         for j := 0; j < w.ind; j++ {
69                                 w.writer.Write([]byte{' ', ' '})
70                         }
71                         w.complete = false
72                 }
73
74                 w.writer.Write([]byte(frag))
75                 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
84 func (w *textWriter) WriteByte(c byte) os.Error {
85         w.c[0] = c
86         _, err := w.Write(w.c[:])
87         return err
88 }
89
90 func (w *textWriter) indent() { w.ind++ }
91
92 func (w *textWriter) unindent() {
93         if w.ind == 0 {
94                 log.Printf("proto: textWriter unindented too far!")
95                 return
96         }
97         w.ind--
98 }
99
100 func writeName(w *textWriter, props *Properties) {
101         io.WriteString(w, props.OrigName)
102         if props.Wire != "group" {
103                 w.WriteByte(':')
104         }
105 }
106
107 var (
108         messageSetType      = reflect.TypeOf((*MessageSet)(nil)).Elem()
109         extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem()
110 )
111
112 func writeStruct(w *textWriter, sv reflect.Value) {
113         if sv.Type() == messageSetType {
114                 writeMessageSet(w, sv.Addr().Interface().(*MessageSet))
115                 return
116         }
117
118         st := sv.Type()
119         sprops := GetProperties(st)
120         for i := 0; i < sv.NumField(); i++ {
121                 fv := sv.Field(i)
122                 if name := st.Field(i).Name; strings.HasPrefix(name, "XXX_") {
123                         // There's only two XXX_ fields:
124                         //   XXX_unrecognized []byte
125                         //   XXX_extensions   map[int32]proto.Extension
126                         // The first is handled here;
127                         // the second is handled at the bottom of this function.
128                         if name == "XXX_unrecognized" && !fv.IsNil() {
129                                 writeUnknownStruct(w, fv.Interface().([]byte))
130                         }
131                         continue
132                 }
133                 props := sprops.Prop[i]
134                 if fv.Kind() == reflect.Ptr && fv.IsNil() {
135                         // Field not filled in. This could be an optional field or
136                         // a required field that wasn't filled in. Either way, there
137                         // isn't anything we can show for it.
138                         continue
139                 }
140                 if fv.Kind() == reflect.Slice && fv.IsNil() {
141                         // Repeated field that is empty, or a bytes field that is unused.
142                         continue
143                 }
144
145                 if props.Repeated && fv.Kind() == reflect.Slice {
146                         // Repeated field.
147                         for j := 0; j < fv.Len(); j++ {
148                                 writeName(w, props)
149                                 if !w.compact {
150                                         w.WriteByte(' ')
151                                 }
152                                 writeAny(w, fv.Index(j), props)
153                                 w.WriteByte('\n')
154                         }
155                         continue
156                 }
157
158                 writeName(w, props)
159                 if !w.compact {
160                         w.WriteByte(' ')
161                 }
162                 if props.Enum != "" && tryWriteEnum(w, props.Enum, fv) {
163                         // Enum written.
164                 } else {
165                         writeAny(w, fv, props)
166                 }
167                 w.WriteByte('\n')
168         }
169
170         // Extensions (the XXX_extensions field).
171         pv := sv.Addr()
172         if pv.Type().Implements(extendableProtoType) {
173                 writeExtensions(w, pv)
174         }
175 }
176
177 // tryWriteEnum attempts to write an enum value as a symbolic constant.
178 // If the enum is unregistered, nothing is written and false is returned.
179 func tryWriteEnum(w *textWriter, enum string, v reflect.Value) bool {
180         v = reflect.Indirect(v)
181         if v.Type().Kind() != reflect.Int32 {
182                 return false
183         }
184         m, ok := enumNameMaps[enum]
185         if !ok {
186                 return false
187         }
188         str, ok := m[int32(v.Int())]
189         if !ok {
190                 return false
191         }
192         fmt.Fprintf(w, str)
193         return true
194 }
195
196 // writeAny writes an arbitrary field.
197 func writeAny(w *textWriter, v reflect.Value, props *Properties) {
198         v = reflect.Indirect(v)
199
200         // We don't attempt to serialise every possible value type; only those
201         // that can occur in protocol buffers, plus a few extra that were easy.
202         switch v.Kind() {
203         case reflect.Slice:
204                 // Should only be a []byte; repeated fields are handled in writeStruct.
205                 writeString(w, string(v.Interface().([]byte)))
206         case reflect.String:
207                 writeString(w, v.String())
208         case reflect.Struct:
209                 // Required/optional group/message.
210                 var bra, ket byte = '<', '>'
211                 if props != nil && props.Wire == "group" {
212                         bra, ket = '{', '}'
213                 }
214                 w.WriteByte(bra)
215                 if !w.compact {
216                         w.WriteByte('\n')
217                 }
218                 w.indent()
219                 writeStruct(w, v)
220                 w.unindent()
221                 w.WriteByte(ket)
222         default:
223                 fmt.Fprint(w, v.Interface())
224         }
225 }
226
227 // equivalent to C's isprint.
228 func isprint(c byte) bool {
229         return c >= 0x20 && c < 0x7f
230 }
231
232 // writeString writes a string in the protocol buffer text format.
233 // It is similar to strconv.Quote except we don't use Go escape sequences,
234 // we treat the string as a byte sequence, and we use octal escapes.
235 // These differences are to maintain interoperability with the other
236 // languages' implementations of the text format.
237 func writeString(w *textWriter, s string) {
238         w.WriteByte('"')
239
240         // Loop over the bytes, not the runes.
241         for i := 0; i < len(s); i++ {
242                 // Divergence from C++: we don't escape apostrophes.
243                 // There's no need to escape them, and the C++ parser
244                 // copes with a naked apostrophe.
245                 switch c := s[i]; c {
246                 case '\n':
247                         w.Write([]byte{'\\', 'n'})
248                 case '\r':
249                         w.Write([]byte{'\\', 'r'})
250                 case '\t':
251                         w.Write([]byte{'\\', 't'})
252                 case '"':
253                         w.Write([]byte{'\\', '"'})
254                 case '\\':
255                         w.Write([]byte{'\\', '\\'})
256                 default:
257                         if isprint(c) {
258                                 w.WriteByte(c)
259                         } else {
260                                 fmt.Fprintf(w, "\\%03o", c)
261                         }
262                 }
263         }
264
265         w.WriteByte('"')
266 }
267
268 func writeMessageSet(w *textWriter, ms *MessageSet) {
269         for _, item := range ms.Item {
270                 id := *item.TypeId
271                 if msd, ok := messageSetMap[id]; ok {
272                         // Known message set type.
273                         fmt.Fprintf(w, "[%s]: <\n", msd.name)
274                         w.indent()
275
276                         pb := reflect.New(msd.t.Elem())
277                         if err := Unmarshal(item.Message, pb.Interface()); err != nil {
278                                 fmt.Fprintf(w, "/* bad message: %v */\n", err)
279                         } else {
280                                 writeStruct(w, pb.Elem())
281                         }
282                 } else {
283                         // Unknown type.
284                         fmt.Fprintf(w, "[%d]: <\n", id)
285                         w.indent()
286                         writeUnknownStruct(w, item.Message)
287                 }
288                 w.unindent()
289                 w.Write([]byte(">\n"))
290         }
291 }
292
293 func writeUnknownStruct(w *textWriter, data []byte) {
294         if !w.compact {
295                 fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data))
296         }
297         b := NewBuffer(data)
298         for b.index < len(b.buf) {
299                 x, err := b.DecodeVarint()
300                 if err != nil {
301                         fmt.Fprintf(w, "/* %v */\n", err)
302                         return
303                 }
304                 wire, tag := x&7, x>>3
305                 if wire == WireEndGroup {
306                         w.unindent()
307                         w.Write([]byte("}\n"))
308                         continue
309                 }
310                 fmt.Fprintf(w, "tag%d", tag)
311                 if wire != WireStartGroup {
312                         w.WriteByte(':')
313                 }
314                 if !w.compact || wire == WireStartGroup {
315                         w.WriteByte(' ')
316                 }
317                 switch wire {
318                 case WireBytes:
319                         buf, err := b.DecodeRawBytes(false)
320                         if err == nil {
321                                 fmt.Fprintf(w, "%q", buf)
322                         } else {
323                                 fmt.Fprintf(w, "/* %v */", err)
324                         }
325                 case WireFixed32:
326                         x, err := b.DecodeFixed32()
327                         writeUnknownInt(w, x, err)
328                 case WireFixed64:
329                         x, err := b.DecodeFixed64()
330                         writeUnknownInt(w, x, err)
331                 case WireStartGroup:
332                         fmt.Fprint(w, "{")
333                         w.indent()
334                 case WireVarint:
335                         x, err := b.DecodeVarint()
336                         writeUnknownInt(w, x, err)
337                 default:
338                         fmt.Fprintf(w, "/* unknown wire type %d */", wire)
339                 }
340                 w.WriteByte('\n')
341         }
342 }
343
344 func writeUnknownInt(w *textWriter, x uint64, err os.Error) {
345         if err == nil {
346                 fmt.Fprint(w, x)
347         } else {
348                 fmt.Fprintf(w, "/* %v */", err)
349         }
350 }
351
352 type int32Slice []int32
353
354 func (s int32Slice) Len() int           { return len(s) }
355 func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] }
356 func (s int32Slice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
357
358 // writeExtensions writes all the extensions in pv.
359 // pv is assumed to be a pointer to a protocol message struct that is extendable.
360 func writeExtensions(w *textWriter, pv reflect.Value) {
361         emap := extensionMaps[pv.Type().Elem()]
362         ep := pv.Interface().(extendableProto)
363
364         // Order the extensions by ID.
365         // This isn't strictly necessary, but it will give us
366         // canonical output, which will also make testing easier.
367         m := ep.ExtensionMap()
368         ids := make([]int32, 0, len(m))
369         for id := range m {
370                 ids = append(ids, id)
371         }
372         sort.Sort(int32Slice(ids))
373
374         for _, extNum := range ids {
375                 ext := m[extNum]
376                 var desc *ExtensionDesc
377                 if emap != nil {
378                         desc = emap[extNum]
379                 }
380                 if desc == nil {
381                         // Unknown extension.
382                         writeUnknownStruct(w, ext.enc)
383                         continue
384                 }
385
386                 pb, err := GetExtension(ep, desc)
387                 if err != nil {
388                         fmt.Fprintln(os.Stderr, "proto: failed getting extension: ", err)
389                         continue
390                 }
391
392                 fmt.Fprintf(w, "[%s]:", desc.Name)
393                 if !w.compact {
394                         w.WriteByte(' ')
395                 }
396                 writeAny(w, reflect.ValueOf(pb), nil)
397                 w.WriteByte('\n')
398         }
399 }
400
401 func marshalText(w io.Writer, pb interface{}, compact bool) {
402         if pb == nil {
403                 w.Write([]byte("<nil>"))
404                 return
405         }
406         aw := new(textWriter)
407         aw.writer = w
408         aw.complete = true
409         aw.compact = compact
410
411         v := reflect.ValueOf(pb)
412         // We should normally be passed a struct, or a pointer to a struct,
413         // and we don't want the outer < and > in that case.
414         v = reflect.Indirect(v)
415         if v.Kind() == reflect.Struct {
416                 writeStruct(aw, v)
417         } else {
418                 writeAny(aw, v, nil)
419         }
420 }
421
422 // MarshalText writes a given protocol buffer in text format.
423 // Values that are not protocol buffers can also be written, but their formatting is not guaranteed.
424 func MarshalText(w io.Writer, pb interface{}) { marshalText(w, pb, false) }
425
426 // CompactText writes a given protocl buffer in compact text format (one line).
427 // Values that are not protocol buffers can also be written, but their formatting is not guaranteed.
428 func CompactText(w io.Writer, pb interface{}) { marshalText(w, pb, true) }
429
430 // CompactTextString is the same as CompactText, but returns the string directly.
431 func CompactTextString(pb interface{}) string {
432         buf := new(bytes.Buffer)
433         marshalText(buf, pb, true)
434         return buf.String()
435 }