blob: 62c55624a8a8c25cfcbc0c09872d118c0b6c0e5e [file] [log] [blame]
Scott Bakereee8dd82019-09-24 12:52:34 -07001// Protocol Buffers for Go with Gadgets
2//
3// Copyright (c) 2013, The GoGo Authors. All rights reserved.
4// http://github.com/gogo/protobuf
5//
6// Go support for Protocol Buffers - Google's data interchange format
7//
8// Copyright 2010 The Go Authors. All rights reserved.
9// https://github.com/golang/protobuf
10//
11// Redistribution and use in source and binary forms, with or without
12// modification, are permitted provided that the following conditions are
13// met:
14//
15// * Redistributions of source code must retain the above copyright
16// notice, this list of conditions and the following disclaimer.
17// * Redistributions in binary form must reproduce the above
18// copyright notice, this list of conditions and the following disclaimer
19// in the documentation and/or other materials provided with the
20// distribution.
21// * Neither the name of Google Inc. nor the names of its
22// contributors may be used to endorse or promote products derived from
23// this software without specific prior written permission.
24//
25// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
37package proto
38
39/*
40 * Routines for encoding data into the wire format for protocol buffers.
41 */
42
43import (
44 "fmt"
45 "log"
46 "os"
47 "reflect"
48 "sort"
49 "strconv"
50 "strings"
51 "sync"
52)
53
54const debug bool = false
55
56// Constants that identify the encoding of a value on the wire.
57const (
58 WireVarint = 0
59 WireFixed64 = 1
60 WireBytes = 2
61 WireStartGroup = 3
62 WireEndGroup = 4
63 WireFixed32 = 5
64)
65
66// tagMap is an optimization over map[int]int for typical protocol buffer
67// use-cases. Encoded protocol buffers are often in tag order with small tag
68// numbers.
69type tagMap struct {
70 fastTags []int
71 slowTags map[int]int
72}
73
74// tagMapFastLimit is the upper bound on the tag number that will be stored in
75// the tagMap slice rather than its map.
76const tagMapFastLimit = 1024
77
78func (p *tagMap) get(t int) (int, bool) {
79 if t > 0 && t < tagMapFastLimit {
80 if t >= len(p.fastTags) {
81 return 0, false
82 }
83 fi := p.fastTags[t]
84 return fi, fi >= 0
85 }
86 fi, ok := p.slowTags[t]
87 return fi, ok
88}
89
90func (p *tagMap) put(t int, fi int) {
91 if t > 0 && t < tagMapFastLimit {
92 for len(p.fastTags) < t+1 {
93 p.fastTags = append(p.fastTags, -1)
94 }
95 p.fastTags[t] = fi
96 return
97 }
98 if p.slowTags == nil {
99 p.slowTags = make(map[int]int)
100 }
101 p.slowTags[t] = fi
102}
103
104// StructProperties represents properties for all the fields of a struct.
105// decoderTags and decoderOrigNames should only be used by the decoder.
106type StructProperties struct {
107 Prop []*Properties // properties for each field
108 reqCount int // required count
109 decoderTags tagMap // map from proto tag to struct field number
110 decoderOrigNames map[string]int // map from original name to struct field number
111 order []int // list of struct field numbers in tag order
112
113 // OneofTypes contains information about the oneof fields in this message.
114 // It is keyed by the original name of a field.
115 OneofTypes map[string]*OneofProperties
116}
117
118// OneofProperties represents information about a specific field in a oneof.
119type OneofProperties struct {
120 Type reflect.Type // pointer to generated struct type for this oneof field
121 Field int // struct field number of the containing oneof in the message
122 Prop *Properties
123}
124
125// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec.
126// See encode.go, (*Buffer).enc_struct.
127
128func (sp *StructProperties) Len() int { return len(sp.order) }
129func (sp *StructProperties) Less(i, j int) bool {
130 return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag
131}
132func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] }
133
134// Properties represents the protocol-specific behavior of a single struct field.
135type Properties struct {
136 Name string // name of the field, for error messages
137 OrigName string // original name before protocol compiler (always set)
138 JSONName string // name to use for JSON; determined by protoc
139 Wire string
140 WireType int
141 Tag int
142 Required bool
143 Optional bool
144 Repeated bool
145 Packed bool // relevant for repeated primitives only
146 Enum string // set for enum types only
147 proto3 bool // whether this is known to be a proto3 field
148 oneof bool // whether this is a oneof field
149
150 Default string // default value
151 HasDefault bool // whether an explicit default was provided
152 CustomType string
153 CastType string
154 StdTime bool
155 StdDuration bool
156 WktPointer bool
157
158 stype reflect.Type // set for struct types only
159 ctype reflect.Type // set for custom types only
160 sprop *StructProperties // set for struct types only
161
162 mtype reflect.Type // set for map types only
163 MapKeyProp *Properties // set for map types only
164 MapValProp *Properties // set for map types only
165}
166
167// String formats the properties in the protobuf struct field tag style.
168func (p *Properties) String() string {
169 s := p.Wire
170 s += ","
171 s += strconv.Itoa(p.Tag)
172 if p.Required {
173 s += ",req"
174 }
175 if p.Optional {
176 s += ",opt"
177 }
178 if p.Repeated {
179 s += ",rep"
180 }
181 if p.Packed {
182 s += ",packed"
183 }
184 s += ",name=" + p.OrigName
185 if p.JSONName != p.OrigName {
186 s += ",json=" + p.JSONName
187 }
188 if p.proto3 {
189 s += ",proto3"
190 }
191 if p.oneof {
192 s += ",oneof"
193 }
194 if len(p.Enum) > 0 {
195 s += ",enum=" + p.Enum
196 }
197 if p.HasDefault {
198 s += ",def=" + p.Default
199 }
200 return s
201}
202
203// Parse populates p by parsing a string in the protobuf struct field tag style.
204func (p *Properties) Parse(s string) {
205 // "bytes,49,opt,name=foo,def=hello!"
206 fields := strings.Split(s, ",") // breaks def=, but handled below.
207 if len(fields) < 2 {
208 fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s)
209 return
210 }
211
212 p.Wire = fields[0]
213 switch p.Wire {
214 case "varint":
215 p.WireType = WireVarint
216 case "fixed32":
217 p.WireType = WireFixed32
218 case "fixed64":
219 p.WireType = WireFixed64
220 case "zigzag32":
221 p.WireType = WireVarint
222 case "zigzag64":
223 p.WireType = WireVarint
224 case "bytes", "group":
225 p.WireType = WireBytes
226 // no numeric converter for non-numeric types
227 default:
228 fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s)
229 return
230 }
231
232 var err error
233 p.Tag, err = strconv.Atoi(fields[1])
234 if err != nil {
235 return
236 }
237
238outer:
239 for i := 2; i < len(fields); i++ {
240 f := fields[i]
241 switch {
242 case f == "req":
243 p.Required = true
244 case f == "opt":
245 p.Optional = true
246 case f == "rep":
247 p.Repeated = true
248 case f == "packed":
249 p.Packed = true
250 case strings.HasPrefix(f, "name="):
251 p.OrigName = f[5:]
252 case strings.HasPrefix(f, "json="):
253 p.JSONName = f[5:]
254 case strings.HasPrefix(f, "enum="):
255 p.Enum = f[5:]
256 case f == "proto3":
257 p.proto3 = true
258 case f == "oneof":
259 p.oneof = true
260 case strings.HasPrefix(f, "def="):
261 p.HasDefault = true
262 p.Default = f[4:] // rest of string
263 if i+1 < len(fields) {
264 // Commas aren't escaped, and def is always last.
265 p.Default += "," + strings.Join(fields[i+1:], ",")
266 break outer
267 }
268 case strings.HasPrefix(f, "embedded="):
269 p.OrigName = strings.Split(f, "=")[1]
270 case strings.HasPrefix(f, "customtype="):
271 p.CustomType = strings.Split(f, "=")[1]
272 case strings.HasPrefix(f, "casttype="):
273 p.CastType = strings.Split(f, "=")[1]
274 case f == "stdtime":
275 p.StdTime = true
276 case f == "stdduration":
277 p.StdDuration = true
278 case f == "wktptr":
279 p.WktPointer = true
280 }
281 }
282}
283
284var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem()
285
286// setFieldProps initializes the field properties for submessages and maps.
287func (p *Properties) setFieldProps(typ reflect.Type, f *reflect.StructField, lockGetProp bool) {
288 isMap := typ.Kind() == reflect.Map
289 if len(p.CustomType) > 0 && !isMap {
290 p.ctype = typ
291 p.setTag(lockGetProp)
292 return
293 }
294 if p.StdTime && !isMap {
295 p.setTag(lockGetProp)
296 return
297 }
298 if p.StdDuration && !isMap {
299 p.setTag(lockGetProp)
300 return
301 }
302 if p.WktPointer && !isMap {
303 p.setTag(lockGetProp)
304 return
305 }
306 switch t1 := typ; t1.Kind() {
307 case reflect.Struct:
308 p.stype = typ
309 case reflect.Ptr:
310 if t1.Elem().Kind() == reflect.Struct {
311 p.stype = t1.Elem()
312 }
313 case reflect.Slice:
314 switch t2 := t1.Elem(); t2.Kind() {
315 case reflect.Ptr:
316 switch t3 := t2.Elem(); t3.Kind() {
317 case reflect.Struct:
318 p.stype = t3
319 }
320 case reflect.Struct:
321 p.stype = t2
322 }
323
324 case reflect.Map:
325
326 p.mtype = t1
327 p.MapKeyProp = &Properties{}
328 p.MapKeyProp.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp)
329 p.MapValProp = &Properties{}
330 vtype := p.mtype.Elem()
331 if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice {
332 // The value type is not a message (*T) or bytes ([]byte),
333 // so we need encoders for the pointer to this type.
334 vtype = reflect.PtrTo(vtype)
335 }
336
337 p.MapValProp.CustomType = p.CustomType
338 p.MapValProp.StdDuration = p.StdDuration
339 p.MapValProp.StdTime = p.StdTime
340 p.MapValProp.WktPointer = p.WktPointer
341 p.MapValProp.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp)
342 }
343 p.setTag(lockGetProp)
344}
345
346func (p *Properties) setTag(lockGetProp bool) {
347 if p.stype != nil {
348 if lockGetProp {
349 p.sprop = GetProperties(p.stype)
350 } else {
351 p.sprop = getPropertiesLocked(p.stype)
352 }
353 }
354}
355
356var (
357 marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
358)
359
360// Init populates the properties from a protocol buffer struct tag.
361func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
362 p.init(typ, name, tag, f, true)
363}
364
365func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) {
366 // "bytes,49,opt,def=hello!"
367 p.Name = name
368 p.OrigName = name
369 if tag == "" {
370 return
371 }
372 p.Parse(tag)
373 p.setFieldProps(typ, f, lockGetProp)
374}
375
376var (
377 propertiesMu sync.RWMutex
378 propertiesMap = make(map[reflect.Type]*StructProperties)
379)
380
381// GetProperties returns the list of properties for the type represented by t.
382// t must represent a generated struct type of a protocol message.
383func GetProperties(t reflect.Type) *StructProperties {
384 if t.Kind() != reflect.Struct {
385 panic("proto: type must have kind struct")
386 }
387
388 // Most calls to GetProperties in a long-running program will be
389 // retrieving details for types we have seen before.
390 propertiesMu.RLock()
391 sprop, ok := propertiesMap[t]
392 propertiesMu.RUnlock()
393 if ok {
394 return sprop
395 }
396
397 propertiesMu.Lock()
398 sprop = getPropertiesLocked(t)
399 propertiesMu.Unlock()
400 return sprop
401}
402
Scott Baker611f6bd2019-10-18 13:45:19 -0700403type (
404 oneofFuncsIface interface {
405 XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
406 }
407 oneofWrappersIface interface {
408 XXX_OneofWrappers() []interface{}
409 }
410)
411
Scott Bakereee8dd82019-09-24 12:52:34 -0700412// getPropertiesLocked requires that propertiesMu is held.
413func getPropertiesLocked(t reflect.Type) *StructProperties {
414 if prop, ok := propertiesMap[t]; ok {
415 return prop
416 }
417
418 prop := new(StructProperties)
419 // in case of recursive protos, fill this in now.
420 propertiesMap[t] = prop
421
422 // build properties
423 prop.Prop = make([]*Properties, t.NumField())
424 prop.order = make([]int, t.NumField())
425
426 isOneofMessage := false
427 for i := 0; i < t.NumField(); i++ {
428 f := t.Field(i)
429 p := new(Properties)
430 name := f.Name
431 p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false)
432
433 oneof := f.Tag.Get("protobuf_oneof") // special case
434 if oneof != "" {
435 isOneofMessage = true
436 // Oneof fields don't use the traditional protobuf tag.
437 p.OrigName = oneof
438 }
439 prop.Prop[i] = p
440 prop.order[i] = i
441 if debug {
442 print(i, " ", f.Name, " ", t.String(), " ")
443 if p.Tag > 0 {
444 print(p.String())
445 }
446 print("\n")
447 }
448 }
449
450 // Re-order prop.order.
451 sort.Sort(prop)
452
Scott Baker611f6bd2019-10-18 13:45:19 -0700453 if isOneofMessage {
Scott Bakereee8dd82019-09-24 12:52:34 -0700454 var oots []interface{}
Scott Baker611f6bd2019-10-18 13:45:19 -0700455 switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) {
456 case oneofFuncsIface:
457 _, _, _, oots = m.XXX_OneofFuncs()
458 case oneofWrappersIface:
459 oots = m.XXX_OneofWrappers()
460 }
461 if len(oots) > 0 {
462 // Interpret oneof metadata.
463 prop.OneofTypes = make(map[string]*OneofProperties)
464 for _, oot := range oots {
465 oop := &OneofProperties{
466 Type: reflect.ValueOf(oot).Type(), // *T
467 Prop: new(Properties),
Scott Bakereee8dd82019-09-24 12:52:34 -0700468 }
Scott Baker611f6bd2019-10-18 13:45:19 -0700469 sft := oop.Type.Elem().Field(0)
470 oop.Prop.Name = sft.Name
471 oop.Prop.Parse(sft.Tag.Get("protobuf"))
472 // There will be exactly one interface field that
473 // this new value is assignable to.
474 for i := 0; i < t.NumField(); i++ {
475 f := t.Field(i)
476 if f.Type.Kind() != reflect.Interface {
477 continue
478 }
479 if !oop.Type.AssignableTo(f.Type) {
480 continue
481 }
482 oop.Field = i
483 break
Scott Bakereee8dd82019-09-24 12:52:34 -0700484 }
Scott Baker611f6bd2019-10-18 13:45:19 -0700485 prop.OneofTypes[oop.Prop.OrigName] = oop
Scott Bakereee8dd82019-09-24 12:52:34 -0700486 }
Scott Bakereee8dd82019-09-24 12:52:34 -0700487 }
488 }
489
490 // build required counts
491 // build tags
492 reqCount := 0
493 prop.decoderOrigNames = make(map[string]int)
494 for i, p := range prop.Prop {
495 if strings.HasPrefix(p.Name, "XXX_") {
496 // Internal fields should not appear in tags/origNames maps.
497 // They are handled specially when encoding and decoding.
498 continue
499 }
500 if p.Required {
501 reqCount++
502 }
503 prop.decoderTags.put(p.Tag, i)
504 prop.decoderOrigNames[p.OrigName] = i
505 }
506 prop.reqCount = reqCount
507
508 return prop
509}
510
511// A global registry of enum types.
512// The generated code will register the generated maps by calling RegisterEnum.
513
514var enumValueMaps = make(map[string]map[string]int32)
515var enumStringMaps = make(map[string]map[int32]string)
516
517// RegisterEnum is called from the generated code to install the enum descriptor
518// maps into the global table to aid parsing text format protocol buffers.
519func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) {
520 if _, ok := enumValueMaps[typeName]; ok {
521 panic("proto: duplicate enum registered: " + typeName)
522 }
523 enumValueMaps[typeName] = valueMap
524 if _, ok := enumStringMaps[typeName]; ok {
525 panic("proto: duplicate enum registered: " + typeName)
526 }
527 enumStringMaps[typeName] = unusedNameMap
528}
529
530// EnumValueMap returns the mapping from names to integers of the
531// enum type enumType, or a nil if not found.
532func EnumValueMap(enumType string) map[string]int32 {
533 return enumValueMaps[enumType]
534}
535
536// A registry of all linked message types.
537// The string is a fully-qualified proto name ("pkg.Message").
538var (
539 protoTypedNils = make(map[string]Message) // a map from proto names to typed nil pointers
540 protoMapTypes = make(map[string]reflect.Type) // a map from proto names to map types
541 revProtoTypes = make(map[reflect.Type]string)
542)
543
544// RegisterType is called from generated code and maps from the fully qualified
545// proto name to the type (pointer to struct) of the protocol buffer.
546func RegisterType(x Message, name string) {
547 if _, ok := protoTypedNils[name]; ok {
548 // TODO: Some day, make this a panic.
549 log.Printf("proto: duplicate proto type registered: %s", name)
550 return
551 }
552 t := reflect.TypeOf(x)
553 if v := reflect.ValueOf(x); v.Kind() == reflect.Ptr && v.Pointer() == 0 {
554 // Generated code always calls RegisterType with nil x.
555 // This check is just for extra safety.
556 protoTypedNils[name] = x
557 } else {
558 protoTypedNils[name] = reflect.Zero(t).Interface().(Message)
559 }
560 revProtoTypes[t] = name
561}
562
563// RegisterMapType is called from generated code and maps from the fully qualified
564// proto name to the native map type of the proto map definition.
565func RegisterMapType(x interface{}, name string) {
566 if reflect.TypeOf(x).Kind() != reflect.Map {
567 panic(fmt.Sprintf("RegisterMapType(%T, %q); want map", x, name))
568 }
569 if _, ok := protoMapTypes[name]; ok {
570 log.Printf("proto: duplicate proto type registered: %s", name)
571 return
572 }
573 t := reflect.TypeOf(x)
574 protoMapTypes[name] = t
575 revProtoTypes[t] = name
576}
577
578// MessageName returns the fully-qualified proto name for the given message type.
579func MessageName(x Message) string {
580 type xname interface {
581 XXX_MessageName() string
582 }
583 if m, ok := x.(xname); ok {
584 return m.XXX_MessageName()
585 }
586 return revProtoTypes[reflect.TypeOf(x)]
587}
588
589// MessageType returns the message type (pointer to struct) for a named message.
590// The type is not guaranteed to implement proto.Message if the name refers to a
591// map entry.
592func MessageType(name string) reflect.Type {
593 if t, ok := protoTypedNils[name]; ok {
594 return reflect.TypeOf(t)
595 }
596 return protoMapTypes[name]
597}
598
599// A registry of all linked proto files.
600var (
601 protoFiles = make(map[string][]byte) // file name => fileDescriptor
602)
603
604// RegisterFile is called from generated code and maps from the
605// full file name of a .proto file to its compressed FileDescriptorProto.
606func RegisterFile(filename string, fileDescriptor []byte) {
607 protoFiles[filename] = fileDescriptor
608}
609
610// FileDescriptor returns the compressed FileDescriptorProto for a .proto file.
611func FileDescriptor(filename string) []byte { return protoFiles[filename] }