blob: 9ff1968827ff83080e3f34b74541959b3f5efa32 [file] [log] [blame]
Rob Pikeaaa3a622010-03-20 22:32:34 -07001// Go support for Protocol Buffers - Google's data interchange format
2//
David Symondsee6e9c52012-11-29 08:51:07 +11003// Copyright 2010 The Go Authors. All rights reserved.
Rob Pikeaaa3a622010-03-20 22:32:34 -07004// 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
Rob Pikeaaa3a622010-03-20 22:32:34 -070034/*
35 * Types and routines for supporting protocol buffer extensions.
36 */
37
38import (
Rob Pikea17fdd92011-11-02 12:43:05 -070039 "errors"
Rob Pikeaaa3a622010-03-20 22:32:34 -070040 "reflect"
David Symondse37856c2011-06-22 12:52:53 +100041 "strconv"
Rob Pikeaaa3a622010-03-20 22:32:34 -070042)
43
David Symondsa7e9ef92012-01-18 18:27:58 +110044// ErrMissingExtension is the error returned by GetExtension if the named extension is not in the message.
45var ErrMissingExtension = errors.New("proto: missing extension")
46
Rob Pikeaaa3a622010-03-20 22:32:34 -070047// ExtensionRange represents a range of message extensions for a protocol buffer.
48// Used in code generated by the protocol compiler.
49type ExtensionRange struct {
50 Start, End int32 // both inclusive
51}
52
53// extendableProto is an interface implemented by any protocol buffer that may be extended.
54type extendableProto interface {
David Symonds9f60f432012-06-14 09:45:25 +100055 Message
Rob Pikeaaa3a622010-03-20 22:32:34 -070056 ExtensionRangeArray() []ExtensionRange
David Symonds1d72f7a2011-08-19 18:28:52 +100057 ExtensionMap() map[int32]Extension
Rob Pikeaaa3a622010-03-20 22:32:34 -070058}
59
Russ Coxd4ce3f12012-09-12 10:36:26 +100060var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem()
61
Rob Pikeaaa3a622010-03-20 22:32:34 -070062// ExtensionDesc represents an extension specification.
63// Used in generated code from the protocol compiler.
64type ExtensionDesc struct {
David Symonds9f60f432012-06-14 09:45:25 +100065 ExtendedType Message // nil pointer to the type that is being extended
Rob Pikeaaa3a622010-03-20 22:32:34 -070066 ExtensionType interface{} // nil pointer to the extension type
67 Field int32 // field number
David Symondsc057ad52012-02-11 15:43:42 +110068 Name string // fully-qualified name of extension, for text formatting
David Symonds8935abf2011-07-04 15:53:16 +100069 Tag string // protobuf tag style
Rob Pikeaaa3a622010-03-20 22:32:34 -070070}
71
David Symonds61826da2012-05-05 09:31:28 +100072func (ed *ExtensionDesc) repeated() bool {
73 t := reflect.TypeOf(ed.ExtensionType)
74 return t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8
75}
76
David Symondsf511ee32012-09-06 11:36:28 +100077// Extension represents an extension in a message.
David Symonds1d72f7a2011-08-19 18:28:52 +100078type Extension struct {
David Symondsf511ee32012-09-06 11:36:28 +100079 // When an extension is stored in a message using SetExtension
80 // only desc and value are set. When the message is marshaled
81 // enc will be set to the encoded form of the message.
82 //
83 // When a message is unmarshaled and contains extensions, each
84 // extension will have only enc set. When such an extension is
85 // accessed using GetExtension (or GetExtensions) desc and value
86 // will be set.
David Symonds1d72f7a2011-08-19 18:28:52 +100087 desc *ExtensionDesc
88 value interface{}
89 enc []byte
90}
91
92// SetRawExtension is for testing only.
93func SetRawExtension(base extendableProto, id int32, b []byte) {
94 base.ExtensionMap()[id] = Extension{enc: b}
95}
96
David Symonds940b9612011-04-01 10:45:23 +110097// isExtensionField returns true iff the given field number is in an extension range.
98func isExtensionField(pb extendableProto, field int32) bool {
99 for _, er := range pb.ExtensionRangeArray() {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700100 if er.Start <= field && field <= er.End {
101 return true
102 }
103 }
104 return false
105}
106
David Symonds940b9612011-04-01 10:45:23 +1100107// checkExtensionTypes checks that the given extension is valid for pb.
Rob Pikea17fdd92011-11-02 12:43:05 -0700108func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700109 // Check the extended type.
Nigel Tao4ede8452011-04-28 11:27:25 +1000110 if a, b := reflect.TypeOf(pb), reflect.TypeOf(extension.ExtendedType); a != b {
Rob Pikea17fdd92011-11-02 12:43:05 -0700111 return errors.New("bad extended type; " + b.String() + " does not extend " + a.String())
Rob Pikeaaa3a622010-03-20 22:32:34 -0700112 }
113 // Check the range.
David Symonds940b9612011-04-01 10:45:23 +1100114 if !isExtensionField(pb, extension.Field) {
Rob Pikea17fdd92011-11-02 12:43:05 -0700115 return errors.New("bad extension number; not in declared ranges")
Rob Pikeaaa3a622010-03-20 22:32:34 -0700116 }
117 return nil
118}
119
David Symonds1d72f7a2011-08-19 18:28:52 +1000120// encodeExtensionMap encodes any unmarshaled (unencoded) extensions in m.
Rob Pikea17fdd92011-11-02 12:43:05 -0700121func encodeExtensionMap(m map[int32]Extension) error {
David Symonds1d72f7a2011-08-19 18:28:52 +1000122 for k, e := range m {
123 if e.value == nil || e.desc == nil {
124 // Extension is only in its encoded form.
125 continue
126 }
127
128 // We don't skip extensions that have an encoded form set,
129 // because the extension value may have been mutated after
130 // the last time this function was called.
131
132 et := reflect.TypeOf(e.desc.ExtensionType)
133 props := new(Properties)
Russ Coxd4ce3f12012-09-12 10:36:26 +1000134 props.Init(et, "unknown_name", e.desc.Tag, nil)
David Symonds1d72f7a2011-08-19 18:28:52 +1000135
136 p := NewBuffer(nil)
Russ Coxd4ce3f12012-09-12 10:36:26 +1000137 // If e.value has type T, the encoder expects a *struct{ X T }.
138 // Pass a *T with a zero field and hope it all works out.
David Symonds1d72f7a2011-08-19 18:28:52 +1000139 x := reflect.New(et)
140 x.Elem().Set(reflect.ValueOf(e.value))
Russ Coxd4ce3f12012-09-12 10:36:26 +1000141 if err := props.enc(p, props, toStructPointer(x)); err != nil {
David Symonds1d72f7a2011-08-19 18:28:52 +1000142 return err
143 }
144 e.enc = p.buf
145 m[k] = e
146 }
147 return nil
148}
149
David Symonds940b9612011-04-01 10:45:23 +1100150// HasExtension returns whether the given extension is present in pb.
151func HasExtension(pb extendableProto, extension *ExtensionDesc) bool {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700152 // TODO: Check types, field numbers, etc.?
David Symonds940b9612011-04-01 10:45:23 +1100153 _, ok := pb.ExtensionMap()[extension.Field]
Rob Pikeaaa3a622010-03-20 22:32:34 -0700154 return ok
155}
156
David Symonds940b9612011-04-01 10:45:23 +1100157// ClearExtension removes the given extension from pb.
158func ClearExtension(pb extendableProto, extension *ExtensionDesc) {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700159 // TODO: Check types, field numbers, etc.?
Rob Pikef48475f2011-10-28 12:07:40 -0700160 delete(pb.ExtensionMap(), extension.Field)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700161}
162
David Symonds940b9612011-04-01 10:45:23 +1100163// GetExtension parses and returns the given extension of pb.
David Symondsa7e9ef92012-01-18 18:27:58 +1100164// If the extension is not present it returns ErrMissingExtension.
David Symondsf511ee32012-09-06 11:36:28 +1000165// If the returned extension is modified, SetExtension must be called
166// for the modifications to be reflected in pb.
Rob Pikea17fdd92011-11-02 12:43:05 -0700167func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, error) {
David Symonds940b9612011-04-01 10:45:23 +1100168 if err := checkExtensionTypes(pb, extension); err != nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700169 return nil, err
170 }
171
David Symonds1d72f7a2011-08-19 18:28:52 +1000172 e, ok := pb.ExtensionMap()[extension.Field]
Rob Pikeaaa3a622010-03-20 22:32:34 -0700173 if !ok {
David Symondsa7e9ef92012-01-18 18:27:58 +1100174 return nil, ErrMissingExtension
Rob Pikeaaa3a622010-03-20 22:32:34 -0700175 }
David Symonds1d72f7a2011-08-19 18:28:52 +1000176 if e.value != nil {
177 // Already decoded. Check the descriptor, though.
178 if e.desc != extension {
179 // This shouldn't happen. If it does, it means that
180 // GetExtension was called twice with two different
181 // descriptors with the same field number.
Rob Pikea17fdd92011-11-02 12:43:05 -0700182 return nil, errors.New("proto: descriptor conflict")
David Symonds1d72f7a2011-08-19 18:28:52 +1000183 }
184 return e.value, nil
185 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700186
David Symondsa4b61c02011-09-07 14:06:00 +1000187 v, err := decodeExtension(e.enc, extension)
188 if err != nil {
189 return nil, err
190 }
191
192 // Remember the decoded version and drop the encoded version.
193 // That way it is safe to mutate what we return.
194 e.value = v
195 e.desc = extension
196 e.enc = nil
197 return e.value, nil
198}
199
200// decodeExtension decodes an extension encoded in b.
Rob Pikea17fdd92011-11-02 12:43:05 -0700201func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) {
David Symonds61826da2012-05-05 09:31:28 +1000202 o := NewBuffer(b)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700203
Nigel Tao4ede8452011-04-28 11:27:25 +1000204 t := reflect.TypeOf(extension.ExtensionType)
David Symonds61826da2012-05-05 09:31:28 +1000205 rep := extension.repeated()
206
Rob Pikeaaa3a622010-03-20 22:32:34 -0700207 props := &Properties{}
Russ Coxd4ce3f12012-09-12 10:36:26 +1000208 props.Init(t, "irrelevant_name", extension.Tag, nil)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700209
David Symonds61826da2012-05-05 09:31:28 +1000210 // t is a pointer to a struct, pointer to basic type or a slice.
211 // Allocate a "field" to store the pointer/slice itself; the
212 // pointer/slice will be stored here. We pass
Rob Pikeb0447c02011-10-20 15:20:04 -0700213 // the address of this field to props.dec.
Russ Coxd4ce3f12012-09-12 10:36:26 +1000214 // This passes a zero field and a *t and lets props.dec
215 // interpret it as a *struct{ x t }.
Rob Pikeb0447c02011-10-20 15:20:04 -0700216 value := reflect.New(t).Elem()
David Symonds61826da2012-05-05 09:31:28 +1000217
218 for {
219 // Discard wire type and field number varint. It isn't needed.
220 if _, err := o.DecodeVarint(); err != nil {
221 return nil, err
222 }
223
Russ Coxd4ce3f12012-09-12 10:36:26 +1000224 if err := props.dec(o, props, toStructPointer(value.Addr())); err != nil {
David Symonds61826da2012-05-05 09:31:28 +1000225 return nil, err
226 }
227
228 if !rep || o.index >= len(o.buf) {
229 break
230 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700231 }
Rob Pikeb0447c02011-10-20 15:20:04 -0700232 return value.Interface(), nil
Rob Pikeaaa3a622010-03-20 22:32:34 -0700233}
234
David Symonds940b9612011-04-01 10:45:23 +1100235// GetExtensions returns a slice of the extensions present in pb that are also listed in es.
236// The returned slice has the same length as es; missing extensions will appear as nil elements.
David Symonds9f60f432012-06-14 09:45:25 +1000237func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) {
David Symonds940b9612011-04-01 10:45:23 +1100238 epb, ok := pb.(extendableProto)
239 if !ok {
Rob Pikea17fdd92011-11-02 12:43:05 -0700240 err = errors.New("not an extendable proto")
David Symonds940b9612011-04-01 10:45:23 +1100241 return
242 }
243 extensions = make([]interface{}, len(es))
244 for i, e := range es {
245 extensions[i], err = GetExtension(epb, e)
246 if err != nil {
247 return
248 }
249 }
250 return
251}
252
David Symonds940b9612011-04-01 10:45:23 +1100253// SetExtension sets the specified extension of pb to the specified value.
Rob Pikea17fdd92011-11-02 12:43:05 -0700254func SetExtension(pb extendableProto, extension *ExtensionDesc, value interface{}) error {
David Symonds940b9612011-04-01 10:45:23 +1100255 if err := checkExtensionTypes(pb, extension); err != nil {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700256 return err
257 }
Nigel Tao4ede8452011-04-28 11:27:25 +1000258 typ := reflect.TypeOf(extension.ExtensionType)
259 if typ != reflect.TypeOf(value) {
Rob Pikea17fdd92011-11-02 12:43:05 -0700260 return errors.New("bad extension value type")
Rob Pikeaaa3a622010-03-20 22:32:34 -0700261 }
262
David Symonds1d72f7a2011-08-19 18:28:52 +1000263 pb.ExtensionMap()[extension.Field] = Extension{desc: extension, value: value}
Rob Pikeaaa3a622010-03-20 22:32:34 -0700264 return nil
265}
David Symondse37856c2011-06-22 12:52:53 +1000266
267// A global registry of extensions.
268// The generated code will register the generated descriptors by calling RegisterExtension.
269
270var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc)
271
272// RegisterExtension is called from the generated code.
273func RegisterExtension(desc *ExtensionDesc) {
274 st := reflect.TypeOf(desc.ExtendedType).Elem()
275 m := extensionMaps[st]
276 if m == nil {
277 m = make(map[int32]*ExtensionDesc)
278 extensionMaps[st] = m
279 }
280 if _, ok := m[desc.Field]; ok {
281 panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field)))
282 }
283 m[desc.Field] = desc
284}
David Symondsc7cb3fd2011-08-29 16:49:58 +1000285
286// RegisteredExtensions returns a map of the registered extensions of a
287// protocol buffer struct, indexed by the extension number.
288// The argument pb should be a nil pointer to the struct type.
David Symonds9f60f432012-06-14 09:45:25 +1000289func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc {
David Symondsc7cb3fd2011-08-29 16:49:58 +1000290 return extensionMaps[reflect.TypeOf(pb).Elem()]
291}