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