From 9bd28f39a50cdf4d4cbf4a5cab5150fde66658c2 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Boric Date: Thu, 10 Dec 2020 22:42:04 +0100 Subject: [PATCH] StringUtil: Add base support and hexadecimal functions --- src/common/string_util.cpp | 28 +++++++++++++++++++++++ src/common/string_util.h | 47 +++++++++++++++++++++++--------------- 2 files changed, 57 insertions(+), 18 deletions(-) diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 420830d25..fcbf44435 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #ifdef WIN32 #include "windows_headers.h" @@ -163,6 +164,33 @@ std::size_t Strlcpy(char* dst, const std::string_view& src, std::size_t size) return len; } +std::optional> DecodeHex(const std::string_view& in) +{ + std::vector data; + data.reserve(in.size()/2); + + for (int i = 0; i < in.size()/2; i++) { + auto byte = StringUtil::FromChars(in.substr(i*2, 2), 16); + if (byte) { + data.push_back(*byte); + } + else { + return std::nullopt; + } + } + + return { data }; +} + +std::string EncodeHex(const u8* data, int length) +{ + std::stringstream ss; + for (int i = 0; i < length; i++) { + ss << std::hex << std::setfill('0') << std::setw(2) << static_cast(data[i]); + } + return ss.str(); +} + #ifdef WIN32 std::wstring UTF8StringToWideString(const std::string_view& str) diff --git a/src/common/string_util.h b/src/common/string_util.h index f1a43111c..50aa31572 100644 --- a/src/common/string_util.h +++ b/src/common/string_util.h @@ -3,9 +3,11 @@ #include #include #include +#include #include #include #include +#include #if defined(__has_include) && __has_include() #include @@ -52,16 +54,37 @@ static inline int Strncasecmp(const char* s1, const char* s2, std::size_t n) } /// Wrapper arond std::from_chars -template -inline std::optional FromChars(const std::string_view& str) +template::value, bool> = true> +inline std::optional FromChars(const std::string_view& str, int base = 10) { T value; #if defined(__has_include) && __has_include() + const std::from_chars_result result = std::from_chars(str.data(), str.data() + str.length(), value, base); + if (result.ec != std::errc()) + return std::nullopt; +#else + std::string temp(str); + std::istringstream ss(temp); + ss >> std::setbase(base) >> value; + if (ss.fail()) + return std::nullopt; +#endif + + return value; +} + +template::value, bool> = true> +inline std::optional FromChars(const std::string_view& str) +{ + T value; + +#if defined(__has_include) && __has_include() && defined(_MSC_VER) const std::from_chars_result result = std::from_chars(str.data(), str.data() + str.length(), value); if (result.ec != std::errc()) return std::nullopt; #else + /// libstdc++ does not support from_chars with floats yet std::string temp(str); std::istringstream ss(temp); ss >> value; @@ -74,7 +97,7 @@ inline std::optional FromChars(const std::string_view& str) /// Explicit override for booleans template<> -inline std::optional FromChars(const std::string_view& str) +inline std::optional FromChars(const std::string_view& str, int base) { if (Strncasecmp("true", str.data(), str.length()) == 0 || Strncasecmp("yes", str.data(), str.length()) == 0 || Strncasecmp("on", str.data(), str.length()) == 0 || Strncasecmp("1", str.data(), str.length()) == 0) @@ -91,21 +114,9 @@ inline std::optional FromChars(const std::string_view& str) return std::nullopt; } -#ifndef _MSC_VER -/// from_chars doesn't seem to work with floats on gcc -template<> -inline std::optional FromChars(const std::string_view& str) -{ - float value; - std::string temp(str); - std::istringstream ss(temp); - ss >> value; - if (ss.fail()) - return std::nullopt; - else - return value; -} -#endif +/// Encode/decode hexadecimal byte buffers +std::optional> DecodeHex(const std::string_view& str); +std::string EncodeHex(const u8* data, int length); /// starts_with from C++20 ALWAYS_INLINE static bool StartsWith(const std::string_view& str, const char* prefix)