1// Protocol Buffers - Google's data interchange format 2// Copyright 2008 Google Inc. All rights reserved. 3// http://code.google.com/p/protobuf/ 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 <stack> 36#include <google/protobuf/stubs/hash.h> 37 38#include <google/protobuf/message.h> 39 40#include <google/protobuf/stubs/common.h> 41#include <google/protobuf/stubs/once.h> 42#include <google/protobuf/io/coded_stream.h> 43#include <google/protobuf/io/zero_copy_stream_impl.h> 44#include <google/protobuf/descriptor.pb.h> 45#include <google/protobuf/descriptor.h> 46#include <google/protobuf/reflection_ops.h> 47#include <google/protobuf/wire_format.h> 48#include <google/protobuf/stubs/strutil.h> 49#include <google/protobuf/stubs/map-util.h> 50#include <google/protobuf/stubs/stl_util-inl.h> 51 52namespace google { 53namespace protobuf { 54 55using internal::WireFormat; 56using internal::ReflectionOps; 57 58Message::~Message() {} 59 60void Message::MergeFrom(const Message& from) { 61 const Descriptor* descriptor = GetDescriptor(); 62 GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor) 63 << ": Tried to merge from a message with a different type. " 64 "to: " << descriptor->full_name() << ", " 65 "from:" << from.GetDescriptor()->full_name(); 66 ReflectionOps::Merge(from, this); 67} 68 69void Message::CheckTypeAndMergeFrom(const MessageLite& other) { 70 MergeFrom(*down_cast<const Message*>(&other)); 71} 72 73void Message::CopyFrom(const Message& from) { 74 const Descriptor* descriptor = GetDescriptor(); 75 GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor) 76 << ": Tried to copy from a message with a different type." 77 "to: " << descriptor->full_name() << ", " 78 "from:" << from.GetDescriptor()->full_name(); 79 ReflectionOps::Copy(from, this); 80} 81 82string Message::GetTypeName() const { 83 return GetDescriptor()->full_name(); 84} 85 86void Message::Clear() { 87 ReflectionOps::Clear(this); 88} 89 90bool Message::IsInitialized() const { 91 return ReflectionOps::IsInitialized(*this); 92} 93 94void Message::FindInitializationErrors(vector<string>* errors) const { 95 return ReflectionOps::FindInitializationErrors(*this, "", errors); 96} 97 98string Message::InitializationErrorString() const { 99 vector<string> errors; 100 FindInitializationErrors(&errors); 101 return JoinStrings(errors, ", "); 102} 103 104void Message::CheckInitialized() const { 105 GOOGLE_CHECK(IsInitialized()) 106 << "Message of type \"" << GetDescriptor()->full_name() 107 << "\" is missing required fields: " << InitializationErrorString(); 108} 109 110void Message::DiscardUnknownFields() { 111 return ReflectionOps::DiscardUnknownFields(this); 112} 113 114bool Message::MergePartialFromCodedStream(io::CodedInputStream* input) { 115 return WireFormat::ParseAndMergePartial(input, this); 116} 117 118bool Message::ParseFromFileDescriptor(int file_descriptor) { 119 io::FileInputStream input(file_descriptor); 120 return ParseFromZeroCopyStream(&input) && input.GetErrno() == 0; 121} 122 123bool Message::ParsePartialFromFileDescriptor(int file_descriptor) { 124 io::FileInputStream input(file_descriptor); 125 return ParsePartialFromZeroCopyStream(&input) && input.GetErrno() == 0; 126} 127 128bool Message::ParseFromIstream(istream* input) { 129 io::IstreamInputStream zero_copy_input(input); 130 return ParseFromZeroCopyStream(&zero_copy_input) && input->eof(); 131} 132 133bool Message::ParsePartialFromIstream(istream* input) { 134 io::IstreamInputStream zero_copy_input(input); 135 return ParsePartialFromZeroCopyStream(&zero_copy_input) && input->eof(); 136} 137 138 139void Message::SerializeWithCachedSizes( 140 io::CodedOutputStream* output) const { 141 WireFormat::SerializeWithCachedSizes(*this, GetCachedSize(), output); 142} 143 144int Message::ByteSize() const { 145 int size = WireFormat::ByteSize(*this); 146 SetCachedSize(size); 147 return size; 148} 149 150void Message::SetCachedSize(int size) const { 151 GOOGLE_LOG(FATAL) << "Message class \"" << GetDescriptor()->full_name() 152 << "\" implements neither SetCachedSize() nor ByteSize(). " 153 "Must implement one or the other."; 154} 155 156int Message::SpaceUsed() const { 157 return GetReflection()->SpaceUsed(*this); 158} 159 160bool Message::SerializeToFileDescriptor(int file_descriptor) const { 161 io::FileOutputStream output(file_descriptor); 162 return SerializeToZeroCopyStream(&output); 163} 164 165bool Message::SerializePartialToFileDescriptor(int file_descriptor) const { 166 io::FileOutputStream output(file_descriptor); 167 return SerializePartialToZeroCopyStream(&output); 168} 169 170bool Message::SerializeToOstream(ostream* output) const { 171 { 172 io::OstreamOutputStream zero_copy_output(output); 173 if (!SerializeToZeroCopyStream(&zero_copy_output)) return false; 174 } 175 return output->good(); 176} 177 178bool Message::SerializePartialToOstream(ostream* output) const { 179 io::OstreamOutputStream zero_copy_output(output); 180 return SerializePartialToZeroCopyStream(&zero_copy_output); 181} 182 183 184Reflection::~Reflection() {} 185 186// =================================================================== 187// MessageFactory 188 189MessageFactory::~MessageFactory() {} 190 191namespace { 192 193class GeneratedMessageFactory : public MessageFactory { 194 public: 195 GeneratedMessageFactory(); 196 ~GeneratedMessageFactory(); 197 198 static GeneratedMessageFactory* singleton(); 199 200 typedef void RegistrationFunc(const string&); 201 void RegisterFile(const char* file, RegistrationFunc* registration_func); 202 void RegisterType(const Descriptor* descriptor, const Message* prototype); 203 204 // implements MessageFactory --------------------------------------- 205 const Message* GetPrototype(const Descriptor* type); 206 207 private: 208 // Only written at static init time, so does not require locking. 209 hash_map<const char*, RegistrationFunc*, 210 hash<const char*>, streq> file_map_; 211 212 // Initialized lazily, so requires locking. 213 Mutex mutex_; 214 hash_map<const Descriptor*, const Message*> type_map_; 215}; 216 217GeneratedMessageFactory* generated_message_factory_ = NULL; 218GOOGLE_PROTOBUF_DECLARE_ONCE(generated_message_factory_once_init_); 219 220void ShutdownGeneratedMessageFactory() { 221 delete generated_message_factory_; 222} 223 224void InitGeneratedMessageFactory() { 225 generated_message_factory_ = new GeneratedMessageFactory; 226 internal::OnShutdown(&ShutdownGeneratedMessageFactory); 227} 228 229GeneratedMessageFactory::GeneratedMessageFactory() {} 230GeneratedMessageFactory::~GeneratedMessageFactory() {} 231 232GeneratedMessageFactory* GeneratedMessageFactory::singleton() { 233 ::google::protobuf::GoogleOnceInit(&generated_message_factory_once_init_, 234 &InitGeneratedMessageFactory); 235 return generated_message_factory_; 236} 237 238void GeneratedMessageFactory::RegisterFile( 239 const char* file, RegistrationFunc* registration_func) { 240 if (!InsertIfNotPresent(&file_map_, file, registration_func)) { 241 GOOGLE_LOG(FATAL) << "File is already registered: " << file; 242 } 243} 244 245void GeneratedMessageFactory::RegisterType(const Descriptor* descriptor, 246 const Message* prototype) { 247 GOOGLE_DCHECK_EQ(descriptor->file()->pool(), DescriptorPool::generated_pool()) 248 << "Tried to register a non-generated type with the generated " 249 "type registry."; 250 251 // This should only be called as a result of calling a file registration 252 // function during GetPrototype(), in which case we already have locked 253 // the mutex. 254 mutex_.AssertHeld(); 255 if (!InsertIfNotPresent(&type_map_, descriptor, prototype)) { 256 GOOGLE_LOG(DFATAL) << "Type is already registered: " << descriptor->full_name(); 257 } 258} 259 260const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) { 261 { 262 ReaderMutexLock lock(&mutex_); 263 const Message* result = FindPtrOrNull(type_map_, type); 264 if (result != NULL) return result; 265 } 266 267 // If the type is not in the generated pool, then we can't possibly handle 268 // it. 269 if (type->file()->pool() != DescriptorPool::generated_pool()) return NULL; 270 271 // Apparently the file hasn't been registered yet. Let's do that now. 272 RegistrationFunc* registration_func = 273 FindPtrOrNull(file_map_, type->file()->name().c_str()); 274 if (registration_func == NULL) { 275 GOOGLE_LOG(DFATAL) << "File appears to be in generated pool but wasn't " 276 "registered: " << type->file()->name(); 277 return NULL; 278 } 279 280 WriterMutexLock lock(&mutex_); 281 282 // Check if another thread preempted us. 283 const Message* result = FindPtrOrNull(type_map_, type); 284 if (result == NULL) { 285 // Nope. OK, register everything. 286 registration_func(type->file()->name()); 287 // Should be here now. 288 result = FindPtrOrNull(type_map_, type); 289 } 290 291 if (result == NULL) { 292 GOOGLE_LOG(DFATAL) << "Type appears to be in generated pool but wasn't " 293 << "registered: " << type->full_name(); 294 } 295 296 return result; 297} 298 299} // namespace 300 301MessageFactory* MessageFactory::generated_factory() { 302 return GeneratedMessageFactory::singleton(); 303} 304 305void MessageFactory::InternalRegisterGeneratedFile( 306 const char* filename, void (*register_messages)(const string&)) { 307 GeneratedMessageFactory::singleton()->RegisterFile(filename, 308 register_messages); 309} 310 311void MessageFactory::InternalRegisterGeneratedMessage( 312 const Descriptor* descriptor, const Message* prototype) { 313 GeneratedMessageFactory::singleton()->RegisterType(descriptor, prototype); 314} 315 316 317} // namespace protobuf 318} // namespace google 319