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 32package proto 33 34/* 35 * Support for message sets. 36 */ 37 38import ( 39 "errors" 40) 41 42// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID. 43// A message type ID is required for storing a protocol buffer in a message set. 44var errNoMessageTypeID = errors.New("proto does not have a message type ID") 45 46// The first two types (_MessageSet_Item and messageSet) 47// model what the protocol compiler produces for the following protocol message: 48// message MessageSet { 49// repeated group Item = 1 { 50// required int32 type_id = 2; 51// required string message = 3; 52// }; 53// } 54// That is the MessageSet wire format. We can't use a proto to generate these 55// because that would introduce a circular dependency between it and this package. 56 57type _MessageSet_Item struct { 58 TypeId *int32 `protobuf:"varint,2,req,name=type_id"` 59 Message []byte `protobuf:"bytes,3,req,name=message"` 60} 61 62type messageSet struct { 63 Item []*_MessageSet_Item `protobuf:"group,1,rep"` 64 XXX_unrecognized []byte 65 // TODO: caching? 66} 67 68// Make sure messageSet is a Message. 69var _ Message = (*messageSet)(nil) 70 71// messageTypeIder is an interface satisfied by a protocol buffer type 72// that may be stored in a MessageSet. 73type messageTypeIder interface { 74 MessageTypeId() int32 75} 76 77func (ms *messageSet) find(pb Message) *_MessageSet_Item { 78 mti, ok := pb.(messageTypeIder) 79 if !ok { 80 return nil 81 } 82 id := mti.MessageTypeId() 83 for _, item := range ms.Item { 84 if *item.TypeId == id { 85 return item 86 } 87 } 88 return nil 89} 90 91func (ms *messageSet) Has(pb Message) bool { 92 return ms.find(pb) != nil 93} 94 95func (ms *messageSet) Unmarshal(pb Message) error { 96 if item := ms.find(pb); item != nil { 97 return Unmarshal(item.Message, pb) 98 } 99 if _, ok := pb.(messageTypeIder); !ok { 100 return errNoMessageTypeID 101 } 102 return nil // TODO: return error instead? 103} 104 105func (ms *messageSet) Marshal(pb Message) error { 106 msg, err := Marshal(pb) 107 if err != nil { 108 return err 109 } 110 if item := ms.find(pb); item != nil { 111 // reuse existing item 112 item.Message = msg 113 return nil 114 } 115 116 mti, ok := pb.(messageTypeIder) 117 if !ok { 118 return errNoMessageTypeID 119 } 120 121 mtid := mti.MessageTypeId() 122 ms.Item = append(ms.Item, &_MessageSet_Item{ 123 TypeId: &mtid, 124 Message: msg, 125 }) 126 return nil 127} 128 129func (ms *messageSet) Reset() { *ms = messageSet{} } 130func (ms *messageSet) String() string { return CompactTextString(ms) } 131func (*messageSet) ProtoMessage() {} 132 133// Support for the message_set_wire_format message option. 134 135func skipVarint(buf []byte) []byte { 136 i := 0 137 for ; buf[i]&0x80 != 0; i++ { 138 } 139 return buf[i+1:] 140} 141 142// unmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. 143// It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option. 144func unmarshalMessageSet(buf []byte, exts interface{}) error { 145 var m map[int32]Extension 146 switch exts := exts.(type) { 147 case *XXX_InternalExtensions: 148 m = exts.extensionsWrite() 149 case map[int32]Extension: 150 m = exts 151 default: 152 return errors.New("proto: not an extension map") 153 } 154 155 ms := new(messageSet) 156 if err := Unmarshal(buf, ms); err != nil { 157 return err 158 } 159 for _, item := range ms.Item { 160 id := *item.TypeId 161 msg := item.Message 162 163 // Restore wire type and field number varint, plus length varint. 164 // Be careful to preserve duplicate items. 165 b := EncodeVarint(uint64(id)<<3 | WireBytes) 166 if ext, ok := m[id]; ok { 167 // Existing data; rip off the tag and length varint 168 // so we join the new data correctly. 169 // We can assume that ext.enc is set because we are unmarshaling. 170 o := ext.enc[len(b):] // skip wire type and field number 171 _, n := DecodeVarint(o) // calculate length of length varint 172 o = o[n:] // skip length varint 173 msg = append(o, msg...) // join old data and new data 174 } 175 b = append(b, EncodeVarint(uint64(len(msg)))...) 176 b = append(b, msg...) 177 178 m[id] = Extension{enc: b} 179 } 180 return nil 181} 182