| OLD | NEW |
| 1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
| 2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
| 3 // https://developers.google.com/protocol-buffers/ | 3 // https://developers.google.com/protocol-buffers/ |
| 4 // | 4 // |
| 5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
| 6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
| 7 // met: | 7 // met: |
| 8 // | 8 // |
| 9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
| 10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 87 // point types (double, float) only. | 87 // point types (double, float) only. |
| 88 template <typename To, typename From> | 88 template <typename To, typename From> |
| 89 StatusOr<To> FloatingPointToIntConvertAndCheck(From before) { | 89 StatusOr<To> FloatingPointToIntConvertAndCheck(From before) { |
| 90 if (::google::protobuf::internal::is_same<From, To>::value) return before; | 90 if (::google::protobuf::internal::is_same<From, To>::value) return before; |
| 91 | 91 |
| 92 To after = static_cast<To>(before); | 92 To after = static_cast<To>(before); |
| 93 return ValidateNumberConversion(after, before); | 93 return ValidateNumberConversion(after, before); |
| 94 } | 94 } |
| 95 | 95 |
| 96 // For conversion between double and float only. | 96 // For conversion between double and float only. |
| 97 template <typename To, typename From> | 97 StatusOr<double> FloatToDouble(float before) { |
| 98 StatusOr<To> FloatingPointConvertAndCheck(From before) { | 98 // Casting float to double should just work as double has more precision |
| 99 if (MathLimits<From>::IsNaN(before)) { | 99 // than float. |
| 100 return std::numeric_limits<To>::quiet_NaN(); | 100 return static_cast<double>(before); |
| 101 } | 101 } |
| 102 | 102 |
| 103 To after = static_cast<To>(before); | 103 StatusOr<float> DoubleToFloat(double before) { |
| 104 if (MathUtil::AlmostEquals<To>(after, before)) { | 104 if (MathLimits<double>::IsNaN(before)) { |
| 105 return after; | 105 return std::numeric_limits<float>::quiet_NaN(); |
| 106 } else if (!MathLimits<double>::IsFinite(before)) { |
| 107 // Converting a double +inf/-inf to float should just work. |
| 108 return static_cast<float>(before); |
| 109 } else if (before > std::numeric_limits<float>::max() || |
| 110 before < -std::numeric_limits<float>::max()) { |
| 111 // Double value outside of the range of float. |
| 112 return InvalidArgument(DoubleAsString(before)); |
| 106 } else { | 113 } else { |
| 107 return InvalidArgument(::google::protobuf::internal::is_same<From, double>::
value | 114 return static_cast<float>(before); |
| 108 ? DoubleAsString(before) | |
| 109 : FloatAsString(before)); | |
| 110 } | 115 } |
| 111 } | 116 } |
| 112 | 117 |
| 113 } // namespace | 118 } // namespace |
| 114 | 119 |
| 115 StatusOr<int32> DataPiece::ToInt32() const { | 120 StatusOr<int32> DataPiece::ToInt32() const { |
| 116 if (type_ == TYPE_STRING) return StringToNumber<int32>(safe_strto32); | 121 if (type_ == TYPE_STRING) return StringToNumber<int32>(safe_strto32); |
| 117 | 122 |
| 118 if (type_ == TYPE_DOUBLE) | 123 if (type_ == TYPE_DOUBLE) |
| 119 return FloatingPointToIntConvertAndCheck<int32, double>(double_); | 124 return FloatingPointToIntConvertAndCheck<int32, double>(double_); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 155 return FloatingPointToIntConvertAndCheck<uint64, double>(double_); | 160 return FloatingPointToIntConvertAndCheck<uint64, double>(double_); |
| 156 | 161 |
| 157 if (type_ == TYPE_FLOAT) | 162 if (type_ == TYPE_FLOAT) |
| 158 return FloatingPointToIntConvertAndCheck<uint64, float>(float_); | 163 return FloatingPointToIntConvertAndCheck<uint64, float>(float_); |
| 159 | 164 |
| 160 return GenericConvert<uint64>(); | 165 return GenericConvert<uint64>(); |
| 161 } | 166 } |
| 162 | 167 |
| 163 StatusOr<double> DataPiece::ToDouble() const { | 168 StatusOr<double> DataPiece::ToDouble() const { |
| 164 if (type_ == TYPE_FLOAT) { | 169 if (type_ == TYPE_FLOAT) { |
| 165 return FloatingPointConvertAndCheck<double, float>(float_); | 170 return FloatToDouble(float_); |
| 166 } | 171 } |
| 167 if (type_ == TYPE_STRING) { | 172 if (type_ == TYPE_STRING) { |
| 168 if (str_ == "Infinity") return std::numeric_limits<double>::infinity(); | 173 if (str_ == "Infinity") return std::numeric_limits<double>::infinity(); |
| 169 if (str_ == "-Infinity") return -std::numeric_limits<double>::infinity(); | 174 if (str_ == "-Infinity") return -std::numeric_limits<double>::infinity(); |
| 170 if (str_ == "NaN") return std::numeric_limits<double>::quiet_NaN(); | 175 if (str_ == "NaN") return std::numeric_limits<double>::quiet_NaN(); |
| 171 return StringToNumber<double>(safe_strtod); | 176 StatusOr<double> value = StringToNumber<double>(safe_strtod); |
| 177 if (value.ok() && !MathLimits<double>::IsFinite(value.ValueOrDie())) { |
| 178 // safe_strtod converts out-of-range values to +inf/-inf, but we want |
| 179 // to report them as errors. |
| 180 return InvalidArgument(StrCat("\"", str_, "\"")); |
| 181 } else { |
| 182 return value; |
| 183 } |
| 172 } | 184 } |
| 173 return GenericConvert<double>(); | 185 return GenericConvert<double>(); |
| 174 } | 186 } |
| 175 | 187 |
| 176 StatusOr<float> DataPiece::ToFloat() const { | 188 StatusOr<float> DataPiece::ToFloat() const { |
| 177 if (type_ == TYPE_DOUBLE) { | 189 if (type_ == TYPE_DOUBLE) { |
| 178 return FloatingPointConvertAndCheck<float, double>(double_); | 190 return DoubleToFloat(double_); |
| 179 } | 191 } |
| 180 if (type_ == TYPE_STRING) { | 192 if (type_ == TYPE_STRING) { |
| 181 if (str_ == "Infinity") return std::numeric_limits<float>::infinity(); | 193 if (str_ == "Infinity") return std::numeric_limits<float>::infinity(); |
| 182 if (str_ == "-Infinity") return -std::numeric_limits<float>::infinity(); | 194 if (str_ == "-Infinity") return -std::numeric_limits<float>::infinity(); |
| 183 if (str_ == "NaN") return std::numeric_limits<float>::quiet_NaN(); | 195 if (str_ == "NaN") return std::numeric_limits<float>::quiet_NaN(); |
| 184 // SafeStrToFloat() is used instead of safe_strtof() because the later | 196 // SafeStrToFloat() is used instead of safe_strtof() because the later |
| 185 // does not fail on inputs like SimpleDtoa(DBL_MAX). | 197 // does not fail on inputs like SimpleDtoa(DBL_MAX). |
| 186 return StringToNumber<float>(SafeStrToFloat); | 198 return StringToNumber<float>(SafeStrToFloat); |
| 187 } | 199 } |
| 188 return GenericConvert<float>(); | 200 return GenericConvert<float>(); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 252 if (!DecodeBase64(str_, &decoded)) { | 264 if (!DecodeBase64(str_, &decoded)) { |
| 253 return InvalidArgument(ValueAsStringOrDefault("Invalid data in input.")); | 265 return InvalidArgument(ValueAsStringOrDefault("Invalid data in input.")); |
| 254 } | 266 } |
| 255 return decoded; | 267 return decoded; |
| 256 } else { | 268 } else { |
| 257 return InvalidArgument(ValueAsStringOrDefault( | 269 return InvalidArgument(ValueAsStringOrDefault( |
| 258 "Wrong type. Only String or Bytes can be converted to Bytes.")); | 270 "Wrong type. Only String or Bytes can be converted to Bytes.")); |
| 259 } | 271 } |
| 260 } | 272 } |
| 261 | 273 |
| 262 StatusOr<int> DataPiece::ToEnum(const google::protobuf::Enum* enum_type) const { | 274 StatusOr<int> DataPiece::ToEnum(const google::protobuf::Enum* enum_type, |
| 275 bool use_lower_camel_for_enums) const { |
| 263 if (type_ == TYPE_NULL) return google::protobuf::NULL_VALUE; | 276 if (type_ == TYPE_NULL) return google::protobuf::NULL_VALUE; |
| 264 | 277 |
| 265 if (type_ == TYPE_STRING) { | 278 if (type_ == TYPE_STRING) { |
| 266 // First try the given value as a name. | 279 // First try the given value as a name. |
| 267 string enum_name = str_.ToString(); | 280 string enum_name = str_.ToString(); |
| 268 const google::protobuf::EnumValue* value = | 281 const google::protobuf::EnumValue* value = |
| 269 FindEnumValueByNameOrNull(enum_type, enum_name); | 282 FindEnumValueByNameOrNull(enum_type, enum_name); |
| 270 if (value != NULL) return value->number(); | 283 if (value != NULL) return value->number(); |
| 284 |
| 285 // Check if int version of enum is sent as string. |
| 286 StatusOr<int32> int_value = ToInt32(); |
| 287 if (int_value.ok()) { |
| 288 if (const google::protobuf::EnumValue* enum_value = |
| 289 FindEnumValueByNumberOrNull(enum_type, int_value.ValueOrDie())) { |
| 290 return enum_value->number(); |
| 291 } |
| 292 } |
| 293 |
| 271 // Next try a normalized name. | 294 // Next try a normalized name. |
| 272 for (string::iterator it = enum_name.begin(); it != enum_name.end(); ++it) { | 295 for (string::iterator it = enum_name.begin(); it != enum_name.end(); ++it) { |
| 273 *it = *it == '-' ? '_' : ascii_toupper(*it); | 296 *it = *it == '-' ? '_' : ascii_toupper(*it); |
| 274 } | 297 } |
| 275 value = FindEnumValueByNameOrNull(enum_type, enum_name); | 298 value = FindEnumValueByNameOrNull(enum_type, enum_name); |
| 276 if (value != NULL) return value->number(); | 299 if (value != NULL) return value->number(); |
| 300 |
| 301 // If use_lower_camel_for_enums is true try with enum name without |
| 302 // underscore. This will also accept camel case names as the enum_name has |
| 303 // been normalized before. |
| 304 if (use_lower_camel_for_enums) { |
| 305 value = FindEnumValueByNameWithoutUnderscoreOrNull(enum_type, enum_name); |
| 306 if (value != NULL) return value->number(); |
| 307 } |
| 277 } else { | 308 } else { |
| 278 StatusOr<int32> value = ToInt32(); | 309 // We don't need to check whether the value is actually declared in the |
| 279 if (value.ok()) { | 310 // enum because we preserve unknown enum values as well. |
| 280 if (const google::protobuf::EnumValue* enum_value = | 311 return ToInt32(); |
| 281 FindEnumValueByNumberOrNull(enum_type, value.ValueOrDie())) { | |
| 282 return enum_value->number(); | |
| 283 } | |
| 284 } | |
| 285 } | 312 } |
| 286 return InvalidArgument( | 313 return InvalidArgument( |
| 287 ValueAsStringOrDefault("Cannot find enum with given value.")); | 314 ValueAsStringOrDefault("Cannot find enum with given value.")); |
| 288 } | 315 } |
| 289 | 316 |
| 290 template <typename To> | 317 template <typename To> |
| 291 StatusOr<To> DataPiece::GenericConvert() const { | 318 StatusOr<To> DataPiece::GenericConvert() const { |
| 292 switch (type_) { | 319 switch (type_) { |
| 293 case TYPE_INT32: | 320 case TYPE_INT32: |
| 294 return NumberConvertAndCheck<To, int32>(i32_); | 321 return NumberConvertAndCheck<To, int32>(i32_); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 322 bool DataPiece::DecodeBase64(StringPiece src, string* dest) const { | 349 bool DataPiece::DecodeBase64(StringPiece src, string* dest) const { |
| 323 // Try web-safe decode first, if it fails, try the non-web-safe decode. | 350 // Try web-safe decode first, if it fails, try the non-web-safe decode. |
| 324 if (WebSafeBase64Unescape(src, dest)) { | 351 if (WebSafeBase64Unescape(src, dest)) { |
| 325 if (use_strict_base64_decoding_) { | 352 if (use_strict_base64_decoding_) { |
| 326 // In strict mode, check if the escaped version gives us the same value as | 353 // In strict mode, check if the escaped version gives us the same value as |
| 327 // unescaped. | 354 // unescaped. |
| 328 string encoded; | 355 string encoded; |
| 329 // WebSafeBase64Escape does no padding by default. | 356 // WebSafeBase64Escape does no padding by default. |
| 330 WebSafeBase64Escape(*dest, &encoded); | 357 WebSafeBase64Escape(*dest, &encoded); |
| 331 // Remove trailing padding '=' characters before comparison. | 358 // Remove trailing padding '=' characters before comparison. |
| 332 StringPiece src_no_padding(src, 0, src.ends_with("=") | 359 StringPiece src_no_padding = StringPiece(src).substr( |
| 333 ? src.find_last_not_of('=') + 1 | 360 0, src.ends_with("=") ? src.find_last_not_of('=') + 1 : src.length()); |
| 334 : src.length()); | |
| 335 return encoded == src_no_padding; | 361 return encoded == src_no_padding; |
| 336 } | 362 } |
| 337 return true; | 363 return true; |
| 338 } | 364 } |
| 339 | 365 |
| 340 if (Base64Unescape(src, dest)) { | 366 if (Base64Unescape(src, dest)) { |
| 341 if (use_strict_base64_decoding_) { | 367 if (use_strict_base64_decoding_) { |
| 342 string encoded; | 368 string encoded; |
| 343 Base64Escape( | 369 Base64Escape( |
| 344 reinterpret_cast<const unsigned char*>(dest->data()), dest->length(), | 370 reinterpret_cast<const unsigned char*>(dest->data()), dest->length(), |
| 345 &encoded, false); | 371 &encoded, false); |
| 346 StringPiece src_no_padding(src, 0, src.ends_with("=") | 372 StringPiece src_no_padding = StringPiece(src).substr( |
| 347 ? src.find_last_not_of('=') + 1 | 373 0, src.ends_with("=") ? src.find_last_not_of('=') + 1 : src.length()); |
| 348 : src.length()); | |
| 349 return encoded == src_no_padding; | 374 return encoded == src_no_padding; |
| 350 } | 375 } |
| 351 return true; | 376 return true; |
| 352 } | 377 } |
| 353 | 378 |
| 354 return false; | 379 return false; |
| 355 } | 380 } |
| 356 | 381 |
| 382 void DataPiece::InternalCopy(const DataPiece& other) { |
| 383 type_ = other.type_; |
| 384 use_strict_base64_decoding_ = other.use_strict_base64_decoding_; |
| 385 switch (type_) { |
| 386 case TYPE_INT32: |
| 387 case TYPE_INT64: |
| 388 case TYPE_UINT32: |
| 389 case TYPE_UINT64: |
| 390 case TYPE_DOUBLE: |
| 391 case TYPE_FLOAT: |
| 392 case TYPE_BOOL: |
| 393 case TYPE_ENUM: |
| 394 case TYPE_NULL: |
| 395 case TYPE_BYTES: |
| 396 case TYPE_STRING: { |
| 397 str_ = other.str_; |
| 398 break; |
| 399 } |
| 400 } |
| 401 } |
| 402 |
| 357 } // namespace converter | 403 } // namespace converter |
| 358 } // namespace util | 404 } // namespace util |
| 359 } // namespace protobuf | 405 } // namespace protobuf |
| 360 } // namespace google | 406 } // namespace google |
| OLD | NEW |