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/parse_context.h>
35 #include <google/protobuf/extension_set.h>
36
37 namespace google {
38 namespace protobuf {
39 namespace internal {
40
41 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
42 template <typename T>
ParseFieldWithExtensionInfo(int number,bool was_packed_on_wire,const ExtensionInfo & extension,T * metadata,const char * ptr,internal::ParseContext * ctx)43 const char* ExtensionSet::ParseFieldWithExtensionInfo(
44 int number, bool was_packed_on_wire, const ExtensionInfo& extension,
45 T* 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(
71 MutableRawRepeatedField(number, extension.type, extension.is_packed,
72 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 value; \
87 ptr = ParseVarint64(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 #undef HANDLE_VARINT_TYPE
103 #define HANDLE_SVARINT_TYPE(UPPERCASE, CPP_CAMELCASE, SIZE) \
104 case WireFormatLite::TYPE_##UPPERCASE: { \
105 uint64 val; \
106 ptr = ParseVarint64(ptr, &val); \
107 GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); \
108 auto value = WireFormatLite::ZigZagDecode##SIZE(val); \
109 if (extension.is_repeated) { \
110 Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \
111 extension.is_packed, value, extension.descriptor); \
112 } else { \
113 Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \
114 extension.descriptor); \
115 } \
116 } break
117
118 HANDLE_SVARINT_TYPE(SINT32, Int32, 32);
119 HANDLE_SVARINT_TYPE(SINT64, Int64, 64);
120 #undef HANDLE_SVARINT_TYPE
121 #define HANDLE_FIXED_TYPE(UPPERCASE, CPP_CAMELCASE, CPPTYPE) \
122 case WireFormatLite::TYPE_##UPPERCASE: { \
123 CPPTYPE value; \
124 std::memcpy(&value, ptr, sizeof(CPPTYPE)); \
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);
136 HANDLE_FIXED_TYPE(FIXED64, UInt64, uint64);
137 HANDLE_FIXED_TYPE(SFIXED32, Int32, int32);
138 HANDLE_FIXED_TYPE(SFIXED64, Int64, int64);
139 HANDLE_FIXED_TYPE(FLOAT, Float, float);
140 HANDLE_FIXED_TYPE(DOUBLE, Double, double);
141 HANDLE_FIXED_TYPE(BOOL, Bool, bool);
142 #undef HANDLE_FIXED_TYPE
143
144 case WireFormatLite::TYPE_ENUM: {
145 uint64 val;
146 ptr = ParseVarint64(ptr, &val);
147 GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
148 int value = val;
149
150 if (!extension.enum_validity_check.func(
151 extension.enum_validity_check.arg, value)) {
152 WriteVarint(number, val, metadata->mutable_unknown_fields());
153 } else if (extension.is_repeated) {
154 AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed, value,
155 extension.descriptor);
156 } else {
157 SetEnum(number, WireFormatLite::TYPE_ENUM, value,
158 extension.descriptor);
159 }
160 break;
161 }
162
163 case WireFormatLite::TYPE_BYTES:
164 case WireFormatLite::TYPE_STRING: {
165 std::string* value =
166 extension.is_repeated
167 ? AddString(number, WireFormatLite::TYPE_STRING,
168 extension.descriptor)
169 : MutableString(number, WireFormatLite::TYPE_STRING,
170 extension.descriptor);
171 int size = ReadSize(&ptr);
172 GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
173 return ctx->ReadString(ptr, size, value);
174 }
175
176 case WireFormatLite::TYPE_GROUP: {
177 MessageLite* value =
178 extension.is_repeated
179 ? AddMessage(number, WireFormatLite::TYPE_GROUP,
180 *extension.message_info.prototype,
181 extension.descriptor)
182 : MutableMessage(number, WireFormatLite::TYPE_GROUP,
183 *extension.message_info.prototype,
184 extension.descriptor);
185 uint32 tag = (number << 3) + WireFormatLite::WIRETYPE_START_GROUP;
186 return ctx->ParseGroup(value, ptr, tag);
187 }
188
189 case WireFormatLite::TYPE_MESSAGE: {
190 MessageLite* value =
191 extension.is_repeated
192 ? AddMessage(number, WireFormatLite::TYPE_MESSAGE,
193 *extension.message_info.prototype,
194 extension.descriptor)
195 : MutableMessage(number, WireFormatLite::TYPE_MESSAGE,
196 *extension.message_info.prototype,
197 extension.descriptor);
198 return ctx->ParseMessage(value, ptr);
199 }
200 }
201 }
202 return ptr;
203 }
204
205 template <typename Msg, typename Metadata>
ParseMessageSetItemTmpl(const char * ptr,const Msg * containing_type,Metadata * metadata,internal::ParseContext * ctx)206 const char* ExtensionSet::ParseMessageSetItemTmpl(const char* ptr,
207 const Msg* containing_type,
208 Metadata* metadata,
209 internal::ParseContext* ctx) {
210 std::string payload;
211 uint32 type_id = 0;
212 while (!ctx->Done(&ptr)) {
213 uint32 tag = static_cast<uint8>(*ptr++);
214 if (tag == WireFormatLite::kMessageSetTypeIdTag) {
215 uint64 tmp;
216 ptr = ParseVarint64Inline(ptr, &tmp);
217 GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
218 type_id = tmp;
219 if (!payload.empty()) {
220 ExtensionInfo extension;
221 bool was_packed_on_wire;
222 if (!FindExtension(2, type_id, containing_type, ctx, &extension,
223 &was_packed_on_wire)) {
224 WriteLengthDelimited(type_id, payload,
225 metadata->mutable_unknown_fields());
226 } else {
227 MessageLite* value =
228 extension.is_repeated
229 ? AddMessage(type_id, WireFormatLite::TYPE_MESSAGE,
230 *extension.message_info.prototype,
231 extension.descriptor)
232 : MutableMessage(type_id, WireFormatLite::TYPE_MESSAGE,
233 *extension.message_info.prototype,
234 extension.descriptor);
235
236 const char* p;
237 // We can't use regular parse from string as we have to track
238 // proper recursion depth and descriptor pools.
239 ParseContext tmp_ctx(ctx->depth(), false, &p, payload);
240 tmp_ctx.data().pool = ctx->data().pool;
241 tmp_ctx.data().factory = ctx->data().factory;
242 GOOGLE_PROTOBUF_PARSER_ASSERT(value->_InternalParse(p, &tmp_ctx) &&
243 tmp_ctx.EndedAtLimit());
244 }
245 type_id = 0;
246 }
247 } else if (tag == WireFormatLite::kMessageSetMessageTag) {
248 if (type_id != 0) {
249 ptr = ParseFieldMaybeLazily(static_cast<uint64>(type_id) * 8 + 2, ptr,
250 containing_type, metadata, ctx);
251 GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
252 type_id = 0;
253 } else {
254 int32 size = ReadSize(&ptr);
255 GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
256 ptr = ctx->ReadString(ptr, size, &payload);
257 GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
258 }
259 } else {
260 if (tag >= 128) {
261 // Parse remainder of tag varint
262 uint32 tmp;
263 ptr = VarintParse<4>(ptr, &tmp);
264 GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
265 tag += (tmp - 1) << 7;
266 }
267 if (tag == 0 || (tag & 7) == 4) {
268 ctx->SetLastTag(tag);
269 return ptr;
270 }
271 ptr = ParseField(tag, ptr, containing_type, metadata, ctx);
272 GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
273 }
274 }
275 return ptr;
276 }
277 #endif // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
278
279 } // namespace internal
280 } // namespace protobuf
281 } // namespace google
282
283 #endif // GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__
284