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 44namespace google { 45namespace protobuf { 46namespace util { 47namespace converter { 48 49namespace { 50const 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 59bool 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 69int64 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 79double 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 89string 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 99template <typename T> 100void 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. 106bool GetBoolFromAny(const google::protobuf::Any& any) { 107 google::protobuf::BoolValue b; 108 ParseFromAny(any.value(), &b); 109 return b.value(); 110} 111 112int64 GetInt64FromAny(const google::protobuf::Any& any) { 113 google::protobuf::Int64Value i; 114 ParseFromAny(any.value(), &i); 115 return i.value(); 116} 117 118double GetDoubleFromAny(const google::protobuf::Any& any) { 119 google::protobuf::DoubleValue i; 120 ParseFromAny(any.value(), &i); 121 return i.value(); 122} 123 124string GetStringFromAny(const google::protobuf::Any& any) { 125 google::protobuf::StringValue s; 126 ParseFromAny(any.value(), &s); 127 return s.value(); 128} 129 130const StringPiece GetTypeWithoutUrl(StringPiece type_url) { 131 size_t idx = type_url.rfind('/'); 132 return type_url.substr(idx + 1); 133} 134 135const string GetFullTypeWithUrl(StringPiece simple_type) { 136 return StrCat(kTypeServiceBaseUrl, "/", simple_type); 137} 138 139const 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 151const 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 164const 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 177const 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 190const 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 203string 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 246string 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 282set<string>* well_known_types_ = NULL; 283GOOGLE_PROTOBUF_DECLARE_ONCE(well_known_types_init_); 284const 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 292void DeleteWellKnownTypes() { delete well_known_types_; } 293 294void 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 302bool IsWellKnownType(const string& type_name) { 303 InitWellKnownTypes(); 304 return ContainsKey(*well_known_types_, type_name); 305} 306 307bool IsValidBoolString(const string& bool_string) { 308 return bool_string == "true" || bool_string == "false" || 309 bool_string == "1" || bool_string == "0"; 310} 311 312bool 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 320bool IsMessageSetWireFormat(const google::protobuf::Type& type) { 321 return GetBoolOptionOrDefault( 322 type.options(), "google.protobuf.MessageOptions.message_set_wire_format", false); 323} 324 325string 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 333string FloatAsString(float value) { 334 if (MathLimits<float>::IsFinite(value)) return SimpleFtoa(value); 335 return DoubleAsString(value); 336} 337 338bool 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