From aee1f2d9573bcb3b600a870e9827626afe4c4dba Mon Sep 17 00:00:00 2001 From: Dakoda Greaves Date: Fri, 29 Mar 2024 12:54:31 -0700 Subject: [PATCH] Implements custom tolower and toupper functions. This commit implements custom equivalents for the C and C++ `tolower` and `toupper` Standard Library functions. In addition it implements a utility function to capitalize the first letter of a string. Cherry-picked from: 7a208d9fade56e2347891daff2f6b903923c9d50 --- src/test/netbase_tests.cpp | 8 +++---- src/test/util_tests.cpp | 39 +++++++++++++++++++++++++++++++++ src/utilstrencodings.cpp | 12 +++++++++++ src/utilstrencodings.h | 44 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 4 deletions(-) diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index 2a017fd9aaa..1cb6b5ab031 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -305,13 +305,13 @@ BOOST_AUTO_TEST_CASE(netbase_parsenetwork) { BOOST_CHECK_EQUAL(ParseNetwork("ipv4"), NET_IPV4); BOOST_CHECK_EQUAL(ParseNetwork("ipv6"), NET_IPV6); - BOOST_CHECK_EQUAL(ParseNetwork("onion"), NET_ONION); - BOOST_CHECK_EQUAL(ParseNetwork("tor"), NET_ONION); + BOOST_CHECK_EQUAL(ParseNetwork("onion"), NET_TOR); + BOOST_CHECK_EQUAL(ParseNetwork("tor"), NET_TOR); BOOST_CHECK_EQUAL(ParseNetwork("IPv4"), NET_IPV4); BOOST_CHECK_EQUAL(ParseNetwork("IPv6"), NET_IPV6); - BOOST_CHECK_EQUAL(ParseNetwork("ONION"), NET_ONION); - BOOST_CHECK_EQUAL(ParseNetwork("TOR"), NET_ONION); + BOOST_CHECK_EQUAL(ParseNetwork("ONION"), NET_TOR); + BOOST_CHECK_EQUAL(ParseNetwork("TOR"), NET_TOR); BOOST_CHECK_EQUAL(ParseNetwork(":)"), NET_UNROUTABLE); BOOST_CHECK_EQUAL(ParseNetwork("tÖr"), NET_UNROUTABLE); diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index d33c4f1cb14..4414ff10ea4 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -565,4 +565,43 @@ BOOST_AUTO_TEST_CASE(test_ParseFixedPoint) BOOST_CHECK(!ParseFixedPoint("1.", 8, &amount)); } +BOOST_AUTO_TEST_CASE(test_ToLower) +{ + BOOST_CHECK_EQUAL(ToLower('@'), '@'); + BOOST_CHECK_EQUAL(ToLower('A'), 'a'); + BOOST_CHECK_EQUAL(ToLower('Z'), 'z'); + BOOST_CHECK_EQUAL(ToLower('['), '['); + BOOST_CHECK_EQUAL(ToLower(0), 0); + BOOST_CHECK_EQUAL(ToLower(255), 255); + + std::string testVector; + Downcase(testVector); + BOOST_CHECK_EQUAL(testVector, ""); + + testVector = "#HODL"; + Downcase(testVector); + BOOST_CHECK_EQUAL(testVector, "#hodl"); + + testVector = "\x00\xfe\xff"; + Downcase(testVector); + BOOST_CHECK_EQUAL(testVector, "\x00\xfe\xff"); +} + +BOOST_AUTO_TEST_CASE(test_ToUpper) +{ + BOOST_CHECK_EQUAL(ToUpper('`'), '`'); + BOOST_CHECK_EQUAL(ToUpper('a'), 'A'); + BOOST_CHECK_EQUAL(ToUpper('z'), 'Z'); + BOOST_CHECK_EQUAL(ToUpper('{'), '{'); + BOOST_CHECK_EQUAL(ToUpper(0), 0); + BOOST_CHECK_EQUAL(ToUpper(255), 255); +} + +BOOST_AUTO_TEST_CASE(test_Capitalize) +{ + BOOST_CHECK_EQUAL(Capitalize(""), ""); + BOOST_CHECK_EQUAL(Capitalize("bitcoin"), "Bitcoin"); + BOOST_CHECK_EQUAL(Capitalize("\x00\xfe\xff"), "\x00\xfe\xff"); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index 5bb177c0c09..d3b74cca426 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -8,6 +8,7 @@ #include "tinyformat.h" +#include #include #include #include @@ -707,3 +708,14 @@ bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out) return true; } +void Downcase(std::string& str) +{ + std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c){return ToLower(c);}); +} + +std::string Capitalize(std::string str) +{ + if (str.empty()) return str; + str[0] = ToUpper(str.front()); + return str; +} diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h index eacd075d645..234390fb193 100644 --- a/src/utilstrencodings.h +++ b/src/utilstrencodings.h @@ -141,4 +141,48 @@ bool TimingResistantEqual(const T& a, const T& b) */ bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out); +/** + * Converts the given character to its lowercase equivalent. + * This function is locale independent. It only converts uppercase + * characters in the standard 7-bit ASCII range. + * @param[in] c the character to convert to lowercase. + * @return the lowercase equivalent of c; or the argument + * if no conversion is possible. + */ +constexpr unsigned char ToLower(unsigned char c) +{ + return (c >= 'A' && c <= 'Z' ? (c - 'A') + 'a' : c); +} + +/** + * Converts the given string to its lowercase equivalent. + * This function is locale independent. It only converts uppercase + * characters in the standard 7-bit ASCII range. + * @param[in,out] str the string to convert to lowercase. + */ +void Downcase(std::string& str); + +/** + * Converts the given character to its uppercase equivalent. + * This function is locale independent. It only converts lowercase + * characters in the standard 7-bit ASCII range. + * @param[in] c the character to convert to uppercase. + * @return the uppercase equivalent of c; or the argument + * if no conversion is possible. + */ +constexpr unsigned char ToUpper(unsigned char c) +{ + return (c >= 'a' && c <= 'z' ? (c - 'a') + 'A' : c); +} + +/** + * Capitalizes the first character of the given string. + * This function is locale independent. It only capitalizes the + * first character of the argument if it has an uppercase equivalent + * in the standard 7-bit ASCII range. + * @param[in] str the string to capitalize. + * @return string with the first letter capitalized. + */ +std::string Capitalize(std::string str); + #endif // BITCOIN_UTILSTRENCODINGS_H