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 | // Author: kenton@google.com (Kenton Varda) |
32 | // Based on original Protocol Buffers design by |
33 | // Sanjay Ghemawat, Jeff Dean, and others. |
34 | // |
35 | // Contains methods defined in extension_set.h which cannot be part of the |
36 | // lite library because they use descriptors or reflection. |
37 | |
38 | #include <google/protobuf/stubs/casts.h> |
39 | #include <google/protobuf/io/coded_stream.h> |
40 | #include <google/protobuf/arena.h> |
41 | #include <google/protobuf/descriptor.h> |
42 | #include <google/protobuf/descriptor.pb.h> |
43 | #include <google/protobuf/extension_set.h> |
44 | #include <google/protobuf/extension_set_inl.h> |
45 | #include <google/protobuf/message.h> |
46 | #include <google/protobuf/message_lite.h> |
47 | #include <google/protobuf/parse_context.h> |
48 | #include <google/protobuf/repeated_field.h> |
49 | #include <google/protobuf/unknown_field_set.h> |
50 | #include <google/protobuf/wire_format.h> |
51 | #include <google/protobuf/wire_format_lite.h> |
52 | |
53 | |
54 | // Must be included last. |
55 | #include <google/protobuf/port_def.inc> |
56 | |
57 | namespace google { |
58 | namespace protobuf { |
59 | namespace internal { |
60 | |
61 | // Implementation of ExtensionFinder which finds extensions in a given |
62 | // DescriptorPool, using the given MessageFactory to construct sub-objects. |
63 | // This class is implemented in extension_set_heavy.cc. |
64 | class DescriptorPoolExtensionFinder { |
65 | public: |
66 | DescriptorPoolExtensionFinder(const DescriptorPool* pool, |
67 | MessageFactory* factory, |
68 | const Descriptor* containing_type) |
69 | : pool_(pool), factory_(factory), containing_type_(containing_type) {} |
70 | |
71 | bool Find(int number, ExtensionInfo* output); |
72 | |
73 | private: |
74 | const DescriptorPool* pool_; |
75 | MessageFactory* factory_; |
76 | const Descriptor* containing_type_; |
77 | }; |
78 | |
79 | void ExtensionSet::AppendToList( |
80 | const Descriptor* containing_type, const DescriptorPool* pool, |
81 | std::vector<const FieldDescriptor*>* output) const { |
82 | ForEach(func: [containing_type, pool, &output](int number, const Extension& ext) { |
83 | bool has = false; |
84 | if (ext.is_repeated) { |
85 | has = ext.GetSize() > 0; |
86 | } else { |
87 | has = !ext.is_cleared; |
88 | } |
89 | |
90 | if (has) { |
91 | // TODO(kenton): Looking up each field by number is somewhat unfortunate. |
92 | // Is there a better way? The problem is that descriptors are lazily- |
93 | // initialized, so they might not even be constructed until |
94 | // AppendToList() is called. |
95 | |
96 | if (ext.descriptor == nullptr) { |
97 | output->push_back(x: pool->FindExtensionByNumber(extendee: containing_type, number)); |
98 | } else { |
99 | output->push_back(x: ext.descriptor); |
100 | } |
101 | } |
102 | }); |
103 | } |
104 | |
105 | inline FieldDescriptor::Type real_type(FieldType type) { |
106 | GOOGLE_DCHECK(type > 0 && type <= FieldDescriptor::MAX_TYPE); |
107 | return static_cast<FieldDescriptor::Type>(type); |
108 | } |
109 | |
110 | inline FieldDescriptor::CppType cpp_type(FieldType type) { |
111 | return FieldDescriptor::TypeToCppType( |
112 | type: static_cast<FieldDescriptor::Type>(type)); |
113 | } |
114 | |
115 | inline WireFormatLite::FieldType field_type(FieldType type) { |
116 | GOOGLE_DCHECK(type > 0 && type <= WireFormatLite::MAX_FIELD_TYPE); |
117 | return static_cast<WireFormatLite::FieldType>(type); |
118 | } |
119 | |
120 | #define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE) \ |
121 | GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? FieldDescriptor::LABEL_REPEATED \ |
122 | : FieldDescriptor::LABEL_OPTIONAL, \ |
123 | FieldDescriptor::LABEL_##LABEL); \ |
124 | GOOGLE_DCHECK_EQ(cpp_type((EXTENSION).type), FieldDescriptor::CPPTYPE_##CPPTYPE) |
125 | |
126 | const MessageLite& ExtensionSet::GetMessage(int number, |
127 | const Descriptor* message_type, |
128 | MessageFactory* factory) const { |
129 | const Extension* extension = FindOrNull(key: number); |
130 | if (extension == nullptr || extension->is_cleared) { |
131 | // Not present. Return the default value. |
132 | return *factory->GetPrototype(type: message_type); |
133 | } else { |
134 | GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE); |
135 | if (extension->is_lazy) { |
136 | return extension->lazymessage_value->GetMessage( |
137 | prototype: *factory->GetPrototype(type: message_type), arena: arena_); |
138 | } else { |
139 | return *extension->message_value; |
140 | } |
141 | } |
142 | } |
143 | |
144 | MessageLite* ExtensionSet::MutableMessage(const FieldDescriptor* descriptor, |
145 | MessageFactory* factory) { |
146 | Extension* extension; |
147 | if (MaybeNewExtension(number: descriptor->number(), descriptor, result: &extension)) { |
148 | extension->type = descriptor->type(); |
149 | GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); |
150 | extension->is_repeated = false; |
151 | extension->is_packed = false; |
152 | const MessageLite* prototype = |
153 | factory->GetPrototype(type: descriptor->message_type()); |
154 | extension->is_lazy = false; |
155 | extension->message_value = prototype->New(arena: arena_); |
156 | extension->is_cleared = false; |
157 | return extension->message_value; |
158 | } else { |
159 | GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE); |
160 | extension->is_cleared = false; |
161 | if (extension->is_lazy) { |
162 | return extension->lazymessage_value->MutableMessage( |
163 | prototype: *factory->GetPrototype(type: descriptor->message_type()), arena: arena_); |
164 | } else { |
165 | return extension->message_value; |
166 | } |
167 | } |
168 | } |
169 | |
170 | MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor, |
171 | MessageFactory* factory) { |
172 | Extension* extension = FindOrNull(key: descriptor->number()); |
173 | if (extension == nullptr) { |
174 | // Not present. Return nullptr. |
175 | return nullptr; |
176 | } else { |
177 | GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE); |
178 | MessageLite* ret = nullptr; |
179 | if (extension->is_lazy) { |
180 | ret = extension->lazymessage_value->ReleaseMessage( |
181 | prototype: *factory->GetPrototype(type: descriptor->message_type()), arena: arena_); |
182 | if (arena_ == nullptr) { |
183 | delete extension->lazymessage_value; |
184 | } |
185 | } else { |
186 | if (arena_ != nullptr) { |
187 | ret = extension->message_value->New(); |
188 | ret->CheckTypeAndMergeFrom(other: *extension->message_value); |
189 | } else { |
190 | ret = extension->message_value; |
191 | } |
192 | } |
193 | Erase(key: descriptor->number()); |
194 | return ret; |
195 | } |
196 | } |
197 | |
198 | MessageLite* ExtensionSet::UnsafeArenaReleaseMessage( |
199 | const FieldDescriptor* descriptor, MessageFactory* factory) { |
200 | Extension* extension = FindOrNull(key: descriptor->number()); |
201 | if (extension == nullptr) { |
202 | // Not present. Return nullptr. |
203 | return nullptr; |
204 | } else { |
205 | GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE); |
206 | MessageLite* ret = nullptr; |
207 | if (extension->is_lazy) { |
208 | ret = extension->lazymessage_value->UnsafeArenaReleaseMessage( |
209 | prototype: *factory->GetPrototype(type: descriptor->message_type()), arena: arena_); |
210 | if (arena_ == nullptr) { |
211 | delete extension->lazymessage_value; |
212 | } |
213 | } else { |
214 | ret = extension->message_value; |
215 | } |
216 | Erase(key: descriptor->number()); |
217 | return ret; |
218 | } |
219 | } |
220 | |
221 | ExtensionSet::Extension* ExtensionSet::MaybeNewRepeatedExtension( |
222 | const FieldDescriptor* descriptor) { |
223 | Extension* extension; |
224 | if (MaybeNewExtension(number: descriptor->number(), descriptor, result: &extension)) { |
225 | extension->type = descriptor->type(); |
226 | GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); |
227 | extension->is_repeated = true; |
228 | extension->repeated_message_value = |
229 | Arena::CreateMessage<RepeatedPtrField<MessageLite> >(arena: arena_); |
230 | } else { |
231 | GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE); |
232 | } |
233 | return extension; |
234 | } |
235 | |
236 | MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor, |
237 | MessageFactory* factory) { |
238 | Extension* extension = MaybeNewRepeatedExtension(descriptor); |
239 | |
240 | // RepeatedPtrField<Message> does not know how to Add() since it cannot |
241 | // allocate an abstract object, so we have to be tricky. |
242 | MessageLite* result = |
243 | reinterpret_cast<internal::RepeatedPtrFieldBase*>( |
244 | extension->repeated_message_value) |
245 | ->AddFromCleared<GenericTypeHandler<MessageLite> >(); |
246 | if (result == nullptr) { |
247 | const MessageLite* prototype; |
248 | if (extension->repeated_message_value->empty()) { |
249 | prototype = factory->GetPrototype(type: descriptor->message_type()); |
250 | GOOGLE_CHECK(prototype != nullptr); |
251 | } else { |
252 | prototype = &extension->repeated_message_value->Get(index: 0); |
253 | } |
254 | result = prototype->New(arena: arena_); |
255 | extension->repeated_message_value->AddAllocated(value: result); |
256 | } |
257 | return result; |
258 | } |
259 | |
260 | void ExtensionSet::AddAllocatedMessage(const FieldDescriptor* descriptor, |
261 | MessageLite* new_entry) { |
262 | Extension* extension = MaybeNewRepeatedExtension(descriptor); |
263 | |
264 | extension->repeated_message_value->AddAllocated(value: new_entry); |
265 | } |
266 | |
267 | void ExtensionSet::UnsafeArenaAddAllocatedMessage( |
268 | const FieldDescriptor* descriptor, MessageLite* new_entry) { |
269 | Extension* extension = MaybeNewRepeatedExtension(descriptor); |
270 | |
271 | extension->repeated_message_value->UnsafeArenaAddAllocated(value: new_entry); |
272 | } |
273 | |
274 | static bool ValidateEnumUsingDescriptor(const void* arg, int number) { |
275 | return reinterpret_cast<const EnumDescriptor*>(arg)->FindValueByNumber( |
276 | number) != nullptr; |
277 | } |
278 | |
279 | bool DescriptorPoolExtensionFinder::Find(int number, ExtensionInfo* output) { |
280 | const FieldDescriptor* extension = |
281 | pool_->FindExtensionByNumber(extendee: containing_type_, number); |
282 | if (extension == nullptr) { |
283 | return false; |
284 | } else { |
285 | output->type = extension->type(); |
286 | output->is_repeated = extension->is_repeated(); |
287 | output->is_packed = extension->options().packed(); |
288 | output->descriptor = extension; |
289 | if (extension->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
290 | output->message_info.prototype = |
291 | factory_->GetPrototype(type: extension->message_type()); |
292 | GOOGLE_CHECK(output->message_info.prototype != nullptr) |
293 | << "Extension factory's GetPrototype() returned nullptr; extension: " |
294 | << extension->full_name(); |
295 | } else if (extension->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { |
296 | output->enum_validity_check.func = ValidateEnumUsingDescriptor; |
297 | output->enum_validity_check.arg = extension->enum_type(); |
298 | } |
299 | |
300 | return true; |
301 | } |
302 | } |
303 | |
304 | |
305 | bool ExtensionSet::FindExtension(int wire_type, uint32_t field, |
306 | const Message* containing_type, |
307 | const internal::ParseContext* ctx, |
308 | ExtensionInfo* extension, |
309 | bool* was_packed_on_wire) { |
310 | if (ctx->data().pool == nullptr) { |
311 | GeneratedExtensionFinder finder(containing_type); |
312 | if (!FindExtensionInfoFromFieldNumber(wire_type, field_number: field, extension_finder: &finder, extension, |
313 | was_packed_on_wire)) { |
314 | return false; |
315 | } |
316 | } else { |
317 | DescriptorPoolExtensionFinder finder(ctx->data().pool, ctx->data().factory, |
318 | containing_type->GetDescriptor()); |
319 | if (!FindExtensionInfoFromFieldNumber(wire_type, field_number: field, extension_finder: &finder, extension, |
320 | was_packed_on_wire)) { |
321 | return false; |
322 | } |
323 | } |
324 | return true; |
325 | } |
326 | |
327 | const char* ExtensionSet::ParseField(uint64_t tag, const char* ptr, |
328 | const Message* containing_type, |
329 | internal::InternalMetadata* metadata, |
330 | internal::ParseContext* ctx) { |
331 | int number = tag >> 3; |
332 | bool was_packed_on_wire; |
333 | ExtensionInfo extension; |
334 | if (!FindExtension(wire_type: tag & 7, field: number, containing_type, ctx, extension: &extension, |
335 | was_packed_on_wire: &was_packed_on_wire)) { |
336 | return UnknownFieldParse( |
337 | tag, unknown: metadata->mutable_unknown_fields<UnknownFieldSet>(), ptr, ctx); |
338 | } |
339 | return ParseFieldWithExtensionInfo<UnknownFieldSet>( |
340 | number, was_packed_on_wire, extension, metadata, ptr, ctx); |
341 | } |
342 | |
343 | const char* ExtensionSet::ParseFieldMaybeLazily( |
344 | uint64_t tag, const char* ptr, const Message* containing_type, |
345 | internal::InternalMetadata* metadata, internal::ParseContext* ctx) { |
346 | return ParseField(tag, ptr, containing_type, metadata, ctx); |
347 | } |
348 | |
349 | const char* ExtensionSet::ParseMessageSetItem( |
350 | const char* ptr, const Message* containing_type, |
351 | internal::InternalMetadata* metadata, internal::ParseContext* ctx) { |
352 | return ParseMessageSetItemTmpl<Message, UnknownFieldSet>(ptr, extendee: containing_type, |
353 | metadata, ctx); |
354 | } |
355 | |
356 | int ExtensionSet::SpaceUsedExcludingSelf() const { |
357 | return internal::FromIntSize(size: SpaceUsedExcludingSelfLong()); |
358 | } |
359 | |
360 | size_t ExtensionSet::SpaceUsedExcludingSelfLong() const { |
361 | size_t total_size = |
362 | (is_large() ? map_.large->size() : flat_capacity_) * sizeof(KeyValue); |
363 | ForEach(func: [&total_size](int /* number */, const Extension& ext) { |
364 | total_size += ext.SpaceUsedExcludingSelfLong(); |
365 | }); |
366 | return total_size; |
367 | } |
368 | |
369 | inline size_t ExtensionSet::RepeatedMessage_SpaceUsedExcludingSelfLong( |
370 | RepeatedPtrFieldBase* field) { |
371 | return field->SpaceUsedExcludingSelfLong<GenericTypeHandler<Message> >(); |
372 | } |
373 | |
374 | size_t ExtensionSet::Extension::SpaceUsedExcludingSelfLong() const { |
375 | size_t total_size = 0; |
376 | if (is_repeated) { |
377 | switch (cpp_type(type)) { |
378 | #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ |
379 | case FieldDescriptor::CPPTYPE_##UPPERCASE: \ |
380 | total_size += sizeof(*repeated_##LOWERCASE##_value) + \ |
381 | repeated_##LOWERCASE##_value->SpaceUsedExcludingSelfLong(); \ |
382 | break |
383 | |
384 | HANDLE_TYPE(INT32, int32_t); |
385 | HANDLE_TYPE(INT64, int64_t); |
386 | HANDLE_TYPE(UINT32, uint32_t); |
387 | HANDLE_TYPE(UINT64, uint64_t); |
388 | HANDLE_TYPE(FLOAT, float); |
389 | HANDLE_TYPE(DOUBLE, double); |
390 | HANDLE_TYPE(BOOL, bool); |
391 | HANDLE_TYPE(ENUM, enum); |
392 | HANDLE_TYPE(STRING, string); |
393 | #undef HANDLE_TYPE |
394 | |
395 | case FieldDescriptor::CPPTYPE_MESSAGE: |
396 | // repeated_message_value is actually a RepeatedPtrField<MessageLite>, |
397 | // but MessageLite has no SpaceUsedLong(), so we must directly call |
398 | // RepeatedPtrFieldBase::SpaceUsedExcludingSelfLong() with a different |
399 | // type handler. |
400 | total_size += sizeof(*repeated_message_value) + |
401 | RepeatedMessage_SpaceUsedExcludingSelfLong( |
402 | field: reinterpret_cast<internal::RepeatedPtrFieldBase*>( |
403 | repeated_message_value)); |
404 | break; |
405 | } |
406 | } else { |
407 | switch (cpp_type(type)) { |
408 | case FieldDescriptor::CPPTYPE_STRING: |
409 | total_size += sizeof(*string_value) + |
410 | StringSpaceUsedExcludingSelfLong(str: *string_value); |
411 | break; |
412 | case FieldDescriptor::CPPTYPE_MESSAGE: |
413 | if (is_lazy) { |
414 | total_size += lazymessage_value->SpaceUsedLong(); |
415 | } else { |
416 | total_size += down_cast<Message*>(f: message_value)->SpaceUsedLong(); |
417 | } |
418 | break; |
419 | default: |
420 | // No extra storage costs for primitive types. |
421 | break; |
422 | } |
423 | } |
424 | return total_size; |
425 | } |
426 | |
427 | uint8_t* ExtensionSet::SerializeMessageSetWithCachedSizesToArray( |
428 | const MessageLite* extendee, uint8_t* target) const { |
429 | io::EpsCopyOutputStream stream( |
430 | target, MessageSetByteSize(), |
431 | io::CodedOutputStream::IsDefaultSerializationDeterministic()); |
432 | return InternalSerializeMessageSetWithCachedSizesToArray(extendee, target, |
433 | stream: &stream); |
434 | } |
435 | |
436 | } // namespace internal |
437 | } // namespace protobuf |
438 | } // namespace google |
439 | |
440 | #include <google/protobuf/port_undef.inc> |
441 | |