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