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