• 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 #include <google/protobuf/util/type_resolver_util.h>
32 
33 #include <google/protobuf/type.pb.h>
34 #include <google/protobuf/wrappers.pb.h>
35 #include <google/protobuf/descriptor.pb.h>
36 #include <google/protobuf/descriptor.h>
37 #include <google/protobuf/util/internal/utility.h>
38 #include <google/protobuf/util/type_resolver.h>
39 #include <google/protobuf/stubs/strutil.h>
40 #include <google/protobuf/stubs/status.h>
41 
42 // clang-format off
43 #include <google/protobuf/port_def.inc>
44 // clang-format on
45 
46 namespace google {
47 namespace protobuf {
48 namespace util {
49 namespace {
50 using google::protobuf::Any;
51 using google::protobuf::BoolValue;
52 using google::protobuf::BytesValue;
53 using google::protobuf::DoubleValue;
54 using google::protobuf::Enum;
55 using google::protobuf::EnumValue;
56 using google::protobuf::Field;
57 using google::protobuf::FloatValue;
58 using google::protobuf::Int32Value;
59 using google::protobuf::Int64Value;
60 using google::protobuf::Option;
61 using google::protobuf::StringValue;
62 using google::protobuf::Type;
63 using google::protobuf::UInt32Value;
64 using google::protobuf::UInt64Value;
65 
66 using util::Status;
67 using util::error::INVALID_ARGUMENT;
68 using util::error::NOT_FOUND;
69 
70 class DescriptorPoolTypeResolver : public TypeResolver {
71  public:
DescriptorPoolTypeResolver(const std::string & url_prefix,const DescriptorPool * pool)72   DescriptorPoolTypeResolver(const std::string& url_prefix,
73                              const DescriptorPool* pool)
74       : url_prefix_(url_prefix), pool_(pool) {}
75 
ResolveMessageType(const std::string & type_url,Type * type)76   Status ResolveMessageType(const std::string& type_url, Type* type) override {
77     std::string type_name;
78     Status status = ParseTypeUrl(type_url, &type_name);
79     if (!status.ok()) {
80       return status;
81     }
82 
83     const Descriptor* descriptor = pool_->FindMessageTypeByName(type_name);
84     if (descriptor == NULL) {
85       return Status(util::error::NOT_FOUND,
86                     "Invalid type URL, unknown type: " + type_name);
87     }
88     ConvertDescriptor(descriptor, type);
89     return Status();
90   }
91 
ResolveEnumType(const std::string & type_url,Enum * enum_type)92   Status ResolveEnumType(const std::string& type_url,
93                          Enum* enum_type) override {
94     std::string type_name;
95     Status status = ParseTypeUrl(type_url, &type_name);
96     if (!status.ok()) {
97       return status;
98     }
99 
100     const EnumDescriptor* descriptor = pool_->FindEnumTypeByName(type_name);
101     if (descriptor == NULL) {
102       return Status(util::error::NOT_FOUND,
103                     "Invalid type URL, unknown type: " + type_name);
104     }
105     ConvertEnumDescriptor(descriptor, enum_type);
106     return Status();
107   }
108 
109  private:
ConvertDescriptor(const Descriptor * descriptor,Type * type)110   void ConvertDescriptor(const Descriptor* descriptor, Type* type) {
111     type->Clear();
112     type->set_name(descriptor->full_name());
113     for (int i = 0; i < descriptor->field_count(); ++i) {
114       ConvertFieldDescriptor(descriptor->field(i), type->add_fields());
115     }
116     for (int i = 0; i < descriptor->oneof_decl_count(); ++i) {
117       type->add_oneofs(descriptor->oneof_decl(i)->name());
118     }
119     type->mutable_source_context()->set_file_name(descriptor->file()->name());
120     ConvertMessageOptions(descriptor->options(), type->mutable_options());
121   }
122 
ConvertMessageOptions(const MessageOptions & options,RepeatedPtrField<Option> * output)123   void ConvertMessageOptions(const MessageOptions& options,
124                              RepeatedPtrField<Option>* output) {
125     return ConvertOptionsInternal(options, output);
126   }
127 
ConvertFieldOptions(const FieldOptions & options,RepeatedPtrField<Option> * output)128   void ConvertFieldOptions(const FieldOptions& options,
129                            RepeatedPtrField<Option>* output) {
130     return ConvertOptionsInternal(options, output);
131   }
132 
ConvertEnumOptions(const EnumOptions & options,RepeatedPtrField<Option> * output)133   void ConvertEnumOptions(const EnumOptions& options,
134                           RepeatedPtrField<Option>* output) {
135     return ConvertOptionsInternal(options, output);
136   }
137 
ConvertEnumValueOptions(const EnumValueOptions & options,RepeatedPtrField<Option> * output)138   void ConvertEnumValueOptions(const EnumValueOptions& options,
139                                RepeatedPtrField<Option>* output) {
140     return ConvertOptionsInternal(options, output);
141   }
142 
143   // Implementation details for Convert*Options.
ConvertOptionsInternal(const Message & options,RepeatedPtrField<Option> * output)144   void ConvertOptionsInternal(const Message& options,
145                               RepeatedPtrField<Option>* output) {
146     const Reflection* reflection = options.GetReflection();
147     std::vector<const FieldDescriptor*> fields;
148     reflection->ListFields(options, &fields);
149     for (const FieldDescriptor* field : fields) {
150       if (field->is_repeated()) {
151         const int size = reflection->FieldSize(options, field);
152         for (int i = 0; i < size; i++) {
153           ConvertOptionField(reflection, options, field, i, output->Add());
154         }
155       } else {
156         ConvertOptionField(reflection, options, field, -1, output->Add());
157       }
158     }
159   }
160 
ConvertOptionField(const Reflection * reflection,const Message & options,const FieldDescriptor * field,int index,Option * out)161   static void ConvertOptionField(const Reflection* reflection,
162                                  const Message& options,
163                                  const FieldDescriptor* field, int index,
164                                  Option* out) {
165     out->set_name(field->is_extension() ? field->full_name() : field->name());
166     Any* value = out->mutable_value();
167     switch (field->cpp_type()) {
168       case FieldDescriptor::CPPTYPE_MESSAGE:
169         value->PackFrom(
170             field->is_repeated()
171                 ? reflection->GetRepeatedMessage(options, field, index)
172                 : reflection->GetMessage(options, field));
173         return;
174       case FieldDescriptor::CPPTYPE_DOUBLE:
175         value->PackFrom(WrapValue<DoubleValue>(
176             field->is_repeated()
177                 ? reflection->GetRepeatedDouble(options, field, index)
178                 : reflection->GetDouble(options, field)));
179         return;
180       case FieldDescriptor::CPPTYPE_FLOAT:
181         value->PackFrom(WrapValue<FloatValue>(
182             field->is_repeated()
183                 ? reflection->GetRepeatedFloat(options, field, index)
184                 : reflection->GetFloat(options, field)));
185         return;
186       case FieldDescriptor::CPPTYPE_INT64:
187         value->PackFrom(WrapValue<Int64Value>(
188             field->is_repeated()
189                 ? reflection->GetRepeatedInt64(options, field, index)
190                 : reflection->GetInt64(options, field)));
191         return;
192       case FieldDescriptor::CPPTYPE_UINT64:
193         value->PackFrom(WrapValue<UInt64Value>(
194             field->is_repeated()
195                 ? reflection->GetRepeatedUInt64(options, field, index)
196                 : reflection->GetUInt64(options, field)));
197         return;
198       case FieldDescriptor::CPPTYPE_INT32:
199         value->PackFrom(WrapValue<Int32Value>(
200             field->is_repeated()
201                 ? reflection->GetRepeatedInt32(options, field, index)
202                 : reflection->GetInt32(options, field)));
203         return;
204       case FieldDescriptor::CPPTYPE_UINT32:
205         value->PackFrom(WrapValue<UInt32Value>(
206             field->is_repeated()
207                 ? reflection->GetRepeatedUInt32(options, field, index)
208                 : reflection->GetUInt32(options, field)));
209         return;
210       case FieldDescriptor::CPPTYPE_BOOL:
211         value->PackFrom(WrapValue<BoolValue>(
212             field->is_repeated()
213                 ? reflection->GetRepeatedBool(options, field, index)
214                 : reflection->GetBool(options, field)));
215         return;
216       case FieldDescriptor::CPPTYPE_STRING: {
217         const std::string& val =
218             field->is_repeated()
219                 ? reflection->GetRepeatedString(options, field, index)
220                 : reflection->GetString(options, field);
221         if (field->type() == FieldDescriptor::TYPE_STRING) {
222           value->PackFrom(WrapValue<StringValue>(val));
223         } else {
224           value->PackFrom(WrapValue<BytesValue>(val));
225         }
226         return;
227       }
228       case FieldDescriptor::CPPTYPE_ENUM: {
229         const EnumValueDescriptor* val =
230             field->is_repeated()
231                 ? reflection->GetRepeatedEnum(options, field, index)
232                 : reflection->GetEnum(options, field);
233         value->PackFrom(WrapValue<Int32Value>(val->number()));
234         return;
235       }
236     }
237   }
238 
239   template <typename WrapperT, typename T>
WrapValue(T value)240   static WrapperT WrapValue(T value) {
241     WrapperT wrapper;
242     wrapper.set_value(value);
243     return wrapper;
244   }
245 
ConvertFieldDescriptor(const FieldDescriptor * descriptor,Field * field)246   void ConvertFieldDescriptor(const FieldDescriptor* descriptor, Field* field) {
247     field->set_kind(static_cast<Field::Kind>(descriptor->type()));
248     switch (descriptor->label()) {
249       case FieldDescriptor::LABEL_OPTIONAL:
250         field->set_cardinality(Field::CARDINALITY_OPTIONAL);
251         break;
252       case FieldDescriptor::LABEL_REPEATED:
253         field->set_cardinality(Field::CARDINALITY_REPEATED);
254         break;
255       case FieldDescriptor::LABEL_REQUIRED:
256         field->set_cardinality(Field::CARDINALITY_REQUIRED);
257         break;
258     }
259     field->set_number(descriptor->number());
260     field->set_name(descriptor->name());
261     field->set_json_name(descriptor->json_name());
262     if (descriptor->has_default_value()) {
263       field->set_default_value(DefaultValueAsString(descriptor));
264     }
265     if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE ||
266         descriptor->type() == FieldDescriptor::TYPE_GROUP) {
267       field->set_type_url(GetTypeUrl(descriptor->message_type()));
268     } else if (descriptor->type() == FieldDescriptor::TYPE_ENUM) {
269       field->set_type_url(GetTypeUrl(descriptor->enum_type()));
270     }
271     if (descriptor->containing_oneof() != NULL) {
272       field->set_oneof_index(descriptor->containing_oneof()->index() + 1);
273     }
274     if (descriptor->is_packed()) {
275       field->set_packed(true);
276     }
277 
278     ConvertFieldOptions(descriptor->options(), field->mutable_options());
279   }
280 
ConvertEnumDescriptor(const EnumDescriptor * descriptor,Enum * enum_type)281   void ConvertEnumDescriptor(const EnumDescriptor* descriptor,
282                              Enum* enum_type) {
283     enum_type->Clear();
284     enum_type->set_name(descriptor->full_name());
285     enum_type->mutable_source_context()->set_file_name(
286         descriptor->file()->name());
287     for (int i = 0; i < descriptor->value_count(); ++i) {
288       const EnumValueDescriptor* value_descriptor = descriptor->value(i);
289       EnumValue* value = enum_type->mutable_enumvalue()->Add();
290       value->set_name(value_descriptor->name());
291       value->set_number(value_descriptor->number());
292 
293       ConvertEnumValueOptions(value_descriptor->options(),
294                               value->mutable_options());
295     }
296 
297     ConvertEnumOptions(descriptor->options(), enum_type->mutable_options());
298   }
299 
GetTypeUrl(const Descriptor * descriptor)300   std::string GetTypeUrl(const Descriptor* descriptor) {
301     return url_prefix_ + "/" + descriptor->full_name();
302   }
303 
GetTypeUrl(const EnumDescriptor * descriptor)304   std::string GetTypeUrl(const EnumDescriptor* descriptor) {
305     return url_prefix_ + "/" + descriptor->full_name();
306   }
307 
ParseTypeUrl(const std::string & type_url,std::string * type_name)308   Status ParseTypeUrl(const std::string& type_url, std::string* type_name) {
309     if (type_url.substr(0, url_prefix_.size() + 1) != url_prefix_ + "/") {
310       return Status(
311           util::error::INVALID_ARGUMENT,
312           StrCat("Invalid type URL, type URLs must be of the form '",
313                        url_prefix_, "/<typename>', got: ", type_url));
314     }
315     *type_name = type_url.substr(url_prefix_.size() + 1);
316     return Status();
317   }
318 
DefaultValueAsString(const FieldDescriptor * descriptor)319   std::string DefaultValueAsString(const FieldDescriptor* descriptor) {
320     switch (descriptor->cpp_type()) {
321       case FieldDescriptor::CPPTYPE_INT32:
322         return StrCat(descriptor->default_value_int32());
323         break;
324       case FieldDescriptor::CPPTYPE_INT64:
325         return StrCat(descriptor->default_value_int64());
326         break;
327       case FieldDescriptor::CPPTYPE_UINT32:
328         return StrCat(descriptor->default_value_uint32());
329         break;
330       case FieldDescriptor::CPPTYPE_UINT64:
331         return StrCat(descriptor->default_value_uint64());
332         break;
333       case FieldDescriptor::CPPTYPE_FLOAT:
334         return SimpleFtoa(descriptor->default_value_float());
335         break;
336       case FieldDescriptor::CPPTYPE_DOUBLE:
337         return SimpleDtoa(descriptor->default_value_double());
338         break;
339       case FieldDescriptor::CPPTYPE_BOOL:
340         return descriptor->default_value_bool() ? "true" : "false";
341         break;
342       case FieldDescriptor::CPPTYPE_STRING:
343         if (descriptor->type() == FieldDescriptor::TYPE_BYTES) {
344           return CEscape(descriptor->default_value_string());
345         } else {
346           return descriptor->default_value_string();
347         }
348         break;
349       case FieldDescriptor::CPPTYPE_ENUM:
350         return descriptor->default_value_enum()->name();
351         break;
352       case FieldDescriptor::CPPTYPE_MESSAGE:
353         GOOGLE_LOG(DFATAL) << "Messages can't have default values!";
354         break;
355     }
356     return "";
357   }
358 
359   std::string url_prefix_;
360   const DescriptorPool* pool_;
361 };
362 
363 }  // namespace
364 
NewTypeResolverForDescriptorPool(const std::string & url_prefix,const DescriptorPool * pool)365 TypeResolver* NewTypeResolverForDescriptorPool(const std::string& url_prefix,
366                                                const DescriptorPool* pool) {
367   return new DescriptorPoolTypeResolver(url_prefix, pool);
368 }
369 
370 }  // namespace util
371 }  // namespace protobuf
372 }  // namespace google
373