• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
52 namespace google {
53 namespace protobuf {
54 
55 using internal::WireFormat;
56 using internal::ReflectionOps;
57 
~Message()58 Message::~Message() {}
59 
MergeFrom(const Message & from)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 
CheckTypeAndMergeFrom(const MessageLite & other)69 void Message::CheckTypeAndMergeFrom(const MessageLite& other) {
70   MergeFrom(*down_cast<const Message*>(&other));
71 }
72 
CopyFrom(const Message & from)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 
GetTypeName() const82 string Message::GetTypeName() const {
83   return GetDescriptor()->full_name();
84 }
85 
Clear()86 void Message::Clear() {
87   ReflectionOps::Clear(this);
88 }
89 
IsInitialized() const90 bool Message::IsInitialized() const {
91   return ReflectionOps::IsInitialized(*this);
92 }
93 
FindInitializationErrors(vector<string> * errors) const94 void Message::FindInitializationErrors(vector<string>* errors) const {
95   return ReflectionOps::FindInitializationErrors(*this, "", errors);
96 }
97 
InitializationErrorString() const98 string Message::InitializationErrorString() const {
99   vector<string> errors;
100   FindInitializationErrors(&errors);
101   return JoinStrings(errors, ", ");
102 }
103 
CheckInitialized() const104 void Message::CheckInitialized() const {
105   GOOGLE_CHECK(IsInitialized())
106     << "Message of type \"" << GetDescriptor()->full_name()
107     << "\" is missing required fields: " << InitializationErrorString();
108 }
109 
DiscardUnknownFields()110 void Message::DiscardUnknownFields() {
111   return ReflectionOps::DiscardUnknownFields(this);
112 }
113 
MergePartialFromCodedStream(io::CodedInputStream * input)114 bool Message::MergePartialFromCodedStream(io::CodedInputStream* input) {
115   return WireFormat::ParseAndMergePartial(input, this);
116 }
117 
ParseFromFileDescriptor(int file_descriptor)118 bool Message::ParseFromFileDescriptor(int file_descriptor) {
119   io::FileInputStream input(file_descriptor);
120   return ParseFromZeroCopyStream(&input) && input.GetErrno() == 0;
121 }
122 
ParsePartialFromFileDescriptor(int file_descriptor)123 bool Message::ParsePartialFromFileDescriptor(int file_descriptor) {
124   io::FileInputStream input(file_descriptor);
125   return ParsePartialFromZeroCopyStream(&input) && input.GetErrno() == 0;
126 }
127 
ParseFromIstream(istream * input)128 bool Message::ParseFromIstream(istream* input) {
129   io::IstreamInputStream zero_copy_input(input);
130   return ParseFromZeroCopyStream(&zero_copy_input) && input->eof();
131 }
132 
ParsePartialFromIstream(istream * input)133 bool Message::ParsePartialFromIstream(istream* input) {
134   io::IstreamInputStream zero_copy_input(input);
135   return ParsePartialFromZeroCopyStream(&zero_copy_input) && input->eof();
136 }
137 
138 
SerializeWithCachedSizes(io::CodedOutputStream * output) const139 void Message::SerializeWithCachedSizes(
140     io::CodedOutputStream* output) const {
141   WireFormat::SerializeWithCachedSizes(*this, GetCachedSize(), output);
142 }
143 
ByteSize() const144 int Message::ByteSize() const {
145   int size = WireFormat::ByteSize(*this);
146   SetCachedSize(size);
147   return size;
148 }
149 
SetCachedSize(int size) const150 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 
SpaceUsed() const156 int Message::SpaceUsed() const {
157   return GetReflection()->SpaceUsed(*this);
158 }
159 
SerializeToFileDescriptor(int file_descriptor) const160 bool Message::SerializeToFileDescriptor(int file_descriptor) const {
161   io::FileOutputStream output(file_descriptor);
162   return SerializeToZeroCopyStream(&output);
163 }
164 
SerializePartialToFileDescriptor(int file_descriptor) const165 bool Message::SerializePartialToFileDescriptor(int file_descriptor) const {
166   io::FileOutputStream output(file_descriptor);
167   return SerializePartialToZeroCopyStream(&output);
168 }
169 
SerializeToOstream(ostream * output) const170 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 
SerializePartialToOstream(ostream * output) const178 bool Message::SerializePartialToOstream(ostream* output) const {
179   io::OstreamOutputStream zero_copy_output(output);
180   return SerializePartialToZeroCopyStream(&zero_copy_output);
181 }
182 
183 
~Reflection()184 Reflection::~Reflection() {}
185 
186 // ===================================================================
187 // MessageFactory
188 
~MessageFactory()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 
ShutdownGeneratedMessageFactory()220 void ShutdownGeneratedMessageFactory() {
221   delete generated_message_factory_;
222 }
223 
InitGeneratedMessageFactory()224 void InitGeneratedMessageFactory() {
225   generated_message_factory_ = new GeneratedMessageFactory;
226   internal::OnShutdown(&ShutdownGeneratedMessageFactory);
227 }
228 
GeneratedMessageFactory()229 GeneratedMessageFactory::GeneratedMessageFactory() {}
~GeneratedMessageFactory()230 GeneratedMessageFactory::~GeneratedMessageFactory() {}
231 
singleton()232 GeneratedMessageFactory* GeneratedMessageFactory::singleton() {
233   ::google::protobuf::GoogleOnceInit(&generated_message_factory_once_init_,
234                  &InitGeneratedMessageFactory);
235   return generated_message_factory_;
236 }
237 
RegisterFile(const char * file,RegistrationFunc * registration_func)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 
RegisterType(const Descriptor * descriptor,const Message * prototype)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 
GetPrototype(const Descriptor * type)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 
generated_factory()301 MessageFactory* MessageFactory::generated_factory() {
302   return GeneratedMessageFactory::singleton();
303 }
304 
InternalRegisterGeneratedFile(const char * filename,void (* register_messages)(const string &))305 void MessageFactory::InternalRegisterGeneratedFile(
306     const char* filename, void (*register_messages)(const string&)) {
307   GeneratedMessageFactory::singleton()->RegisterFile(filename,
308                                                      register_messages);
309 }
310 
InternalRegisterGeneratedMessage(const Descriptor * descriptor,const Message * prototype)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