| Index: net/base/parse_number.cc
|
| diff --git a/net/base/parse_number.cc b/net/base/parse_number.cc
|
| index d315bec63a906dba00b5f27e56dd20161ace6266..478b5585294cf001a6e2c92d9522bb70509de174 100644
|
| --- a/net/base/parse_number.cc
|
| +++ b/net/base/parse_number.cc
|
| @@ -4,20 +4,144 @@
|
|
|
| #include "net/base/parse_number.h"
|
|
|
| +#include "base/logging.h"
|
| #include "base/strings/string_number_conversions.h"
|
|
|
| namespace net {
|
|
|
| -bool ParseNonNegativeDecimalInt(const base::StringPiece& input, int* output) {
|
| - if (input.empty() || input[0] > '9' || input[0] < '0')
|
| - return false;
|
| +namespace {
|
|
|
| - int result;
|
| - if (!base::StringToInt(input, &result))
|
| - return false;
|
| +// The string to number conversion functions in //base include the type in the
|
| +// name (like StringToInt64()). The following wrapper methods create a
|
| +// consistent interface to StringToXXX() that calls the appropriate //base
|
| +// version. This simplifies writing generic code with a template.
|
|
|
| - *output = result;
|
| - return true;
|
| +bool StringToNumber(const base::StringPiece& input, int32_t* output) {
|
| + // This assumes ints are 32-bits.
|
| + return base::StringToInt(input, output);
|
| +}
|
| +
|
| +bool StringToNumber(const base::StringPiece& input, uint32_t* output) {
|
| + // This assumes ints are 32-bits
|
| + return base::StringToUint(input, output);
|
| +}
|
| +
|
| +bool StringToNumber(const base::StringPiece& input, int64_t* output) {
|
| + return base::StringToInt64(input, output);
|
| +}
|
| +
|
| +bool StringToNumber(const base::StringPiece& input, uint64_t* output) {
|
| + return base::StringToUint64(input, output);
|
| +}
|
| +
|
| +template <typename T>
|
| +ParseIntegerResult ParseIntegerHelper(const base::StringPiece& input,
|
| + ParseIntegerSignPolicy sign_policy,
|
| + T* output) {
|
| + if (input.empty())
|
| + return ParseIntegerResult::FAILED_PARSE;
|
| +
|
| + bool starts_with_negative = input[0] == '-';
|
| + bool starts_with_digit = input[0] >= '0' && input[0] <= '9';
|
| +
|
| + // Numbers must start with either a digit or a negative sign
|
| + //
|
| + // Reject everythin else to prevent the permissive behavior of
|
| + // StringToIntXXX() when it comes to accepting a leading '+'.
|
| + switch (sign_policy) {
|
| + case ParseIntegerSignPolicy::NON_NEGATIVE:
|
| + if (!starts_with_digit)
|
| + return ParseIntegerResult::FAILED_PARSE;
|
| + break;
|
| +
|
| + case ParseIntegerSignPolicy::ANY:
|
| + if (!starts_with_digit && !starts_with_negative)
|
| + return ParseIntegerResult::FAILED_PARSE;
|
| + break;
|
| + }
|
| +
|
| + // Dispatch to the appropriate flavor of base::StringToXXX() by calling one of
|
| + // the type-specific overloads.
|
| + T result;
|
| + if (StringToNumber(input, &result)) {
|
| + *output = result;
|
| + return ParseIntegerResult::OK;
|
| + }
|
| +
|
| + // Set an error that distinguishes between parsing/underflow/overflow errors.
|
| + //
|
| + // Note that base::StringToXXX() functions have a magical API that modify the
|
| + // output on failure to indicate whether underflow/overflow happened.
|
| + //
|
| + // You would think these can be used here, but unfortunately they return those
|
| + // magic values in multiple cases making it impossible to distinguish
|
| + // underflow/overflow from failed parsing due to leading/trailing whitespace.
|
| + //
|
| + // So instead look at the number to see if it was valid.
|
| +
|
| + // Strip any leading negative sign off the number.
|
| + base::StringPiece numeric_portion =
|
| + starts_with_negative ? input.substr(1) : input;
|
| +
|
| + // Test if |numeric_portion| is a valid non-negative integer.
|
| + if (!numeric_portion.empty() &&
|
| + numeric_portion.find_first_not_of("0123456789") == std::string::npos) {
|
| + // If it was, the failure must have been due to underflow/overflow.
|
| + return starts_with_negative ? ParseIntegerResult::FAILED_UNDERFLOW
|
| + : ParseIntegerResult::FAILED_OVERFLOW;
|
| + }
|
| +
|
| + // Otherwise it was a mundane parsing error.
|
| + return ParseIntegerResult::FAILED_PARSE;
|
| +}
|
| +
|
| +template <typename T>
|
| +bool ParseNonNegativeIntegerHelper(const base::StringPiece& input, T* output) {
|
| + auto result =
|
| + ParseIntegerHelper(input, ParseIntegerSignPolicy::NON_NEGATIVE, output);
|
| + return result == ParseIntegerResult::OK;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +ParseIntegerResult ParseInteger(const base::StringPiece& input,
|
| + ParseIntegerSignPolicy sign_policy,
|
| + int32_t* output) {
|
| + return ParseIntegerHelper(input, sign_policy, output);
|
| +}
|
| +
|
| +ParseIntegerResult ParseInteger(const base::StringPiece& input,
|
| + ParseIntegerSignPolicy sign_policy,
|
| + uint32_t* output) {
|
| + return ParseIntegerHelper(input, sign_policy, output);
|
| +}
|
| +
|
| +ParseIntegerResult ParseInteger(const base::StringPiece& input,
|
| + ParseIntegerSignPolicy sign_policy,
|
| + int64_t* output) {
|
| + return ParseIntegerHelper(input, sign_policy, output);
|
| +}
|
| +
|
| +ParseIntegerResult ParseInteger(const base::StringPiece& input,
|
| + ParseIntegerSignPolicy sign_policy,
|
| + uint64_t* output) {
|
| + return ParseIntegerHelper(input, sign_policy, output);
|
| +}
|
| +
|
| +bool ParseNonNegativeInteger(const base::StringPiece& input, int32_t* output) {
|
| + return ParseNonNegativeIntegerHelper(input, output);
|
| +}
|
| +
|
| +bool ParseNonNegativeInteger(const base::StringPiece& input, uint32_t* output) {
|
| + return ParseNonNegativeIntegerHelper(input, output);
|
| +}
|
| +
|
| +bool ParseNonNegativeInteger(const base::StringPiece& input, int64_t* output) {
|
| + return ParseNonNegativeIntegerHelper(input, output);
|
| +}
|
| +
|
| +bool ParseNonNegativeInteger(const base::StringPiece& input, uint64_t* output) {
|
| + return ParseNonNegativeIntegerHelper(input, output);
|
| }
|
|
|
| } // namespace net
|
|
|