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