• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 #ifndef GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__
9 #define GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__
10 
11 #include "google/protobuf/extension_set.h"
12 #include "google/protobuf/metadata_lite.h"
13 #include "google/protobuf/parse_context.h"
14 
15 namespace google {
16 namespace protobuf {
17 namespace internal {
18 
19 template <typename T>
ParseFieldWithExtensionInfo(int number,bool was_packed_on_wire,const ExtensionInfo & extension,InternalMetadata * metadata,const char * ptr,internal::ParseContext * ctx)20 const char* ExtensionSet::ParseFieldWithExtensionInfo(
21     int number, bool was_packed_on_wire, const ExtensionInfo& extension,
22     InternalMetadata* metadata, const char* ptr, internal::ParseContext* ctx) {
23   if (was_packed_on_wire) {
24     switch (extension.type) {
25 #define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE)                                \
26   case WireFormatLite::TYPE_##UPPERCASE:                                     \
27     return internal::Packed##CPP_CAMELCASE##Parser(                          \
28         MutableRawRepeatedField(number, extension.type, extension.is_packed, \
29                                 extension.descriptor),                       \
30         ptr, ctx);
31       HANDLE_TYPE(INT32, Int32);
32       HANDLE_TYPE(INT64, Int64);
33       HANDLE_TYPE(UINT32, UInt32);
34       HANDLE_TYPE(UINT64, UInt64);
35       HANDLE_TYPE(SINT32, SInt32);
36       HANDLE_TYPE(SINT64, SInt64);
37       HANDLE_TYPE(FIXED32, Fixed32);
38       HANDLE_TYPE(FIXED64, Fixed64);
39       HANDLE_TYPE(SFIXED32, SFixed32);
40       HANDLE_TYPE(SFIXED64, SFixed64);
41       HANDLE_TYPE(FLOAT, Float);
42       HANDLE_TYPE(DOUBLE, Double);
43       HANDLE_TYPE(BOOL, Bool);
44 #undef HANDLE_TYPE
45 
46       case WireFormatLite::TYPE_ENUM:
47         return internal::PackedEnumParserArg<T>(
48             MutableRawRepeatedField(number, extension.type, extension.is_packed,
49                                     extension.descriptor),
50             ptr, ctx, extension.enum_validity_check.func,
51             extension.enum_validity_check.arg, metadata, number);
52       case WireFormatLite::TYPE_STRING:
53       case WireFormatLite::TYPE_BYTES:
54       case WireFormatLite::TYPE_GROUP:
55       case WireFormatLite::TYPE_MESSAGE:
56         ABSL_LOG(FATAL) << "Non-primitive types can't be packed.";
57         break;
58     }
59   } else {
60     switch (extension.type) {
61 #define HANDLE_VARINT_TYPE(UPPERCASE, CPP_CAMELCASE)                        \
62   case WireFormatLite::TYPE_##UPPERCASE: {                                  \
63     uint64_t value;                                                         \
64     ptr = VarintParse(ptr, &value);                                         \
65     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);                                    \
66     if (extension.is_repeated) {                                            \
67       Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
68                          extension.is_packed, value, extension.descriptor); \
69     } else {                                                                \
70       Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value,   \
71                          extension.descriptor);                             \
72     }                                                                       \
73   } break
74 
75       HANDLE_VARINT_TYPE(INT32, Int32);
76       HANDLE_VARINT_TYPE(INT64, Int64);
77       HANDLE_VARINT_TYPE(UINT32, UInt32);
78       HANDLE_VARINT_TYPE(UINT64, UInt64);
79       HANDLE_VARINT_TYPE(BOOL, Bool);
80 #undef HANDLE_VARINT_TYPE
81 #define HANDLE_SVARINT_TYPE(UPPERCASE, CPP_CAMELCASE, SIZE)                 \
82   case WireFormatLite::TYPE_##UPPERCASE: {                                  \
83     uint64_t val;                                                           \
84     ptr = VarintParse(ptr, &val);                                           \
85     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);                                    \
86     auto value = WireFormatLite::ZigZagDecode##SIZE(val);                   \
87     if (extension.is_repeated) {                                            \
88       Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
89                          extension.is_packed, value, extension.descriptor); \
90     } else {                                                                \
91       Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value,   \
92                          extension.descriptor);                             \
93     }                                                                       \
94   } break
95 
96       HANDLE_SVARINT_TYPE(SINT32, Int32, 32);
97       HANDLE_SVARINT_TYPE(SINT64, Int64, 64);
98 #undef HANDLE_SVARINT_TYPE
99 #define HANDLE_FIXED_TYPE(UPPERCASE, CPP_CAMELCASE, CPPTYPE)                \
100   case WireFormatLite::TYPE_##UPPERCASE: {                                  \
101     auto value = UnalignedLoad<CPPTYPE>(ptr);                               \
102     ptr += sizeof(CPPTYPE);                                                 \
103     if (extension.is_repeated) {                                            \
104       Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
105                          extension.is_packed, value, extension.descriptor); \
106     } else {                                                                \
107       Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value,   \
108                          extension.descriptor);                             \
109     }                                                                       \
110   } break
111 
112       HANDLE_FIXED_TYPE(FIXED32, UInt32, uint32_t);
113       HANDLE_FIXED_TYPE(FIXED64, UInt64, uint64_t);
114       HANDLE_FIXED_TYPE(SFIXED32, Int32, int32_t);
115       HANDLE_FIXED_TYPE(SFIXED64, Int64, int64_t);
116       HANDLE_FIXED_TYPE(FLOAT, Float, float);
117       HANDLE_FIXED_TYPE(DOUBLE, Double, double);
118 #undef HANDLE_FIXED_TYPE
119 
120       case WireFormatLite::TYPE_ENUM: {
121         uint64_t tmp;
122         ptr = VarintParse(ptr, &tmp);
123         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
124         int value = tmp;
125 
126         if (!extension.enum_validity_check.func(
127                 extension.enum_validity_check.arg, value)) {
128           WriteVarint(number, value, metadata->mutable_unknown_fields<T>());
129         } else if (extension.is_repeated) {
130           AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed, value,
131                   extension.descriptor);
132         } else {
133           SetEnum(number, WireFormatLite::TYPE_ENUM, value,
134                   extension.descriptor);
135         }
136         break;
137       }
138 
139       case WireFormatLite::TYPE_BYTES:
140       case WireFormatLite::TYPE_STRING: {
141         std::string* value =
142             extension.is_repeated
143                 ? AddString(number, WireFormatLite::TYPE_STRING,
144                             extension.descriptor)
145                 : MutableString(number, WireFormatLite::TYPE_STRING,
146                                 extension.descriptor);
147         int size = ReadSize(&ptr);
148         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
149         return ctx->ReadString(ptr, size, value);
150       }
151 
152       case WireFormatLite::TYPE_GROUP: {
153         MessageLite* value =
154             extension.is_repeated
155                 ? AddMessage(number, WireFormatLite::TYPE_GROUP,
156                              *extension.message_info.prototype,
157                              extension.descriptor)
158                 : MutableMessage(number, WireFormatLite::TYPE_GROUP,
159                                  *extension.message_info.prototype,
160                                  extension.descriptor);
161         uint32_t tag = (number << 3) + WireFormatLite::WIRETYPE_START_GROUP;
162         return ctx->ParseGroup(value, ptr, tag);
163       }
164 
165       case WireFormatLite::TYPE_MESSAGE: {
166         MessageLite* value =
167             extension.is_repeated
168                 ? AddMessage(number, WireFormatLite::TYPE_MESSAGE,
169                              *extension.message_info.prototype,
170                              extension.descriptor)
171                 : MutableMessage(number, WireFormatLite::TYPE_MESSAGE,
172                                  *extension.message_info.prototype,
173                                  extension.descriptor);
174         return ctx->ParseMessage(value, ptr);
175       }
176     }
177   }
178   return ptr;
179 }
180 
181 template <typename Msg, typename T>
ParseMessageSetItemTmpl(const char * ptr,const Msg * extendee,internal::InternalMetadata * metadata,internal::ParseContext * ctx)182 const char* ExtensionSet::ParseMessageSetItemTmpl(
183     const char* ptr, const Msg* extendee, internal::InternalMetadata* metadata,
184     internal::ParseContext* ctx) {
185   std::string payload;
186   uint32_t type_id = 0;
187   enum class State { kNoTag, kHasType, kHasPayload, kDone };
188   State state = State::kNoTag;
189 
190   while (!ctx->Done(&ptr)) {
191     uint32_t tag = static_cast<uint8_t>(*ptr++);
192     if (tag == WireFormatLite::kMessageSetTypeIdTag) {
193       uint64_t tmp;
194       ptr = ParseBigVarint(ptr, &tmp);
195       // We should fail parsing if type id is 0 after cast to uint32.
196       GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr &&
197                                      static_cast<uint32_t>(tmp) != 0);
198       if (state == State::kNoTag) {
199         type_id = static_cast<uint32_t>(tmp);
200         state = State::kHasType;
201       } else if (state == State::kHasPayload) {
202         type_id = static_cast<uint32_t>(tmp);
203         ExtensionInfo extension;
204         bool was_packed_on_wire;
205         if (!FindExtension(2, type_id, extendee, ctx, &extension,
206                            &was_packed_on_wire)) {
207           WriteLengthDelimited(type_id, payload,
208                                metadata->mutable_unknown_fields<T>());
209         } else {
210           MessageLite* value =
211               extension.is_repeated
212                   ? AddMessage(type_id, WireFormatLite::TYPE_MESSAGE,
213                                *extension.message_info.prototype,
214                                extension.descriptor)
215                   : MutableMessage(type_id, WireFormatLite::TYPE_MESSAGE,
216                                    *extension.message_info.prototype,
217                                    extension.descriptor);
218 
219           const char* p;
220           // We can't use regular parse from string as we have to track
221           // proper recursion depth and descriptor pools. Spawn a new
222           // ParseContext inheriting those attributes.
223           ParseContext tmp_ctx(ParseContext::kSpawn, *ctx, &p, payload);
224           GOOGLE_PROTOBUF_PARSER_ASSERT(value->_InternalParse(p, &tmp_ctx) &&
225                                          tmp_ctx.EndedAtLimit());
226         }
227         state = State::kDone;
228       }
229     } else if (tag == WireFormatLite::kMessageSetMessageTag) {
230       if (state == State::kHasType) {
231         ptr = ParseFieldMaybeLazily(static_cast<uint64_t>(type_id) * 8 + 2, ptr,
232                                     extendee, metadata, ctx);
233         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
234         state = State::kDone;
235       } else {
236         std::string tmp;
237         int32_t size = ReadSize(&ptr);
238         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
239         ptr = ctx->ReadString(ptr, size, &tmp);
240         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
241         if (state == State::kNoTag) {
242           payload = std::move(tmp);
243           state = State::kHasPayload;
244         }
245       }
246     } else {
247       ptr = ReadTag(ptr - 1, &tag);
248       if (tag == 0 || (tag & 7) == 4) {
249         ctx->SetLastTag(tag);
250         return ptr;
251       }
252       ptr = ParseField(tag, ptr, extendee, metadata, ctx);
253       GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
254     }
255   }
256   return ptr;
257 }
258 
259 }  // namespace internal
260 }  // namespace protobuf
261 }  // namespace google
262 
263 #endif  // GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__
264