Skip to content

Commit d366185

Browse files
committed
Merge #8168: util: Add ParseUInt32 and ParseUInt64
e012f3c util: Add ParseUInt32 and ParseUInt64 (Wladimir J. van der Laan)
2 parents 7e6dd7b + e012f3c commit d366185

File tree

4 files changed

+112
-1
lines changed

4 files changed

+112
-1
lines changed

doc/developer-notes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ Strings and formatting
323323
buffer overflows and surprises with `\0` characters. Also some C string manipulations
324324
tend to act differently depending on platform, or even the user locale
325325

326-
- Use `ParseInt32`, `ParseInt64`, `ParseDouble` from `utilstrencodings.h` for number parsing
326+
- Use `ParseInt32`, `ParseInt64`, `ParseUInt32`, `ParseUInt64`, `ParseDouble` from `utilstrencodings.h` for number parsing
327327

328328
- *Rationale*: These functions do overflow checking, and avoid pesky locale issues
329329

src/test/util_tests.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,69 @@ BOOST_AUTO_TEST_CASE(test_ParseInt64)
376376
BOOST_CHECK(!ParseInt64("32482348723847471234", NULL));
377377
}
378378

379+
BOOST_AUTO_TEST_CASE(test_ParseUInt32)
380+
{
381+
uint32_t n;
382+
// Valid values
383+
BOOST_CHECK(ParseUInt32("1234", NULL));
384+
BOOST_CHECK(ParseUInt32("0", &n) && n == 0);
385+
BOOST_CHECK(ParseUInt32("1234", &n) && n == 1234);
386+
BOOST_CHECK(ParseUInt32("01234", &n) && n == 1234); // no octal
387+
BOOST_CHECK(ParseUInt32("2147483647", &n) && n == 2147483647);
388+
BOOST_CHECK(ParseUInt32("2147483648", &n) && n == (uint32_t)2147483648);
389+
BOOST_CHECK(ParseUInt32("4294967295", &n) && n == (uint32_t)4294967295);
390+
// Invalid values
391+
BOOST_CHECK(!ParseUInt32("", &n));
392+
BOOST_CHECK(!ParseUInt32(" 1", &n)); // no padding inside
393+
BOOST_CHECK(!ParseUInt32(" -1", &n));
394+
BOOST_CHECK(!ParseUInt32("1 ", &n));
395+
BOOST_CHECK(!ParseUInt32("1a", &n));
396+
BOOST_CHECK(!ParseUInt32("aap", &n));
397+
BOOST_CHECK(!ParseUInt32("0x1", &n)); // no hex
398+
BOOST_CHECK(!ParseUInt32("0x1", &n)); // no hex
399+
const char test_bytes[] = {'1', 0, '1'};
400+
std::string teststr(test_bytes, sizeof(test_bytes));
401+
BOOST_CHECK(!ParseUInt32(teststr, &n)); // no embedded NULs
402+
// Overflow and underflow
403+
BOOST_CHECK(!ParseUInt32("-2147483648", &n));
404+
BOOST_CHECK(!ParseUInt32("4294967296", &n));
405+
BOOST_CHECK(!ParseUInt32("-1234", &n));
406+
BOOST_CHECK(!ParseUInt32("-32482348723847471234", NULL));
407+
BOOST_CHECK(!ParseUInt32("32482348723847471234", NULL));
408+
}
409+
410+
BOOST_AUTO_TEST_CASE(test_ParseUInt64)
411+
{
412+
uint64_t n;
413+
// Valid values
414+
BOOST_CHECK(ParseUInt64("1234", NULL));
415+
BOOST_CHECK(ParseUInt64("0", &n) && n == 0LL);
416+
BOOST_CHECK(ParseUInt64("1234", &n) && n == 1234LL);
417+
BOOST_CHECK(ParseUInt64("01234", &n) && n == 1234LL); // no octal
418+
BOOST_CHECK(ParseUInt64("2147483647", &n) && n == 2147483647LL);
419+
BOOST_CHECK(ParseUInt64("9223372036854775807", &n) && n == 9223372036854775807ULL);
420+
BOOST_CHECK(ParseUInt64("9223372036854775808", &n) && n == 9223372036854775808ULL);
421+
BOOST_CHECK(ParseUInt64("18446744073709551615", &n) && n == 18446744073709551615ULL);
422+
// Invalid values
423+
BOOST_CHECK(!ParseUInt64("", &n));
424+
BOOST_CHECK(!ParseUInt64(" 1", &n)); // no padding inside
425+
BOOST_CHECK(!ParseUInt64(" -1", &n));
426+
BOOST_CHECK(!ParseUInt64("1 ", &n));
427+
BOOST_CHECK(!ParseUInt64("1a", &n));
428+
BOOST_CHECK(!ParseUInt64("aap", &n));
429+
BOOST_CHECK(!ParseUInt64("0x1", &n)); // no hex
430+
const char test_bytes[] = {'1', 0, '1'};
431+
std::string teststr(test_bytes, sizeof(test_bytes));
432+
BOOST_CHECK(!ParseUInt64(teststr, &n)); // no embedded NULs
433+
// Overflow and underflow
434+
BOOST_CHECK(!ParseUInt64("-9223372036854775809", NULL));
435+
BOOST_CHECK(!ParseUInt64("18446744073709551616", NULL));
436+
BOOST_CHECK(!ParseUInt64("-32482348723847471234", NULL));
437+
BOOST_CHECK(!ParseUInt64("-2147483648", &n));
438+
BOOST_CHECK(!ParseUInt64("-9223372036854775808", &n));
439+
BOOST_CHECK(!ParseUInt64("-1234", &n));
440+
}
441+
379442
BOOST_AUTO_TEST_CASE(test_ParseDouble)
380443
{
381444
double n;

src/utilstrencodings.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,40 @@ bool ParseInt64(const std::string& str, int64_t *out)
461461
n <= std::numeric_limits<int64_t>::max();
462462
}
463463

