Loading base/include/android-base/parseint.h +25 −7 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <errno.h> #include <errno.h> #include <stdlib.h> #include <stdlib.h> #include <string.h> #include <limits> #include <limits> #include <string> #include <string> Loading @@ -31,14 +32,20 @@ namespace base { // otherwise valid values will be rejected. Returns boolean success; 'out' // otherwise valid values will be rejected. Returns boolean success; 'out' // is untouched if parsing fails. // is untouched if parsing fails. template <typename T> template <typename T> bool ParseUint(const char* s, T* out, bool ParseUint(const char* s, T* out, T max = std::numeric_limits<T>::max(), T max = std::numeric_limits<T>::max()) { bool allow_suffixes = false) { int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10; int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10; errno = 0; errno = 0; char* end; char* end; unsigned long long int result = strtoull(s, &end, base); unsigned long long int result = strtoull(s, &end, base); if (errno != 0 || s == end || *end != '\0') { if (errno != 0 || end == s) return false; return false; if (*end != '\0') { const char* suffixes = "bkmgtpe"; const char* suffix; if (!allow_suffixes || (suffix = strchr(suffixes, tolower(*end))) == nullptr) return false; #if __clang__ // TODO: win32 still builds with GCC :-( if (__builtin_mul_overflow(result, 1ULL << (10 * (suffix - suffixes)), &result)) return false; #endif } } if (max < result) { if (max < result) { return false; return false; Loading @@ -49,9 +56,20 @@ bool ParseUint(const char* s, T* out, // TODO: string_view // TODO: string_view template <typename T> template <typename T> bool ParseUint(const std::string& s, T* out, bool ParseUint(const std::string& s, T* out, T max = std::numeric_limits<T>::max(), T max = std::numeric_limits<T>::max()) { bool allow_suffixes = false) { return ParseUint(s.c_str(), out, max); return ParseUint(s.c_str(), out, max, allow_suffixes); } template <typename T> bool ParseByteCount(const char* s, T* out, T max = std::numeric_limits<T>::max()) { return ParseUint(s, out, max, true); } // TODO: string_view template <typename T> bool ParseByteCount(const std::string& s, T* out, T max = std::numeric_limits<T>::max()) { return ParseByteCount(s.c_str(), out, max); } } // Parses the signed decimal integer in the string 's' and sets 'out' to // Parses the signed decimal integer in the string 's' and sets 'out' to Loading base/parseint_test.cpp +41 −0 Original line number Original line Diff line number Diff line Loading @@ -96,3 +96,44 @@ TEST(parseint, untouched_on_failure) { ASSERT_FALSE(android::base::ParseInt("456x", &u)); ASSERT_FALSE(android::base::ParseInt("456x", &u)); ASSERT_EQ(123u, u); ASSERT_EQ(123u, u); } } TEST(parseint, ParseByteCount) { uint64_t i = 0; ASSERT_TRUE(android::base::ParseByteCount("123b", &i)); ASSERT_EQ(123ULL, i); ASSERT_TRUE(android::base::ParseByteCount("8k", &i)); ASSERT_EQ(8ULL * 1024, i); ASSERT_TRUE(android::base::ParseByteCount("8M", &i)); ASSERT_EQ(8ULL * 1024 * 1024, i); ASSERT_TRUE(android::base::ParseByteCount("6g", &i)); ASSERT_EQ(6ULL * 1024 * 1024 * 1024, i); ASSERT_TRUE(android::base::ParseByteCount("1T", &i)); ASSERT_EQ(1ULL * 1024 * 1024 * 1024 * 1024, i); ASSERT_TRUE(android::base::ParseByteCount("2p", &i)); ASSERT_EQ(2ULL * 1024 * 1024 * 1024 * 1024 * 1024, i); ASSERT_TRUE(android::base::ParseByteCount("4e", &i)); ASSERT_EQ(4ULL * 1024 * 1024 * 1024 * 1024 * 1024 * 1024, i); } TEST(parseint, ParseByteCount_invalid_suffix) { unsigned u; ASSERT_FALSE(android::base::ParseByteCount("1x", &u)); } TEST(parseint, ParseByteCount_overflow) { uint64_t u64; ASSERT_FALSE(android::base::ParseByteCount("4294967295E", &u64)); uint16_t u16; ASSERT_TRUE(android::base::ParseByteCount("63k", &u16)); ASSERT_EQ(63U * 1024, u16); ASSERT_TRUE(android::base::ParseByteCount("65535b", &u16)); ASSERT_EQ(65535U, u16); ASSERT_FALSE(android::base::ParseByteCount("65k", &u16)); } Loading
base/include/android-base/parseint.h +25 −7 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <errno.h> #include <errno.h> #include <stdlib.h> #include <stdlib.h> #include <string.h> #include <limits> #include <limits> #include <string> #include <string> Loading @@ -31,14 +32,20 @@ namespace base { // otherwise valid values will be rejected. Returns boolean success; 'out' // otherwise valid values will be rejected. Returns boolean success; 'out' // is untouched if parsing fails. // is untouched if parsing fails. template <typename T> template <typename T> bool ParseUint(const char* s, T* out, bool ParseUint(const char* s, T* out, T max = std::numeric_limits<T>::max(), T max = std::numeric_limits<T>::max()) { bool allow_suffixes = false) { int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10; int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10; errno = 0; errno = 0; char* end; char* end; unsigned long long int result = strtoull(s, &end, base); unsigned long long int result = strtoull(s, &end, base); if (errno != 0 || s == end || *end != '\0') { if (errno != 0 || end == s) return false; return false; if (*end != '\0') { const char* suffixes = "bkmgtpe"; const char* suffix; if (!allow_suffixes || (suffix = strchr(suffixes, tolower(*end))) == nullptr) return false; #if __clang__ // TODO: win32 still builds with GCC :-( if (__builtin_mul_overflow(result, 1ULL << (10 * (suffix - suffixes)), &result)) return false; #endif } } if (max < result) { if (max < result) { return false; return false; Loading @@ -49,9 +56,20 @@ bool ParseUint(const char* s, T* out, // TODO: string_view // TODO: string_view template <typename T> template <typename T> bool ParseUint(const std::string& s, T* out, bool ParseUint(const std::string& s, T* out, T max = std::numeric_limits<T>::max(), T max = std::numeric_limits<T>::max()) { bool allow_suffixes = false) { return ParseUint(s.c_str(), out, max); return ParseUint(s.c_str(), out, max, allow_suffixes); } template <typename T> bool ParseByteCount(const char* s, T* out, T max = std::numeric_limits<T>::max()) { return ParseUint(s, out, max, true); } // TODO: string_view template <typename T> bool ParseByteCount(const std::string& s, T* out, T max = std::numeric_limits<T>::max()) { return ParseByteCount(s.c_str(), out, max); } } // Parses the signed decimal integer in the string 's' and sets 'out' to // Parses the signed decimal integer in the string 's' and sets 'out' to Loading
base/parseint_test.cpp +41 −0 Original line number Original line Diff line number Diff line Loading @@ -96,3 +96,44 @@ TEST(parseint, untouched_on_failure) { ASSERT_FALSE(android::base::ParseInt("456x", &u)); ASSERT_FALSE(android::base::ParseInt("456x", &u)); ASSERT_EQ(123u, u); ASSERT_EQ(123u, u); } } TEST(parseint, ParseByteCount) { uint64_t i = 0; ASSERT_TRUE(android::base::ParseByteCount("123b", &i)); ASSERT_EQ(123ULL, i); ASSERT_TRUE(android::base::ParseByteCount("8k", &i)); ASSERT_EQ(8ULL * 1024, i); ASSERT_TRUE(android::base::ParseByteCount("8M", &i)); ASSERT_EQ(8ULL * 1024 * 1024, i); ASSERT_TRUE(android::base::ParseByteCount("6g", &i)); ASSERT_EQ(6ULL * 1024 * 1024 * 1024, i); ASSERT_TRUE(android::base::ParseByteCount("1T", &i)); ASSERT_EQ(1ULL * 1024 * 1024 * 1024 * 1024, i); ASSERT_TRUE(android::base::ParseByteCount("2p", &i)); ASSERT_EQ(2ULL * 1024 * 1024 * 1024 * 1024 * 1024, i); ASSERT_TRUE(android::base::ParseByteCount("4e", &i)); ASSERT_EQ(4ULL * 1024 * 1024 * 1024 * 1024 * 1024 * 1024, i); } TEST(parseint, ParseByteCount_invalid_suffix) { unsigned u; ASSERT_FALSE(android::base::ParseByteCount("1x", &u)); } TEST(parseint, ParseByteCount_overflow) { uint64_t u64; ASSERT_FALSE(android::base::ParseByteCount("4294967295E", &u64)); uint16_t u16; ASSERT_TRUE(android::base::ParseByteCount("63k", &u16)); ASSERT_EQ(63U * 1024, u16); ASSERT_TRUE(android::base::ParseByteCount("65535b", &u16)); ASSERT_EQ(65535U, u16); ASSERT_FALSE(android::base::ParseByteCount("65k", &u16)); }