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