aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorMarcoFalke <falke.marco@gmail.com>2021-11-24 10:48:30 +0100
committerMarcoFalke <falke.marco@gmail.com>2021-11-24 10:49:13 +0100
commit73ac195e29cc3991cb97c6c3dce8d64eaad0e57a (patch)
treee1b0fa784359b49d2b81400b38aacca2756f19de /src/util
parent4018e23aa7e7bb57d721c7c41c55dfbb659b8c34 (diff)
parent21b58f430fa05fdb7c5db79b545302417a5dbceb (diff)
Merge bitcoin/bitcoin#23249: util: ParseByteUnits - Parse a string with suffix unit
21b58f430fa05fdb7c5db79b545302417a5dbceb util: ParseByteUnits - Parse a string with suffix unit [k|K|m|M|g|G|t|T] (Douglas Chimento) Pull request description: A convenience utility for parsing human readable strings sizes e.g. `500G` is `500 * 1 << 30` The argument/setting `maxuploadtarget` now accept human readable byte units `[k|K|m|M|g|G||t|T]` This change backward compatible, defaults to `M` if no unit specified. ACKs for top commit: vasild: ACK 21b58f430fa05fdb7c5db79b545302417a5dbceb ryanofsky: Code review ACK 21b58f430fa05fdb7c5db79b545302417a5dbceb. Only changes since last review are dropping optional has_value call, fixing comment punctuation, squashing commits. Tree-SHA512: c9b85acc0f77c847a0290b27ac5dc586ecc078110cf133063140576a04c11aa9c553159b9b4993488edcf6e60db6837de7c83b2964639bc21e8ffa4d455a5eb7
Diffstat (limited to 'src/util')
-rw-r--r--src/util/strencodings.cpp46
-rw-r--r--src/util/strencodings.h30
2 files changed, 76 insertions, 0 deletions
diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp
index 15bd07b374..5e7c99f140 100644
--- a/src/util/strencodings.cpp
+++ b/src/util/strencodings.cpp
@@ -11,6 +11,7 @@
#include <algorithm>
#include <cstdlib>
#include <cstring>
+#include <limits>
#include <optional>
static const std::string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
@@ -526,3 +527,48 @@ std::string HexStr(const Span<const uint8_t> s)
assert(it == rv.end());
return rv;
}
+
+std::optional<uint64_t> ParseByteUnits(const std::string& str, ByteUnit default_multiplier)
+{
+ if (str.empty()) {
+ return std::nullopt;
+ }
+ auto multiplier = default_multiplier;
+ char unit = str.back();
+ switch (unit) {
+ case 'k':
+ multiplier = ByteUnit::k;
+ break;
+ case 'K':
+ multiplier = ByteUnit::K;
+ break;
+ case 'm':
+ multiplier = ByteUnit::m;
+ break;
+ case 'M':
+ multiplier = ByteUnit::M;
+ break;
+ case 'g':
+ multiplier = ByteUnit::g;
+ break;
+ case 'G':
+ multiplier = ByteUnit::G;
+ break;
+ case 't':
+ multiplier = ByteUnit::t;
+ break;
+ case 'T':
+ multiplier = ByteUnit::T;
+ break;
+ default:
+ unit = 0;
+ break;
+ }
+
+ uint64_t unit_amount = static_cast<uint64_t>(multiplier);
+ auto parsed_num = ToIntegral<uint64_t>(unit ? str.substr(0, str.size() - 1) : str);
+ if (!parsed_num || parsed_num > std::numeric_limits<uint64_t>::max() / unit_amount) { // check overflow
+ return std::nullopt;
+ }
+ return *parsed_num * unit_amount;
+}
diff --git a/src/util/strencodings.h b/src/util/strencodings.h
index eedb5ec2f8..bc0a6233ab 100644
--- a/src/util/strencodings.h
+++ b/src/util/strencodings.h
@@ -30,6 +30,23 @@ enum SafeChars
};
/**
+ * Used by ParseByteUnits()
+ * Lowercase base 1000
+ * Uppercase base 1024
+*/
+enum class ByteUnit : uint64_t {
+ NOOP = 1ULL,
+ k = 1000ULL,
+ K = 1024ULL,
+ m = 1'000'000ULL,
+ M = 1ULL << 20,
+ g = 1'000'000'000ULL,
+ G = 1ULL << 30,
+ t = 1'000'000'000'000ULL,
+ T = 1ULL << 40,
+};
+
+/**
* Remove unsafe chars. Safe chars chosen to allow simple messages/URLs/email
* addresses, but avoid anything even possibly remotely dangerous like & or >
* @param[in] str The string to sanitize
@@ -305,4 +322,17 @@ std::string ToUpper(const std::string& str);
*/
std::string Capitalize(std::string str);
+/**
+ * Parse a string with suffix unit [k|K|m|M|g|G|t|T].
+ * Must be a whole integer, fractions not allowed (0.5t), no whitespace or +-
+ * Lowercase units are 1000 base. Uppercase units are 1024 base.
+ * Examples: 2m,27M,19g,41T
+ *
+ * @param[in] str the string to convert into bytes
+ * @param[in] default_multiplier if no unit is found in str use this unit
+ * @returns optional uint64_t bytes from str or nullopt
+ * if ToIntegral is false, str is empty, trailing whitespace or overflow
+ */
+std::optional<uint64_t> ParseByteUnits(const std::string& str, ByteUnit default_multiplier);
+
#endif // BITCOIN_UTIL_STRENCODINGS_H