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/internal/type_info.h> 32 33 #include <map> 34 #include <set> 35 36 #include <google/protobuf/stubs/common.h> 37 #include <google/protobuf/type.pb.h> 38 #include <google/protobuf/util/internal/utility.h> 39 #include <google/protobuf/stubs/stringpiece.h> 40 #include <google/protobuf/stubs/map_util.h> 41 #include <google/protobuf/stubs/status.h> 42 #include <google/protobuf/stubs/statusor.h> 43 44 namespace google { 45 namespace protobuf { 46 namespace util { 47 namespace converter { 48 49 namespace { 50 // A TypeInfo that looks up information provided by a TypeResolver. 51 class TypeInfoForTypeResolver : public TypeInfo { 52 public: 53 explicit TypeInfoForTypeResolver(TypeResolver* type_resolver) 54 : type_resolver_(type_resolver) {} 55 56 virtual ~TypeInfoForTypeResolver() { 57 DeleteCachedTypes(&cached_types_); 58 DeleteCachedTypes(&cached_enums_); 59 } 60 61 virtual util::StatusOr<const google::protobuf::Type*> ResolveTypeUrl( 62 StringPiece type_url) const { 63 map<StringPiece, StatusOrType>::iterator it = cached_types_.find(type_url); 64 if (it != cached_types_.end()) { 65 return it->second; 66 } 67 // Stores the string value so it can be referenced using StringPiece in the 68 // cached_types_ map. 69 const string& string_type_url = 70 *string_storage_.insert(type_url.ToString()).first; 71 google::protobuf::scoped_ptr<google::protobuf::Type> type(new google::protobuf::Type()); 72 util::Status status = 73 type_resolver_->ResolveMessageType(string_type_url, type.get()); 74 StatusOrType result = 75 status.ok() ? StatusOrType(type.release()) : StatusOrType(status); 76 cached_types_[string_type_url] = result; 77 return result; 78 } 79 80 virtual const google::protobuf::Type* GetTypeByTypeUrl( 81 StringPiece type_url) const { 82 StatusOrType result = ResolveTypeUrl(type_url); 83 return result.ok() ? result.ValueOrDie() : NULL; 84 } 85 86 virtual const google::protobuf::Enum* GetEnumByTypeUrl( 87 StringPiece type_url) const { 88 map<StringPiece, StatusOrEnum>::iterator it = cached_enums_.find(type_url); 89 if (it != cached_enums_.end()) { 90 return it->second.ok() ? it->second.ValueOrDie() : NULL; 91 } 92 // Stores the string value so it can be referenced using StringPiece in the 93 // cached_enums_ map. 94 const string& string_type_url = 95 *string_storage_.insert(type_url.ToString()).first; 96 google::protobuf::scoped_ptr<google::protobuf::Enum> enum_type( 97 new google::protobuf::Enum()); 98 util::Status status = 99 type_resolver_->ResolveEnumType(string_type_url, enum_type.get()); 100 StatusOrEnum result = 101 status.ok() ? StatusOrEnum(enum_type.release()) : StatusOrEnum(status); 102 cached_enums_[string_type_url] = result; 103 return result.ok() ? result.ValueOrDie() : NULL; 104 } 105 106 virtual const google::protobuf::Field* FindField( 107 const google::protobuf::Type* type, StringPiece camel_case_name) const { 108 if (indexed_types_.find(type) == indexed_types_.end()) { 109 PopulateNameLookupTable(type); 110 indexed_types_.insert(type); 111 } 112 StringPiece name = 113 FindWithDefault(camel_case_name_table_, camel_case_name, StringPiece()); 114 if (name.empty()) { 115 // Didn't find a mapping. Use whatever provided. 116 name = camel_case_name; 117 } 118 return FindFieldInTypeOrNull(type, name); 119 } 120 121 private: 122 typedef util::StatusOr<const google::protobuf::Type*> StatusOrType; 123 typedef util::StatusOr<const google::protobuf::Enum*> StatusOrEnum; 124 125 template <typename T> 126 static void DeleteCachedTypes(map<StringPiece, T>* cached_types) { 127 for (typename map<StringPiece, T>::iterator it = cached_types->begin(); 128 it != cached_types->end(); ++it) { 129 if (it->second.ok()) { 130 delete it->second.ValueOrDie(); 131 } 132 } 133 } 134 135 void PopulateNameLookupTable(const google::protobuf::Type* type) const { 136 for (int i = 0; i < type->fields_size(); ++i) { 137 const google::protobuf::Field& field = type->fields(i); 138 StringPiece name = field.name(); 139 StringPiece camel_case_name = field.json_name(); 140 const StringPiece* existing = InsertOrReturnExisting( 141 &camel_case_name_table_, camel_case_name, name); 142 if (existing && *existing != name) { 143 GOOGLE_LOG(WARNING) << "Field '" << name << "' and '" << *existing 144 << "' map to the same camel case name '" << camel_case_name 145 << "'."; 146 } 147 } 148 } 149 150 TypeResolver* type_resolver_; 151 152 // Stores string values that will be referenced by StringPieces in 153 // cached_types_, cached_enums_ and camel_case_name_table_. 154 mutable set<string> string_storage_; 155 156 mutable map<StringPiece, StatusOrType> cached_types_; 157 mutable map<StringPiece, StatusOrEnum> cached_enums_; 158 159 mutable set<const google::protobuf::Type*> indexed_types_; 160 mutable map<StringPiece, StringPiece> camel_case_name_table_; 161 }; 162 } // namespace 163 164 TypeInfo* TypeInfo::NewTypeInfo(TypeResolver* type_resolver) { 165 return new TypeInfoForTypeResolver(type_resolver); 166 } 167 168 } // namespace converter 169 } // namespace util 170 } // namespace protobuf 171 } // namespace google 172