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