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// Author: kenton@google.com (Kenton Varda)
32// Based on original Protocol Buffers design by
33// Sanjay Ghemawat, Jeff Dean, and others.
34
35#include <google/protobuf/generated_message_util.h>
36
37#include <atomic>
38#include <limits>
39#include <vector>
40
41#include <google/protobuf/io/coded_stream.h>
42#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
43#include <google/protobuf/arenastring.h>
44#include <google/protobuf/extension_set.h>
45#include <google/protobuf/message_lite.h>
46#include <google/protobuf/metadata_lite.h>
47#include <google/protobuf/repeated_field.h>
48#include <google/protobuf/wire_format_lite.h>
49
50// Must be included last
51#include <google/protobuf/port_def.inc>
52
53PROTOBUF_PRAGMA_INIT_SEG
54
55
56namespace google {
57namespace protobuf {
58namespace internal {
59
60void DestroyMessage(const void* message) {
61 static_cast<const MessageLite*>(message)->~MessageLite();
62}
63void DestroyString(const void* s) {
64 static_cast<const std::string*>(s)->~basic_string();
65}
66
67PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT
68 PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ExplicitlyConstructedArenaString
69 fixed_address_empty_string{}; // NOLINT
70
71
72PROTOBUF_CONSTINIT std::atomic<bool> init_protobuf_defaults_state{false};
73static bool InitProtobufDefaultsImpl() {
74 fixed_address_empty_string.DefaultConstruct();
75 OnShutdownDestroyString(ptr: fixed_address_empty_string.get_mutable());
76
77
78 init_protobuf_defaults_state.store(i: true, m: std::memory_order_release);
79 return true;
80}
81
82void InitProtobufDefaultsSlow() {
83 static bool is_inited = InitProtobufDefaultsImpl();
84 (void)is_inited;
85}
86// Force the initialization of the empty string.
87// Normally, registration would do it, but we don't have any guarantee that
88// there is any object with reflection.
89PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 static std::true_type init_empty_string =
90 (InitProtobufDefaultsSlow(), std::true_type{});
91
92size_t StringSpaceUsedExcludingSelfLong(const std::string& str) {
93 const void* start = &str;
94 const void* end = &str + 1;
95 if (start <= str.data() && str.data() < end) {
96 // The string's data is stored inside the string object itself.
97 return 0;
98 } else {
99 return str.capacity();
100 }
101}
102
103template <typename T>
104const T& Get(const void* ptr) {
105 return *static_cast<const T*>(ptr);
106}
107
108// PrimitiveTypeHelper is a wrapper around the interface of WireFormatLite.
109// WireFormatLite has a very inconvenient interface with respect to template
110// meta-programming. This class wraps the different named functions into
111// a single Serialize / SerializeToArray interface.
112template <int type>
113struct PrimitiveTypeHelper;
114
115template <>
116struct PrimitiveTypeHelper<WireFormatLite::TYPE_BOOL> {
117 typedef bool Type;
118 static void Serialize(const void* ptr, io::CodedOutputStream* output) {
119 WireFormatLite::WriteBoolNoTag(value: Get<bool>(ptr), output);
120 }
121 static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
122 return WireFormatLite::WriteBoolNoTagToArray(value: Get<Type>(ptr), target: buffer);
123 }
124};
125
126template <>
127struct PrimitiveTypeHelper<WireFormatLite::TYPE_INT32> {
128 typedef int32_t Type;
129 static void Serialize(const void* ptr, io::CodedOutputStream* output) {
130 WireFormatLite::WriteInt32NoTag(value: Get<int32_t>(ptr), output);
131 }
132 static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
133 return WireFormatLite::WriteInt32NoTagToArray(value: Get<Type>(ptr), target: buffer);
134 }
135};
136
137template <>
138struct PrimitiveTypeHelper<WireFormatLite::TYPE_SINT32> {
139 typedef int32_t Type;
140 static void Serialize(const void* ptr, io::CodedOutputStream* output) {
141 WireFormatLite::WriteSInt32NoTag(value: Get<int32_t>(ptr), output);
142 }
143 static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
144 return WireFormatLite::WriteSInt32NoTagToArray(value: Get<Type>(ptr), target: buffer);
145 }
146};
147
148template <>
149struct PrimitiveTypeHelper<WireFormatLite::TYPE_UINT32> {
150 typedef uint32_t Type;
151 static void Serialize(const void* ptr, io::CodedOutputStream* output) {
152 WireFormatLite::WriteUInt32NoTag(value: Get<uint32_t>(ptr), output);
153 }
154 static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
155 return WireFormatLite::WriteUInt32NoTagToArray(value: Get<Type>(ptr), target: buffer);
156 }
157};
158template <>
159struct PrimitiveTypeHelper<WireFormatLite::TYPE_INT64> {
160 typedef int64_t Type;
161 static void Serialize(const void* ptr, io::CodedOutputStream* output) {
162 WireFormatLite::WriteInt64NoTag(value: Get<int64_t>(ptr), output);
163 }
164 static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
165 return WireFormatLite::WriteInt64NoTagToArray(value: Get<Type>(ptr), target: buffer);
166 }
167};
168
169template <>
170struct PrimitiveTypeHelper<WireFormatLite::TYPE_SINT64> {
171 typedef int64_t Type;
172 static void Serialize(const void* ptr, io::CodedOutputStream* output) {
173 WireFormatLite::WriteSInt64NoTag(value: Get<int64_t>(ptr), output);
174 }
175 static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
176 return WireFormatLite::WriteSInt64NoTagToArray(value: Get<Type>(ptr), target: buffer);
177 }
178};
179template <>
180struct PrimitiveTypeHelper<WireFormatLite::TYPE_UINT64> {
181 typedef uint64_t Type;
182 static void Serialize(const void* ptr, io::CodedOutputStream* output) {
183 WireFormatLite::WriteUInt64NoTag(value: Get<uint64_t>(ptr), output);
184 }
185 static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
186 return WireFormatLite::WriteUInt64NoTagToArray(value: Get<Type>(ptr), target: buffer);
187 }
188};
189
190template <>
191struct PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
192 typedef uint32_t Type;
193 static void Serialize(const void* ptr, io::CodedOutputStream* output) {
194 WireFormatLite::WriteFixed32NoTag(value: Get<uint32_t>(ptr), output);
195 }
196 static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
197 return WireFormatLite::WriteFixed32NoTagToArray(value: Get<Type>(ptr), target: buffer);
198 }
199};
200
201template <>
202struct PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
203 typedef uint64_t Type;
204 static void Serialize(const void* ptr, io::CodedOutputStream* output) {
205 WireFormatLite::WriteFixed64NoTag(value: Get<uint64_t>(ptr), output);
206 }
207 static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
208 return WireFormatLite::WriteFixed64NoTagToArray(value: Get<Type>(ptr), target: buffer);
209 }
210};
211
212template <>
213struct PrimitiveTypeHelper<WireFormatLite::TYPE_ENUM>
214 : PrimitiveTypeHelper<WireFormatLite::TYPE_INT32> {};
215
216template <>
217struct PrimitiveTypeHelper<WireFormatLite::TYPE_SFIXED32>
218 : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
219 typedef int32_t Type;
220};
221template <>
222struct PrimitiveTypeHelper<WireFormatLite::TYPE_SFIXED64>
223 : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
224 typedef int64_t Type;
225};
226template <>
227struct PrimitiveTypeHelper<WireFormatLite::TYPE_FLOAT>
228 : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
229 typedef float Type;
230};
231template <>
232struct PrimitiveTypeHelper<WireFormatLite::TYPE_DOUBLE>
233 : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
234 typedef double Type;
235};
236
237template <>
238struct PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {
239 typedef std::string Type;
240 static void Serialize(const void* ptr, io::CodedOutputStream* output) {
241 const Type& value = *static_cast<const Type*>(ptr);
242 output->WriteVarint32(value: value.size());
243 output->WriteRawMaybeAliased(data: value.data(), size: value.size());
244 }
245 static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
246 const Type& value = *static_cast<const Type*>(ptr);
247 return io::CodedOutputStream::WriteStringWithSizeToArray(str: value, target: buffer);
248 }
249};
250
251template <>
252struct PrimitiveTypeHelper<WireFormatLite::TYPE_BYTES>
253 : PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {};
254
255// We want to serialize to both CodedOutputStream and directly into byte arrays
256// without duplicating the code. In fact we might want extra output channels in
257// the future.
258template <typename O, int type>
259struct OutputHelper;
260
261template <int type, typename O>
262void SerializeTo(const void* ptr, O* output) {
263 OutputHelper<O, type>::Serialize(ptr, output);
264}
265
266template <typename O>
267void WriteTagTo(uint32_t tag, O* output) {
268 SerializeTo<WireFormatLite::TYPE_UINT32>(&tag, output);
269}
270
271template <typename O>
272void WriteLengthTo(uint32_t length, O* output) {
273 SerializeTo<WireFormatLite::TYPE_UINT32>(&length, output);
274}
275
276// Specialization for coded output stream
277template <int type>
278struct OutputHelper<io::CodedOutputStream, type> {
279 static void Serialize(const void* ptr, io::CodedOutputStream* output) {
280 PrimitiveTypeHelper<type>::Serialize(ptr, output);
281 }
282};
283
284// Specialization for writing into a plain array
285struct ArrayOutput {
286 uint8_t* ptr;
287 bool is_deterministic;
288};
289
290template <int type>
291struct OutputHelper<ArrayOutput, type> {
292 static void Serialize(const void* ptr, ArrayOutput* output) {
293 output->ptr = PrimitiveTypeHelper<type>::SerializeToArray(ptr, output->ptr);
294 }
295};
296
297void SerializeMessageNoTable(const MessageLite* msg,
298 io::CodedOutputStream* output) {
299 msg->SerializeWithCachedSizes(output);
300}
301
302void SerializeMessageNoTable(const MessageLite* msg, ArrayOutput* output) {
303 io::ArrayOutputStream array_stream(output->ptr, INT_MAX);
304 io::CodedOutputStream o(&array_stream);
305 o.SetSerializationDeterministic(output->is_deterministic);
306 msg->SerializeWithCachedSizes(output: &o);
307 output->ptr += o.ByteCount();
308}
309
310// We need to use a helper class to get access to the private members
311class AccessorHelper {
312 public:
313 static int Size(const RepeatedPtrFieldBase& x) { return x.size(); }
314 static void const* Get(const RepeatedPtrFieldBase& x, int idx) {
315 return x.raw_data()[idx];
316 }
317};
318
319void SerializeNotImplemented(int field) {
320 GOOGLE_LOG(FATAL) << "Not implemented field number " << field;
321}
322
323// When switching to c++11 we should make these constexpr functions
324#define SERIALIZE_TABLE_OP(type, type_class) \
325 ((type - 1) + static_cast<int>(type_class) * FieldMetadata::kNumTypes)
326
327template <int type>
328bool IsNull(const void* ptr) {
329 return *static_cast<const typename PrimitiveTypeHelper<type>::Type*>(ptr) ==
330 0;
331}
332
333template <>
334bool IsNull<WireFormatLite::TYPE_STRING>(const void* ptr) {
335 return static_cast<const ArenaStringPtr*>(ptr)->Get().size() == 0;
336}
337
338template <>
339bool IsNull<WireFormatLite::TYPE_BYTES>(const void* ptr) {
340 return static_cast<const ArenaStringPtr*>(ptr)->Get().size() == 0;
341}
342
343template <>
344bool IsNull<WireFormatLite::TYPE_GROUP>(const void* ptr) {
345 return Get<const MessageLite*>(ptr) == nullptr;
346}
347
348template <>
349bool IsNull<WireFormatLite::TYPE_MESSAGE>(const void* ptr) {
350 return Get<const MessageLite*>(ptr) == nullptr;
351}
352
353void ExtensionSerializer(const MessageLite* extendee, const uint8_t* ptr,
354 uint32_t offset, uint32_t tag, uint32_t has_offset,
355 io::CodedOutputStream* output) {
356 reinterpret_cast<const ExtensionSet*>(ptr + offset)
357 ->SerializeWithCachedSizes(extendee, start_field_number: tag, end_field_number: has_offset, output);
358}
359
360void UnknownFieldSerializerLite(const uint8_t* ptr, uint32_t offset,
361 uint32_t /*tag*/, uint32_t /*has_offset*/,
362 io::CodedOutputStream* output) {
363 output->WriteString(
364 str: reinterpret_cast<const InternalMetadata*>(ptr + offset)
365 ->unknown_fields<std::string>(default_instance: &internal::GetEmptyString));
366}
367
368MessageLite* DuplicateIfNonNullInternal(MessageLite* message) {
369 if (message) {
370 MessageLite* ret = message->New();
371 ret->CheckTypeAndMergeFrom(other: *message);
372 return ret;
373 } else {
374 return nullptr;
375 }
376}
377
378void GenericSwap(MessageLite* m1, MessageLite* m2) {
379 std::unique_ptr<MessageLite> tmp(m1->New());
380 tmp->CheckTypeAndMergeFrom(other: *m1);
381 m1->Clear();
382 m1->CheckTypeAndMergeFrom(other: *m2);
383 m2->Clear();
384 m2->CheckTypeAndMergeFrom(other: *tmp);
385}
386
387// Returns a message owned by this Arena. This may require Own()ing or
388// duplicating the message.
389MessageLite* GetOwnedMessageInternal(Arena* message_arena,
390 MessageLite* submessage,
391 Arena* submessage_arena) {
392 GOOGLE_DCHECK(Arena::InternalGetOwningArena(submessage) == submessage_arena);
393 GOOGLE_DCHECK(message_arena != submessage_arena);
394 GOOGLE_DCHECK_EQ(submessage_arena, nullptr);
395 if (message_arena != nullptr && submessage_arena == nullptr) {
396 message_arena->Own(object: submessage);
397 return submessage;
398 } else {
399 MessageLite* ret = submessage->New(arena: message_arena);
400 ret->CheckTypeAndMergeFrom(other: *submessage);
401 return ret;
402 }
403}
404
405} // namespace internal
406} // namespace protobuf
407} // namespace google
408
409#include <google/protobuf/port_undef.inc>
410