// Go support for Protocol Buffers - Google's data interchange format // // Copyright 2010 Google Inc. All rights reserved. // http://code.google.com/p/goprotobuf/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package proto /* * Types and routines for supporting protocol buffer extensions. */ import ( "os" "reflect" "strconv" "unsafe" ) // ExtensionRange represents a range of message extensions for a protocol buffer. // Used in code generated by the protocol compiler. type ExtensionRange struct { Start, End int32 // both inclusive } // extendableProto is an interface implemented by any protocol buffer that may be extended. type extendableProto interface { ExtensionRangeArray() []ExtensionRange ExtensionMap() map[int32]Extension } // ExtensionDesc represents an extension specification. // Used in generated code from the protocol compiler. type ExtensionDesc struct { ExtendedType interface{} // nil pointer to the type that is being extended ExtensionType interface{} // nil pointer to the extension type Field int32 // field number Name string // fully-qualified name of extension Tag string // protobuf tag style } /* Extension represents an extension in a message. When an extension is stored in a message using SetExtension only desc and value are set. When the message is marshaled enc will be set to the encoded form of the message. When a message is unmarshaled and contains extensions, each extension will have only enc set. When such an extension is accessed using GetExtension (or GetExtensions) desc and value will be set. */ type Extension struct { desc *ExtensionDesc value interface{} enc []byte } // SetRawExtension is for testing only. func SetRawExtension(base extendableProto, id int32, b []byte) { base.ExtensionMap()[id] = Extension{enc: b} } // isExtensionField returns true iff the given field number is in an extension range. func isExtensionField(pb extendableProto, field int32) bool { for _, er := range pb.ExtensionRangeArray() { if er.Start <= field && field <= er.End { return true } } return false } // checkExtensionTypes checks that the given extension is valid for pb. func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) os.Error { // Check the extended type. if a, b := reflect.TypeOf(pb), reflect.TypeOf(extension.ExtendedType); a != b { return os.NewError("bad extended type; " + b.String() + " does not extend " + a.String()) } // Check the range. if !isExtensionField(pb, extension.Field) { return os.NewError("bad extension number; not in declared ranges") } return nil } // encodeExtensionMap encodes any unmarshaled (unencoded) extensions in m. func encodeExtensionMap(m map[int32]Extension) os.Error { for k, e := range m { if e.value == nil || e.desc == nil { // Extension is only in its encoded form. continue } // We don't skip extensions that have an encoded form set, // because the extension value may have been mutated after // the last time this function was called. et := reflect.TypeOf(e.desc.ExtensionType) props := new(Properties) props.Init(et, "unknown_name", e.desc.Tag, 0) p := NewBuffer(nil) // The encoder must be passed a pointer to e.value. // Allocate a copy of value so that we can use its address. x := reflect.New(et) x.Elem().Set(reflect.ValueOf(e.value)) if err := props.enc(p, props, x.Pointer()); err != nil { return err } e.enc = p.buf m[k] = e } return nil } // HasExtension returns whether the given extension is present in pb. func HasExtension(pb extendableProto, extension *ExtensionDesc) bool { // TODO: Check types, field numbers, etc.? _, ok := pb.ExtensionMap()[extension.Field] return ok } // ClearExtension removes the given extension from pb. func ClearExtension(pb extendableProto, extension *ExtensionDesc) { // TODO: Check types, field numbers, etc.? pb.ExtensionMap()[extension.Field] = Extension{}, false } // GetExtension parses and returns the given extension of pb. // If the extension is not present it returns (nil, nil). func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, os.Error) { if err := checkExtensionTypes(pb, extension); err != nil { return nil, err } e, ok := pb.ExtensionMap()[extension.Field] if !ok { return nil, nil // not an error } if e.value != nil { // Already decoded. Check the descriptor, though. if e.desc != extension { // This shouldn't happen. If it does, it means that // GetExtension was called twice with two different // descriptors with the same field number. return nil, os.NewError("proto: descriptor conflict") } return e.value, nil } v, err := decodeExtension(e.enc, extension) if err != nil { return nil, err } // Remember the decoded version and drop the encoded version. // That way it is safe to mutate what we return. e.value = v e.desc = extension e.enc = nil return e.value, nil } // decodeExtension decodes an extension encoded in b. func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, os.Error) { // Discard wire type and field number varint. It isn't needed. _, n := DecodeVarint(b) o := NewBuffer(b[n:]) t := reflect.TypeOf(extension.ExtensionType) props := &Properties{} props.Init(t, "irrelevant_name", extension.Tag, 0) base := unsafe.New(t) var sbase uintptr if t.Elem().Kind() == reflect.Struct { // props.dec will be dec_struct_message, which does not refer to sbase. *(*unsafe.Pointer)(base) = unsafe.New(t.Elem()) } else { sbase = uintptr(unsafe.New(t.Elem())) } if err := props.dec(o, props, uintptr(base), sbase); err != nil { return nil, err } return unsafe.Unreflect(t, base), nil } // GetExtensions returns a slice of the extensions present in pb that are also listed in es. // The returned slice has the same length as es; missing extensions will appear as nil elements. func GetExtensions(pb interface{}, es []*ExtensionDesc) (extensions []interface{}, err os.Error) { epb, ok := pb.(extendableProto) if !ok { err = os.NewError("not an extendable proto") return } extensions = make([]interface{}, len(es)) for i, e := range es { extensions[i], err = GetExtension(epb, e) if err != nil { return } } return } // TODO: (needed for repeated extensions) // - ExtensionSize // - AddExtension // SetExtension sets the specified extension of pb to the specified value. func SetExtension(pb extendableProto, extension *ExtensionDesc, value interface{}) os.Error { if err := checkExtensionTypes(pb, extension); err != nil { return err } typ := reflect.TypeOf(extension.ExtensionType) if typ != reflect.TypeOf(value) { return os.NewError("bad extension value type") } pb.ExtensionMap()[extension.Field] = Extension{desc: extension, value: value} return nil } // A global registry of extensions. // The generated code will register the generated descriptors by calling RegisterExtension. var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc) // RegisterExtension is called from the generated code. func RegisterExtension(desc *ExtensionDesc) { st := reflect.TypeOf(desc.ExtendedType).Elem() m := extensionMaps[st] if m == nil { m = make(map[int32]*ExtensionDesc) extensionMaps[st] = m } if _, ok := m[desc.Field]; ok { panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field))) } m[desc.Field] = desc } // RegisteredExtensions returns a map of the registered extensions of a // protocol buffer struct, indexed by the extension number. // The argument pb should be a nil pointer to the struct type. func RegisteredExtensions(pb interface{}) map[int32]*ExtensionDesc { return extensionMaps[reflect.TypeOf(pb).Elem()] }