Home | History | Annotate | Download | only in protobuf
      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