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