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 44namespace google { 45namespace protobuf { 46namespace util { 47namespace converter { 48 49namespace { 50// A TypeInfo that looks up information provided by a TypeResolver. 51class 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 164TypeInfo* 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