// 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 #include #include #include #include #include #include #include #include #include #include namespace google { namespace protobuf { using internal::WireFormat; using internal::ReflectionOps; void Message::MergeFrom(const Message& from) { const Descriptor* descriptor = GetDescriptor(); GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor) << ": Tried to merge from a message with a different type. " "to: " << descriptor->full_name() << ", " "from: " << from.GetDescriptor()->full_name(); ReflectionOps::Merge(from, this); } void Message::CheckTypeAndMergeFrom(const MessageLite& other) { MergeFrom(*down_cast(&other)); } void Message::CopyFrom(const Message& from) { const Descriptor* descriptor = GetDescriptor(); GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor) << ": Tried to copy from a message with a different type. " "to: " << descriptor->full_name() << ", " "from: " << from.GetDescriptor()->full_name(); ReflectionOps::Copy(from, this); } string Message::GetTypeName() const { return GetDescriptor()->full_name(); } void Message::Clear() { ReflectionOps::Clear(this); } bool Message::IsInitialized() const { return ReflectionOps::IsInitialized(*this); } void Message::FindInitializationErrors(std::vector* errors) const { return ReflectionOps::FindInitializationErrors(*this, "", errors); } string Message::InitializationErrorString() const { std::vector errors; FindInitializationErrors(&errors); return Join(errors, ", "); } void Message::CheckInitialized() const { GOOGLE_CHECK(IsInitialized()) << "Message of type \"" << GetDescriptor()->full_name() << "\" is missing required fields: " << InitializationErrorString(); } void Message::DiscardUnknownFields() { return ReflectionOps::DiscardUnknownFields(this); } bool Message::MergePartialFromCodedStream(io::CodedInputStream* input) { return WireFormat::ParseAndMergePartial(input, this); } bool Message::ParseFromFileDescriptor(int file_descriptor) { io::FileInputStream input(file_descriptor); return ParseFromZeroCopyStream(&input) && input.GetErrno() == 0; } bool Message::ParsePartialFromFileDescriptor(int file_descriptor) { io::FileInputStream input(file_descriptor); return ParsePartialFromZeroCopyStream(&input) && input.GetErrno() == 0; } bool Message::ParseFromIstream(std::istream* input) { io::IstreamInputStream zero_copy_input(input); return ParseFromZeroCopyStream(&zero_copy_input) && input->eof(); } bool Message::ParsePartialFromIstream(std::istream* input) { io::IstreamInputStream zero_copy_input(input); return ParsePartialFromZeroCopyStream(&zero_copy_input) && input->eof(); } void Message::SerializeWithCachedSizes( io::CodedOutputStream* output) const { const internal::SerializationTable* table = static_cast(InternalGetTable()); if (table == 0) { WireFormat::SerializeWithCachedSizes(*this, GetCachedSize(), output); } else { internal::TableSerialize(*this, table, output); } } size_t Message::ByteSizeLong() const { size_t size = WireFormat::ByteSize(*this); SetCachedSize(internal::ToCachedSize(size)); return size; } void Message::SetCachedSize(int /* size */) const { GOOGLE_LOG(FATAL) << "Message class \"" << GetDescriptor()->full_name() << "\" implements neither SetCachedSize() nor ByteSize(). " "Must implement one or the other."; } size_t Message::SpaceUsedLong() const { return GetReflection()->SpaceUsedLong(*this); } bool Message::SerializeToFileDescriptor(int file_descriptor) const { io::FileOutputStream output(file_descriptor); return SerializeToZeroCopyStream(&output) && output.Flush(); } bool Message::SerializePartialToFileDescriptor(int file_descriptor) const { io::FileOutputStream output(file_descriptor); return SerializePartialToZeroCopyStream(&output) && output.Flush(); } bool Message::SerializeToOstream(std::ostream* output) const { { io::OstreamOutputStream zero_copy_output(output); if (!SerializeToZeroCopyStream(&zero_copy_output)) return false; } return output->good(); } bool Message::SerializePartialToOstream(std::ostream* output) const { io::OstreamOutputStream zero_copy_output(output); return SerializePartialToZeroCopyStream(&zero_copy_output); } // ============================================================================= // Reflection and associated Template Specializations Reflection::~Reflection() {} void Reflection::AddAllocatedMessage(Message* /* message */, const FieldDescriptor* /*field */, Message* /* new_entry */) const {} #define HANDLE_TYPE(TYPE, CPPTYPE, CTYPE) \ template<> \ const RepeatedField& Reflection::GetRepeatedField( \ const Message& message, const FieldDescriptor* field) const { \ return *static_cast* >( \ MutableRawRepeatedField(const_cast(&message), \ field, CPPTYPE, CTYPE, NULL)); \ } \ \ template<> \ RepeatedField* Reflection::MutableRepeatedField( \ Message* message, const FieldDescriptor* field) const { \ return static_cast* >( \ MutableRawRepeatedField(message, field, CPPTYPE, CTYPE, NULL)); \ } HANDLE_TYPE(int32, FieldDescriptor::CPPTYPE_INT32, -1); HANDLE_TYPE(int64, FieldDescriptor::CPPTYPE_INT64, -1); HANDLE_TYPE(uint32, FieldDescriptor::CPPTYPE_UINT32, -1); HANDLE_TYPE(uint64, FieldDescriptor::CPPTYPE_UINT64, -1); HANDLE_TYPE(float, FieldDescriptor::CPPTYPE_FLOAT, -1); HANDLE_TYPE(double, FieldDescriptor::CPPTYPE_DOUBLE, -1); HANDLE_TYPE(bool, FieldDescriptor::CPPTYPE_BOOL, -1); #undef HANDLE_TYPE void* Reflection::MutableRawRepeatedString( Message* message, const FieldDescriptor* field, bool is_string) const { return MutableRawRepeatedField(message, field, FieldDescriptor::CPPTYPE_STRING, FieldOptions::STRING, NULL); } MapIterator Reflection::MapBegin( Message* message, const FieldDescriptor* field) const { GOOGLE_LOG(FATAL) << "Unimplemented Map Reflection API."; MapIterator iter(message, field); return iter; } MapIterator Reflection::MapEnd( Message* message, const FieldDescriptor* field) const { GOOGLE_LOG(FATAL) << "Unimplemented Map Reflection API."; MapIterator iter(message, field); return iter; } // ============================================================================= // MessageFactory MessageFactory::~MessageFactory() {} namespace { class GeneratedMessageFactory : public MessageFactory { public: static GeneratedMessageFactory* singleton(); typedef void RegistrationFunc(const string&); void RegisterFile(const char* file, RegistrationFunc* registration_func); void RegisterType(const Descriptor* descriptor, const Message* prototype); // implements MessageFactory --------------------------------------- const Message* GetPrototype(const Descriptor* type); private: // Only written at static init time, so does not require locking. hash_map, streq> file_map_; Mutex mutex_; // Initialized lazily, so requires locking. hash_map type_map_; }; GeneratedMessageFactory* GeneratedMessageFactory::singleton() { static auto instance = internal::OnShutdownDelete(new GeneratedMessageFactory); return instance; } void GeneratedMessageFactory::RegisterFile( const char* file, RegistrationFunc* registration_func) { if (!InsertIfNotPresent(&file_map_, file, registration_func)) { GOOGLE_LOG(FATAL) << "File is already registered: " << file; } } void GeneratedMessageFactory::RegisterType(const Descriptor* descriptor, const Message* prototype) { GOOGLE_DCHECK_EQ(descriptor->file()->pool(), DescriptorPool::generated_pool()) << "Tried to register a non-generated type with the generated " "type registry."; // This should only be called as a result of calling a file registration // function during GetPrototype(), in which case we already have locked // the mutex. mutex_.AssertHeld(); if (!InsertIfNotPresent(&type_map_, descriptor, prototype)) { GOOGLE_LOG(DFATAL) << "Type is already registered: " << descriptor->full_name(); } } const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) { { ReaderMutexLock lock(&mutex_); const Message* result = FindPtrOrNull(type_map_, type); if (result != NULL) return result; } // If the type is not in the generated pool, then we can't possibly handle // it. if (type->file()->pool() != DescriptorPool::generated_pool()) return NULL; // Apparently the file hasn't been registered yet. Let's do that now. RegistrationFunc* registration_func = FindPtrOrNull(file_map_, type->file()->name().c_str()); if (registration_func == NULL) { GOOGLE_LOG(DFATAL) << "File appears to be in generated pool but wasn't " "registered: " << type->file()->name(); return NULL; } WriterMutexLock lock(&mutex_); // Check if another thread preempted us. const Message* result = FindPtrOrNull(type_map_, type); if (result == NULL) { // Nope. OK, register everything. registration_func(type->file()->name()); // Should be here now. result = FindPtrOrNull(type_map_, type); } if (result == NULL) { GOOGLE_LOG(DFATAL) << "Type appears to be in generated pool but wasn't " << "registered: " << type->full_name(); } return result; } } // namespace MessageFactory* MessageFactory::generated_factory() { return GeneratedMessageFactory::singleton(); } void MessageFactory::InternalRegisterGeneratedFile( const char* filename, void (*register_messages)(const string&)) { GeneratedMessageFactory::singleton()->RegisterFile(filename, register_messages); } void MessageFactory::InternalRegisterGeneratedMessage( const Descriptor* descriptor, const Message* prototype) { GeneratedMessageFactory::singleton()->RegisterType(descriptor, prototype); } MessageFactory* Reflection::GetMessageFactory() const { GOOGLE_LOG(FATAL) << "Not implemented."; return NULL; } void* Reflection::RepeatedFieldData( Message* message, const FieldDescriptor* field, FieldDescriptor::CppType cpp_type, const Descriptor* message_type) const { GOOGLE_LOG(FATAL) << "Not implemented."; return NULL; } namespace internal { RepeatedFieldAccessor::~RepeatedFieldAccessor() { } } // namespace internal const internal::RepeatedFieldAccessor* Reflection::RepeatedFieldAccessor( const FieldDescriptor* field) const { GOOGLE_CHECK(field->is_repeated()); switch (field->cpp_type()) { #define HANDLE_PRIMITIVE_TYPE(TYPE, type) \ case FieldDescriptor::CPPTYPE_ ## TYPE: \ return internal::Singleton >::get(); HANDLE_PRIMITIVE_TYPE(INT32, int32) HANDLE_PRIMITIVE_TYPE(UINT32, uint32) HANDLE_PRIMITIVE_TYPE(INT64, int64) HANDLE_PRIMITIVE_TYPE(UINT64, uint64) HANDLE_PRIMITIVE_TYPE(FLOAT, float) HANDLE_PRIMITIVE_TYPE(DOUBLE, double) HANDLE_PRIMITIVE_TYPE(BOOL, bool) HANDLE_PRIMITIVE_TYPE(ENUM, int32) #undef HANDLE_PRIMITIVE_TYPE case FieldDescriptor::CPPTYPE_STRING: switch (field->options().ctype()) { default: case FieldOptions::STRING: return internal::Singleton::get(); } break; case FieldDescriptor::CPPTYPE_MESSAGE: if (field->is_map()) { return internal::Singleton::get(); } else { return internal::Singleton::get(); } } GOOGLE_LOG(FATAL) << "Should not reach here."; return NULL; } namespace internal { namespace { void ShutdownRepeatedFieldAccessor() { internal::Singleton >::ShutDown(); internal::Singleton >::ShutDown(); internal::Singleton >::ShutDown(); internal::Singleton >::ShutDown(); internal::Singleton >::ShutDown(); internal::Singleton >::ShutDown(); internal::Singleton >::ShutDown(); internal::Singleton::ShutDown(); internal::Singleton::ShutDown(); internal::Singleton::ShutDown(); } struct ShutdownRepeatedFieldRegister { ShutdownRepeatedFieldRegister() { OnShutdown(&ShutdownRepeatedFieldAccessor); } } shutdown_; } // namespace } // namespace internal namespace internal { template<> #if defined(_MSC_VER) && (_MSC_VER >= 1800) // Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue #240 GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE #endif Message* GenericTypeHandler::NewFromPrototype( const Message* prototype, google::protobuf::Arena* arena) { return prototype->New(arena); } template<> #if defined(_MSC_VER) && (_MSC_VER >= 1800) // Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue #240 GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE #endif google::protobuf::Arena* GenericTypeHandler::GetArena( Message* value) { return value->GetArena(); } template<> #if defined(_MSC_VER) && (_MSC_VER >= 1800) // Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue #240 GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE #endif void* GenericTypeHandler::GetMaybeArenaPointer( Message* value) { return value->GetMaybeArenaPointer(); } } // namespace internal } // namespace protobuf } // namespace google