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
38namespace google {
39namespace protobuf {
40namespace internal {
41
42template <typename T>
43const 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
204template <typename Msg, typename T>
205const 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