Index: third_party/protobuf/src/google/protobuf/util/internal/datapiece.cc |
diff --git a/third_party/protobuf/src/google/protobuf/util/internal/datapiece.cc b/third_party/protobuf/src/google/protobuf/util/internal/datapiece.cc |
index 72c0aca6090f6a5f288fabec1c06be4717911d48..213c2c40c0aadd6861588faa9fc4deaacab34ff1 100644 |
--- a/third_party/protobuf/src/google/protobuf/util/internal/datapiece.cc |
+++ b/third_party/protobuf/src/google/protobuf/util/internal/datapiece.cc |
@@ -94,19 +94,24 @@ StatusOr<To> FloatingPointToIntConvertAndCheck(From before) { |
} |
// For conversion between double and float only. |
-template <typename To, typename From> |
-StatusOr<To> FloatingPointConvertAndCheck(From before) { |
- if (MathLimits<From>::IsNaN(before)) { |
- return std::numeric_limits<To>::quiet_NaN(); |
- } |
+StatusOr<double> FloatToDouble(float before) { |
+ // Casting float to double should just work as double has more precision |
+ // than float. |
+ return static_cast<double>(before); |
+} |
- To after = static_cast<To>(before); |
- if (MathUtil::AlmostEquals<To>(after, before)) { |
- return after; |
+StatusOr<float> DoubleToFloat(double before) { |
+ if (MathLimits<double>::IsNaN(before)) { |
+ return std::numeric_limits<float>::quiet_NaN(); |
+ } else if (!MathLimits<double>::IsFinite(before)) { |
+ // Converting a double +inf/-inf to float should just work. |
+ return static_cast<float>(before); |
+ } else if (before > std::numeric_limits<float>::max() || |
+ before < -std::numeric_limits<float>::max()) { |
+ // Double value outside of the range of float. |
+ return InvalidArgument(DoubleAsString(before)); |
} else { |
- return InvalidArgument(::google::protobuf::internal::is_same<From, double>::value |
- ? DoubleAsString(before) |
- : FloatAsString(before)); |
+ return static_cast<float>(before); |
} |
} |
@@ -162,20 +167,27 @@ StatusOr<uint64> DataPiece::ToUint64() const { |
StatusOr<double> DataPiece::ToDouble() const { |
if (type_ == TYPE_FLOAT) { |
- return FloatingPointConvertAndCheck<double, float>(float_); |
+ return FloatToDouble(float_); |
} |
if (type_ == TYPE_STRING) { |
if (str_ == "Infinity") return std::numeric_limits<double>::infinity(); |
if (str_ == "-Infinity") return -std::numeric_limits<double>::infinity(); |
if (str_ == "NaN") return std::numeric_limits<double>::quiet_NaN(); |
- return StringToNumber<double>(safe_strtod); |
+ StatusOr<double> value = StringToNumber<double>(safe_strtod); |
+ if (value.ok() && !MathLimits<double>::IsFinite(value.ValueOrDie())) { |
+ // safe_strtod converts out-of-range values to +inf/-inf, but we want |
+ // to report them as errors. |
+ return InvalidArgument(StrCat("\"", str_, "\"")); |
+ } else { |
+ return value; |
+ } |
} |
return GenericConvert<double>(); |
} |
StatusOr<float> DataPiece::ToFloat() const { |
if (type_ == TYPE_DOUBLE) { |
- return FloatingPointConvertAndCheck<float, double>(double_); |
+ return DoubleToFloat(double_); |
} |
if (type_ == TYPE_STRING) { |
if (str_ == "Infinity") return std::numeric_limits<float>::infinity(); |
@@ -259,7 +271,8 @@ StatusOr<string> DataPiece::ToBytes() const { |
} |
} |
-StatusOr<int> DataPiece::ToEnum(const google::protobuf::Enum* enum_type) const { |
+StatusOr<int> DataPiece::ToEnum(const google::protobuf::Enum* enum_type, |
+ bool use_lower_camel_for_enums) const { |
if (type_ == TYPE_NULL) return google::protobuf::NULL_VALUE; |
if (type_ == TYPE_STRING) { |
@@ -268,20 +281,34 @@ StatusOr<int> DataPiece::ToEnum(const google::protobuf::Enum* enum_type) const { |
const google::protobuf::EnumValue* value = |
FindEnumValueByNameOrNull(enum_type, enum_name); |
if (value != NULL) return value->number(); |
+ |
+ // Check if int version of enum is sent as string. |
+ StatusOr<int32> int_value = ToInt32(); |
+ if (int_value.ok()) { |
+ if (const google::protobuf::EnumValue* enum_value = |
+ FindEnumValueByNumberOrNull(enum_type, int_value.ValueOrDie())) { |
+ return enum_value->number(); |
+ } |
+ } |
+ |
// Next try a normalized name. |
for (string::iterator it = enum_name.begin(); it != enum_name.end(); ++it) { |
*it = *it == '-' ? '_' : ascii_toupper(*it); |
} |
value = FindEnumValueByNameOrNull(enum_type, enum_name); |
if (value != NULL) return value->number(); |
- } else { |
- StatusOr<int32> value = ToInt32(); |
- if (value.ok()) { |
- if (const google::protobuf::EnumValue* enum_value = |
- FindEnumValueByNumberOrNull(enum_type, value.ValueOrDie())) { |
- return enum_value->number(); |
- } |
+ |
+ // If use_lower_camel_for_enums is true try with enum name without |
+ // underscore. This will also accept camel case names as the enum_name has |
+ // been normalized before. |
+ if (use_lower_camel_for_enums) { |
+ value = FindEnumValueByNameWithoutUnderscoreOrNull(enum_type, enum_name); |
+ if (value != NULL) return value->number(); |
} |
+ } else { |
+ // We don't need to check whether the value is actually declared in the |
+ // enum because we preserve unknown enum values as well. |
+ return ToInt32(); |
} |
return InvalidArgument( |
ValueAsStringOrDefault("Cannot find enum with given value.")); |
@@ -329,9 +356,8 @@ bool DataPiece::DecodeBase64(StringPiece src, string* dest) const { |
// WebSafeBase64Escape does no padding by default. |
WebSafeBase64Escape(*dest, &encoded); |
// Remove trailing padding '=' characters before comparison. |
- StringPiece src_no_padding(src, 0, src.ends_with("=") |
- ? src.find_last_not_of('=') + 1 |
- : src.length()); |
+ StringPiece src_no_padding = StringPiece(src).substr( |
+ 0, src.ends_with("=") ? src.find_last_not_of('=') + 1 : src.length()); |
return encoded == src_no_padding; |
} |
return true; |
@@ -343,9 +369,8 @@ bool DataPiece::DecodeBase64(StringPiece src, string* dest) const { |
Base64Escape( |
reinterpret_cast<const unsigned char*>(dest->data()), dest->length(), |
&encoded, false); |
- StringPiece src_no_padding(src, 0, src.ends_with("=") |
- ? src.find_last_not_of('=') + 1 |
- : src.length()); |
+ StringPiece src_no_padding = StringPiece(src).substr( |
+ 0, src.ends_with("=") ? src.find_last_not_of('=') + 1 : src.length()); |
return encoded == src_no_padding; |
} |
return true; |
@@ -354,6 +379,27 @@ bool DataPiece::DecodeBase64(StringPiece src, string* dest) const { |
return false; |
} |
+void DataPiece::InternalCopy(const DataPiece& other) { |
+ type_ = other.type_; |
+ use_strict_base64_decoding_ = other.use_strict_base64_decoding_; |
+ switch (type_) { |
+ case TYPE_INT32: |
+ case TYPE_INT64: |
+ case TYPE_UINT32: |
+ case TYPE_UINT64: |
+ case TYPE_DOUBLE: |
+ case TYPE_FLOAT: |
+ case TYPE_BOOL: |
+ case TYPE_ENUM: |
+ case TYPE_NULL: |
+ case TYPE_BYTES: |
+ case TYPE_STRING: { |
+ str_ = other.str_; |
+ break; |
+ } |
+ } |
+} |
+ |
} // namespace converter |
} // namespace util |
} // namespace protobuf |