1 | // Protocol Buffers - Google's data interchange format |
2 | // Copyright 2008 Google Inc. All rights reserved. |
3 | // https://developers.google.com/protocol-buffers/ |
4 | // |
5 | // Redistribution and use in source and binary forms, with or without |
6 | // modification, are permitted provided that the following conditions are |
7 | // met: |
8 | // |
9 | // * Redistributions of source code must retain the above copyright |
10 | // notice, this list of conditions and the following disclaimer. |
11 | // * Redistributions in binary form must reproduce the above |
12 | // copyright notice, this list of conditions and the following disclaimer |
13 | // in the documentation and/or other materials provided with the |
14 | // distribution. |
15 | // * Neither the name of Google Inc. nor the names of its |
16 | // contributors may be used to endorse or promote products derived from |
17 | // this software without specific prior written permission. |
18 | // |
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | |
31 | #ifndef GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__ |
32 | #define GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__ |
33 | |
34 | #include <google/protobuf/extension_set.h> |
35 | #include <google/protobuf/metadata_lite.h> |
36 | #include <google/protobuf/parse_context.h> |
37 | |
38 | namespace google { |
39 | namespace protobuf { |
40 | namespace internal { |
41 | |
42 | template <typename T> |
43 | const char* ExtensionSet::ParseFieldWithExtensionInfo( |
44 | int number, bool was_packed_on_wire, const ExtensionInfo& extension, |
45 | InternalMetadata* metadata, const char* ptr, internal::ParseContext* ctx) { |
46 | if (was_packed_on_wire) { |
47 | switch (extension.type) { |
48 | #define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE) \ |
49 | case WireFormatLite::TYPE_##UPPERCASE: \ |
50 | return internal::Packed##CPP_CAMELCASE##Parser( \ |
51 | MutableRawRepeatedField(number, extension.type, extension.is_packed, \ |
52 | extension.descriptor), \ |
53 | ptr, ctx); |
54 | HANDLE_TYPE(INT32, Int32); |
55 | HANDLE_TYPE(INT64, Int64); |
56 | HANDLE_TYPE(UINT32, UInt32); |
57 | HANDLE_TYPE(UINT64, UInt64); |
58 | HANDLE_TYPE(SINT32, SInt32); |
59 | HANDLE_TYPE(SINT64, SInt64); |
60 | HANDLE_TYPE(FIXED32, Fixed32); |
61 | HANDLE_TYPE(FIXED64, Fixed64); |
62 | HANDLE_TYPE(SFIXED32, SFixed32); |
63 | HANDLE_TYPE(SFIXED64, SFixed64); |
64 | HANDLE_TYPE(FLOAT, Float); |
65 | HANDLE_TYPE(DOUBLE, Double); |
66 | HANDLE_TYPE(BOOL, Bool); |
67 | #undef HANDLE_TYPE |
68 | |
69 | case WireFormatLite::TYPE_ENUM: |
70 | return internal::PackedEnumParserArg<T>( |
71 | MutableRawRepeatedField(number, field_type: extension.type, packed: extension.is_packed, |
72 | desc: extension.descriptor), |
73 | ptr, ctx, extension.enum_validity_check.func, |
74 | extension.enum_validity_check.arg, metadata, number); |
75 | case WireFormatLite::TYPE_STRING: |
76 | case WireFormatLite::TYPE_BYTES: |
77 | case WireFormatLite::TYPE_GROUP: |
78 | case WireFormatLite::TYPE_MESSAGE: |
79 | GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed." ; |
80 | break; |
81 | } |
82 | } else { |
83 | switch (extension.type) { |
84 | #define HANDLE_VARINT_TYPE(UPPERCASE, CPP_CAMELCASE) \ |
85 | case WireFormatLite::TYPE_##UPPERCASE: { \ |
86 | uint64_t value; \ |
87 | ptr = VarintParse(ptr, &value); \ |
88 | GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); \ |
89 | if (extension.is_repeated) { \ |
90 | Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \ |
91 | extension.is_packed, value, extension.descriptor); \ |
92 | } else { \ |
93 | Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \ |
94 | extension.descriptor); \ |
95 | } \ |
96 | } break |
97 | |
98 | HANDLE_VARINT_TYPE(INT32, Int32); |
99 | HANDLE_VARINT_TYPE(INT64, Int64); |
100 | HANDLE_VARINT_TYPE(UINT32, UInt32); |
101 | HANDLE_VARINT_TYPE(UINT64, UInt64); |
102 | HANDLE_VARINT_TYPE(BOOL, Bool); |
103 | #undef HANDLE_VARINT_TYPE |
104 | #define HANDLE_SVARINT_TYPE(UPPERCASE, CPP_CAMELCASE, SIZE) \ |
105 | case WireFormatLite::TYPE_##UPPERCASE: { \ |
106 | uint64_t val; \ |
107 | ptr = VarintParse(ptr, &val); \ |
108 | GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); \ |
109 | auto value = WireFormatLite::ZigZagDecode##SIZE(val); \ |
110 | if (extension.is_repeated) { \ |
111 | Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \ |
112 | extension.is_packed, value, extension.descriptor); \ |
113 | } else { \ |
114 | Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \ |
115 | extension.descriptor); \ |
116 | } \ |
117 | } break |
118 | |
119 | HANDLE_SVARINT_TYPE(SINT32, Int32, 32); |
120 | HANDLE_SVARINT_TYPE(SINT64, Int64, 64); |
121 | #undef HANDLE_SVARINT_TYPE |
122 | #define HANDLE_FIXED_TYPE(UPPERCASE, CPP_CAMELCASE, CPPTYPE) \ |
123 | case WireFormatLite::TYPE_##UPPERCASE: { \ |
124 | auto value = UnalignedLoad<CPPTYPE>(ptr); \ |
125 | ptr += sizeof(CPPTYPE); \ |
126 | if (extension.is_repeated) { \ |
127 | Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \ |
128 | extension.is_packed, value, extension.descriptor); \ |
129 | } else { \ |
130 | Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \ |
131 | extension.descriptor); \ |
132 | } \ |
133 | } break |
134 | |
135 | HANDLE_FIXED_TYPE(FIXED32, UInt32, uint32_t); |
136 | HANDLE_FIXED_TYPE(FIXED64, UInt64, uint64_t); |
137 | HANDLE_FIXED_TYPE(SFIXED32, Int32, int32_t); |
138 | HANDLE_FIXED_TYPE(SFIXED64, Int64, int64_t); |
139 | HANDLE_FIXED_TYPE(FLOAT, Float, float); |
140 | HANDLE_FIXED_TYPE(DOUBLE, Double, double); |
141 | #undef HANDLE_FIXED_TYPE |
142 | |
143 | case WireFormatLite::TYPE_ENUM: { |
144 | uint64_t val; |
145 | ptr = VarintParse(p: ptr, out: &val); |
146 | GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); |
147 | int value = val; |
148 | |
149 | if (!extension.enum_validity_check.func( |
150 | extension.enum_validity_check.arg, value)) { |
151 | WriteVarint(number, val, metadata->mutable_unknown_fields<T>()); |
152 | } else if (extension.is_repeated) { |
153 | AddEnum(number, type: WireFormatLite::TYPE_ENUM, packed: extension.is_packed, value, |
154 | descriptor: extension.descriptor); |
155 | } else { |
156 | SetEnum(number, type: WireFormatLite::TYPE_ENUM, value, |
157 | descriptor: extension.descriptor); |
158 | } |
159 | break; |
160 | } |
161 | |
162 | case WireFormatLite::TYPE_BYTES: |
163 | case WireFormatLite::TYPE_STRING: { |
164 | std::string* value = |
165 | extension.is_repeated |
166 | ? AddString(number, type: WireFormatLite::TYPE_STRING, |
167 | descriptor: extension.descriptor) |
168 | : MutableString(number, type: WireFormatLite::TYPE_STRING, |
169 | descriptor: extension.descriptor); |
170 | int size = ReadSize(pp: &ptr); |
171 | GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); |
172 | return ctx->ReadString(ptr, size, s: value); |
173 | } |
174 | |
175 | case WireFormatLite::TYPE_GROUP: { |
176 | MessageLite* value = |
177 | extension.is_repeated |
178 | ? AddMessage(number, type: WireFormatLite::TYPE_GROUP, |
179 | prototype: *extension.message_info.prototype, |
180 | descriptor: extension.descriptor) |
181 | : MutableMessage(number, type: WireFormatLite::TYPE_GROUP, |
182 | prototype: *extension.message_info.prototype, |
183 | descriptor: extension.descriptor); |
184 | uint32_t tag = (number << 3) + WireFormatLite::WIRETYPE_START_GROUP; |
185 | return ctx->ParseGroup(msg: value, ptr, tag); |
186 | } |
187 | |
188 | case WireFormatLite::TYPE_MESSAGE: { |
189 | MessageLite* value = |
190 | extension.is_repeated |
191 | ? AddMessage(number, type: WireFormatLite::TYPE_MESSAGE, |
192 | prototype: *extension.message_info.prototype, |
193 | descriptor: extension.descriptor) |
194 | : MutableMessage(number, type: WireFormatLite::TYPE_MESSAGE, |
195 | prototype: *extension.message_info.prototype, |
196 | descriptor: extension.descriptor); |
197 | return ctx->ParseMessage(msg: value, ptr); |
198 | } |
199 | } |
200 | } |
201 | return ptr; |
202 | } |
203 | |
204 | template <typename Msg, typename T> |
205 | const char* ExtensionSet::ParseMessageSetItemTmpl( |
206 | const char* ptr, const Msg* extendee, internal::InternalMetadata* metadata, |
207 | internal::ParseContext* ctx) { |
208 | std::string payload; |
209 | uint32_t type_id = 0; |
210 | bool payload_read = false; |
211 | while (!ctx->Done(ptr: &ptr)) { |
212 | uint32_t tag = static_cast<uint8_t>(*ptr++); |
213 | if (tag == WireFormatLite::kMessageSetTypeIdTag) { |
214 | uint64_t tmp; |
215 | ptr = ParseBigVarint(p: ptr, out: &tmp); |
216 | GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); |
217 | type_id = tmp; |
218 | if (payload_read) { |
219 | ExtensionInfo extension; |
220 | bool was_packed_on_wire; |
221 | if (!FindExtension(2, type_id, extendee, ctx, &extension, |
222 | &was_packed_on_wire)) { |
223 | WriteLengthDelimited(type_id, payload, |
224 | metadata->mutable_unknown_fields<T>()); |
225 | } else { |
226 | MessageLite* value = |
227 | extension.is_repeated |
228 | ? AddMessage(number: type_id, type: WireFormatLite::TYPE_MESSAGE, |
229 | prototype: *extension.message_info.prototype, |
230 | descriptor: extension.descriptor) |
231 | : MutableMessage(number: type_id, type: WireFormatLite::TYPE_MESSAGE, |
232 | prototype: *extension.message_info.prototype, |
233 | descriptor: extension.descriptor); |
234 | |
235 | const char* p; |
236 | // We can't use regular parse from string as we have to track |
237 | // proper recursion depth and descriptor pools. |
238 | ParseContext tmp_ctx(ctx->depth(), false, &p, payload); |
239 | tmp_ctx.data().pool = ctx->data().pool; |
240 | tmp_ctx.data().factory = ctx->data().factory; |
241 | GOOGLE_PROTOBUF_PARSER_ASSERT(value->_InternalParse(p, &tmp_ctx) && |
242 | tmp_ctx.EndedAtLimit()); |
243 | } |
244 | type_id = 0; |
245 | } |
246 | } else if (tag == WireFormatLite::kMessageSetMessageTag) { |
247 | if (type_id != 0) { |
248 | ptr = ParseFieldMaybeLazily(static_cast<uint64_t>(type_id) * 8 + 2, ptr, |
249 | extendee, metadata, ctx); |
250 | GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr); |
251 | type_id = 0; |
252 | } else { |
253 | int32_t size = ReadSize(pp: &ptr); |
254 | GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); |
255 | ptr = ctx->ReadString(ptr, size, s: &payload); |
256 | GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); |
257 | payload_read = true; |
258 | } |
259 | } else { |
260 | ptr = ReadTag(p: ptr - 1, out: &tag); |
261 | if (tag == 0 || (tag & 7) == 4) { |
262 | ctx->SetLastTag(tag); |
263 | return ptr; |
264 | } |
265 | ptr = ParseField(tag, ptr, extendee, metadata, ctx); |
266 | GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); |
267 | } |
268 | } |
269 | return ptr; |
270 | } |
271 | |
272 | } // namespace internal |
273 | } // namespace protobuf |
274 | } // namespace google |
275 | |
276 | #endif // GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__ |
277 | |