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 namespace google { 43 namespace protobuf { 44 namespace util { 45 namespace { 46 using google::protobuf::BoolValue; 47 using google::protobuf::Enum; 48 using google::protobuf::EnumValue; 49 using google::protobuf::Field; 50 using google::protobuf::Option; 51 using google::protobuf::Type; 52 53 using util::Status; 54 using util::error::INVALID_ARGUMENT; 55 using util::error::NOT_FOUND; 56 57 bool SplitTypeUrl(const string& type_url, string* url_prefix, 58 string* message_name) { 59 size_t pos = type_url.find_last_of("/"); 60 if (pos == string::npos) { 61 return false; 62 } 63 *url_prefix = type_url.substr(0, pos); 64 *message_name = type_url.substr(pos + 1); 65 return true; 66 } 67 68 class DescriptorPoolTypeResolver : public TypeResolver { 69 public: 70 DescriptorPoolTypeResolver(const string& url_prefix, 71 const DescriptorPool* pool) 72 : url_prefix_(url_prefix), pool_(pool) {} 73 74 Status ResolveMessageType(const string& type_url, Type* type) { 75 string url_prefix, message_name; 76 if (!SplitTypeUrl(type_url, &url_prefix, &message_name) || 77 url_prefix != url_prefix_) { 78 return Status(INVALID_ARGUMENT, 79 StrCat("Invalid type URL, type URLs must be of the form '", 80 url_prefix_, "/<typename>', got: ", type_url)); 81 } 82 if (url_prefix != url_prefix_) { 83 return Status(INVALID_ARGUMENT, 84 "Cannot resolve types from URL: " + url_prefix); 85 } 86 const Descriptor* descriptor = pool_->FindMessageTypeByName(message_name); 87 if (descriptor == NULL) { 88 return Status(NOT_FOUND, 89 "Invalid type URL, unknown type: " + message_name); 90 } 91 ConvertDescriptor(descriptor, type); 92 return Status(); 93 } 94 95 Status ResolveEnumType(const string& type_url, Enum* enum_type) { 96 string url_prefix, type_name; 97 if (!SplitTypeUrl(type_url, &url_prefix, &type_name) || 98 url_prefix != url_prefix_) { 99 return Status(INVALID_ARGUMENT, 100 StrCat("Invalid type URL, type URLs must be of the form '", 101 url_prefix_, "/<typename>', got: ", type_url)); 102 } 103 if (url_prefix != url_prefix_) { 104 return Status(INVALID_ARGUMENT, 105 "Cannot resolve types from URL: " + url_prefix); 106 } 107 const EnumDescriptor* descriptor = pool_->FindEnumTypeByName(type_name); 108 if (descriptor == NULL) { 109 return Status(NOT_FOUND, "Invalid type URL, unknown type: " + type_name); 110 } 111 ConvertEnumDescriptor(descriptor, enum_type); 112 return Status(); 113 } 114 115 private: 116 void ConvertDescriptor(const Descriptor* descriptor, Type* type) { 117 type->Clear(); 118 type->set_name(descriptor->full_name()); 119 for (int i = 0; i < descriptor->field_count(); ++i) { 120 const FieldDescriptor* field = descriptor->field(i); 121 if (field->type() == FieldDescriptor::TYPE_GROUP) { 122 // Group fields cannot be represented with Type. We discard them. 123 continue; 124 } 125 ConvertFieldDescriptor(descriptor->field(i), type->add_fields()); 126 } 127 for (int i = 0; i < descriptor->oneof_decl_count(); ++i) { 128 type->add_oneofs(descriptor->oneof_decl(i)->name()); 129 } 130 type->mutable_source_context()->set_file_name(descriptor->file()->name()); 131 ConvertMessageOptions(descriptor->options(), type->mutable_options()); 132 } 133 134 void ConvertMessageOptions(const MessageOptions& options, 135 RepeatedPtrField<Option>* output) { 136 if (options.map_entry()) { 137 Option* option = output->Add(); 138 option->set_name("map_entry"); 139 BoolValue value; 140 value.set_value(true); 141 option->mutable_value()->PackFrom(value); 142 } 143 144 // TODO(xiaofeng): Set other "options"? 145 } 146 147 void ConvertFieldDescriptor(const FieldDescriptor* descriptor, Field* field) { 148 field->set_kind(static_cast<Field::Kind>(descriptor->type())); 149 switch (descriptor->label()) { 150 case FieldDescriptor::LABEL_OPTIONAL: 151 field->set_cardinality(Field::CARDINALITY_OPTIONAL); 152 break; 153 case FieldDescriptor::LABEL_REPEATED: 154 field->set_cardinality(Field::CARDINALITY_REPEATED); 155 break; 156 case FieldDescriptor::LABEL_REQUIRED: 157 field->set_cardinality(Field::CARDINALITY_REQUIRED); 158 break; 159 } 160 field->set_number(descriptor->number()); 161 field->set_name(descriptor->name()); 162 field->set_json_name(descriptor->json_name()); 163 if (descriptor->has_default_value()) { 164 field->set_default_value(DefaultValueAsString(descriptor)); 165 } 166 if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE) { 167 field->set_type_url(GetTypeUrl(descriptor->message_type())); 168 } else if (descriptor->type() == FieldDescriptor::TYPE_ENUM) { 169 field->set_type_url(GetTypeUrl(descriptor->enum_type())); 170 } 171 if (descriptor->containing_oneof() != NULL) { 172 field->set_oneof_index(descriptor->containing_oneof()->index() + 1); 173 } 174 if (descriptor->is_packed()) { 175 field->set_packed(true); 176 } 177 178 // TODO(xiaofeng): Set other field "options"? 179 } 180 181 void ConvertEnumDescriptor(const EnumDescriptor* descriptor, 182 Enum* enum_type) { 183 enum_type->Clear(); 184 enum_type->set_name(descriptor->full_name()); 185 enum_type->mutable_source_context()->set_file_name( 186 descriptor->file()->name()); 187 for (int i = 0; i < descriptor->value_count(); ++i) { 188 const EnumValueDescriptor* value_descriptor = descriptor->value(i); 189 EnumValue* value = enum_type->mutable_enumvalue()->Add(); 190 value->set_name(value_descriptor->name()); 191 value->set_number(value_descriptor->number()); 192 193 // TODO(xiaofeng): Set EnumValue options. 194 } 195 // TODO(xiaofeng): Set Enum "options". 196 } 197 198 string GetTypeUrl(const Descriptor* descriptor) { 199 return url_prefix_ + "/" + descriptor->full_name(); 200 } 201 202 string GetTypeUrl(const EnumDescriptor* descriptor) { 203 return url_prefix_ + "/" + descriptor->full_name(); 204 } 205 206 string DefaultValueAsString(const FieldDescriptor* descriptor) { 207 switch (descriptor->cpp_type()) { 208 case FieldDescriptor::CPPTYPE_INT32: 209 return SimpleItoa(descriptor->default_value_int32()); 210 break; 211 case FieldDescriptor::CPPTYPE_INT64: 212 return SimpleItoa(descriptor->default_value_int64()); 213 break; 214 case FieldDescriptor::CPPTYPE_UINT32: 215 return SimpleItoa(descriptor->default_value_uint32()); 216 break; 217 case FieldDescriptor::CPPTYPE_UINT64: 218 return SimpleItoa(descriptor->default_value_uint64()); 219 break; 220 case FieldDescriptor::CPPTYPE_FLOAT: 221 return SimpleFtoa(descriptor->default_value_float()); 222 break; 223 case FieldDescriptor::CPPTYPE_DOUBLE: 224 return SimpleDtoa(descriptor->default_value_double()); 225 break; 226 case FieldDescriptor::CPPTYPE_BOOL: 227 return descriptor->default_value_bool() ? "true" : "false"; 228 break; 229 case FieldDescriptor::CPPTYPE_STRING: 230 if (descriptor->type() == FieldDescriptor::TYPE_BYTES) { 231 return CEscape(descriptor->default_value_string()); 232 } else { 233 return descriptor->default_value_string(); 234 } 235 break; 236 case FieldDescriptor::CPPTYPE_ENUM: 237 return descriptor->default_value_enum()->name(); 238 break; 239 case FieldDescriptor::CPPTYPE_MESSAGE: 240 GOOGLE_LOG(DFATAL) << "Messages can't have default values!"; 241 break; 242 } 243 return ""; 244 } 245 246 string url_prefix_; 247 const DescriptorPool* pool_; 248 }; 249 250 } // namespace 251 252 TypeResolver* NewTypeResolverForDescriptorPool(const string& url_prefix, 253 const DescriptorPool* pool) { 254 return new DescriptorPoolTypeResolver(url_prefix, pool); 255 } 256 257 } // namespace util 258 } // namespace protobuf 259 } // namespace google 260