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 (at) 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 52 namespace google { 53 namespace protobuf { 54 55 using internal::WireFormat; 56 using internal::ReflectionOps; 57 58 Message::~Message() {} 59 60 void 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 69 void Message::CheckTypeAndMergeFrom(const MessageLite& other) { 70 MergeFrom(*down_cast<const Message*>(&other)); 71 } 72 73 void 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 82 string Message::GetTypeName() const { 83 return GetDescriptor()->full_name(); 84 } 85 86 void Message::Clear() { 87 ReflectionOps::Clear(this); 88 } 89 90 bool Message::IsInitialized() const { 91 return ReflectionOps::IsInitialized(*this); 92 } 93 94 void Message::FindInitializationErrors(vector<string>* errors) const { 95 return ReflectionOps::FindInitializationErrors(*this, "", errors); 96 } 97 98 string Message::InitializationErrorString() const { 99 vector<string> errors; 100 FindInitializationErrors(&errors); 101 return JoinStrings(errors, ", "); 102 } 103 104 void Message::CheckInitialized() const { 105 GOOGLE_CHECK(IsInitialized()) 106 << "Message of type \"" << GetDescriptor()->full_name() 107 << "\" is missing required fields: " << InitializationErrorString(); 108 } 109 110 void Message::DiscardUnknownFields() { 111 return ReflectionOps::DiscardUnknownFields(this); 112 } 113 114 bool Message::MergePartialFromCodedStream(io::CodedInputStream* input) { 115 return WireFormat::ParseAndMergePartial(input, this); 116 } 117 118 bool Message::ParseFromFileDescriptor(int file_descriptor) { 119 io::FileInputStream input(file_descriptor); 120 return ParseFromZeroCopyStream(&input) && input.GetErrno() == 0; 121 } 122 123 bool Message::ParsePartialFromFileDescriptor(int file_descriptor) { 124 io::FileInputStream input(file_descriptor); 125 return ParsePartialFromZeroCopyStream(&input) && input.GetErrno() == 0; 126 } 127 128 bool Message::ParseFromIstream(istream* input) { 129 io::IstreamInputStream zero_copy_input(input); 130 return ParseFromZeroCopyStream(&zero_copy_input) && input->eof(); 131 } 132 133 bool Message::ParsePartialFromIstream(istream* input) { 134 io::IstreamInputStream zero_copy_input(input); 135 return ParsePartialFromZeroCopyStream(&zero_copy_input) && input->eof(); 136 } 137 138 139 void Message::SerializeWithCachedSizes( 140 io::CodedOutputStream* output) const { 141 WireFormat::SerializeWithCachedSizes(*this, GetCachedSize(), output); 142 } 143 144 int Message::ByteSize() const { 145 int size = WireFormat::ByteSize(*this); 146 SetCachedSize(size); 147 return size; 148 } 149 150 void 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 156 int Message::SpaceUsed() const { 157 return GetReflection()->SpaceUsed(*this); 158 } 159 160 bool Message::SerializeToFileDescriptor(int file_descriptor) const { 161 io::FileOutputStream output(file_descriptor); 162 return SerializeToZeroCopyStream(&output); 163 } 164 165 bool Message::SerializePartialToFileDescriptor(int file_descriptor) const { 166 io::FileOutputStream output(file_descriptor); 167 return SerializePartialToZeroCopyStream(&output); 168 } 169 170 bool 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 178 bool Message::SerializePartialToOstream(ostream* output) const { 179 io::OstreamOutputStream zero_copy_output(output); 180 return SerializePartialToZeroCopyStream(&zero_copy_output); 181 } 182 183 184 Reflection::~Reflection() {} 185 186 // =================================================================== 187 // MessageFactory 188 189 MessageFactory::~MessageFactory() {} 190 191 namespace { 192 193 class 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 217 GeneratedMessageFactory* generated_message_factory_ = NULL; 218 GOOGLE_PROTOBUF_DECLARE_ONCE(generated_message_factory_once_init_); 219 220 void ShutdownGeneratedMessageFactory() { 221 delete generated_message_factory_; 222 } 223 224 void InitGeneratedMessageFactory() { 225 generated_message_factory_ = new GeneratedMessageFactory; 226 internal::OnShutdown(&ShutdownGeneratedMessageFactory); 227 } 228 229 GeneratedMessageFactory::GeneratedMessageFactory() {} 230 GeneratedMessageFactory::~GeneratedMessageFactory() {} 231 232 GeneratedMessageFactory* GeneratedMessageFactory::singleton() { 233 ::google::protobuf::GoogleOnceInit(&generated_message_factory_once_init_, 234 &InitGeneratedMessageFactory); 235 return generated_message_factory_; 236 } 237 238 void 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 245 void 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 260 const 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 301 MessageFactory* MessageFactory::generated_factory() { 302 return GeneratedMessageFactory::singleton(); 303 } 304 305 void MessageFactory::InternalRegisterGeneratedFile( 306 const char* filename, void (*register_messages)(const string&)) { 307 GeneratedMessageFactory::singleton()->RegisterFile(filename, 308 register_messages); 309 } 310 311 void 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