]>
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 | /* | |
35 | * Support for message sets. | |
36 | */ | |
37 | ||
38 | import ( | |
15c0b25d | 39 | "errors" |
15c0b25d AP |
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. | |
44 | var 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 | ||
57 | type _MessageSet_Item struct { | |
58 | TypeId *int32 `protobuf:"varint,2,req,name=type_id"` | |
59 | Message []byte `protobuf:"bytes,3,req,name=message"` | |
60 | } | |
61 | ||
62 | type 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. | |
69 | var _ Message = (*messageSet)(nil) | |
70 | ||
71 | // messageTypeIder is an interface satisfied by a protocol buffer type | |
72 | // that may be stored in a MessageSet. | |
73 | type messageTypeIder interface { | |
74 | MessageTypeId() int32 | |
75 | } | |
76 | ||
77 | func (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 | ||
91 | func (ms *messageSet) Has(pb Message) bool { | |
92 | return ms.find(pb) != nil | |
93 | } | |
94 | ||
95 | func (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 | ||
105 | func (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 | ||
129 | func (ms *messageSet) Reset() { *ms = messageSet{} } | |
130 | func (ms *messageSet) String() string { return CompactTextString(ms) } | |
131 | func (*messageSet) ProtoMessage() {} | |
132 | ||
133 | // Support for the message_set_wire_format message option. | |
134 | ||
135 | func skipVarint(buf []byte) []byte { | |
136 | i := 0 | |
137 | for ; buf[i]&0x80 != 0; i++ { | |
138 | } | |
139 | return buf[i+1:] | |
140 | } | |
141 | ||
107c1cdb | 142 | // unmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. |
15c0b25d | 143 | // It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option. |
107c1cdb | 144 | func unmarshalMessageSet(buf []byte, exts interface{}) error { |
15c0b25d AP |
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 | } |