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