// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__ #define GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__ #include #include #include namespace google { namespace protobuf { namespace internal { template const char* ExtensionSet::ParseFieldWithExtensionInfo( int number, bool was_packed_on_wire, const ExtensionInfo& extension, InternalMetadata* metadata, const char* ptr, internal::ParseContext* ctx) { if (was_packed_on_wire) { switch (extension.type) { #define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE) \ case WireFormatLite::TYPE_##UPPERCASE: \ return internal::Packed##CPP_CAMELCASE##Parser( \ MutableRawRepeatedField(number, extension.type, extension.is_packed, \ extension.descriptor), \ ptr, ctx); HANDLE_TYPE(INT32, Int32); HANDLE_TYPE(INT64, Int64); HANDLE_TYPE(UINT32, UInt32); HANDLE_TYPE(UINT64, UInt64); HANDLE_TYPE(SINT32, SInt32); HANDLE_TYPE(SINT64, SInt64); HANDLE_TYPE(FIXED32, Fixed32); HANDLE_TYPE(FIXED64, Fixed64); HANDLE_TYPE(SFIXED32, SFixed32); HANDLE_TYPE(SFIXED64, SFixed64); HANDLE_TYPE(FLOAT, Float); HANDLE_TYPE(DOUBLE, Double); HANDLE_TYPE(BOOL, Bool); #undef HANDLE_TYPE case WireFormatLite::TYPE_ENUM: return internal::PackedEnumParserArg( MutableRawRepeatedField(number, extension.type, extension.is_packed, extension.descriptor), ptr, ctx, extension.enum_validity_check.func, extension.enum_validity_check.arg, metadata, number); case WireFormatLite::TYPE_STRING: case WireFormatLite::TYPE_BYTES: case WireFormatLite::TYPE_GROUP: case WireFormatLite::TYPE_MESSAGE: GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed."; break; } } else { switch (extension.type) { #define HANDLE_VARINT_TYPE(UPPERCASE, CPP_CAMELCASE) \ case WireFormatLite::TYPE_##UPPERCASE: { \ uint64 value; \ ptr = VarintParse(ptr, &value); \ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); \ if (extension.is_repeated) { \ Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \ extension.is_packed, value, extension.descriptor); \ } else { \ Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \ extension.descriptor); \ } \ } break HANDLE_VARINT_TYPE(INT32, Int32); HANDLE_VARINT_TYPE(INT64, Int64); HANDLE_VARINT_TYPE(UINT32, UInt32); HANDLE_VARINT_TYPE(UINT64, UInt64); HANDLE_VARINT_TYPE(BOOL, Bool); #undef HANDLE_VARINT_TYPE #define HANDLE_SVARINT_TYPE(UPPERCASE, CPP_CAMELCASE, SIZE) \ case WireFormatLite::TYPE_##UPPERCASE: { \ uint64 val; \ ptr = VarintParse(ptr, &val); \ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); \ auto value = WireFormatLite::ZigZagDecode##SIZE(val); \ if (extension.is_repeated) { \ Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \ extension.is_packed, value, extension.descriptor); \ } else { \ Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \ extension.descriptor); \ } \ } break HANDLE_SVARINT_TYPE(SINT32, Int32, 32); HANDLE_SVARINT_TYPE(SINT64, Int64, 64); #undef HANDLE_SVARINT_TYPE #define HANDLE_FIXED_TYPE(UPPERCASE, CPP_CAMELCASE, CPPTYPE) \ case WireFormatLite::TYPE_##UPPERCASE: { \ auto value = UnalignedLoad(ptr); \ ptr += sizeof(CPPTYPE); \ if (extension.is_repeated) { \ Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \ extension.is_packed, value, extension.descriptor); \ } else { \ Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \ extension.descriptor); \ } \ } break HANDLE_FIXED_TYPE(FIXED32, UInt32, uint32); HANDLE_FIXED_TYPE(FIXED64, UInt64, uint64); HANDLE_FIXED_TYPE(SFIXED32, Int32, int32); HANDLE_FIXED_TYPE(SFIXED64, Int64, int64); HANDLE_FIXED_TYPE(FLOAT, Float, float); HANDLE_FIXED_TYPE(DOUBLE, Double, double); #undef HANDLE_FIXED_TYPE case WireFormatLite::TYPE_ENUM: { uint64 val; ptr = VarintParse(ptr, &val); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); int value = val; if (!extension.enum_validity_check.func( extension.enum_validity_check.arg, value)) { WriteVarint(number, val, metadata->mutable_unknown_fields()); } else if (extension.is_repeated) { AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed, value, extension.descriptor); } else { SetEnum(number, WireFormatLite::TYPE_ENUM, value, extension.descriptor); } break; } case WireFormatLite::TYPE_BYTES: case WireFormatLite::TYPE_STRING: { std::string* value = extension.is_repeated ? AddString(number, WireFormatLite::TYPE_STRING, extension.descriptor) : MutableString(number, WireFormatLite::TYPE_STRING, extension.descriptor); int size = ReadSize(&ptr); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); return ctx->ReadString(ptr, size, value); } case WireFormatLite::TYPE_GROUP: { MessageLite* value = extension.is_repeated ? AddMessage(number, WireFormatLite::TYPE_GROUP, *extension.message_info.prototype, extension.descriptor) : MutableMessage(number, WireFormatLite::TYPE_GROUP, *extension.message_info.prototype, extension.descriptor); uint32 tag = (number << 3) + WireFormatLite::WIRETYPE_START_GROUP; return ctx->ParseGroup(value, ptr, tag); } case WireFormatLite::TYPE_MESSAGE: { MessageLite* value = extension.is_repeated ? AddMessage(number, WireFormatLite::TYPE_MESSAGE, *extension.message_info.prototype, extension.descriptor) : MutableMessage(number, WireFormatLite::TYPE_MESSAGE, *extension.message_info.prototype, extension.descriptor); return ctx->ParseMessage(value, ptr); } } } return ptr; } template const char* ExtensionSet::ParseMessageSetItemTmpl( const char* ptr, const Msg* containing_type, internal::InternalMetadata* metadata, internal::ParseContext* ctx) { std::string payload; uint32 type_id = 0; while (!ctx->Done(&ptr)) { uint32 tag = static_cast(*ptr++); if (tag == WireFormatLite::kMessageSetTypeIdTag) { uint64 tmp; ptr = ParseBigVarint(ptr, &tmp); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); type_id = tmp; if (!payload.empty()) { ExtensionInfo extension; bool was_packed_on_wire; if (!FindExtension(2, type_id, containing_type, ctx, &extension, &was_packed_on_wire)) { WriteLengthDelimited(type_id, payload, metadata->mutable_unknown_fields()); } else { MessageLite* value = extension.is_repeated ? AddMessage(type_id, WireFormatLite::TYPE_MESSAGE, *extension.message_info.prototype, extension.descriptor) : MutableMessage(type_id, WireFormatLite::TYPE_MESSAGE, *extension.message_info.prototype, extension.descriptor); const char* p; // We can't use regular parse from string as we have to track // proper recursion depth and descriptor pools. ParseContext tmp_ctx(ctx->depth(), false, &p, payload); tmp_ctx.data().pool = ctx->data().pool; tmp_ctx.data().factory = ctx->data().factory; GOOGLE_PROTOBUF_PARSER_ASSERT(value->_InternalParse(p, &tmp_ctx) && tmp_ctx.EndedAtLimit()); } type_id = 0; } } else if (tag == WireFormatLite::kMessageSetMessageTag) { if (type_id != 0) { ptr = ParseFieldMaybeLazily(static_cast(type_id) * 8 + 2, ptr, containing_type, metadata, ctx); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr); type_id = 0; } else { int32 size = ReadSize(&ptr); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); ptr = ctx->ReadString(ptr, size, &payload); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); } } else { ptr = ReadTag(ptr - 1, &tag); if (tag == 0 || (tag & 7) == 4) { ctx->SetLastTag(tag); return ptr; } ptr = ParseField(tag, ptr, containing_type, metadata, ctx); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); } } return ptr; } } // namespace internal } // namespace protobuf } // namespace google #endif // GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__