]>
Commit | Line | Data |
---|---|---|
15c0b25d AP |
1 | // Go support for Protocol Buffers - Google's data interchange format |
2 | // | |
3 | // Copyright 2010 The Go Authors. All rights reserved. | |
4 | // https://github.com/golang/protobuf | |
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 | "bufio" | |
38 | "bytes" | |
39 | "encoding" | |
40 | "errors" | |
41 | "fmt" | |
42 | "io" | |
43 | "log" | |
44 | "math" | |
45 | "reflect" | |
46 | "sort" | |
47 | "strings" | |
48 | ) | |
49 | ||
50 | var ( | |
51 | newline = []byte("\n") | |
52 | spaces = []byte(" ") | |
53 | endBraceNewline = []byte("}\n") | |
54 | backslashN = []byte{'\\', 'n'} | |
55 | backslashR = []byte{'\\', 'r'} | |
56 | backslashT = []byte{'\\', 't'} | |
57 | backslashDQ = []byte{'\\', '"'} | |
58 | backslashBS = []byte{'\\', '\\'} | |
59 | posInf = []byte("inf") | |
60 | negInf = []byte("-inf") | |
61 | nan = []byte("nan") | |
62 | ) | |
63 | ||
64 | type writer interface { | |
65 | io.Writer | |
66 | WriteByte(byte) error | |
67 | } | |
68 | ||
69 | // textWriter is an io.Writer that tracks its indentation level. | |
70 | type textWriter struct { | |
71 | 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 | |
75 | } | |
76 | ||
77 | func (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 | |
83 | return io.WriteString(w.w, s) | |
84 | } | |
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)) | |
89 | } | |
90 | ||
91 | func (w *textWriter) Write(p []byte) (n int, err error) { | |
92 | newlines := bytes.Count(p, newline) | |
93 | if newlines == 0 { | |
94 | if !w.compact && w.complete { | |
95 | w.writeIndent() | |
96 | } | |
97 | n, err = w.w.Write(p) | |
98 | w.complete = false | |
99 | return n, err | |
100 | } | |
101 | ||
102 | frags := bytes.SplitN(p, newline, newlines+1) | |
103 | if w.compact { | |
104 | for i, frag := range frags { | |
105 | if i > 0 { | |
106 | if err := w.w.WriteByte(' '); err != nil { | |
107 | return n, err | |
108 | } | |
109 | n++ | |
110 | } | |
111 | nn, err := w.w.Write(frag) | |
112 | n += nn | |
113 | if err != nil { | |
114 | return n, err | |
115 | } | |
116 | } | |
117 | return n, nil | |
118 | } | |
119 | ||
120 | for i, frag := range frags { | |
121 | if w.complete { | |
122 | w.writeIndent() | |
123 | } | |
124 | nn, err := w.w.Write(frag) | |
125 | n += nn | |
126 | if err != nil { | |
127 | return n, err | |
128 | } | |
129 | if i+1 < len(frags) { | |
130 | if err := w.w.WriteByte('\n'); err != nil { | |
131 | return n, err | |
132 | } | |
133 | n++ | |
134 | } | |
135 | } | |
136 | w.complete = len(frags[len(frags)-1]) == 0 | |
137 | return n, nil | |
138 | } | |
139 | ||
140 | func (w *textWriter) WriteByte(c byte) error { | |
141 | if w.compact && c == '\n' { | |
142 | c = ' ' | |
143 | } | |
144 | if !w.compact && w.complete { | |
145 | w.writeIndent() | |
146 | } | |
147 | err := w.w.WriteByte(c) | |
148 | w.complete = c == '\n' | |
149 | return err | |
150 | } | |
151 | ||
152 | func (w *textWriter) indent() { w.ind++ } | |
153 | ||
154 | func (w *textWriter) unindent() { | |
155 | if w.ind == 0 { | |
156 | log.Print("proto: textWriter unindented too far") | |
157 | return | |
158 | } | |
159 | w.ind-- | |
160 | } | |
161 | ||
162 | func writeName(w *textWriter, props *Properties) error { | |
163 | if _, err := w.WriteString(props.OrigName); err != nil { | |
164 | return err | |
165 | } | |
166 | if props.Wire != "group" { | |
167 | return w.WriteByte(':') | |
168 | } | |
169 | return nil | |
170 | } | |
171 | ||
172 | func requiresQuotes(u string) bool { | |
173 | // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted. | |
174 | for _, ch := range u { | |
175 | switch { | |
176 | case ch == '.' || ch == '/' || ch == '_': | |
177 | continue | |
178 | case '0' <= ch && ch <= '9': | |
179 | continue | |
180 | case 'A' <= ch && ch <= 'Z': | |
181 | continue | |
182 | case 'a' <= ch && ch <= 'z': | |
183 | continue | |
184 | default: | |
185 | return true | |
186 | } | |
187 | } | |
188 | return false | |
189 | } | |
190 | ||
191 | // isAny reports whether sv is a google.protobuf.Any message | |
192 | func isAny(sv reflect.Value) bool { | |
193 | type wkt interface { | |
194 | XXX_WellKnownType() string | |
195 | } | |
196 | t, ok := sv.Addr().Interface().(wkt) | |
197 | return ok && t.XXX_WellKnownType() == "Any" | |
198 | } | |
199 | ||
200 | // writeProto3Any writes an expanded google.protobuf.Any message. | |
201 | // | |
202 | // It returns (false, nil) if sv value can't be unmarshaled (e.g. because | |
203 | // required messages are not linked in). | |
204 | // | |
205 | // It returns (true, error) when sv was written in expanded format or an error | |
206 | // was encountered. | |
207 | func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) { | |
208 | turl := sv.FieldByName("TypeUrl") | |
209 | val := sv.FieldByName("Value") | |
210 | if !turl.IsValid() || !val.IsValid() { | |
211 | return true, errors.New("proto: invalid google.protobuf.Any message") | |
212 | } | |
213 | ||
214 | b, ok := val.Interface().([]byte) | |
215 | if !ok { | |
216 | return true, errors.New("proto: invalid google.protobuf.Any message") | |
217 | } | |
218 | ||
219 | parts := strings.Split(turl.String(), "/") | |
220 | mt := MessageType(parts[len(parts)-1]) | |
221 | if mt == nil { | |
222 | return false, nil | |
223 | } | |
224 | m := reflect.New(mt.Elem()) | |
225 | if err := Unmarshal(b, m.Interface().(Message)); err != nil { | |
226 | return false, nil | |
227 | } | |
228 | w.Write([]byte("[")) | |
229 | u := turl.String() | |
230 | if requiresQuotes(u) { | |
231 | writeString(w, u) | |
232 | } else { | |
233 | w.Write([]byte(u)) | |
234 | } | |
235 | if w.compact { | |
236 | w.Write([]byte("]:<")) | |
237 | } else { | |
238 | w.Write([]byte("]: <\n")) | |
239 | w.ind++ | |
240 | } | |
241 | if err := tm.writeStruct(w, m.Elem()); err != nil { | |
242 | return true, err | |
243 | } | |
244 | if w.compact { | |
245 | w.Write([]byte("> ")) | |
246 | } else { | |
247 | w.ind-- | |
248 | w.Write([]byte(">\n")) | |
249 | } | |
250 | return true, nil | |
251 | } | |
252 | ||
253 | func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { | |
254 | if tm.ExpandAny && isAny(sv) { | |
255 | if canExpand, err := tm.writeProto3Any(w, sv); canExpand { | |
256 | return err | |
257 | } | |
258 | } | |
259 | st := sv.Type() | |
260 | sprops := GetProperties(st) | |
261 | for i := 0; i < sv.NumField(); i++ { | |
262 | fv := sv.Field(i) | |
263 | props := sprops.Prop[i] | |
264 | name := st.Field(i).Name | |
265 | ||
266 | if name == "XXX_NoUnkeyedLiteral" { | |
267 | continue | |
268 | } | |
269 | ||
270 | if strings.HasPrefix(name, "XXX_") { | |
271 | // There are two XXX_ fields: | |
272 | // XXX_unrecognized []byte | |
273 | // XXX_extensions map[int32]proto.Extension | |
274 | // The first is handled here; | |
275 | // the second is handled at the bottom of this function. | |
276 | if name == "XXX_unrecognized" && !fv.IsNil() { | |
277 | if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil { | |
278 | return err | |
279 | } | |
280 | } | |
281 | continue | |
282 | } | |
283 | if fv.Kind() == reflect.Ptr && fv.IsNil() { | |
284 | // Field not filled in. This could be an optional field or | |
285 | // a required field that wasn't filled in. Either way, there | |
286 | // isn't anything we can show for it. | |
287 | continue | |
288 | } | |
289 | if fv.Kind() == reflect.Slice && fv.IsNil() { | |
290 | // Repeated field that is empty, or a bytes field that is unused. | |
291 | continue | |
292 | } | |
293 | ||
294 | if props.Repeated && fv.Kind() == reflect.Slice { | |
295 | // Repeated field. | |
296 | for j := 0; j < fv.Len(); j++ { | |
297 | if err := writeName(w, props); err != nil { | |
298 | return err | |
299 | } | |
300 | if !w.compact { | |
301 | if err := w.WriteByte(' '); err != nil { | |
302 | return err | |
303 | } | |
304 | } | |
305 | v := fv.Index(j) | |
306 | if v.Kind() == reflect.Ptr && v.IsNil() { | |
307 | // A nil message in a repeated field is not valid, | |
308 | // but we can handle that more gracefully than panicking. | |
309 | if _, err := w.Write([]byte("<nil>\n")); err != nil { | |
310 | return err | |
311 | } | |
312 | continue | |
313 | } | |
314 | if err := tm.writeAny(w, v, props); err != nil { | |
315 | return err | |
316 | } | |
317 | if err := w.WriteByte('\n'); err != nil { | |
318 | return err | |
319 | } | |
320 | } | |
321 | continue | |
322 | } | |
323 | if fv.Kind() == reflect.Map { | |
324 | // Map fields are rendered as a repeated struct with key/value fields. | |
325 | keys := fv.MapKeys() | |
326 | sort.Sort(mapKeys(keys)) | |
327 | for _, key := range keys { | |
328 | val := fv.MapIndex(key) | |
329 | if err := writeName(w, props); err != nil { | |
330 | return err | |
331 | } | |
332 | if !w.compact { | |
333 | if err := w.WriteByte(' '); err != nil { | |
334 | return err | |
335 | } | |
336 | } | |
337 | // open struct | |
338 | if err := w.WriteByte('<'); err != nil { | |
339 | return err | |
340 | } | |
341 | if !w.compact { | |
342 | if err := w.WriteByte('\n'); err != nil { | |
343 | return err | |
344 | } | |
345 | } | |
346 | w.indent() | |
347 | // key | |
348 | if _, err := w.WriteString("key:"); err != nil { | |
349 | return err | |
350 | } | |
351 | if !w.compact { | |
352 | if err := w.WriteByte(' '); err != nil { | |
353 | return err | |
354 | } | |
355 | } | |
356 | if err := tm.writeAny(w, key, props.MapKeyProp); err != nil { | |
357 | return err | |
358 | } | |
359 | if err := w.WriteByte('\n'); err != nil { | |
360 | return err | |
361 | } | |
362 | // nil values aren't legal, but we can avoid panicking because of them. | |
363 | if val.Kind() != reflect.Ptr || !val.IsNil() { | |
364 | // value | |
365 | if _, err := w.WriteString("value:"); err != nil { | |
366 | return err | |
367 | } | |
368 | if !w.compact { | |
369 | if err := w.WriteByte(' '); err != nil { | |
370 | return err | |
371 | } | |
372 | } | |
373 | if err := tm.writeAny(w, val, props.MapValProp); err != nil { | |
374 | return err | |
375 | } | |
376 | if err := w.WriteByte('\n'); err != nil { | |
377 | return err | |
378 | } | |
379 | } | |
380 | // close struct | |
381 | w.unindent() | |
382 | if err := w.WriteByte('>'); err != nil { | |
383 | return err | |
384 | } | |
385 | if err := w.WriteByte('\n'); err != nil { | |
386 | return err | |
387 | } | |
388 | } | |
389 | continue | |
390 | } | |
391 | if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 { | |
392 | // empty bytes field | |
393 | continue | |
394 | } | |
395 | if fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice { | |
396 | // proto3 non-repeated scalar field; skip if zero value | |
397 | if isProto3Zero(fv) { | |
398 | continue | |
399 | } | |
400 | } | |
401 | ||
402 | if fv.Kind() == reflect.Interface { | |
403 | // Check if it is a oneof. | |
404 | if st.Field(i).Tag.Get("protobuf_oneof") != "" { | |
405 | // fv is nil, or holds a pointer to generated struct. | |
406 | // That generated struct has exactly one field, | |
407 | // which has a protobuf struct tag. | |
408 | if fv.IsNil() { | |
409 | continue | |
410 | } | |
411 | inner := fv.Elem().Elem() // interface -> *T -> T | |
412 | tag := inner.Type().Field(0).Tag.Get("protobuf") | |
413 | props = new(Properties) // Overwrite the outer props var, but not its pointee. | |
414 | props.Parse(tag) | |
415 | // Write the value in the oneof, not the oneof itself. | |
416 | fv = inner.Field(0) | |
417 | ||
418 | // Special case to cope with malformed messages gracefully: | |
419 | // If the value in the oneof is a nil pointer, don't panic | |
420 | // in writeAny. | |
421 | if fv.Kind() == reflect.Ptr && fv.IsNil() { | |
422 | // Use errors.New so writeAny won't render quotes. | |
423 | msg := errors.New("/* nil */") | |
424 | fv = reflect.ValueOf(&msg).Elem() | |
425 | } | |
426 | } | |
427 | } | |
428 | ||
429 | if err := writeName(w, props); err != nil { | |
430 | return err | |
431 | } | |
432 | if !w.compact { | |
433 | if err := w.WriteByte(' '); err != nil { | |
434 | return err | |
435 | } | |
436 | } | |
437 | ||
438 | // Enums have a String method, so writeAny will work fine. | |
439 | if err := tm.writeAny(w, fv, props); err != nil { | |
440 | return err | |
441 | } | |
442 | ||
443 | if err := w.WriteByte('\n'); err != nil { | |
444 | return err | |
445 | } | |
446 | } | |
447 | ||
448 | // Extensions (the XXX_extensions field). | |
449 | pv := sv.Addr() | |
450 | if _, err := extendable(pv.Interface()); err == nil { | |
451 | if err := tm.writeExtensions(w, pv); err != nil { | |
452 | return err | |
453 | } | |
454 | } | |
455 | ||
456 | return nil | |
457 | } | |
458 | ||
459 | // writeAny writes an arbitrary field. | |
460 | func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error { | |
461 | v = reflect.Indirect(v) | |
462 | ||
463 | // Floats have special cases. | |
464 | if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 { | |
465 | x := v.Float() | |
466 | var b []byte | |
467 | switch { | |
468 | case math.IsInf(x, 1): | |
469 | b = posInf | |
470 | case math.IsInf(x, -1): | |
471 | b = negInf | |
472 | case math.IsNaN(x): | |
473 | b = nan | |
474 | } | |
475 | if b != nil { | |
476 | _, err := w.Write(b) | |
477 | return err | |
478 | } | |
479 | // Other values are handled below. | |
480 | } | |
481 | ||
482 | // We don't attempt to serialise every possible value type; only those | |
483 | // that can occur in protocol buffers. | |
484 | switch v.Kind() { | |
485 | case reflect.Slice: | |
486 | // Should only be a []byte; repeated fields are handled in writeStruct. | |
487 | if err := writeString(w, string(v.Bytes())); err != nil { | |
488 | return err | |
489 | } | |
490 | case reflect.String: | |
491 | if err := writeString(w, v.String()); err != nil { | |
492 | return err | |
493 | } | |
494 | case reflect.Struct: | |
495 | // Required/optional group/message. | |
496 | var bra, ket byte = '<', '>' | |
497 | if props != nil && props.Wire == "group" { | |
498 | bra, ket = '{', '}' | |
499 | } | |
500 | if err := w.WriteByte(bra); err != nil { | |
501 | return err | |
502 | } | |
503 | if !w.compact { | |
504 | if err := w.WriteByte('\n'); err != nil { | |
505 | return err | |
506 | } | |
507 | } | |
508 | w.indent() | |
509 | if v.CanAddr() { | |
510 | // Calling v.Interface on a struct causes the reflect package to | |
511 | // copy the entire struct. This is racy with the new Marshaler | |
512 | // since we atomically update the XXX_sizecache. | |
513 | // | |
514 | // Thus, we retrieve a pointer to the struct if possible to avoid | |
515 | // a race since v.Interface on the pointer doesn't copy the struct. | |
516 | // | |
517 | // If v is not addressable, then we are not worried about a race | |
518 | // since it implies that the binary Marshaler cannot possibly be | |
519 | // mutating this value. | |
520 | v = v.Addr() | |
521 | } | |
522 | if etm, ok := v.Interface().(encoding.TextMarshaler); ok { | |
523 | text, err := etm.MarshalText() | |
524 | if err != nil { | |
525 | return err | |
526 | } | |
527 | if _, err = w.Write(text); err != nil { | |
528 | return err | |
529 | } | |
530 | } else { | |
531 | if v.Kind() == reflect.Ptr { | |
532 | v = v.Elem() | |
533 | } | |
534 | if err := tm.writeStruct(w, v); err != nil { | |
535 | return err | |
536 | } | |
537 | } | |
538 | w.unindent() | |
539 | if err := w.WriteByte(ket); err != nil { | |
540 | return err | |
541 | } | |
542 | default: | |
543 | _, err := fmt.Fprint(w, v.Interface()) | |
544 | return err | |
545 | } | |
546 | return nil | |
547 | } | |
548 | ||
549 | // equivalent to C's isprint. | |
550 | func isprint(c byte) bool { | |
551 | return c >= 0x20 && c < 0x7f | |
552 | } | |
553 | ||
554 | // writeString writes a string in the protocol buffer text format. | |
555 | // It is similar to strconv.Quote except we don't use Go escape sequences, | |
556 | // we treat the string as a byte sequence, and we use octal escapes. | |
557 | // These differences are to maintain interoperability with the other | |
558 | // languages' implementations of the text format. | |
559 | func writeString(w *textWriter, s string) error { | |
560 | // use WriteByte here to get any needed indent | |
561 | if err := w.WriteByte('"'); err != nil { | |
562 | return err | |
563 | } | |
564 | // Loop over the bytes, not the runes. | |
565 | for i := 0; i < len(s); i++ { | |
566 | var err error | |
567 | // Divergence from C++: we don't escape apostrophes. | |
568 | // There's no need to escape them, and the C++ parser | |
569 | // copes with a naked apostrophe. | |
570 | switch c := s[i]; c { | |
571 | case '\n': | |
572 | _, err = w.w.Write(backslashN) | |
573 | case '\r': | |
574 | _, err = w.w.Write(backslashR) | |
575 | case '\t': | |
576 | _, err = w.w.Write(backslashT) | |
577 | case '"': | |
578 | _, err = w.w.Write(backslashDQ) | |
579 | case '\\': | |
580 | _, err = w.w.Write(backslashBS) | |
581 | default: | |
582 | if isprint(c) { | |
583 | err = w.w.WriteByte(c) | |
584 | } else { | |
585 | _, err = fmt.Fprintf(w.w, "\\%03o", c) | |
586 | } | |
587 | } | |
588 | if err != nil { | |
589 | return err | |
590 | } | |
591 | } | |
592 | return w.WriteByte('"') | |
593 | } | |
594 | ||
595 | func writeUnknownStruct(w *textWriter, data []byte) (err error) { | |
596 | if !w.compact { | |
597 | if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil { | |
598 | return err | |
599 | } | |
600 | } | |
601 | b := NewBuffer(data) | |
602 | for b.index < len(b.buf) { | |
603 | x, err := b.DecodeVarint() | |
604 | if err != nil { | |
605 | _, err := fmt.Fprintf(w, "/* %v */\n", err) | |
606 | return err | |
607 | } | |
608 | wire, tag := x&7, x>>3 | |
609 | if wire == WireEndGroup { | |
610 | w.unindent() | |
611 | if _, err := w.Write(endBraceNewline); err != nil { | |
612 | return err | |
613 | } | |
614 | continue | |
615 | } | |
616 | if _, err := fmt.Fprint(w, tag); err != nil { | |
617 | return err | |
618 | } | |
619 | if wire != WireStartGroup { | |
620 | if err := w.WriteByte(':'); err != nil { | |
621 | return err | |
622 | } | |
623 | } | |
624 | if !w.compact || wire == WireStartGroup { | |
625 | if err := w.WriteByte(' '); err != nil { | |
626 | return err | |
627 | } | |
628 | } | |
629 | switch wire { | |
630 | case WireBytes: | |
631 | buf, e := b.DecodeRawBytes(false) | |
632 | if e == nil { | |
633 | _, err = fmt.Fprintf(w, "%q", buf) | |
634 | } else { | |
635 | _, err = fmt.Fprintf(w, "/* %v */", e) | |
636 | } | |
637 | case WireFixed32: | |
638 | x, err = b.DecodeFixed32() | |
639 | err = writeUnknownInt(w, x, err) | |
640 | case WireFixed64: | |
641 | x, err = b.DecodeFixed64() | |
642 | err = writeUnknownInt(w, x, err) | |
643 | case WireStartGroup: | |
644 | err = w.WriteByte('{') | |
645 | w.indent() | |
646 | case WireVarint: | |
647 | x, err = b.DecodeVarint() | |
648 | err = writeUnknownInt(w, x, err) | |
649 | default: | |
650 | _, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire) | |
651 | } | |
652 | if err != nil { | |
653 | return err | |
654 | } | |
655 | if err = w.WriteByte('\n'); err != nil { | |
656 | return err | |
657 | } | |
658 | } | |
659 | return nil | |
660 | } | |
661 | ||
662 | func writeUnknownInt(w *textWriter, x uint64, err error) error { | |
663 | if err == nil { | |
664 | _, err = fmt.Fprint(w, x) | |
665 | } else { | |
666 | _, err = fmt.Fprintf(w, "/* %v */", err) | |
667 | } | |
668 | return err | |
669 | } | |
670 | ||
671 | type int32Slice []int32 | |
672 | ||
673 | func (s int32Slice) Len() int { return len(s) } | |
674 | func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] } | |
675 | func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } | |
676 | ||
677 | // writeExtensions writes all the extensions in pv. | |
678 | // pv is assumed to be a pointer to a protocol message struct that is extendable. | |
679 | func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error { | |
680 | emap := extensionMaps[pv.Type().Elem()] | |
681 | ep, _ := extendable(pv.Interface()) | |
682 | ||
683 | // Order the extensions by ID. | |
684 | // This isn't strictly necessary, but it will give us | |
685 | // canonical output, which will also make testing easier. | |
686 | m, mu := ep.extensionsRead() | |
687 | if m == nil { | |
688 | return nil | |
689 | } | |
690 | mu.Lock() | |
691 | ids := make([]int32, 0, len(m)) | |
692 | for id := range m { | |
693 | ids = append(ids, id) | |
694 | } | |
695 | sort.Sort(int32Slice(ids)) | |
696 | mu.Unlock() | |
697 | ||
698 | for _, extNum := range ids { | |
699 | ext := m[extNum] | |
700 | var desc *ExtensionDesc | |
701 | if emap != nil { | |
702 | desc = emap[extNum] | |
703 | } | |
704 | if desc == nil { | |
705 | // Unknown extension. | |
706 | if err := writeUnknownStruct(w, ext.enc); err != nil { | |
707 | return err | |
708 | } | |
709 | continue | |
710 | } | |
711 | ||
712 | pb, err := GetExtension(ep, desc) | |
713 | if err != nil { | |
714 | return fmt.Errorf("failed getting extension: %v", err) | |
715 | } | |
716 | ||
717 | // Repeated extensions will appear as a slice. | |
718 | if !desc.repeated() { | |
719 | if err := tm.writeExtension(w, desc.Name, pb); err != nil { | |
720 | return err | |
721 | } | |
722 | } else { | |
723 | v := reflect.ValueOf(pb) | |
724 | for i := 0; i < v.Len(); i++ { | |
725 | if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil { | |
726 | return err | |
727 | } | |
728 | } | |
729 | } | |
730 | } | |
731 | return nil | |
732 | } | |
733 | ||
734 | func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error { | |
735 | if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil { | |
736 | return err | |
737 | } | |
738 | if !w.compact { | |
739 | if err := w.WriteByte(' '); err != nil { | |
740 | return err | |
741 | } | |
742 | } | |
743 | if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil { | |
744 | return err | |
745 | } | |
746 | if err := w.WriteByte('\n'); err != nil { | |
747 | return err | |
748 | } | |
749 | return nil | |
750 | } | |
751 | ||
752 | func (w *textWriter) writeIndent() { | |
753 | if !w.complete { | |
754 | return | |
755 | } | |
756 | remain := w.ind * 2 | |
757 | for remain > 0 { | |
758 | n := remain | |
759 | if n > len(spaces) { | |
760 | n = len(spaces) | |
761 | } | |
762 | w.w.Write(spaces[:n]) | |
763 | remain -= n | |
764 | } | |
765 | w.complete = false | |
766 | } | |
767 | ||
768 | // TextMarshaler is a configurable text format marshaler. | |
769 | type TextMarshaler struct { | |
770 | Compact bool // use compact text format (one line). | |
771 | ExpandAny bool // expand google.protobuf.Any messages of known types | |
772 | } | |
773 | ||
774 | // Marshal writes a given protocol buffer in text format. | |
775 | // The only errors returned are from w. | |
776 | func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error { | |
777 | val := reflect.ValueOf(pb) | |
778 | if pb == nil || val.IsNil() { | |
779 | w.Write([]byte("<nil>")) | |
780 | return nil | |
781 | } | |
782 | var bw *bufio.Writer | |
783 | ww, ok := w.(writer) | |
784 | if !ok { | |
785 | bw = bufio.NewWriter(w) | |
786 | ww = bw | |
787 | } | |
788 | aw := &textWriter{ | |
789 | w: ww, | |
790 | complete: true, | |
791 | compact: tm.Compact, | |
792 | } | |
793 | ||
794 | if etm, ok := pb.(encoding.TextMarshaler); ok { | |
795 | text, err := etm.MarshalText() | |
796 | if err != nil { | |
797 | return err | |
798 | } | |
799 | if _, err = aw.Write(text); err != nil { | |
800 | return err | |
801 | } | |
802 | if bw != nil { | |
803 | return bw.Flush() | |
804 | } | |
805 | return nil | |
806 | } | |
807 | // Dereference the received pointer so we don't have outer < and >. | |
808 | v := reflect.Indirect(val) | |
809 | if err := tm.writeStruct(aw, v); err != nil { | |
810 | return err | |
811 | } | |
812 | if bw != nil { | |
813 | return bw.Flush() | |
814 | } | |
815 | return nil | |
816 | } | |
817 | ||
818 | // Text is the same as Marshal, but returns the string directly. | |
819 | func (tm *TextMarshaler) Text(pb Message) string { | |
820 | var buf bytes.Buffer | |
821 | tm.Marshal(&buf, pb) | |
822 | return buf.String() | |
823 | } | |
824 | ||
825 | var ( | |
826 | defaultTextMarshaler = TextMarshaler{} | |
827 | compactTextMarshaler = TextMarshaler{Compact: true} | |
828 | ) | |
829 | ||
830 | // TODO: consider removing some of the Marshal functions below. | |
831 | ||
832 | // MarshalText writes a given protocol buffer in text format. | |
833 | // The only errors returned are from w. | |
834 | func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) } | |
835 | ||
836 | // MarshalTextString is the same as MarshalText, but returns the string directly. | |
837 | func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) } | |
838 | ||
839 | // CompactText writes a given protocol buffer in compact text format (one line). | |
840 | func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) } | |
841 | ||
842 | // CompactTextString is the same as CompactText, but returns the string directly. | |
843 | func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) } |