| 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 | |