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