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