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