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/extension_set.h>
39
40 #include <google/protobuf/stubs/casts.h>
41 #include <google/protobuf/descriptor.pb.h>
42 #include <google/protobuf/extension_set_inl.h>
43 #include <google/protobuf/parse_context.h>
44 #include <google/protobuf/io/coded_stream.h>
45 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
46 #include <google/protobuf/descriptor.h>
47 #include <google/protobuf/message.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 #include <google/protobuf/port_def.inc>
55
56 namespace google {
57 namespace protobuf {
58 namespace internal {
59
60 // A FieldSkipper used to store unknown MessageSet fields into UnknownFieldSet.
61 class MessageSetFieldSkipper : public UnknownFieldSetFieldSkipper {
62 public:
MessageSetFieldSkipper(UnknownFieldSet * unknown_fields)63 explicit MessageSetFieldSkipper(UnknownFieldSet* unknown_fields)
64 : UnknownFieldSetFieldSkipper(unknown_fields) {}
~MessageSetFieldSkipper()65 virtual ~MessageSetFieldSkipper() {}
66
67 virtual bool SkipMessageSetField(io::CodedInputStream* input,
68 int field_number);
69 };
SkipMessageSetField(io::CodedInputStream * input,int field_number)70 bool MessageSetFieldSkipper::SkipMessageSetField(io::CodedInputStream* input,
71 int field_number) {
72 uint32 length;
73 if (!input->ReadVarint32(&length)) return false;
74 if (unknown_fields_ == NULL) {
75 return input->Skip(length);
76 } else {
77 return input->ReadString(unknown_fields_->AddLengthDelimited(field_number),
78 length);
79 }
80 }
81
82
83 // Implementation of ExtensionFinder which finds extensions in a given
84 // DescriptorPool, using the given MessageFactory to construct sub-objects.
85 // This class is implemented in extension_set_heavy.cc.
86 class DescriptorPoolExtensionFinder : public ExtensionFinder {
87 public:
DescriptorPoolExtensionFinder(const DescriptorPool * pool,MessageFactory * factory,const Descriptor * containing_type)88 DescriptorPoolExtensionFinder(const DescriptorPool* pool,
89 MessageFactory* factory,
90 const Descriptor* containing_type)
91 : pool_(pool), factory_(factory), containing_type_(containing_type) {}
~DescriptorPoolExtensionFinder()92 ~DescriptorPoolExtensionFinder() override {}
93
94 bool Find(int number, ExtensionInfo* output) override;
95
96 private:
97 const DescriptorPool* pool_;
98 MessageFactory* factory_;
99 const Descriptor* containing_type_;
100 };
101
AppendToList(const Descriptor * containing_type,const DescriptorPool * pool,std::vector<const FieldDescriptor * > * output) const102 void ExtensionSet::AppendToList(
103 const Descriptor* containing_type, const DescriptorPool* pool,
104 std::vector<const FieldDescriptor*>* output) const {
105 ForEach([containing_type, pool, &output](int number, const Extension& ext) {
106 bool has = false;
107 if (ext.is_repeated) {
108 has = ext.GetSize() > 0;
109 } else {
110 has = !ext.is_cleared;
111 }
112
113 if (has) {
114 // TODO(kenton): Looking up each field by number is somewhat unfortunate.
115 // Is there a better way? The problem is that descriptors are lazily-
116 // initialized, so they might not even be constructed until
117 // AppendToList() is called.
118
119 if (ext.descriptor == NULL) {
120 output->push_back(pool->FindExtensionByNumber(containing_type, number));
121 } else {
122 output->push_back(ext.descriptor);
123 }
124 }
125 });
126 }
127
real_type(FieldType type)128 inline FieldDescriptor::Type real_type(FieldType type) {
129 GOOGLE_DCHECK(type > 0 && type <= FieldDescriptor::MAX_TYPE);
130 return static_cast<FieldDescriptor::Type>(type);
131 }
132
cpp_type(FieldType type)133 inline FieldDescriptor::CppType cpp_type(FieldType type) {
134 return FieldDescriptor::TypeToCppType(
135 static_cast<FieldDescriptor::Type>(type));
136 }
137
field_type(FieldType type)138 inline WireFormatLite::FieldType field_type(FieldType type) {
139 GOOGLE_DCHECK(type > 0 && type <= WireFormatLite::MAX_FIELD_TYPE);
140 return static_cast<WireFormatLite::FieldType>(type);
141 }
142
143 #define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE) \
144 GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? FieldDescriptor::LABEL_REPEATED \
145 : FieldDescriptor::LABEL_OPTIONAL, \
146 FieldDescriptor::LABEL_##LABEL); \
147 GOOGLE_DCHECK_EQ(cpp_type((EXTENSION).type), FieldDescriptor::CPPTYPE_##CPPTYPE)
148
GetMessage(int number,const Descriptor * message_type,MessageFactory * factory) const149 const MessageLite& ExtensionSet::GetMessage(int number,
150 const Descriptor* message_type,
151 MessageFactory* factory) const {
152 const Extension* extension = FindOrNull(number);
153 if (extension == NULL || extension->is_cleared) {
154 // Not present. Return the default value.
155 return *factory->GetPrototype(message_type);
156 } else {
157 GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
158 if (extension->is_lazy) {
159 return extension->lazymessage_value->GetMessage(
160 *factory->GetPrototype(message_type));
161 } else {
162 return *extension->message_value;
163 }
164 }
165 }
166
MutableMessage(const FieldDescriptor * descriptor,MessageFactory * factory)167 MessageLite* ExtensionSet::MutableMessage(const FieldDescriptor* descriptor,
168 MessageFactory* factory) {
169 Extension* extension;
170 if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) {
171 extension->type = descriptor->type();
172 GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE);
173 extension->is_repeated = false;
174 extension->is_packed = false;
175 const MessageLite* prototype =
176 factory->GetPrototype(descriptor->message_type());
177 extension->is_lazy = false;
178 extension->message_value = prototype->New(arena_);
179 extension->is_cleared = false;
180 return extension->message_value;
181 } else {
182 GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
183 extension->is_cleared = false;
184 if (extension->is_lazy) {
185 return extension->lazymessage_value->MutableMessage(
186 *factory->GetPrototype(descriptor->message_type()));
187 } else {
188 return extension->message_value;
189 }
190 }
191 }
192
ReleaseMessage(const FieldDescriptor * descriptor,MessageFactory * factory)193 MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor,
194 MessageFactory* factory) {
195 Extension* extension = FindOrNull(descriptor->number());
196 if (extension == NULL) {
197 // Not present. Return NULL.
198 return NULL;
199 } else {
200 GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
201 MessageLite* ret = NULL;
202 if (extension->is_lazy) {
203 ret = extension->lazymessage_value->ReleaseMessage(
204 *factory->GetPrototype(descriptor->message_type()));
205 if (arena_ == NULL) {
206 delete extension->lazymessage_value;
207 }
208 } else {
209 if (arena_ != NULL) {
210 ret = extension->message_value->New();
211 ret->CheckTypeAndMergeFrom(*extension->message_value);
212 } else {
213 ret = extension->message_value;
214 }
215 }
216 Erase(descriptor->number());
217 return ret;
218 }
219 }
220
UnsafeArenaReleaseMessage(const FieldDescriptor * descriptor,MessageFactory * factory)221 MessageLite* ExtensionSet::UnsafeArenaReleaseMessage(
222 const FieldDescriptor* descriptor, MessageFactory* factory) {
223 Extension* extension = FindOrNull(descriptor->number());
224 if (extension == NULL) {
225 // Not present. Return NULL.
226 return NULL;
227 } else {
228 GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
229 MessageLite* ret = NULL;
230 if (extension->is_lazy) {
231 ret = extension->lazymessage_value->UnsafeArenaReleaseMessage(
232 *factory->GetPrototype(descriptor->message_type()));
233 if (arena_ == NULL) {
234 delete extension->lazymessage_value;
235 }
236 } else {
237 ret = extension->message_value;
238 }
239 Erase(descriptor->number());
240 return ret;
241 }
242 }
243
MaybeNewRepeatedExtension(const FieldDescriptor * descriptor)244 ExtensionSet::Extension* ExtensionSet::MaybeNewRepeatedExtension(
245 const FieldDescriptor* descriptor) {
246 Extension* extension;
247 if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) {
248 extension->type = descriptor->type();
249 GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE);
250 extension->is_repeated = true;
251 extension->repeated_message_value =
252 Arena::CreateMessage<RepeatedPtrField<MessageLite> >(arena_);
253 } else {
254 GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE);
255 }
256 return extension;
257 }
258
AddMessage(const FieldDescriptor * descriptor,MessageFactory * factory)259 MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor,
260 MessageFactory* factory) {
261 Extension* extension = MaybeNewRepeatedExtension(descriptor);
262
263 // RepeatedPtrField<Message> does not know how to Add() since it cannot
264 // allocate an abstract object, so we have to be tricky.
265 MessageLite* result =
266 reinterpret_cast<internal::RepeatedPtrFieldBase*>(
267 extension->repeated_message_value)
268 ->AddFromCleared<GenericTypeHandler<MessageLite> >();
269 if (result == NULL) {
270 const MessageLite* prototype;
271 if (extension->repeated_message_value->size() == 0) {
272 prototype = factory->GetPrototype(descriptor->message_type());
273 GOOGLE_CHECK(prototype != NULL);
274 } else {
275 prototype = &extension->repeated_message_value->Get(0);
276 }
277 result = prototype->New(arena_);
278 extension->repeated_message_value->AddAllocated(result);
279 }
280 return result;
281 }
282
AddAllocatedMessage(const FieldDescriptor * descriptor,MessageLite * new_entry)283 void ExtensionSet::AddAllocatedMessage(const FieldDescriptor* descriptor,
284 MessageLite* new_entry) {
285 Extension* extension = MaybeNewRepeatedExtension(descriptor);
286
287 extension->repeated_message_value->AddAllocated(new_entry);
288 }
289
ValidateEnumUsingDescriptor(const void * arg,int number)290 static bool ValidateEnumUsingDescriptor(const void* arg, int number) {
291 return reinterpret_cast<const EnumDescriptor*>(arg)->FindValueByNumber(
292 number) != NULL;
293 }
294
Find(int number,ExtensionInfo * output)295 bool DescriptorPoolExtensionFinder::Find(int number, ExtensionInfo* output) {
296 const FieldDescriptor* extension =
297 pool_->FindExtensionByNumber(containing_type_, number);
298 if (extension == NULL) {
299 return false;
300 } else {
301 output->type = extension->type();
302 output->is_repeated = extension->is_repeated();
303 output->is_packed = extension->options().packed();
304 output->descriptor = extension;
305 if (extension->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
306 output->message_info.prototype =
307 factory_->GetPrototype(extension->message_type());
308 GOOGLE_CHECK(output->message_info.prototype != nullptr)
309 << "Extension factory's GetPrototype() returned NULL for extension: "
310 << extension->full_name();
311 } else if (extension->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
312 output->enum_validity_check.func = ValidateEnumUsingDescriptor;
313 output->enum_validity_check.arg = extension->enum_type();
314 }
315
316 return true;
317 }
318 }
319
320
FindExtension(int wire_type,uint32 field,const Message * containing_type,const internal::ParseContext * ctx,ExtensionInfo * extension,bool * was_packed_on_wire)321 bool ExtensionSet::FindExtension(int wire_type, uint32 field,
322 const Message* containing_type,
323 const internal::ParseContext* ctx,
324 ExtensionInfo* extension,
325 bool* was_packed_on_wire) {
326 if (ctx->data().pool == nullptr) {
327 GeneratedExtensionFinder finder(containing_type);
328 if (!FindExtensionInfoFromFieldNumber(wire_type, field, &finder, extension,
329 was_packed_on_wire)) {
330 return false;
331 }
332 } else {
333 DescriptorPoolExtensionFinder finder(ctx->data().pool, ctx->data().factory,
334 containing_type->GetDescriptor());
335 if (!FindExtensionInfoFromFieldNumber(wire_type, field, &finder, extension,
336 was_packed_on_wire)) {
337 return false;
338 }
339 }
340 return true;
341 }
342
ParseField(uint64 tag,const char * ptr,const Message * containing_type,internal::InternalMetadata * metadata,internal::ParseContext * ctx)343 const char* ExtensionSet::ParseField(uint64 tag, const char* ptr,
344 const Message* containing_type,
345 internal::InternalMetadata* metadata,
346 internal::ParseContext* ctx) {
347 int number = tag >> 3;
348 bool was_packed_on_wire;
349 ExtensionInfo extension;
350 if (!FindExtension(tag & 7, number, containing_type, ctx, &extension,
351 &was_packed_on_wire)) {
352 return UnknownFieldParse(
353 tag, metadata->mutable_unknown_fields<UnknownFieldSet>(), ptr, ctx);
354 }
355 return ParseFieldWithExtensionInfo<UnknownFieldSet>(
356 number, was_packed_on_wire, extension, metadata, ptr, ctx);
357 }
358
ParseFieldMaybeLazily(uint64 tag,const char * ptr,const Message * containing_type,internal::InternalMetadata * metadata,internal::ParseContext * ctx)359 const char* ExtensionSet::ParseFieldMaybeLazily(
360 uint64 tag, const char* ptr, const Message* containing_type,
361 internal::InternalMetadata* metadata, internal::ParseContext* ctx) {
362 return ParseField(tag, ptr, containing_type, metadata, ctx);
363 }
364
ParseMessageSetItem(const char * ptr,const Message * containing_type,internal::InternalMetadata * metadata,internal::ParseContext * ctx)365 const char* ExtensionSet::ParseMessageSetItem(
366 const char* ptr, const Message* containing_type,
367 internal::InternalMetadata* metadata, internal::ParseContext* ctx) {
368 return ParseMessageSetItemTmpl<Message, UnknownFieldSet>(ptr, containing_type,
369 metadata, ctx);
370 }
371
ParseField(uint32 tag,io::CodedInputStream * input,const Message * containing_type,UnknownFieldSet * unknown_fields)372 bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
373 const Message* containing_type,
374 UnknownFieldSet* unknown_fields) {
375 UnknownFieldSetFieldSkipper skipper(unknown_fields);
376 if (input->GetExtensionPool() == NULL) {
377 GeneratedExtensionFinder finder(containing_type);
378 return ParseField(tag, input, &finder, &skipper);
379 } else {
380 DescriptorPoolExtensionFinder finder(input->GetExtensionPool(),
381 input->GetExtensionFactory(),
382 containing_type->GetDescriptor());
383 return ParseField(tag, input, &finder, &skipper);
384 }
385 }
386
ParseMessageSet(io::CodedInputStream * input,const Message * containing_type,UnknownFieldSet * unknown_fields)387 bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
388 const Message* containing_type,
389 UnknownFieldSet* unknown_fields) {
390 MessageSetFieldSkipper skipper(unknown_fields);
391 if (input->GetExtensionPool() == NULL) {
392 GeneratedExtensionFinder finder(containing_type);
393 return ParseMessageSet(input, &finder, &skipper);
394 } else {
395 DescriptorPoolExtensionFinder finder(input->GetExtensionPool(),
396 input->GetExtensionFactory(),
397 containing_type->GetDescriptor());
398 return ParseMessageSet(input, &finder, &skipper);
399 }
400 }
401
SpaceUsedExcludingSelf() const402 int ExtensionSet::SpaceUsedExcludingSelf() const {
403 return internal::FromIntSize(SpaceUsedExcludingSelfLong());
404 }
405
SpaceUsedExcludingSelfLong() const406 size_t ExtensionSet::SpaceUsedExcludingSelfLong() const {
407 size_t total_size = Size() * sizeof(KeyValue);
408 ForEach([&total_size](int /* number */, const Extension& ext) {
409 total_size += ext.SpaceUsedExcludingSelfLong();
410 });
411 return total_size;
412 }
413
RepeatedMessage_SpaceUsedExcludingSelfLong(RepeatedPtrFieldBase * field)414 inline size_t ExtensionSet::RepeatedMessage_SpaceUsedExcludingSelfLong(
415 RepeatedPtrFieldBase* field) {
416 return field->SpaceUsedExcludingSelfLong<GenericTypeHandler<Message> >();
417 }
418
SpaceUsedExcludingSelfLong() const419 size_t ExtensionSet::Extension::SpaceUsedExcludingSelfLong() const {
420 size_t total_size = 0;
421 if (is_repeated) {
422 switch (cpp_type(type)) {
423 #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
424 case FieldDescriptor::CPPTYPE_##UPPERCASE: \
425 total_size += sizeof(*repeated_##LOWERCASE##_value) + \
426 repeated_##LOWERCASE##_value->SpaceUsedExcludingSelfLong(); \
427 break
428
429 HANDLE_TYPE(INT32, int32);
430 HANDLE_TYPE(INT64, int64);
431 HANDLE_TYPE(UINT32, uint32);
432 HANDLE_TYPE(UINT64, uint64);
433 HANDLE_TYPE(FLOAT, float);
434 HANDLE_TYPE(DOUBLE, double);
435 HANDLE_TYPE(BOOL, bool);
436 HANDLE_TYPE(ENUM, enum);
437 HANDLE_TYPE(STRING, string);
438 #undef HANDLE_TYPE
439
440 case FieldDescriptor::CPPTYPE_MESSAGE:
441 // repeated_message_value is actually a RepeatedPtrField<MessageLite>,
442 // but MessageLite has no SpaceUsedLong(), so we must directly call
443 // RepeatedPtrFieldBase::SpaceUsedExcludingSelfLong() with a different
444 // type handler.
445 total_size += sizeof(*repeated_message_value) +
446 RepeatedMessage_SpaceUsedExcludingSelfLong(
447 reinterpret_cast<internal::RepeatedPtrFieldBase*>(
448 repeated_message_value));
449 break;
450 }
451 } else {
452 switch (cpp_type(type)) {
453 case FieldDescriptor::CPPTYPE_STRING:
454 total_size += sizeof(*string_value) +
455 StringSpaceUsedExcludingSelfLong(*string_value);
456 break;
457 case FieldDescriptor::CPPTYPE_MESSAGE:
458 if (is_lazy) {
459 total_size += lazymessage_value->SpaceUsedLong();
460 } else {
461 total_size += down_cast<Message*>(message_value)->SpaceUsedLong();
462 }
463 break;
464 default:
465 // No extra storage costs for primitive types.
466 break;
467 }
468 }
469 return total_size;
470 }
471
SerializeMessageSetWithCachedSizesToArray(uint8 * target) const472 uint8* ExtensionSet::SerializeMessageSetWithCachedSizesToArray(
473 uint8* target) const {
474 io::EpsCopyOutputStream stream(
475 target, MessageSetByteSize(),
476 io::CodedOutputStream::IsDefaultSerializationDeterministic());
477 return InternalSerializeMessageSetWithCachedSizesToArray(target, &stream);
478 }
479
ParseFieldMaybeLazily(int wire_type,int field_number,io::CodedInputStream * input,ExtensionFinder * extension_finder,MessageSetFieldSkipper * field_skipper)480 bool ExtensionSet::ParseFieldMaybeLazily(
481 int wire_type, int field_number, io::CodedInputStream* input,
482 ExtensionFinder* extension_finder, MessageSetFieldSkipper* field_skipper) {
483 return ParseField(
484 WireFormatLite::MakeTag(field_number,
485 static_cast<WireFormatLite::WireType>(wire_type)),
486 input, extension_finder, field_skipper);
487 }
488
ParseMessageSet(io::CodedInputStream * input,ExtensionFinder * extension_finder,MessageSetFieldSkipper * field_skipper)489 bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
490 ExtensionFinder* extension_finder,
491 MessageSetFieldSkipper* field_skipper) {
492 while (true) {
493 const uint32 tag = input->ReadTag();
494 switch (tag) {
495 case 0:
496 return true;
497 case WireFormatLite::kMessageSetItemStartTag:
498 if (!ParseMessageSetItem(input, extension_finder, field_skipper)) {
499 return false;
500 }
501 break;
502 default:
503 if (!ParseField(tag, input, extension_finder, field_skipper)) {
504 return false;
505 }
506 break;
507 }
508 }
509 }
510
ParseMessageSetItem(io::CodedInputStream * input,ExtensionFinder * extension_finder,MessageSetFieldSkipper * field_skipper)511 bool ExtensionSet::ParseMessageSetItem(io::CodedInputStream* input,
512 ExtensionFinder* extension_finder,
513 MessageSetFieldSkipper* field_skipper) {
514 struct MSFull {
515 bool ParseField(int type_id, io::CodedInputStream* input) {
516 return me->ParseFieldMaybeLazily(
517 WireFormatLite::WIRETYPE_LENGTH_DELIMITED, type_id, input,
518 extension_finder, field_skipper);
519 }
520
521 bool SkipField(uint32 tag, io::CodedInputStream* input) {
522 return field_skipper->SkipField(input, tag);
523 }
524
525 ExtensionSet* me;
526 ExtensionFinder* extension_finder;
527 MessageSetFieldSkipper* field_skipper;
528 };
529
530 return ParseMessageSetItemImpl(input,
531 MSFull{this, extension_finder, field_skipper});
532 }
533
534 } // namespace internal
535 } // namespace protobuf
536 } // namespace google
537