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/utility.h> 32 33 #include <google/protobuf/stubs/callback.h> 34 #include <google/protobuf/stubs/common.h> 35 #include <google/protobuf/stubs/logging.h> 36 #include <google/protobuf/wrappers.pb.h> 37 #include <google/protobuf/descriptor.pb.h> 38 #include <google/protobuf/descriptor.h> 39 #include <google/protobuf/util/internal/constants.h> 40 #include <google/protobuf/stubs/strutil.h> 41 #include <google/protobuf/stubs/map_util.h> 42 #include <google/protobuf/stubs/mathlimits.h> 43 44 namespace google { 45 namespace protobuf { 46 namespace util { 47 namespace converter { 48 49 namespace { 50 const StringPiece SkipWhiteSpace(StringPiece str) { 51 StringPiece::size_type i; 52 for (i = 0; i < str.size() && ascii_isspace(str[i]); ++i) { 53 } 54 GOOGLE_DCHECK(i == str.size() || !ascii_isspace(str[i])); 55 return StringPiece(str, i); 56 } 57 } // namespace 58 59 bool GetBoolOptionOrDefault( 60 const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options, 61 const string& option_name, bool default_value) { 62 const google::protobuf::Option* opt = FindOptionOrNull(options, option_name); 63 if (opt == NULL) { 64 return default_value; 65 } 66 return GetBoolFromAny(opt->value()); 67 } 68 69 int64 GetInt64OptionOrDefault( 70 const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options, 71 const string& option_name, int64 default_value) { 72 const google::protobuf::Option* opt = FindOptionOrNull(options, option_name); 73 if (opt == NULL) { 74 return default_value; 75 } 76 return GetInt64FromAny(opt->value()); 77 } 78 79 double GetDoubleOptionOrDefault( 80 const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options, 81 const string& option_name, double default_value) { 82 const google::protobuf::Option* opt = FindOptionOrNull(options, option_name); 83 if (opt == NULL) { 84 return default_value; 85 } 86 return GetDoubleFromAny(opt->value()); 87 } 88 89 string GetStringOptionOrDefault( 90 const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options, 91 const string& option_name, const string& default_value) { 92 const google::protobuf::Option* opt = FindOptionOrNull(options, option_name); 93 if (opt == NULL) { 94 return default_value; 95 } 96 return GetStringFromAny(opt->value()); 97 } 98 99 template <typename T> 100 void ParseFromAny(const string& data, T* result) { 101 result->ParseFromString(data); 102 } 103 104 // Returns a boolean value contained in Any type. 105 // TODO(skarvaje): Add type checking & error messages here. 106 bool GetBoolFromAny(const google::protobuf::Any& any) { 107 google::protobuf::BoolValue b; 108 ParseFromAny(any.value(), &b); 109 return b.value(); 110 } 111 112 int64 GetInt64FromAny(const google::protobuf::Any& any) { 113 google::protobuf::Int64Value i; 114 ParseFromAny(any.value(), &i); 115 return i.value(); 116 } 117 118 double GetDoubleFromAny(const google::protobuf::Any& any) { 119 google::protobuf::DoubleValue i; 120 ParseFromAny(any.value(), &i); 121 return i.value(); 122 } 123 124 string GetStringFromAny(const google::protobuf::Any& any) { 125 google::protobuf::StringValue s; 126 ParseFromAny(any.value(), &s); 127 return s.value(); 128 } 129 130 const StringPiece GetTypeWithoutUrl(StringPiece type_url) { 131 size_t idx = type_url.rfind('/'); 132 return type_url.substr(idx + 1); 133 } 134 135 const string GetFullTypeWithUrl(StringPiece simple_type) { 136 return StrCat(kTypeServiceBaseUrl, "/", simple_type); 137 } 138 139 const google::protobuf::Option* FindOptionOrNull( 140 const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options, 141 const string& option_name) { 142 for (int i = 0; i < options.size(); ++i) { 143 const google::protobuf::Option& opt = options.Get(i); 144 if (opt.name() == option_name) { 145 return &opt; 146 } 147 } 148 return NULL; 149 } 150 151 const google::protobuf::Field* FindFieldInTypeOrNull( 152 const google::protobuf::Type* type, StringPiece field_name) { 153 if (type != NULL) { 154 for (int i = 0; i < type->fields_size(); ++i) { 155 const google::protobuf::Field& field = type->fields(i); 156 if (field.name() == field_name) { 157 return &field; 158 } 159 } 160 } 161 return NULL; 162 } 163 164 const google::protobuf::Field* FindJsonFieldInTypeOrNull( 165 const google::protobuf::Type* type, StringPiece json_name) { 166 if (type != NULL) { 167 for (int i = 0; i < type->fields_size(); ++i) { 168 const google::protobuf::Field& field = type->fields(i); 169 if (field.json_name() == json_name) { 170 return &field; 171 } 172 } 173 } 174 return NULL; 175 } 176 177 const google::protobuf::EnumValue* FindEnumValueByNameOrNull( 178 const google::protobuf::Enum* enum_type, StringPiece enum_name) { 179 if (enum_type != NULL) { 180 for (int i = 0; i < enum_type->enumvalue_size(); ++i) { 181 const google::protobuf::EnumValue& enum_value = enum_type->enumvalue(i); 182 if (enum_value.name() == enum_name) { 183 return &enum_value; 184 } 185 } 186 } 187 return NULL; 188 } 189 190 const google::protobuf::EnumValue* FindEnumValueByNumberOrNull( 191 const google::protobuf::Enum* enum_type, int32 value) { 192 if (enum_type != NULL) { 193 for (int i = 0; i < enum_type->enumvalue_size(); ++i) { 194 const google::protobuf::EnumValue& enum_value = enum_type->enumvalue(i); 195 if (enum_value.number() == value) { 196 return &enum_value; 197 } 198 } 199 } 200 return NULL; 201 } 202 203 string ToCamelCase(const StringPiece input) { 204 bool capitalize_next = false; 205 bool was_cap = true; 206 bool is_cap = false; 207 bool first_word = true; 208 string result; 209 result.reserve(input.size()); 210 211 for (size_t i = 0; i < input.size(); ++i, was_cap = is_cap) { 212 is_cap = ascii_isupper(input[i]); 213 if (input[i] == '_') { 214 capitalize_next = true; 215 if (!result.empty()) first_word = false; 216 continue; 217 } else if (first_word) { 218 // Consider when the current character B is capitalized, 219 // first word ends when: 220 // 1) following a lowercase: "...aB..." 221 // 2) followed by a lowercase: "...ABc..." 222 if (!result.empty() && is_cap && 223 (!was_cap || (i + 1 < input.size() && ascii_islower(input[i + 1])))) { 224 first_word = false; 225 result.push_back(input[i]); 226 } else { 227 result.push_back(ascii_tolower(input[i])); 228 continue; 229 } 230 } else if (capitalize_next) { 231 capitalize_next = false; 232 if (ascii_islower(input[i])) { 233 result.push_back(ascii_toupper(input[i])); 234 continue; 235 } else { 236 result.push_back(input[i]); 237 continue; 238 } 239 } else { 240 result.push_back(ascii_tolower(input[i])); 241 } 242 } 243 return result; 244 } 245 246 string ToSnakeCase(StringPiece input) { 247 bool was_not_underscore = false; // Initialize to false for case 1 (below) 248 bool was_not_cap = false; 249 string result; 250 result.reserve(input.size() << 1); 251 252 for (size_t i = 0; i < input.size(); ++i) { 253 if (ascii_isupper(input[i])) { 254 // Consider when the current character B is capitalized: 255 // 1) At beginning of input: "B..." => "b..." 256 // (e.g. "Biscuit" => "biscuit") 257 // 2) Following a lowercase: "...aB..." => "...a_b..." 258 // (e.g. "gBike" => "g_bike") 259 // 3) At the end of input: "...AB" => "...ab" 260 // (e.g. "GoogleLAB" => "google_lab") 261 // 4) Followed by a lowercase: "...ABc..." => "...a_bc..." 262 // (e.g. "GBike" => "g_bike") 263 if (was_not_underscore && // case 1 out 264 (was_not_cap || // case 2 in, case 3 out 265 (i + 1 < input.size() && // case 3 out 266 ascii_islower(input[i + 1])))) { // case 4 in 267 // We add an underscore for case 2 and case 4. 268 result.push_back('_'); 269 } 270 result.push_back(ascii_tolower(input[i])); 271 was_not_underscore = true; 272 was_not_cap = false; 273 } else { 274 result.push_back(input[i]); 275 was_not_underscore = input[i] != '_'; 276 was_not_cap = true; 277 } 278 } 279 return result; 280 } 281 282 set<string>* well_known_types_ = NULL; 283 GOOGLE_PROTOBUF_DECLARE_ONCE(well_known_types_init_); 284 const char* well_known_types_name_array_[] = { 285 "google.protobuf.Timestamp", "google.protobuf.Duration", 286 "google.protobuf.DoubleValue", "google.protobuf.FloatValue", 287 "google.protobuf.Int64Value", "google.protobuf.UInt64Value", 288 "google.protobuf.Int32Value", "google.protobuf.UInt32Value", 289 "google.protobuf.BoolValue", "google.protobuf.StringValue", 290 "google.protobuf.BytesValue", "google.protobuf.FieldMask"}; 291 292 void DeleteWellKnownTypes() { delete well_known_types_; } 293 294 void InitWellKnownTypes() { 295 well_known_types_ = new set<string>; 296 for (int i = 0; i < GOOGLE_ARRAYSIZE(well_known_types_name_array_); ++i) { 297 well_known_types_->insert(well_known_types_name_array_[i]); 298 } 299 google::protobuf::internal::OnShutdown(&DeleteWellKnownTypes); 300 } 301 302 bool IsWellKnownType(const string& type_name) { 303 InitWellKnownTypes(); 304 return ContainsKey(*well_known_types_, type_name); 305 } 306 307 bool IsValidBoolString(const string& bool_string) { 308 return bool_string == "true" || bool_string == "false" || 309 bool_string == "1" || bool_string == "0"; 310 } 311 312 bool IsMap(const google::protobuf::Field& field, 313 const google::protobuf::Type& type) { 314 return (field.cardinality() == 315 google::protobuf::Field_Cardinality_CARDINALITY_REPEATED && 316 GetBoolOptionOrDefault(type.options(), 317 "google.protobuf.MessageOptions.map_entry", false)); 318 } 319 320 bool IsMessageSetWireFormat(const google::protobuf::Type& type) { 321 return GetBoolOptionOrDefault( 322 type.options(), "google.protobuf.MessageOptions.message_set_wire_format", false); 323 } 324 325 string DoubleAsString(double value) { 326 if (MathLimits<double>::IsPosInf(value)) return "Infinity"; 327 if (MathLimits<double>::IsNegInf(value)) return "-Infinity"; 328 if (MathLimits<double>::IsNaN(value)) return "NaN"; 329 330 return SimpleDtoa(value); 331 } 332 333 string FloatAsString(float value) { 334 if (MathLimits<float>::IsFinite(value)) return SimpleFtoa(value); 335 return DoubleAsString(value); 336 } 337 338 bool SafeStrToFloat(StringPiece str, float* value) { 339 double double_value; 340 if (!safe_strtod(str, &double_value)) { 341 return false; 342 } 343 344 if (MathLimits<double>::IsInf(double_value) || 345 MathLimits<double>::IsNaN(double_value)) 346 return false; 347 348 // Fail if the value is not representable in float. 349 if (double_value > std::numeric_limits<float>::max() || 350 double_value < -std::numeric_limits<float>::max()) { 351 return false; 352 } 353 354 *value = static_cast<float>(double_value); 355 return true; 356 } 357 358 } // namespace converter 359 } // namespace util 360 } // namespace protobuf 361 } // namespace google 362