464+
bool ParseUInt32(const std::string& str, uint32_t *out)
465+
{
466+
if (!ParsePrechecks(str))
467+
return false;
468+
if (str.size() >= 1 && str[0] == '-') // Reject negative values, unfortunately strtoul accepts these by default if they fit in the range
469+
return false;
470+
char *endp = NULL;
471+
errno = 0; // strtoul will not set errno if valid
472+
unsigned long int n = strtoul(str.c_str(), &endp, 10);
473+
if(out) *out = (uint32_t)n;
474+
// Note that strtoul returns a *unsigned long int*, so even if it doesn't report a over/underflow
475+
// we still have to check that the returned value is within the range of an *uint32_t*. On 64-bit
476+
// platforms the size of these types may be different.
477+
return endp && *endp == 0 && !errno &&
478+
n <= std::numeric_limits<uint32_t>::max();
479+
}
480+
481+
bool ParseUInt64(const std::string& str, uint64_t *out)
482+
{
483+
if (!ParsePrechecks(str))
484+
return false;
485+
if (str.size() >= 1 && str[0] == '-') // Reject negative values, unfortunately strtoull accepts these by default if they fit in the range
486+
return false;
487+
char *endp = NULL;
488+
errno = 0; // strtoull will not set errno if valid
489+
unsigned long long int n = strtoull(str.c_str(), &endp, 10);
490+
if(out) *out = (uint64_t)n;
491+
// Note that strtoull returns a *unsigned long long int*, so even if it doesn't report a over/underflow
492+
// we still have to check that the returned value is within the range of an *uint64_t*.
493+
return endp && *endp == 0 && !errno &&
494+
n <= std::numeric_limits<uint64_t>::max();
495+
}
496+
497+
464498
bool ParseDouble(const std::string& str, double *out)
465499
{
466500
if (!ParsePrechecks(str))

src/utilstrencodings.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,20 @@ bool ParseInt32(const std::string& str, int32_t *out);
7070
*/
7171
bool ParseInt64(const std::string& str, int64_t *out);
7272

73+
/**
74+
* Convert decimal string to unsigned 32-bit integer with strict parse error feedback.
75+
* @returns true if the entire string could be parsed as valid integer,
76+
* false if not the entire string could be parsed or when overflow or underflow occurred.
77+
*/
78+
bool ParseUInt32(const std::string& str, uint32_t *out);
79+
80+
/**
81+
* Convert decimal string to unsigned 64-bit integer with strict parse error feedback.
82+
* @returns true if the entire string could be parsed as valid integer,
83+
* false if not the entire string could be parsed or when overflow or underflow occurred.
84+
*/
85+
bool ParseUInt64(const std::string& str, uint64_t *out);
86+
7387
/**
7488
* Convert string to double with strict parse error feedback.
7589
* @returns true if the entire string could be parsed as valid double,

0 commit comments

Comments
 (0)