util: Add ParseInt64 and ParseDouble functions
Strict parsing functions for other numeric types. - ParseInt64 analogous to ParseInt32, but for 64-bit values. - ParseDouble for doubles. - Make all three Parse* functions more strict (e.g. reject whitespace on the inside) Also add tests.
This commit is contained in:
parent
043df2b568
commit
7e98a3c642
3 changed files with 121 additions and 1 deletions
|
@ -322,9 +322,16 @@ BOOST_AUTO_TEST_CASE(test_ParseInt32)
|
||||||
BOOST_CHECK(ParseInt32("-2147483648", &n) && n == -2147483648);
|
BOOST_CHECK(ParseInt32("-2147483648", &n) && n == -2147483648);
|
||||||
BOOST_CHECK(ParseInt32("-1234", &n) && n == -1234);
|
BOOST_CHECK(ParseInt32("-1234", &n) && n == -1234);
|
||||||
// Invalid values
|
// Invalid values
|
||||||
|
BOOST_CHECK(!ParseInt32("", &n));
|
||||||
|
BOOST_CHECK(!ParseInt32(" 1", &n)); // no padding inside
|
||||||
|
BOOST_CHECK(!ParseInt32("1 ", &n));
|
||||||
BOOST_CHECK(!ParseInt32("1a", &n));
|
BOOST_CHECK(!ParseInt32("1a", &n));
|
||||||
BOOST_CHECK(!ParseInt32("aap", &n));
|
BOOST_CHECK(!ParseInt32("aap", &n));
|
||||||
BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex
|
BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex
|
||||||
|
BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex
|
||||||
|
const char test_bytes[] = {'1', 0, '1'};
|
||||||
|
std::string teststr(test_bytes, sizeof(test_bytes));
|
||||||
|
BOOST_CHECK(!ParseInt32(teststr, &n)); // no embedded NULs
|
||||||
// Overflow and underflow
|
// Overflow and underflow
|
||||||
BOOST_CHECK(!ParseInt32("-2147483649", NULL));
|
BOOST_CHECK(!ParseInt32("-2147483649", NULL));
|
||||||
BOOST_CHECK(!ParseInt32("2147483648", NULL));
|
BOOST_CHECK(!ParseInt32("2147483648", NULL));
|
||||||
|
@ -332,6 +339,64 @@ BOOST_AUTO_TEST_CASE(test_ParseInt32)
|
||||||
BOOST_CHECK(!ParseInt32("32482348723847471234", NULL));
|
BOOST_CHECK(!ParseInt32("32482348723847471234", NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_ParseInt64)
|
||||||
|
{
|
||||||
|
int64_t n;
|
||||||
|
// Valid values
|
||||||
|
BOOST_CHECK(ParseInt64("1234", NULL));
|
||||||
|
BOOST_CHECK(ParseInt64("0", &n) && n == 0LL);
|
||||||
|
BOOST_CHECK(ParseInt64("1234", &n) && n == 1234LL);
|
||||||
|
BOOST_CHECK(ParseInt64("01234", &n) && n == 1234LL); // no octal
|
||||||
|
BOOST_CHECK(ParseInt64("2147483647", &n) && n == 2147483647LL);
|
||||||
|
BOOST_CHECK(ParseInt64("-2147483648", &n) && n == -2147483648LL);
|
||||||
|
BOOST_CHECK(ParseInt64("9223372036854775807", &n) && n == 9223372036854775807LL);
|
||||||
|
BOOST_CHECK(ParseInt64("-9223372036854775808", &n) && n == 9223372036854775808LL);
|
||||||
|
BOOST_CHECK(ParseInt64("-1234", &n) && n == -1234LL);
|
||||||
|
// Invalid values
|
||||||
|
BOOST_CHECK(!ParseInt64("", &n));
|
||||||
|
BOOST_CHECK(!ParseInt64(" 1", &n)); // no padding inside
|
||||||
|
BOOST_CHECK(!ParseInt64("1 ", &n));
|
||||||
|
BOOST_CHECK(!ParseInt64("1a", &n));
|
||||||
|
BOOST_CHECK(!ParseInt64("aap", &n));
|
||||||
|
BOOST_CHECK(!ParseInt64("0x1", &n)); // no hex
|
||||||
|
const char test_bytes[] = {'1', 0, '1'};
|
||||||
|
std::string teststr(test_bytes, sizeof(test_bytes));
|
||||||
|
BOOST_CHECK(!ParseInt64(teststr, &n)); // no embedded NULs
|
||||||
|
// Overflow and underflow
|
||||||
|
BOOST_CHECK(!ParseInt64("-9223372036854775809", NULL));
|
||||||
|
BOOST_CHECK(!ParseInt64("9223372036854775808", NULL));
|
||||||
|
BOOST_CHECK(!ParseInt64("-32482348723847471234", NULL));
|
||||||
|
BOOST_CHECK(!ParseInt64("32482348723847471234", NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_ParseDouble)
|
||||||
|
{
|
||||||
|
double n;
|
||||||
|
// Valid values
|
||||||
|
BOOST_CHECK(ParseDouble("1234", NULL));
|
||||||
|
BOOST_CHECK(ParseDouble("0", &n) && n == 0.0);
|
||||||
|
BOOST_CHECK(ParseDouble("1234", &n) && n == 1234.0);
|
||||||
|
BOOST_CHECK(ParseDouble("01234", &n) && n == 1234.0); // no octal
|
||||||
|
BOOST_CHECK(ParseDouble("2147483647", &n) && n == 2147483647.0);
|
||||||
|
BOOST_CHECK(ParseDouble("-2147483648", &n) && n == -2147483648.0);
|
||||||
|
BOOST_CHECK(ParseDouble("-1234", &n) && n == -1234.0);
|
||||||
|
BOOST_CHECK(ParseDouble("1e6", &n) && n == 1e6);
|
||||||
|
BOOST_CHECK(ParseDouble("-1e6", &n) && n == -1e6);
|
||||||
|
// Invalid values
|
||||||
|
BOOST_CHECK(!ParseDouble("", &n));
|
||||||
|
BOOST_CHECK(!ParseDouble(" 1", &n)); // no padding inside
|
||||||
|
BOOST_CHECK(!ParseDouble("1 ", &n));
|
||||||
|
BOOST_CHECK(!ParseDouble("1a", &n));
|
||||||
|
BOOST_CHECK(!ParseDouble("aap", &n));
|
||||||
|
BOOST_CHECK(!ParseDouble("0x1", &n)); // no hex
|
||||||
|
const char test_bytes[] = {'1', 0, '1'};
|
||||||
|
std::string teststr(test_bytes, sizeof(test_bytes));
|
||||||
|
BOOST_CHECK(!ParseDouble(teststr, &n)); // no embedded NULs
|
||||||
|
// Overflow and underflow
|
||||||
|
BOOST_CHECK(!ParseDouble("-1e10000", NULL));
|
||||||
|
BOOST_CHECK(!ParseDouble("1e10000", NULL));
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_FormatParagraph)
|
BOOST_AUTO_TEST_CASE(test_FormatParagraph)
|
||||||
{
|
{
|
||||||
BOOST_CHECK_EQUAL(FormatParagraph("", 79, 0), "");
|
BOOST_CHECK_EQUAL(FormatParagraph("", 79, 0), "");
|
||||||
|
|
|
@ -416,12 +416,25 @@ string DecodeBase32(const string& str)
|
||||||
return (vchRet.size() == 0) ? string() : string((const char*)&vchRet[0], vchRet.size());
|
return (vchRet.size() == 0) ? string() : string((const char*)&vchRet[0], vchRet.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ParsePrechecks(const std::string& str)
|
||||||
|
{
|
||||||
|
if (str.empty()) // No empty string allowed
|
||||||
|
return false;
|
||||||
|
if (str.size() >= 1 && (isspace(str[0]) || isspace(str[str.size()-1]))) // No padding allowed
|
||||||
|
return false;
|
||||||
|
if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool ParseInt32(const std::string& str, int32_t *out)
|
bool ParseInt32(const std::string& str, int32_t *out)
|
||||||
{
|
{
|
||||||
|
if (!ParsePrechecks(str))
|
||||||
|
return false;
|
||||||
char *endp = NULL;
|
char *endp = NULL;
|
||||||
errno = 0; // strtol will not set errno if valid
|
errno = 0; // strtol will not set errno if valid
|
||||||
long int n = strtol(str.c_str(), &endp, 10);
|
long int n = strtol(str.c_str(), &endp, 10);
|
||||||
if(out) *out = (int)n;
|
if(out) *out = (int32_t)n;
|
||||||
// Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow
|
// Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow
|
||||||
// we still have to check that the returned value is within the range of an *int32_t*. On 64-bit
|
// we still have to check that the returned value is within the range of an *int32_t*. On 64-bit
|
||||||
// platforms the size of these types may be different.
|
// platforms the size of these types may be different.
|
||||||
|
@ -430,6 +443,34 @@ bool ParseInt32(const std::string& str, int32_t *out)
|
||||||
n <= std::numeric_limits<int32_t>::max();
|
n <= std::numeric_limits<int32_t>::max();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ParseInt64(const std::string& str, int64_t *out)
|
||||||
|
{
|
||||||
|
if (!ParsePrechecks(str))
|
||||||
|
return false;
|
||||||
|
char *endp = NULL;
|
||||||
|
errno = 0; // strtoll will not set errno if valid
|
||||||
|
long long int n = strtoll(str.c_str(), &endp, 10);
|
||||||
|
if(out) *out = (int64_t)n;
|
||||||
|
// Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow
|
||||||
|
// we still have to check that the returned value is within the range of an *int64_t*.
|
||||||
|
return endp && *endp == 0 && !errno &&
|
||||||
|
n >= std::numeric_limits<int64_t>::min() &&
|
||||||
|
n <= std::numeric_limits<int64_t>::max();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ParseDouble(const std::string& str, double *out)
|
||||||
|
{
|
||||||
|
if (!ParsePrechecks(str))
|
||||||
|
return false;
|
||||||
|
if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed
|
||||||
|
return false;
|
||||||
|
char *endp = NULL;
|
||||||
|
errno = 0; // strtod will not set errno if valid
|
||||||
|
double n = strtod(str.c_str(), &endp);
|
||||||
|
if(out) *out = n;
|
||||||
|
return endp && *endp == 0 && !errno;
|
||||||
|
}
|
||||||
|
|
||||||
std::string FormatParagraph(const std::string in, size_t width, size_t indent)
|
std::string FormatParagraph(const std::string in, size_t width, size_t indent)
|
||||||
{
|
{
|
||||||
std::stringstream out;
|
std::stringstream out;
|
||||||
|
|
|
@ -49,6 +49,20 @@ int atoi(const std::string& str);
|
||||||
*/
|
*/
|
||||||
bool ParseInt32(const std::string& str, int32_t *out);
|
bool ParseInt32(const std::string& str, int32_t *out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert string to signed 64-bit integer with strict parse error feedback.
|
||||||
|
* @returns true if the entire string could be parsed as valid integer,
|
||||||
|
* false if not the entire string could be parsed or when overflow or underflow occurred.
|
||||||
|
*/
|
||||||
|
bool ParseInt64(const std::string& str, int64_t *out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert string to double with strict parse error feedback.
|
||||||
|
* @returns true if the entire string could be parsed as valid double,
|
||||||
|
* false if not the entire string could be parsed or when overflow or underflow occurred.
|
||||||
|
*/
|
||||||
|
bool ParseDouble(const std::string& str, double *out);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
|
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue