// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Author: kenton@google.com (Kenton Varda) // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. #include #include #include #include #include #include #include #include #include #include #include #include // Must be included last #include PROTOBUF_PRAGMA_INIT_SEG namespace google { namespace protobuf { namespace internal { void DestroyMessage(const void* message) { static_cast(message)->~MessageLite(); } void DestroyString(const void* s) { static_cast(s)->~basic_string(); } PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ExplicitlyConstructedArenaString fixed_address_empty_string{}; // NOLINT PROTOBUF_CONSTINIT std::atomic init_protobuf_defaults_state{false}; static bool InitProtobufDefaultsImpl() { fixed_address_empty_string.DefaultConstruct(); OnShutdownDestroyString(fixed_address_empty_string.get_mutable()); init_protobuf_defaults_state.store(true, std::memory_order_release); return true; } void InitProtobufDefaultsSlow() { static bool is_inited = InitProtobufDefaultsImpl(); (void)is_inited; } // Force the initialization of the empty string. // Normally, registration would do it, but we don't have any guarantee that // there is any object with reflection. PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 static std::true_type init_empty_string = (InitProtobufDefaultsSlow(), std::true_type{}); size_t StringSpaceUsedExcludingSelfLong(const std::string& str) { const void* start = &str; const void* end = &str + 1; if (start <= str.data() && str.data() < end) { // The string's data is stored inside the string object itself. return 0; } else { return str.capacity(); } } template const T& Get(const void* ptr) { return *static_cast(ptr); } // PrimitiveTypeHelper is a wrapper around the interface of WireFormatLite. // WireFormatLite has a very inconvenient interface with respect to template // meta-programming. This class wraps the different named functions into // a single Serialize / SerializeToArray interface. template struct PrimitiveTypeHelper; template <> struct PrimitiveTypeHelper { typedef bool Type; static void Serialize(const void* ptr, io::CodedOutputStream* output) { WireFormatLite::WriteBoolNoTag(Get(ptr), output); } static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) { return WireFormatLite::WriteBoolNoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef int32_t Type; static void Serialize(const void* ptr, io::CodedOutputStream* output) { WireFormatLite::WriteInt32NoTag(Get(ptr), output); } static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) { return WireFormatLite::WriteInt32NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef int32_t Type; static void Serialize(const void* ptr, io::CodedOutputStream* output) { WireFormatLite::WriteSInt32NoTag(Get(ptr), output); } static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) { return WireFormatLite::WriteSInt32NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef uint32_t Type; static void Serialize(const void* ptr, io::CodedOutputStream* output) { WireFormatLite::WriteUInt32NoTag(Get(ptr), output); } static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) { return WireFormatLite::WriteUInt32NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef int64_t Type; static void Serialize(const void* ptr, io::CodedOutputStream* output) { WireFormatLite::WriteInt64NoTag(Get(ptr), output); } static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) { return WireFormatLite::WriteInt64NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef int64_t Type; static void Serialize(const void* ptr, io::CodedOutputStream* output) { WireFormatLite::WriteSInt64NoTag(Get(ptr), output); } static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) { return WireFormatLite::WriteSInt64NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef uint64_t Type; static void Serialize(const void* ptr, io::CodedOutputStream* output) { WireFormatLite::WriteUInt64NoTag(Get(ptr), output); } static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) { return WireFormatLite::WriteUInt64NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef uint32_t Type; static void Serialize(const void* ptr, io::CodedOutputStream* output) { WireFormatLite::WriteFixed32NoTag(Get(ptr), output); } static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) { return WireFormatLite::WriteFixed32NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef uint64_t Type; static void Serialize(const void* ptr, io::CodedOutputStream* output) { WireFormatLite::WriteFixed64NoTag(Get(ptr), output); } static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) { return WireFormatLite::WriteFixed64NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper : PrimitiveTypeHelper {}; template <> struct PrimitiveTypeHelper : PrimitiveTypeHelper { typedef int32_t Type; }; template <> struct PrimitiveTypeHelper : PrimitiveTypeHelper { typedef int64_t Type; }; template <> struct PrimitiveTypeHelper : PrimitiveTypeHelper { typedef float Type; }; template <> struct PrimitiveTypeHelper : PrimitiveTypeHelper { typedef double Type; }; template <> struct PrimitiveTypeHelper { typedef std::string Type; static void Serialize(const void* ptr, io::CodedOutputStream* output) { const Type& value = *static_cast(ptr); output->WriteVarint32(value.size()); output->WriteRawMaybeAliased(value.data(), value.size()); } static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) { const Type& value = *static_cast(ptr); return io::CodedOutputStream::WriteStringWithSizeToArray(value, buffer); } }; template <> struct PrimitiveTypeHelper : PrimitiveTypeHelper {}; // We want to serialize to both CodedOutputStream and directly into byte arrays // without duplicating the code. In fact we might want extra output channels in // the future. template struct OutputHelper; template void SerializeTo(const void* ptr, O* output) { OutputHelper::Serialize(ptr, output); } template void WriteTagTo(uint32_t tag, O* output) { SerializeTo(&tag, output); } template void WriteLengthTo(uint32_t length, O* output) { SerializeTo(&length, output); } // Specialization for coded output stream template struct OutputHelper { static void Serialize(const void* ptr, io::CodedOutputStream* output) { PrimitiveTypeHelper::Serialize(ptr, output); } }; // Specialization for writing into a plain array struct ArrayOutput { uint8_t* ptr; bool is_deterministic; }; template struct OutputHelper { static void Serialize(const void* ptr, ArrayOutput* output) { output->ptr = PrimitiveTypeHelper::SerializeToArray(ptr, output->ptr); } }; void SerializeMessageNoTable(const MessageLite* msg, io::CodedOutputStream* output) { msg->SerializeWithCachedSizes(output); } void SerializeMessageNoTable(const MessageLite* msg, ArrayOutput* output) { io::ArrayOutputStream array_stream(output->ptr, INT_MAX); io::CodedOutputStream o(&array_stream); o.SetSerializationDeterministic(output->is_deterministic); msg->SerializeWithCachedSizes(&o); output->ptr += o.ByteCount(); } // We need to use a helper class to get access to the private members class AccessorHelper { public: static int Size(const RepeatedPtrFieldBase& x) { return x.size(); } static void const* Get(const RepeatedPtrFieldBase& x, int idx) { return x.raw_data()[idx]; } }; void SerializeNotImplemented(int field) { GOOGLE_LOG(FATAL) << "Not implemented field number " << field; } // When switching to c++11 we should make these constexpr functions #define SERIALIZE_TABLE_OP(type, type_class) \ ((type - 1) + static_cast(type_class) * FieldMetadata::kNumTypes) template bool IsNull(const void* ptr) { return *static_cast::Type*>(ptr) == 0; } template <> bool IsNull(const void* ptr) { return static_cast(ptr)->Get().size() == 0; } template <> bool IsNull(const void* ptr) { return static_cast(ptr)->Get().size() == 0; } template <> bool IsNull(const void* ptr) { return Get(ptr) == nullptr; } template <> bool IsNull(const void* ptr) { return Get(ptr) == nullptr; } void ExtensionSerializer(const MessageLite* extendee, const uint8_t* ptr, uint32_t offset, uint32_t tag, uint32_t has_offset, io::CodedOutputStream* output) { reinterpret_cast(ptr + offset) ->SerializeWithCachedSizes(extendee, tag, has_offset, output); } void UnknownFieldSerializerLite(const uint8_t* ptr, uint32_t offset, uint32_t /*tag*/, uint32_t /*has_offset*/, io::CodedOutputStream* output) { output->WriteString( reinterpret_cast(ptr + offset) ->unknown_fields(&internal::GetEmptyString)); } MessageLite* DuplicateIfNonNullInternal(MessageLite* message) { if (message) { MessageLite* ret = message->New(); ret->CheckTypeAndMergeFrom(*message); return ret; } else { return nullptr; } } void GenericSwap(MessageLite* m1, MessageLite* m2) { std::unique_ptr tmp(m1->New()); tmp->CheckTypeAndMergeFrom(*m1); m1->Clear(); m1->CheckTypeAndMergeFrom(*m2); m2->Clear(); m2->CheckTypeAndMergeFrom(*tmp); } // Returns a message owned by this Arena. This may require Own()ing or // duplicating the message. MessageLite* GetOwnedMessageInternal(Arena* message_arena, MessageLite* submessage, Arena* submessage_arena) { GOOGLE_DCHECK(Arena::InternalGetOwningArena(submessage) == submessage_arena); GOOGLE_DCHECK(message_arena != submessage_arena); GOOGLE_DCHECK_EQ(submessage_arena, nullptr); if (message_arena != nullptr && submessage_arena == nullptr) { message_arena->Own(submessage); return submessage; } else { MessageLite* ret = submessage->New(message_arena); ret->CheckTypeAndMergeFrom(*submessage); return ret; } } } // namespace internal } // namespace protobuf } // namespace google #include