• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <google/protobuf/message.h>
36 
37 #include <iostream>
38 #include <stack>
39 #include <unordered_map>
40 
41 #include <google/protobuf/stubs/casts.h>
42 #include <google/protobuf/stubs/logging.h>
43 #include <google/protobuf/stubs/common.h>
44 #include <google/protobuf/descriptor.pb.h>
45 #include <google/protobuf/parse_context.h>
46 #include <google/protobuf/reflection_internal.h>
47 #include <google/protobuf/io/coded_stream.h>
48 #include <google/protobuf/io/zero_copy_stream_impl.h>
49 #include <google/protobuf/descriptor.h>
50 #include <google/protobuf/generated_message_reflection.h>
51 #include <google/protobuf/generated_message_util.h>
52 #include <google/protobuf/map_field.h>
53 #include <google/protobuf/map_field_inl.h>
54 #include <google/protobuf/reflection_ops.h>
55 #include <google/protobuf/unknown_field_set.h>
56 #include <google/protobuf/wire_format.h>
57 #include <google/protobuf/wire_format_lite.h>
58 #include <google/protobuf/stubs/strutil.h>
59 #include <google/protobuf/stubs/map_util.h>
60 #include <google/protobuf/stubs/stl_util.h>
61 #include <google/protobuf/stubs/hash.h>
62 
63 #include <google/protobuf/port_def.inc>
64 
65 namespace google {
66 namespace protobuf {
67 
68 namespace internal {
69 
70 // TODO(gerbens) make this factorized better. This should not have to hop
71 // to reflection. Currently uses GeneratedMessageReflection and thus is
72 // defined in generated_message_reflection.cc
73 void RegisterFileLevelMetadata(const DescriptorTable* descriptor_table);
74 
75 }  // namespace internal
76 
77 using internal::ReflectionOps;
78 using internal::WireFormat;
79 using internal::WireFormatLite;
80 
MergeFrom(const Message & from)81 void Message::MergeFrom(const Message& from) {
82   const Descriptor* descriptor = GetDescriptor();
83   GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor)
84       << ": Tried to merge from a message with a different type.  "
85          "to: "
86       << descriptor->full_name()
87       << ", "
88          "from: "
89       << from.GetDescriptor()->full_name();
90   ReflectionOps::Merge(from, this);
91 }
92 
CheckTypeAndMergeFrom(const MessageLite & other)93 void Message::CheckTypeAndMergeFrom(const MessageLite& other) {
94   MergeFrom(*down_cast<const Message*>(&other));
95 }
96 
CopyFrom(const Message & from)97 void Message::CopyFrom(const Message& from) {
98   const Descriptor* descriptor = GetDescriptor();
99   GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor)
100       << ": Tried to copy from a message with a different type. "
101          "to: "
102       << descriptor->full_name()
103       << ", "
104          "from: "
105       << from.GetDescriptor()->full_name();
106   ReflectionOps::Copy(from, this);
107 }
108 
GetTypeName() const109 std::string Message::GetTypeName() const {
110   return GetDescriptor()->full_name();
111 }
112 
Clear()113 void Message::Clear() { ReflectionOps::Clear(this); }
114 
IsInitialized() const115 bool Message::IsInitialized() const {
116   return ReflectionOps::IsInitialized(*this);
117 }
118 
FindInitializationErrors(std::vector<std::string> * errors) const119 void Message::FindInitializationErrors(std::vector<std::string>* errors) const {
120   return ReflectionOps::FindInitializationErrors(*this, "", errors);
121 }
122 
InitializationErrorString() const123 std::string Message::InitializationErrorString() const {
124   std::vector<std::string> errors;
125   FindInitializationErrors(&errors);
126   return Join(errors, ", ");
127 }
128 
CheckInitialized() const129 void Message::CheckInitialized() const {
130   GOOGLE_CHECK(IsInitialized()) << "Message of type \"" << GetDescriptor()->full_name()
131                          << "\" is missing required fields: "
132                          << InitializationErrorString();
133 }
134 
DiscardUnknownFields()135 void Message::DiscardUnknownFields() {
136   return ReflectionOps::DiscardUnknownFields(this);
137 }
138 
_InternalParse(const char * ptr,internal::ParseContext * ctx)139 const char* Message::_InternalParse(const char* ptr,
140                                     internal::ParseContext* ctx) {
141   return WireFormat::_InternalParse(this, ptr, ctx);
142 }
143 
_InternalSerialize(uint8 * target,io::EpsCopyOutputStream * stream) const144 uint8* Message::_InternalSerialize(uint8* target,
145                                    io::EpsCopyOutputStream* stream) const {
146   return WireFormat::_InternalSerialize(*this, target, stream);
147 }
148 
ByteSizeLong() const149 size_t Message::ByteSizeLong() const {
150   size_t size = WireFormat::ByteSize(*this);
151   SetCachedSize(internal::ToCachedSize(size));
152   return size;
153 }
154 
SetCachedSize(int) const155 void Message::SetCachedSize(int /* size */) const {
156   GOOGLE_LOG(FATAL) << "Message class \"" << GetDescriptor()->full_name()
157              << "\" implements neither SetCachedSize() nor ByteSize().  "
158                 "Must implement one or the other.";
159 }
160 
SpaceUsedLong() const161 size_t Message::SpaceUsedLong() const {
162   return GetReflection()->SpaceUsedLong(*this);
163 }
164 
GetInvariantPerBuild(uint64 salt)165 uint64 Message::GetInvariantPerBuild(uint64 salt) {
166   return salt;
167 }
168 
169 // =============================================================================
170 // MessageFactory
171 
~MessageFactory()172 MessageFactory::~MessageFactory() {}
173 
174 namespace {
175 
176 
177 #define HASH_MAP std::unordered_map
178 #define STR_HASH_FXN hash<::google::protobuf::StringPiece>
179 
180 
181 class GeneratedMessageFactory : public MessageFactory {
182  public:
183   static GeneratedMessageFactory* singleton();
184 
185   void RegisterFile(const google::protobuf::internal::DescriptorTable* table);
186   void RegisterType(const Descriptor* descriptor, const Message* prototype);
187 
188   // implements MessageFactory ---------------------------------------
189   const Message* GetPrototype(const Descriptor* type) override;
190 
191  private:
192   // Only written at static init time, so does not require locking.
193   HASH_MAP<StringPiece, const google::protobuf::internal::DescriptorTable*,
194            STR_HASH_FXN>
195       file_map_;
196 
197   internal::WrappedMutex mutex_;
198   // Initialized lazily, so requires locking.
199   std::unordered_map<const Descriptor*, const Message*> type_map_;
200 };
201 
singleton()202 GeneratedMessageFactory* GeneratedMessageFactory::singleton() {
203   static auto instance =
204       internal::OnShutdownDelete(new GeneratedMessageFactory);
205   return instance;
206 }
207 
RegisterFile(const google::protobuf::internal::DescriptorTable * table)208 void GeneratedMessageFactory::RegisterFile(
209     const google::protobuf::internal::DescriptorTable* table) {
210   if (!InsertIfNotPresent(&file_map_, table->filename, table)) {
211     GOOGLE_LOG(FATAL) << "File is already registered: " << table->filename;
212   }
213 }
214 
RegisterType(const Descriptor * descriptor,const Message * prototype)215 void GeneratedMessageFactory::RegisterType(const Descriptor* descriptor,
216                                            const Message* prototype) {
217   GOOGLE_DCHECK_EQ(descriptor->file()->pool(), DescriptorPool::generated_pool())
218       << "Tried to register a non-generated type with the generated "
219          "type registry.";
220 
221   // This should only be called as a result of calling a file registration
222   // function during GetPrototype(), in which case we already have locked
223   // the mutex.
224   mutex_.AssertHeld();
225   if (!InsertIfNotPresent(&type_map_, descriptor, prototype)) {
226     GOOGLE_LOG(DFATAL) << "Type is already registered: " << descriptor->full_name();
227   }
228 }
229 
230 
GetPrototype(const Descriptor * type)231 const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) {
232   {
233     ReaderMutexLock lock(&mutex_);
234     const Message* result = FindPtrOrNull(type_map_, type);
235     if (result != NULL) return result;
236   }
237 
238   // If the type is not in the generated pool, then we can't possibly handle
239   // it.
240   if (type->file()->pool() != DescriptorPool::generated_pool()) return NULL;
241 
242   // Apparently the file hasn't been registered yet.  Let's do that now.
243   const internal::DescriptorTable* registration_data =
244       FindPtrOrNull(file_map_, type->file()->name().c_str());
245   if (registration_data == NULL) {
246     GOOGLE_LOG(DFATAL) << "File appears to be in generated pool but wasn't "
247                    "registered: "
248                 << type->file()->name();
249     return NULL;
250   }
251 
252   WriterMutexLock lock(&mutex_);
253 
254   // Check if another thread preempted us.
255   const Message* result = FindPtrOrNull(type_map_, type);
256   if (result == NULL) {
257     // Nope.  OK, register everything.
258     internal::RegisterFileLevelMetadata(registration_data);
259     // Should be here now.
260     result = FindPtrOrNull(type_map_, type);
261   }
262 
263   if (result == NULL) {
264     GOOGLE_LOG(DFATAL) << "Type appears to be in generated pool but wasn't "
265                 << "registered: " << type->full_name();
266   }
267 
268   return result;
269 }
270 
271 }  // namespace
272 
generated_factory()273 MessageFactory* MessageFactory::generated_factory() {
274   return GeneratedMessageFactory::singleton();
275 }
276 
InternalRegisterGeneratedFile(const google::protobuf::internal::DescriptorTable * table)277 void MessageFactory::InternalRegisterGeneratedFile(
278     const google::protobuf::internal::DescriptorTable* table) {
279   GeneratedMessageFactory::singleton()->RegisterFile(table);
280 }
281 
InternalRegisterGeneratedMessage(const Descriptor * descriptor,const Message * prototype)282 void MessageFactory::InternalRegisterGeneratedMessage(
283     const Descriptor* descriptor, const Message* prototype) {
284   GeneratedMessageFactory::singleton()->RegisterType(descriptor, prototype);
285 }
286 
287 
288 namespace {
289 template <typename T>
GetSingleton()290 T* GetSingleton() {
291   static T singleton;
292   return &singleton;
293 }
294 }  // namespace
295 
RepeatedFieldAccessor(const FieldDescriptor * field) const296 const internal::RepeatedFieldAccessor* Reflection::RepeatedFieldAccessor(
297     const FieldDescriptor* field) const {
298   GOOGLE_CHECK(field->is_repeated());
299   switch (field->cpp_type()) {
300 #define HANDLE_PRIMITIVE_TYPE(TYPE, type) \
301   case FieldDescriptor::CPPTYPE_##TYPE:   \
302     return GetSingleton<internal::RepeatedFieldPrimitiveAccessor<type> >();
303     HANDLE_PRIMITIVE_TYPE(INT32, int32)
304     HANDLE_PRIMITIVE_TYPE(UINT32, uint32)
305     HANDLE_PRIMITIVE_TYPE(INT64, int64)
306     HANDLE_PRIMITIVE_TYPE(UINT64, uint64)
307     HANDLE_PRIMITIVE_TYPE(FLOAT, float)
308     HANDLE_PRIMITIVE_TYPE(DOUBLE, double)
309     HANDLE_PRIMITIVE_TYPE(BOOL, bool)
310     HANDLE_PRIMITIVE_TYPE(ENUM, int32)
311 #undef HANDLE_PRIMITIVE_TYPE
312     case FieldDescriptor::CPPTYPE_STRING:
313       switch (field->options().ctype()) {
314         default:
315         case FieldOptions::STRING:
316           return GetSingleton<internal::RepeatedPtrFieldStringAccessor>();
317       }
318       break;
319     case FieldDescriptor::CPPTYPE_MESSAGE:
320       if (field->is_map()) {
321         return GetSingleton<internal::MapFieldAccessor>();
322       } else {
323         return GetSingleton<internal::RepeatedPtrFieldMessageAccessor>();
324       }
325   }
326   GOOGLE_LOG(FATAL) << "Should not reach here.";
327   return NULL;
328 }
329 
330 namespace internal {
331 template <>
332 #if defined(_MSC_VER) && (_MSC_VER >= 1800)
333 // Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue
334 // #240
335 PROTOBUF_NOINLINE
336 #endif
337     Message*
NewFromPrototype(const Message * prototype,Arena * arena)338     GenericTypeHandler<Message>::NewFromPrototype(const Message* prototype,
339                                                   Arena* arena) {
340   return prototype->New(arena);
341 }
342 template <>
343 #if defined(_MSC_VER) && (_MSC_VER >= 1800)
344 // Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue
345 // #240
346 PROTOBUF_NOINLINE
347 #endif
348     Arena*
GetArena(Message * value)349     GenericTypeHandler<Message>::GetArena(Message* value) {
350   return value->GetArena();
351 }
352 template <>
353 #if defined(_MSC_VER) && (_MSC_VER >= 1800)
354 // Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue
355 // #240
356 PROTOBUF_NOINLINE
357 #endif
358     void*
GetMaybeArenaPointer(Message * value)359     GenericTypeHandler<Message>::GetMaybeArenaPointer(Message* value) {
360   return value->GetMaybeArenaPointer();
361 }
362 }  // namespace internal
363 
364 }  // namespace protobuf
365 }  // namespace google
366