mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-25 18:53:23 -03:00
Merge bitcoin/bitcoin#25001: Modernize util/strencodings and util/string: string_view
and optional
fa7078d84f
scripted-diff: Rename ValidAsCString to ContainsNoNUL (MacroFake)e7d2fbda63
Use std::string_view throughout util strencodings/string (Pieter Wuille)8ffbd1412d
Make DecodeBase{32,64} take string_view arguments (Pieter Wuille)1a72d62152
Generalize ConvertBits to permit transforming the input (Pieter Wuille)78f3ac51b7
Make DecodeBase{32,64} return optional instead of taking bool* (Pieter Wuille)a65931e3ce
Make DecodeBase{32,64} always return vector, not string (Pieter Wuille)a4377a0843
Reject incorrect base64 in HTTP auth (Pieter Wuille)d648b5120b
Make SanitizeString use string_view (Pieter Wuille)963bc9b576
Make IsHexNumber use string_view (Pieter Wuille)40062997f2
Make IsHex use string_view (Pieter Wuille)c1d165a8c2
Make ParseHex use string_view (Pieter Wuille) Pull request description: Make use of `std::string_view` and `std::optional` in the util/{strencodings, string} files. This avoids many temporary string/vector objects being created, while making the interface easier to read. Changes include: * Make all input arguments in functions in util/strencodings and util/string take `std::string_view` instead of `std::string`. * Add `RemovePrefixView` and `TrimStringView` which also *return* `std::string_view` objects (the corresponding `RemovePrefix` and `TrimString` keep returning an `std::string`, as that's needed in many call sites still). * Stop returning `std::string` from `DecodeBase32` and `DecodeBase64`, but return vectors. Base32/64 are fundamentally algorithms for encoding bytes as strings; returning `std::string` from those (especially doing it conditionally based on the input arguments/types) is just bizarre. * Stop taking a `bool* pf_invalid` output argument pointer in `DecodeBase32` and `DecodeBase64`; return an `std::optional` instead. * Make `DecodeBase32` and `DecodeBase64` more efficient by doing the conversion from characters to integer symbols on-the-fly rather than through a temporary vector. ACKs for top commit: MarcoFalke: re-ACKfa7078d84f
only change is rebase and adding a scripted-diff 🍲 martinus: Code review ACKfa7078d84f
, found no issue laanwj: Code review ACKfa7078d84f
sipa: utACKfa7078d84f
(as far as the commit that isn't mine goes) Tree-SHA512: 5cf02e541caef0bcd100466747664bdb828a68a05dae568cbcd0632a53dd3a4c4e85cd8c48ebbd168d4247d5c9666689c16005f1c8ad75b0f057d8683931f664
This commit is contained in:
commit
132d5f8c2f
22 changed files with 208 additions and 252 deletions
|
@ -126,7 +126,7 @@ std::string EncodeBase58(Span<const unsigned char> input)
|
|||
|
||||
bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret_len)
|
||||
{
|
||||
if (!ValidAsCString(str)) {
|
||||
if (!ContainsNoNUL(str)) {
|
||||
return false;
|
||||
}
|
||||
return DecodeBase58(str.c_str(), vchRet, max_ret_len);
|
||||
|
@ -160,7 +160,7 @@ std::string EncodeBase58Check(Span<const unsigned char> input)
|
|||
|
||||
bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret)
|
||||
{
|
||||
if (!ValidAsCString(str)) {
|
||||
if (!ContainsNoNUL(str)) {
|
||||
return false;
|
||||
}
|
||||
return DecodeBase58Check(str.c_str(), vchRet, max_ret);
|
||||
|
|
|
@ -240,7 +240,7 @@ static void MutateTxRBFOptIn(CMutableTransaction& tx, const std::string& strInId
|
|||
template <typename T>
|
||||
static T TrimAndParse(const std::string& int_str, const std::string& err)
|
||||
{
|
||||
const auto parsed{ToIntegral<T>(TrimString(int_str))};
|
||||
const auto parsed{ToIntegral<T>(TrimStringView(int_str))};
|
||||
if (!parsed.has_value()) {
|
||||
throw std::runtime_error(err + " '" + int_str + "'");
|
||||
}
|
||||
|
|
|
@ -131,8 +131,11 @@ static bool RPCAuthorized(const std::string& strAuth, std::string& strAuthUserna
|
|||
return false;
|
||||
if (strAuth.substr(0, 6) != "Basic ")
|
||||
return false;
|
||||
std::string strUserPass64 = TrimString(strAuth.substr(6));
|
||||
std::string strUserPass = DecodeBase64(strUserPass64);
|
||||
std::string_view strUserPass64 = TrimStringView(std::string_view{strAuth}.substr(6));
|
||||
auto userpass_data = DecodeBase64(strUserPass64);
|
||||
std::string strUserPass;
|
||||
if (!userpass_data) return false;
|
||||
strUserPass.assign(userpass_data->begin(), userpass_data->end());
|
||||
|
||||
if (strUserPass.find(':') != std::string::npos)
|
||||
strAuthUsernameOut = strUserPass.substr(0, strUserPass.find(':'));
|
||||
|
|
|
@ -69,12 +69,11 @@ static std::string SwapBase64(const std::string& from)
|
|||
static Binary DecodeI2PBase64(const std::string& i2p_b64)
|
||||
{
|
||||
const std::string& std_b64 = SwapBase64(i2p_b64);
|
||||
bool invalid;
|
||||
Binary decoded = DecodeBase64(std_b64.c_str(), &invalid);
|
||||
if (invalid) {
|
||||
auto decoded = DecodeBase64(std_b64);
|
||||
if (!decoded) {
|
||||
throw std::runtime_error(strprintf("Cannot decode Base64: \"%s\"", i2p_b64));
|
||||
}
|
||||
return decoded;
|
||||
return std::move(*decoded);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -210,7 +210,7 @@ static void Checksum(Span<const uint8_t> addr_pubkey, uint8_t (&checksum)[CHECKS
|
|||
|
||||
bool CNetAddr::SetSpecial(const std::string& addr)
|
||||
{
|
||||
if (!ValidAsCString(addr)) {
|
||||
if (!ContainsNoNUL(addr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -234,17 +234,16 @@ bool CNetAddr::SetTor(const std::string& addr)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool invalid;
|
||||
const auto& input = DecodeBase32(addr.substr(0, addr.size() - suffix_len).c_str(), &invalid);
|
||||
auto input = DecodeBase32(std::string_view{addr}.substr(0, addr.size() - suffix_len));
|
||||
|
||||
if (invalid) {
|
||||
if (!input) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (input.size() == torv3::TOTAL_LEN) {
|
||||
Span<const uint8_t> input_pubkey{input.data(), ADDR_TORV3_SIZE};
|
||||
Span<const uint8_t> input_checksum{input.data() + ADDR_TORV3_SIZE, torv3::CHECKSUM_LEN};
|
||||
Span<const uint8_t> input_version{input.data() + ADDR_TORV3_SIZE + torv3::CHECKSUM_LEN, sizeof(torv3::VERSION)};
|
||||
if (input->size() == torv3::TOTAL_LEN) {
|
||||
Span<const uint8_t> input_pubkey{input->data(), ADDR_TORV3_SIZE};
|
||||
Span<const uint8_t> input_checksum{input->data() + ADDR_TORV3_SIZE, torv3::CHECKSUM_LEN};
|
||||
Span<const uint8_t> input_version{input->data() + ADDR_TORV3_SIZE + torv3::CHECKSUM_LEN, sizeof(torv3::VERSION)};
|
||||
|
||||
if (input_version != torv3::VERSION) {
|
||||
return false;
|
||||
|
@ -280,15 +279,14 @@ bool CNetAddr::SetI2P(const std::string& addr)
|
|||
// can decode it.
|
||||
const std::string b32_padded = addr.substr(0, b32_len) + "====";
|
||||
|
||||
bool invalid;
|
||||
const auto& address_bytes = DecodeBase32(b32_padded.c_str(), &invalid);
|
||||
auto address_bytes = DecodeBase32(b32_padded);
|
||||
|
||||
if (invalid || address_bytes.size() != ADDR_I2P_SIZE) {
|
||||
if (!address_bytes || address_bytes->size() != ADDR_I2P_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_net = NET_I2P;
|
||||
m_addr.assign(address_bytes.begin(), address_bytes.end());
|
||||
m_addr.assign(address_bytes->begin(), address_bytes->end());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -136,7 +136,7 @@ static bool LookupIntern(const std::string& name, std::vector<CNetAddr>& vIP, un
|
|||
{
|
||||
vIP.clear();
|
||||
|
||||
if (!ValidAsCString(name)) {
|
||||
if (!ContainsNoNUL(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,7 @@ static bool LookupIntern(const std::string& name, std::vector<CNetAddr>& vIP, un
|
|||
|
||||
bool LookupHost(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
|
||||
{
|
||||
if (!ValidAsCString(name)) {
|
||||
if (!ContainsNoNUL(name)) {
|
||||
return false;
|
||||
}
|
||||
std::string strHost = name;
|
||||
|
@ -184,7 +184,7 @@ bool LookupHost(const std::string& name, std::vector<CNetAddr>& vIP, unsigned in
|
|||
|
||||
bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup, DNSLookupFn dns_lookup_function)
|
||||
{
|
||||
if (!ValidAsCString(name)) {
|
||||
if (!ContainsNoNUL(name)) {
|
||||
return false;
|
||||
}
|
||||
std::vector<CNetAddr> vIP;
|
||||
|
@ -197,7 +197,7 @@ bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup, DNSL
|
|||
|
||||
bool Lookup(const std::string& name, std::vector<CService>& vAddr, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function)
|
||||
{
|
||||
if (name.empty() || !ValidAsCString(name)) {
|
||||
if (name.empty() || !ContainsNoNUL(name)) {
|
||||
return false;
|
||||
}
|
||||
uint16_t port{portDefault};
|
||||
|
@ -216,7 +216,7 @@ bool Lookup(const std::string& name, std::vector<CService>& vAddr, uint16_t port
|
|||
|
||||
bool Lookup(const std::string& name, CService& addr, uint16_t portDefault, bool fAllowLookup, DNSLookupFn dns_lookup_function)
|
||||
{
|
||||
if (!ValidAsCString(name)) {
|
||||
if (!ContainsNoNUL(name)) {
|
||||
return false;
|
||||
}
|
||||
std::vector<CService> vService;
|
||||
|
@ -229,7 +229,7 @@ bool Lookup(const std::string& name, CService& addr, uint16_t portDefault, bool
|
|||
|
||||
CService LookupNumeric(const std::string& name, uint16_t portDefault, DNSLookupFn dns_lookup_function)
|
||||
{
|
||||
if (!ValidAsCString(name)) {
|
||||
if (!ContainsNoNUL(name)) {
|
||||
return {};
|
||||
}
|
||||
CService addr;
|
||||
|
@ -684,7 +684,7 @@ bool ConnectThroughProxy(const Proxy& proxy, const std::string& strDest, uint16_
|
|||
|
||||
bool LookupSubNet(const std::string& subnet_str, CSubNet& subnet_out)
|
||||
{
|
||||
if (!ValidAsCString(subnet_str)) {
|
||||
if (!ContainsNoNUL(subnet_str)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
11
src/psbt.cpp
11
src/psbt.cpp
|
@ -388,18 +388,17 @@ std::string PSBTRoleName(PSBTRole role) {
|
|||
|
||||
bool DecodeBase64PSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error)
|
||||
{
|
||||
bool invalid;
|
||||
std::string tx_data = DecodeBase64(base64_tx, &invalid);
|
||||
if (invalid) {
|
||||
auto tx_data = DecodeBase64(base64_tx);
|
||||
if (!tx_data) {
|
||||
error = "invalid base64";
|
||||
return false;
|
||||
}
|
||||
return DecodeRawPSBT(psbt, tx_data, error);
|
||||
return DecodeRawPSBT(psbt, MakeByteSpan(*tx_data), error);
|
||||
}
|
||||
|
||||
bool DecodeRawPSBT(PartiallySignedTransaction& psbt, const std::string& tx_data, std::string& error)
|
||||
bool DecodeRawPSBT(PartiallySignedTransaction& psbt, Span<const std::byte> tx_data, std::string& error)
|
||||
{
|
||||
CDataStream ss_data(MakeByteSpan(tx_data), SER_NETWORK, PROTOCOL_VERSION);
|
||||
CDataStream ss_data(tx_data, SER_NETWORK, PROTOCOL_VERSION);
|
||||
try {
|
||||
ss_data >> psbt;
|
||||
if (!ss_data.empty()) {
|
||||
|
|
|
@ -988,6 +988,6 @@ bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransacti
|
|||
//! Decode a base64ed PSBT into a PartiallySignedTransaction
|
||||
[[nodiscard]] bool DecodeBase64PSBT(PartiallySignedTransaction& decoded_psbt, const std::string& base64_psbt, std::string& error);
|
||||
//! Decode a raw (binary blob) PSBT into a PartiallySignedTransaction
|
||||
[[nodiscard]] bool DecodeRawPSBT(PartiallySignedTransaction& decoded_psbt, const std::string& raw_psbt, std::string& error);
|
||||
[[nodiscard]] bool DecodeRawPSBT(PartiallySignedTransaction& decoded_psbt, Span<const std::byte> raw_psbt, std::string& error);
|
||||
|
||||
#endif // BITCOIN_PSBT_H
|
||||
|
|
|
@ -194,16 +194,16 @@ void WalletFrame::gotoVerifyMessageTab(QString addr)
|
|||
|
||||
void WalletFrame::gotoLoadPSBT(bool from_clipboard)
|
||||
{
|
||||
std::string data;
|
||||
std::vector<unsigned char> data;
|
||||
|
||||
if (from_clipboard) {
|
||||
std::string raw = QApplication::clipboard()->text().toStdString();
|
||||
bool invalid;
|
||||
data = DecodeBase64(raw, &invalid);
|
||||
if (invalid) {
|
||||
auto result = DecodeBase64(raw);
|
||||
if (!result) {
|
||||
Q_EMIT message(tr("Error"), tr("Unable to decode PSBT from clipboard (invalid base64)"), CClientUIInterface::MSG_ERROR);
|
||||
return;
|
||||
}
|
||||
data = std::move(*result);
|
||||
} else {
|
||||
QString filename = GUIUtil::getOpenFileName(this,
|
||||
tr("Load Transaction Data"), QString(),
|
||||
|
@ -214,12 +214,12 @@ void WalletFrame::gotoLoadPSBT(bool from_clipboard)
|
|||
return;
|
||||
}
|
||||
std::ifstream in{filename.toLocal8Bit().data(), std::ios::binary};
|
||||
data = std::string(std::istreambuf_iterator<char>{in}, {});
|
||||
data.assign(std::istream_iterator<unsigned char>{in}, {});
|
||||
}
|
||||
|
||||
std::string error;
|
||||
PartiallySignedTransaction psbtx;
|
||||
if (!DecodeRawPSBT(psbtx, data, error)) {
|
||||
if (!DecodeRawPSBT(psbtx, MakeByteSpan(data), error)) {
|
||||
Q_EMIT message(tr("Error"), tr("Unable to decode PSBT") + "\n" + QString::fromStdString(error), CClientUIInterface::MSG_ERROR);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -22,20 +22,16 @@ BOOST_AUTO_TEST_CASE(base32_testvectors)
|
|||
BOOST_CHECK_EQUAL(strEnc, vstrOut[i]);
|
||||
strEnc = EncodeBase32(vstrIn[i], false);
|
||||
BOOST_CHECK_EQUAL(strEnc, vstrOutNoPadding[i]);
|
||||
std::string strDec = DecodeBase32(vstrOut[i]);
|
||||
BOOST_CHECK_EQUAL(strDec, vstrIn[i]);
|
||||
auto dec = DecodeBase32(vstrOut[i]);
|
||||
BOOST_REQUIRE(dec);
|
||||
BOOST_CHECK_MESSAGE(MakeByteSpan(*dec) == MakeByteSpan(vstrIn[i]), vstrOut[i]);
|
||||
}
|
||||
|
||||
// Decoding strings with embedded NUL characters should fail
|
||||
bool failure;
|
||||
(void)DecodeBase32("invalid\0"s, &failure); // correct size, invalid due to \0
|
||||
BOOST_CHECK(failure);
|
||||
(void)DecodeBase32("AWSX3VPP"s, &failure); // valid
|
||||
BOOST_CHECK(!failure);
|
||||
(void)DecodeBase32("AWSX3VPP\0invalid"s, &failure); // correct size, invalid due to \0
|
||||
BOOST_CHECK(failure);
|
||||
(void)DecodeBase32("AWSX3VPPinvalid"s, &failure); // invalid size
|
||||
BOOST_CHECK(failure);
|
||||
BOOST_CHECK(!DecodeBase32("invalid\0"s)); // correct size, invalid due to \0
|
||||
BOOST_CHECK(DecodeBase32("AWSX3VPP"s)); // valid
|
||||
BOOST_CHECK(!DecodeBase32("AWSX3VPP\0invalid"s)); // correct size, invalid due to \0
|
||||
BOOST_CHECK(!DecodeBase32("AWSX3VPPinvalid"s)); // invalid size
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
|
@ -19,8 +19,9 @@ BOOST_AUTO_TEST_CASE(base64_testvectors)
|
|||
{
|
||||
std::string strEnc = EncodeBase64(vstrIn[i]);
|
||||
BOOST_CHECK_EQUAL(strEnc, vstrOut[i]);
|
||||
std::string strDec = DecodeBase64(strEnc);
|
||||
BOOST_CHECK_EQUAL(strDec, vstrIn[i]);
|
||||
auto dec = DecodeBase64(strEnc);
|
||||
BOOST_REQUIRE(dec);
|
||||
BOOST_CHECK_MESSAGE(MakeByteSpan(*dec) == MakeByteSpan(vstrIn[i]), vstrOut[i]);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -34,15 +35,10 @@ BOOST_AUTO_TEST_CASE(base64_testvectors)
|
|||
}
|
||||
|
||||
// Decoding strings with embedded NUL characters should fail
|
||||
bool failure;
|
||||
(void)DecodeBase64("invalid\0"s, &failure);
|
||||
BOOST_CHECK(failure);
|
||||
(void)DecodeBase64("nQB/pZw="s, &failure);
|
||||
BOOST_CHECK(!failure);
|
||||
(void)DecodeBase64("nQB/pZw=\0invalid"s, &failure);
|
||||
BOOST_CHECK(failure);
|
||||
(void)DecodeBase64("nQB/pZw=invalid\0"s, &failure);
|
||||
BOOST_CHECK(failure);
|
||||
BOOST_CHECK(!DecodeBase64("invalid\0"s));
|
||||
BOOST_CHECK(DecodeBase64("nQB/pZw="s));
|
||||
BOOST_CHECK(!DecodeBase64("nQB/pZw=\0invalid"s));
|
||||
BOOST_CHECK(!DecodeBase64("nQB/pZw=invalid\0"s));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
|
@ -26,7 +26,7 @@ FUZZ_TARGET_INIT(base_encode_decode, initialize_base_encode_decode)
|
|||
std::vector<unsigned char> decoded;
|
||||
if (DecodeBase58(random_encoded_string, decoded, 100)) {
|
||||
const std::string encoded_string = EncodeBase58(decoded);
|
||||
assert(encoded_string == TrimString(encoded_string));
|
||||
assert(encoded_string == TrimStringView(encoded_string));
|
||||
assert(ToLower(encoded_string) == ToLower(TrimString(random_encoded_string)));
|
||||
}
|
||||
|
||||
|
@ -36,17 +36,16 @@ FUZZ_TARGET_INIT(base_encode_decode, initialize_base_encode_decode)
|
|||
assert(ToLower(encoded_string) == ToLower(TrimString(random_encoded_string)));
|
||||
}
|
||||
|
||||
bool pf_invalid;
|
||||
std::string decoded_string = DecodeBase32(random_encoded_string, &pf_invalid);
|
||||
if (!pf_invalid) {
|
||||
const std::string encoded_string = EncodeBase32(decoded_string);
|
||||
assert(encoded_string == TrimString(encoded_string));
|
||||
auto result = DecodeBase32(random_encoded_string);
|
||||
if (result) {
|
||||
const std::string encoded_string = EncodeBase32(*result);
|
||||
assert(encoded_string == TrimStringView(encoded_string));
|
||||
assert(ToLower(encoded_string) == ToLower(TrimString(random_encoded_string)));
|
||||
}
|
||||
|
||||
decoded_string = DecodeBase64(random_encoded_string, &pf_invalid);
|
||||
if (!pf_invalid) {
|
||||
const std::string encoded_string = EncodeBase64(decoded_string);
|
||||
result = DecodeBase64(random_encoded_string);
|
||||
if (result) {
|
||||
const std::string encoded_string = EncodeBase64(*result);
|
||||
assert(encoded_string == TrimString(encoded_string));
|
||||
assert(ToLower(encoded_string) == ToLower(TrimString(random_encoded_string)));
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ FUZZ_TARGET(http_request)
|
|||
// and is a consequence of our hacky but necessary use of the internal function evhttp_parse_firstline_ in
|
||||
// this fuzzing harness. The workaround is not aesthetically pleasing, but it successfully avoids the troublesome
|
||||
// code path. " http:// HTTP/1.1\n" was a crashing input prior to this workaround.
|
||||
const std::string http_buffer_str = ToLower({http_buffer.begin(), http_buffer.end()});
|
||||
const std::string http_buffer_str = ToLower(std::string{http_buffer.begin(), http_buffer.end()});
|
||||
if (http_buffer_str.find(" http://") != std::string::npos || http_buffer_str.find(" https://") != std::string::npos ||
|
||||
evhttp_parse_firstline_(evreq, evbuf) != 1 || evhttp_parse_headers_(evreq, evbuf) != 1) {
|
||||
evbuffer_free(evbuf);
|
||||
|
|
|
@ -32,7 +32,8 @@ FUZZ_TARGET_INIT(psbt, initialize_psbt)
|
|||
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
|
||||
PartiallySignedTransaction psbt_mut;
|
||||
std::string error;
|
||||
if (!DecodeRawPSBT(psbt_mut, fuzzed_data_provider.ConsumeRandomLengthString(), error)) {
|
||||
auto str = fuzzed_data_provider.ConsumeRandomLengthString();
|
||||
if (!DecodeRawPSBT(psbt_mut, MakeByteSpan(str), error)) {
|
||||
return;
|
||||
}
|
||||
const PartiallySignedTransaction psbt = psbt_mut;
|
||||
|
@ -79,7 +80,8 @@ FUZZ_TARGET_INIT(psbt, initialize_psbt)
|
|||
}
|
||||
|
||||
PartiallySignedTransaction psbt_merge;
|
||||
if (!DecodeRawPSBT(psbt_merge, fuzzed_data_provider.ConsumeRandomLengthString(), error)) {
|
||||
str = fuzzed_data_provider.ConsumeRandomLengthString();
|
||||
if (!DecodeRawPSBT(psbt_merge, MakeByteSpan(str), error)) {
|
||||
psbt_merge = psbt;
|
||||
}
|
||||
psbt_mut = psbt;
|
||||
|
|
|
@ -42,7 +42,7 @@ bool LegacyParsePrechecks(const std::string& str)
|
|||
return false;
|
||||
if (str.size() >= 1 && (IsSpace(str[0]) || IsSpace(str[str.size() - 1]))) // No padding allowed
|
||||
return false;
|
||||
if (!ValidAsCString(str)) // No embedded NUL characters allowed
|
||||
if (!ContainsNoNUL(str)) // No embedded NUL characters allowed
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ FUZZ_TARGET(string)
|
|||
(void)TrimString(random_string_1);
|
||||
(void)TrimString(random_string_1, random_string_2);
|
||||
(void)urlDecode(random_string_1);
|
||||
(void)ValidAsCString(random_string_1);
|
||||
(void)ContainsNoNUL(random_string_1);
|
||||
(void)_(random_string_1.c_str());
|
||||
try {
|
||||
throw scriptnum_error{random_string_1};
|
||||
|
|
|
@ -226,17 +226,17 @@ BOOST_AUTO_TEST_CASE(util_Join)
|
|||
BOOST_AUTO_TEST_CASE(util_TrimString)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(TrimString(" foo bar "), "foo bar");
|
||||
BOOST_CHECK_EQUAL(TrimString("\t \n \n \f\n\r\t\v\tfoo \n \f\n\r\t\v\tbar\t \n \f\n\r\t\v\t\n "), "foo \n \f\n\r\t\v\tbar");
|
||||
BOOST_CHECK_EQUAL(TrimStringView("\t \n \n \f\n\r\t\v\tfoo \n \f\n\r\t\v\tbar\t \n \f\n\r\t\v\t\n "), "foo \n \f\n\r\t\v\tbar");
|
||||
BOOST_CHECK_EQUAL(TrimString("\t \n foo \n\tbar\t \n "), "foo \n\tbar");
|
||||
BOOST_CHECK_EQUAL(TrimString("\t \n foo \n\tbar\t \n ", "fobar"), "\t \n foo \n\tbar\t \n ");
|
||||
BOOST_CHECK_EQUAL(TrimStringView("\t \n foo \n\tbar\t \n ", "fobar"), "\t \n foo \n\tbar\t \n ");
|
||||
BOOST_CHECK_EQUAL(TrimString("foo bar"), "foo bar");
|
||||
BOOST_CHECK_EQUAL(TrimString("foo bar", "fobar"), " ");
|
||||
BOOST_CHECK_EQUAL(TrimStringView("foo bar", "fobar"), " ");
|
||||
BOOST_CHECK_EQUAL(TrimString(std::string("\0 foo \0 ", 8)), std::string("\0 foo \0", 7));
|
||||
BOOST_CHECK_EQUAL(TrimString(std::string(" foo ", 5)), std::string("foo", 3));
|
||||
BOOST_CHECK_EQUAL(TrimStringView(std::string(" foo ", 5)), std::string("foo", 3));
|
||||
BOOST_CHECK_EQUAL(TrimString(std::string("\t\t\0\0\n\n", 6)), std::string("\0\0", 2));
|
||||
BOOST_CHECK_EQUAL(TrimString(std::string("\x05\x04\x03\x02\x01\x00", 6)), std::string("\x05\x04\x03\x02\x01\x00", 6));
|
||||
BOOST_CHECK_EQUAL(TrimStringView(std::string("\x05\x04\x03\x02\x01\x00", 6)), std::string("\x05\x04\x03\x02\x01\x00", 6));
|
||||
BOOST_CHECK_EQUAL(TrimString(std::string("\x05\x04\x03\x02\x01\x00", 6), std::string("\x05\x04\x03\x02\x01", 5)), std::string("\0", 1));
|
||||
BOOST_CHECK_EQUAL(TrimString(std::string("\x05\x04\x03\x02\x01\x00", 6), std::string("\x05\x04\x03\x02\x01\x00", 6)), "");
|
||||
BOOST_CHECK_EQUAL(TrimStringView(std::string("\x05\x04\x03\x02\x01\x00", 6), std::string("\x05\x04\x03\x02\x01\x00", 6)), "");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(util_FormatParseISO8601DateTime)
|
||||
|
@ -2618,13 +2618,13 @@ BOOST_AUTO_TEST_CASE(message_hash)
|
|||
BOOST_AUTO_TEST_CASE(remove_prefix)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(RemovePrefix("./util/system.h", "./"), "util/system.h");
|
||||
BOOST_CHECK_EQUAL(RemovePrefix("foo", "foo"), "");
|
||||
BOOST_CHECK_EQUAL(RemovePrefixView("foo", "foo"), "");
|
||||
BOOST_CHECK_EQUAL(RemovePrefix("foo", "fo"), "o");
|
||||
BOOST_CHECK_EQUAL(RemovePrefix("foo", "f"), "oo");
|
||||
BOOST_CHECK_EQUAL(RemovePrefixView("foo", "f"), "oo");
|
||||
BOOST_CHECK_EQUAL(RemovePrefix("foo", ""), "foo");
|
||||
BOOST_CHECK_EQUAL(RemovePrefix("fo", "foo"), "fo");
|
||||
BOOST_CHECK_EQUAL(RemovePrefixView("fo", "foo"), "fo");
|
||||
BOOST_CHECK_EQUAL(RemovePrefix("f", "foo"), "f");
|
||||
BOOST_CHECK_EQUAL(RemovePrefix("", "foo"), "");
|
||||
BOOST_CHECK_EQUAL(RemovePrefixView("", "foo"), "");
|
||||
BOOST_CHECK_EQUAL(RemovePrefix("", ""), "");
|
||||
}
|
||||
|
||||
|
|
|
@ -35,14 +35,13 @@ MessageVerificationResult MessageVerify(
|
|||
return MessageVerificationResult::ERR_ADDRESS_NO_KEY;
|
||||
}
|
||||
|
||||
bool invalid = false;
|
||||
std::vector<unsigned char> signature_bytes = DecodeBase64(signature.c_str(), &invalid);
|
||||
if (invalid) {
|
||||
auto signature_bytes = DecodeBase64(signature);
|
||||
if (!signature_bytes) {
|
||||
return MessageVerificationResult::ERR_MALFORMED_SIGNATURE;
|
||||
}
|
||||
|
||||
CPubKey pubkey;
|
||||
if (!pubkey.RecoverCompact(MessageHash(message), signature_bytes)) {
|
||||
if (!pubkey.RecoverCompact(MessageHash(message), *signature_bytes)) {
|
||||
return MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ std::string FormatMoney(const CAmount n)
|
|||
|
||||
std::optional<CAmount> ParseMoney(const std::string& money_string)
|
||||
{
|
||||
if (!ValidAsCString(money_string)) {
|
||||
if (!ContainsNoNUL(money_string)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const std::string str = TrimString(money_string);
|
||||
|
|
|
@ -24,15 +24,15 @@ static const std::string SAFE_CHARS[] =
|
|||
CHARS_ALPHA_NUM + "!*'();:@&=+$,/?#[]-_.~%", // SAFE_CHARS_URI
|
||||
};
|
||||
|
||||
std::string SanitizeString(const std::string& str, int rule)
|
||||
std::string SanitizeString(std::string_view str, int rule)
|
||||
{
|
||||
std::string strResult;
|
||||
for (std::string::size_type i = 0; i < str.size(); i++)
|
||||
{
|
||||
if (SAFE_CHARS[rule].find(str[i]) != std::string::npos)
|
||||
strResult.push_back(str[i]);
|
||||
std::string result;
|
||||
for (char c : str) {
|
||||
if (SAFE_CHARS[rule].find(c) != std::string::npos) {
|
||||
result.push_back(c);
|
||||
}
|
||||
}
|
||||
return strResult;
|
||||
return result;
|
||||
}
|
||||
|
||||
const signed char p_util_hexdigit[256] =
|
||||
|
@ -58,56 +58,43 @@ signed char HexDigit(char c)
|
|||
return p_util_hexdigit[(unsigned char)c];
|
||||
}
|
||||
|
||||
bool IsHex(const std::string& str)
|
||||
bool IsHex(std::string_view str)
|
||||
{
|
||||
for(std::string::const_iterator it(str.begin()); it != str.end(); ++it)
|
||||
{
|
||||
if (HexDigit(*it) < 0)
|
||||
return false;
|
||||
for (char c : str) {
|
||||
if (HexDigit(c) < 0) return false;
|
||||
}
|
||||
return (str.size() > 0) && (str.size()%2 == 0);
|
||||
}
|
||||
|
||||
bool IsHexNumber(const std::string& str)
|
||||
bool IsHexNumber(std::string_view str)
|
||||
{
|
||||
size_t starting_location = 0;
|
||||
if (str.size() > 2 && *str.begin() == '0' && *(str.begin()+1) == 'x') {
|
||||
starting_location = 2;
|
||||
}
|
||||
for (const char c : str.substr(starting_location)) {
|
||||
if (str.substr(0, 2) == "0x") str.remove_prefix(2);
|
||||
for (char c : str) {
|
||||
if (HexDigit(c) < 0) return false;
|
||||
}
|
||||
// Return false for empty string or "0x".
|
||||
return (str.size() > starting_location);
|
||||
return str.size() > 0;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> ParseHex(const char* psz)
|
||||
std::vector<unsigned char> ParseHex(std::string_view str)
|
||||
{
|
||||
// convert hex dump to vector
|
||||
std::vector<unsigned char> vch;
|
||||
while (true)
|
||||
{
|
||||
while (IsSpace(*psz))
|
||||
psz++;
|
||||
signed char c = HexDigit(*psz++);
|
||||
if (c == (signed char)-1)
|
||||
break;
|
||||
auto n{uint8_t(c << 4)};
|
||||
c = HexDigit(*psz++);
|
||||
if (c == (signed char)-1)
|
||||
break;
|
||||
n |= c;
|
||||
vch.push_back(n);
|
||||
auto it = str.begin();
|
||||
while (it != str.end() && it + 1 != str.end()) {
|
||||
if (IsSpace(*it)) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
auto c1 = HexDigit(*(it++));
|
||||
auto c2 = HexDigit(*(it++));
|
||||
if (c1 < 0 || c2 < 0) break;
|
||||
vch.push_back(uint8_t(c1 << 4) | c2);
|
||||
}
|
||||
return vch;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> ParseHex(const std::string& str)
|
||||
{
|
||||
return ParseHex(str.c_str());
|
||||
}
|
||||
|
||||
void SplitHostPort(std::string in, uint16_t& portOut, std::string& hostOut)
|
||||
void SplitHostPort(std::string_view in, uint16_t& portOut, std::string& hostOut)
|
||||
{
|
||||
size_t colon = in.find_last_of(':');
|
||||
// if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator
|
||||
|
@ -139,7 +126,7 @@ std::string EncodeBase64(Span<const unsigned char> input)
|
|||
return str;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid)
|
||||
std::optional<std::vector<unsigned char>> DecodeBase64(std::string_view str)
|
||||
{
|
||||
static const int8_t decode64_table[256]{
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
|
@ -157,46 +144,23 @@ std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid)
|
|||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
|
||||
};
|
||||
|
||||
const char* e = p;
|
||||
std::vector<uint8_t> val;
|
||||
val.reserve(strlen(p));
|
||||
while (*p != 0) {
|
||||
int x = decode64_table[(unsigned char)*p];
|
||||
if (x == -1) break;
|
||||
val.push_back(uint8_t(x));
|
||||
++p;
|
||||
}
|
||||
if (str.size() % 4 != 0) return {};
|
||||
/* One or two = characters at the end are permitted. */
|
||||
if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
|
||||
if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
|
||||
|
||||
std::vector<unsigned char> ret;
|
||||
ret.reserve((val.size() * 3) / 4);
|
||||
bool valid = ConvertBits<6, 8, false>([&](unsigned char c) { ret.push_back(c); }, val.begin(), val.end());
|
||||
|
||||
const char* q = p;
|
||||
while (valid && *p != 0) {
|
||||
if (*p != '=') {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
valid = valid && (p - e) % 4 == 0 && p - q < 4;
|
||||
if (pf_invalid) *pf_invalid = !valid;
|
||||
ret.reserve((str.size() * 3) / 4);
|
||||
bool valid = ConvertBits<6, 8, false>(
|
||||
[&](unsigned char c) { ret.push_back(c); },
|
||||
str.begin(), str.end(),
|
||||
[](char c) { return decode64_table[uint8_t(c)]; }
|
||||
);
|
||||
if (!valid) return {};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string DecodeBase64(const std::string& str, bool* pf_invalid)
|
||||
{
|
||||
if (!ValidAsCString(str)) {
|
||||
if (pf_invalid) {
|
||||
*pf_invalid = true;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
std::vector<unsigned char> vchRet = DecodeBase64(str.c_str(), pf_invalid);
|
||||
return std::string((const char*)vchRet.data(), vchRet.size());
|
||||
}
|
||||
|
||||
std::string EncodeBase32(Span<const unsigned char> input, bool pad)
|
||||
{
|
||||
static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567";
|
||||
|
@ -212,12 +176,12 @@ std::string EncodeBase32(Span<const unsigned char> input, bool pad)
|
|||
return str;
|
||||
}
|
||||
|
||||
std::string EncodeBase32(const std::string& str, bool pad)
|
||||
std::string EncodeBase32(std::string_view str, bool pad)
|
||||
{
|
||||
return EncodeBase32(MakeUCharSpan(str), pad);
|
||||
}
|
||||
|
||||
std::vector<unsigned char> DecodeBase32(const char* p, bool* pf_invalid)
|
||||
std::optional<std::vector<unsigned char>> DecodeBase32(std::string_view str)
|
||||
{
|
||||
static const int8_t decode32_table[256]{
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
|
@ -235,49 +199,29 @@ std::vector<unsigned char> DecodeBase32(const char* p, bool* pf_invalid)
|
|||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
|
||||
};
|
||||
|
||||
const char* e = p;
|
||||
std::vector<uint8_t> val;
|
||||
val.reserve(strlen(p));
|
||||
while (*p != 0) {
|
||||
int x = decode32_table[(unsigned char)*p];
|
||||
if (x == -1) break;
|
||||
val.push_back(uint8_t(x));
|
||||
++p;
|
||||
}
|
||||
if (str.size() % 8 != 0) return {};
|
||||
/* 1, 3, 4, or 6 padding '=' suffix characters are permitted. */
|
||||
if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
|
||||
if (str.size() >= 2 && str.substr(str.size() - 2) == "==") str.remove_suffix(2);
|
||||
if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
|
||||
if (str.size() >= 2 && str.substr(str.size() - 2) == "==") str.remove_suffix(2);
|
||||
|
||||
std::vector<unsigned char> ret;
|
||||
ret.reserve((val.size() * 5) / 8);
|
||||
bool valid = ConvertBits<5, 8, false>([&](unsigned char c) { ret.push_back(c); }, val.begin(), val.end());
|
||||
ret.reserve((str.size() * 5) / 8);
|
||||
bool valid = ConvertBits<5, 8, false>(
|
||||
[&](unsigned char c) { ret.push_back(c); },
|
||||
str.begin(), str.end(),
|
||||
[](char c) { return decode32_table[uint8_t(c)]; }
|
||||
);
|
||||
|
||||
const char* q = p;
|
||||
while (valid && *p != 0) {
|
||||
if (*p != '=') {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
valid = valid && (p - e) % 8 == 0 && p - q < 8;
|
||||
if (pf_invalid) *pf_invalid = !valid;
|
||||
if (!valid) return {};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string DecodeBase32(const std::string& str, bool* pf_invalid)
|
||||
{
|
||||
if (!ValidAsCString(str)) {
|
||||
if (pf_invalid) {
|
||||
*pf_invalid = true;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
std::vector<unsigned char> vchRet = DecodeBase32(str.c_str(), pf_invalid);
|
||||
return std::string((const char*)vchRet.data(), vchRet.size());
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
bool ParseIntegral(const std::string& str, T* out)
|
||||
bool ParseIntegral(std::string_view str, T* out)
|
||||
{
|
||||
static_assert(std::is_integral<T>::value);
|
||||
// Replicate the exact behavior of strtol/strtoll/strtoul/strtoull when
|
||||
|
@ -296,37 +240,37 @@ bool ParseIntegral(const std::string& str, T* out)
|
|||
}
|
||||
}; // namespace
|
||||
|
||||
bool ParseInt32(const std::string& str, int32_t* out)
|
||||
bool ParseInt32(std::string_view str, int32_t* out)
|
||||
{
|
||||
return ParseIntegral<int32_t>(str, out);
|
||||
}
|
||||
|
||||
bool ParseInt64(const std::string& str, int64_t* out)
|
||||
bool ParseInt64(std::string_view str, int64_t* out)
|
||||
{
|
||||
return ParseIntegral<int64_t>(str, out);
|
||||
}
|
||||
|
||||
bool ParseUInt8(const std::string& str, uint8_t* out)
|
||||
bool ParseUInt8(std::string_view str, uint8_t* out)
|
||||
{
|
||||
return ParseIntegral<uint8_t>(str, out);
|
||||
}
|
||||
|
||||
bool ParseUInt16(const std::string& str, uint16_t* out)
|
||||
bool ParseUInt16(std::string_view str, uint16_t* out)
|
||||
{
|
||||
return ParseIntegral<uint16_t>(str, out);
|
||||
}
|
||||
|
||||
bool ParseUInt32(const std::string& str, uint32_t* out)
|
||||
bool ParseUInt32(std::string_view str, uint32_t* out)
|
||||
{
|
||||
return ParseIntegral<uint32_t>(str, out);
|
||||
}
|
||||
|
||||
bool ParseUInt64(const std::string& str, uint64_t* out)
|
||||
bool ParseUInt64(std::string_view str, uint64_t* out)
|
||||
{
|
||||
return ParseIntegral<uint64_t>(str, out);
|
||||
}
|
||||
|
||||
std::string FormatParagraph(const std::string& in, size_t width, size_t indent)
|
||||
std::string FormatParagraph(std::string_view in, size_t width, size_t indent)
|
||||
{
|
||||
assert(width >= indent);
|
||||
std::stringstream out;
|
||||
|
@ -395,7 +339,7 @@ static inline bool ProcessMantissaDigit(char ch, int64_t &mantissa, int &mantiss
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out)
|
||||
bool ParseFixedPoint(std::string_view val, int decimals, int64_t *amount_out)
|
||||
{
|
||||
int64_t mantissa = 0;
|
||||
int64_t exponent = 0;
|
||||
|
@ -487,14 +431,14 @@ bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out)
|
|||
return true;
|
||||
}
|
||||
|
||||
std::string ToLower(const std::string& str)
|
||||
std::string ToLower(std::string_view str)
|
||||
{
|
||||
std::string r;
|
||||
for (auto ch : str) r += ToLower(ch);
|
||||
return r;
|
||||
}
|
||||
|
||||
std::string ToUpper(const std::string& str)
|
||||
std::string ToUpper(std::string_view str)
|
||||
{
|
||||
std::string r;
|
||||
for (auto ch : str) r += ToUpper(ch);
|
||||
|
@ -522,7 +466,7 @@ std::string HexStr(const Span<const uint8_t> s)
|
|||
return rv;
|
||||
}
|
||||
|
||||
std::optional<uint64_t> ParseByteUnits(const std::string& str, ByteUnit default_multiplier)
|
||||
std::optional<uint64_t> ParseByteUnits(std::string_view str, ByteUnit default_multiplier)
|
||||
{
|
||||
if (str.empty()) {
|
||||
return std::nullopt;
|
||||
|
|
|
@ -54,24 +54,21 @@ enum class ByteUnit : uint64_t {
|
|||
* @param[in] rule The set of safe chars to choose (default: least restrictive)
|
||||
* @return A new string without unsafe chars
|
||||
*/
|
||||
std::string SanitizeString(const std::string& str, int rule = SAFE_CHARS_DEFAULT);
|
||||
std::vector<unsigned char> ParseHex(const char* psz);
|
||||
std::vector<unsigned char> ParseHex(const std::string& str);
|
||||
std::string SanitizeString(std::string_view str, int rule = SAFE_CHARS_DEFAULT);
|
||||
std::vector<unsigned char> ParseHex(std::string_view str);
|
||||
signed char HexDigit(char c);
|
||||
/* Returns true if each character in str is a hex character, and has an even
|
||||
* number of hex digits.*/
|
||||
bool IsHex(const std::string& str);
|
||||
bool IsHex(std::string_view str);
|
||||
/**
|
||||
* Return true if the string is a hex number, optionally prefixed with "0x"
|
||||
*/
|
||||
bool IsHexNumber(const std::string& str);
|
||||
std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid = nullptr);
|
||||
std::string DecodeBase64(const std::string& str, bool* pf_invalid = nullptr);
|
||||
bool IsHexNumber(std::string_view str);
|
||||
std::optional<std::vector<unsigned char>> DecodeBase64(std::string_view str);
|
||||
std::string EncodeBase64(Span<const unsigned char> input);
|
||||
inline std::string EncodeBase64(Span<const std::byte> input) { return EncodeBase64(MakeUCharSpan(input)); }
|
||||
inline std::string EncodeBase64(const std::string& str) { return EncodeBase64(MakeUCharSpan(str)); }
|
||||
std::vector<unsigned char> DecodeBase32(const char* p, bool* pf_invalid = nullptr);
|
||||
std::string DecodeBase32(const std::string& str, bool* pf_invalid = nullptr);
|
||||
inline std::string EncodeBase64(std::string_view str) { return EncodeBase64(MakeUCharSpan(str)); }
|
||||
std::optional<std::vector<unsigned char>> DecodeBase32(std::string_view str);
|
||||
|
||||
/**
|
||||
* Base32 encode.
|
||||
|
@ -85,9 +82,9 @@ std::string EncodeBase32(Span<const unsigned char> input, bool pad = true);
|
|||
* If `pad` is true, then the output will be padded with '=' so that its length
|
||||
* is a multiple of 8.
|
||||
*/
|
||||
std::string EncodeBase32(const std::string& str, bool pad = true);
|
||||
std::string EncodeBase32(std::string_view str, bool pad = true);
|
||||
|
||||
void SplitHostPort(std::string in, uint16_t& portOut, std::string& hostOut);
|
||||
void SplitHostPort(std::string_view in, uint16_t& portOut, std::string& hostOut);
|
||||
|
||||
// LocaleIndependentAtoi is provided for backwards compatibility reasons.
|
||||
//
|
||||
|
@ -101,12 +98,12 @@ void SplitHostPort(std::string in, uint16_t& portOut, std::string& hostOut);
|
|||
// undefined behavior, while this function returns the maximum or minimum
|
||||
// values, respectively.
|
||||
template <typename T>
|
||||
T LocaleIndependentAtoi(const std::string& str)
|
||||
T LocaleIndependentAtoi(std::string_view str)
|
||||
{
|
||||
static_assert(std::is_integral<T>::value);
|
||||
T result;
|
||||
// Emulate atoi(...) handling of white space and leading +/-.
|
||||
std::string s = TrimString(str);
|
||||
std::string_view s = TrimStringView(str);
|
||||
if (!s.empty() && s[0] == '+') {
|
||||
if (s.length() >= 2 && s[1] == '-') {
|
||||
return 0;
|
||||
|
@ -162,7 +159,7 @@ constexpr inline bool IsSpace(char c) noexcept {
|
|||
* parsed value is not in the range representable by the type T.
|
||||
*/
|
||||
template <typename T>
|
||||
std::optional<T> ToIntegral(const std::string& str)
|
||||
std::optional<T> ToIntegral(std::string_view str)
|
||||
{
|
||||
static_assert(std::is_integral<T>::value);
|
||||
T result;
|
||||
|
@ -178,42 +175,42 @@ std::optional<T> ToIntegral(const std::string& str)
|
|||
* @returns true if the entire string could be parsed as valid integer,
|
||||
* false if not the entire string could be parsed or when overflow or underflow occurred.
|
||||
*/
|
||||
[[nodiscard]] bool ParseInt32(const std::string& str, int32_t *out);
|
||||
[[nodiscard]] bool ParseInt32(std::string_view str, int32_t *out);
|
||||
|
||||
/**
|
||||
* Convert string to signed 64-bit integer with strict parse error feedback.
|
||||
* @returns true if the entire string could be parsed as valid integer,
|
||||
* false if not the entire string could be parsed or when overflow or underflow occurred.
|
||||
*/
|
||||
[[nodiscard]] bool ParseInt64(const std::string& str, int64_t *out);
|
||||
[[nodiscard]] bool ParseInt64(std::string_view str, int64_t *out);
|
||||
|
||||
/**
|
||||
* Convert decimal string to unsigned 8-bit integer with strict parse error feedback.
|
||||
* @returns true if the entire string could be parsed as valid integer,
|
||||
* false if not the entire string could be parsed or when overflow or underflow occurred.
|
||||
*/
|
||||
[[nodiscard]] bool ParseUInt8(const std::string& str, uint8_t *out);
|
||||
[[nodiscard]] bool ParseUInt8(std::string_view str, uint8_t *out);
|
||||
|
||||
/**
|
||||
* Convert decimal string to unsigned 16-bit integer with strict parse error feedback.
|
||||
* @returns true if the entire string could be parsed as valid integer,
|
||||
* false if the entire string could not be parsed or if overflow or underflow occurred.
|
||||
*/
|
||||
[[nodiscard]] bool ParseUInt16(const std::string& str, uint16_t* out);
|
||||
[[nodiscard]] bool ParseUInt16(std::string_view str, uint16_t* out);
|
||||
|
||||
/**
|
||||
* Convert decimal string to unsigned 32-bit integer with strict parse error feedback.
|
||||
* @returns true if the entire string could be parsed as valid integer,
|
||||
* false if not the entire string could be parsed or when overflow or underflow occurred.
|
||||
*/
|
||||
[[nodiscard]] bool ParseUInt32(const std::string& str, uint32_t *out);
|
||||
[[nodiscard]] bool ParseUInt32(std::string_view str, uint32_t *out);
|
||||
|
||||
/**
|
||||
* Convert decimal string to unsigned 64-bit integer with strict parse error feedback.
|
||||
* @returns true if the entire string could be parsed as valid integer,
|
||||
* false if not the entire string could be parsed or when overflow or underflow occurred.
|
||||
*/
|
||||
[[nodiscard]] bool ParseUInt64(const std::string& str, uint64_t *out);
|
||||
[[nodiscard]] bool ParseUInt64(std::string_view str, uint64_t *out);
|
||||
|
||||
/**
|
||||
* Convert a span of bytes to a lower-case hexadecimal string.
|
||||
|
@ -226,7 +223,7 @@ inline std::string HexStr(const Span<const std::byte> s) { return HexStr(MakeUCh
|
|||
* Format a paragraph of text to a fixed width, adding spaces for
|
||||
* indentation to any added line.
|
||||
*/
|
||||
std::string FormatParagraph(const std::string& in, size_t width = 79, size_t indent = 0);
|
||||
std::string FormatParagraph(std::string_view in, size_t width = 79, size_t indent = 0);
|
||||
|
||||
/**
|
||||
* Timing-attack-resistant comparison.
|
||||
|
@ -248,17 +245,28 @@ bool TimingResistantEqual(const T& a, const T& b)
|
|||
* @returns true on success, false on error.
|
||||
* @note The result must be in the range (-10^18,10^18), otherwise an overflow error will trigger.
|
||||
*/
|
||||
[[nodiscard]] bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out);
|
||||
[[nodiscard]] bool ParseFixedPoint(std::string_view, int decimals, int64_t *amount_out);
|
||||
|
||||
namespace {
|
||||
/** Helper class for the default infn argument to ConvertBits (just returns the input). */
|
||||
struct IntIdentity
|
||||
{
|
||||
[[maybe_unused]] int operator()(int x) const { return x; }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
/** Convert from one power-of-2 number base to another. */
|
||||
template<int frombits, int tobits, bool pad, typename O, typename I>
|
||||
bool ConvertBits(const O& outfn, I it, I end) {
|
||||
template<int frombits, int tobits, bool pad, typename O, typename It, typename I = IntIdentity>
|
||||
bool ConvertBits(O outfn, It it, It end, I infn = {}) {
|
||||
size_t acc = 0;
|
||||
size_t bits = 0;
|
||||
constexpr size_t maxv = (1 << tobits) - 1;
|
||||
constexpr size_t max_acc = (1 << (frombits + tobits - 1)) - 1;
|
||||
while (it != end) {
|
||||
acc = ((acc << frombits) | *it) & max_acc;
|
||||
int v = infn(*it);
|
||||
if (v < 0) return false;
|
||||
acc = ((acc << frombits) | v) & max_acc;
|
||||
bits += frombits;
|
||||
while (bits >= tobits) {
|
||||
bits -= tobits;
|
||||
|
@ -298,7 +306,7 @@ constexpr char ToLower(char c)
|
|||
* @param[in] str the string to convert to lowercase.
|
||||
* @returns lowercased equivalent of str
|
||||
*/
|
||||
std::string ToLower(const std::string& str);
|
||||
std::string ToLower(std::string_view str);
|
||||
|
||||
/**
|
||||
* Converts the given character to its uppercase equivalent.
|
||||
|
@ -324,7 +332,7 @@ constexpr char ToUpper(char c)
|
|||
* @param[in] str the string to convert to uppercase.
|
||||
* @returns UPPERCASED EQUIVALENT OF str
|
||||
*/
|
||||
std::string ToUpper(const std::string& str);
|
||||
std::string ToUpper(std::string_view str);
|
||||
|
||||
/**
|
||||
* Capitalizes the first character of the given string.
|
||||
|
@ -348,6 +356,6 @@ std::string Capitalize(std::string str);
|
|||
* @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);
|
||||
std::optional<uint64_t> ParseByteUnits(std::string_view str, ByteUnit default_multiplier);
|
||||
|
||||
#endif // BITCOIN_UTIL_STRENCODINGS_H
|
||||
|
|
|
@ -21,17 +21,22 @@
|
|||
return spanparsing::Split<std::string>(str, sep);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string TrimString(const std::string& str, const std::string& pattern = " \f\n\r\t\v")
|
||||
[[nodiscard]] inline std::string_view TrimStringView(std::string_view str, std::string_view pattern = " \f\n\r\t\v")
|
||||
{
|
||||
std::string::size_type front = str.find_first_not_of(pattern);
|
||||
if (front == std::string::npos) {
|
||||
return std::string();
|
||||
return {};
|
||||
}
|
||||
std::string::size_type end = str.find_last_not_of(pattern);
|
||||
return str.substr(front, end - front + 1);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string RemovePrefix(const std::string& str, const std::string& prefix)
|
||||
[[nodiscard]] inline std::string TrimString(std::string_view str, std::string_view pattern = " \f\n\r\t\v")
|
||||
{
|
||||
return std::string(TrimStringView(str, pattern));
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string_view RemovePrefixView(std::string_view str, std::string_view prefix)
|
||||
{
|
||||
if (str.substr(0, prefix.size()) == prefix) {
|
||||
return str.substr(prefix.size());
|
||||
|
@ -39,6 +44,11 @@
|
|||
return str;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string RemovePrefix(std::string_view str, std::string_view prefix)
|
||||
{
|
||||
return std::string(RemovePrefixView(str, prefix));
|
||||
}
|
||||
|
||||
/**
|
||||
* Join a list of items
|
||||
*
|
||||
|
@ -58,14 +68,14 @@ auto Join(const std::vector<T>& list, const BaseType& separator, UnaryOp unary_o
|
|||
return ret;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T Join(const std::vector<T>& list, const T& separator)
|
||||
template <typename T, typename T2>
|
||||
T Join(const std::vector<T>& list, const T2& separator)
|
||||
{
|
||||
return Join(list, separator, [](const T& i) { return i; });
|
||||
}
|
||||
|
||||
// Explicit overload needed for c_str arguments, which would otherwise cause a substitution failure in the template above.
|
||||
inline std::string Join(const std::vector<std::string>& list, const std::string& separator)
|
||||
inline std::string Join(const std::vector<std::string>& list, std::string_view separator)
|
||||
{
|
||||
return Join<std::string>(list, separator);
|
||||
}
|
||||
|
@ -81,9 +91,12 @@ inline std::string MakeUnorderedList(const std::vector<std::string>& items)
|
|||
/**
|
||||
* Check if a string does not contain any embedded NUL (\0) characters
|
||||
*/
|
||||
[[nodiscard]] inline bool ValidAsCString(const std::string& str) noexcept
|
||||
[[nodiscard]] inline bool ContainsNoNUL(std::string_view str) noexcept
|
||||
{
|
||||
return str.size() == strlen(str.c_str());
|
||||
for (auto c : str) {
|
||||
if (c == 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -853,8 +853,8 @@ static bool GetConfigOptions(std::istream& stream, const std::string& filepath,
|
|||
error = strprintf("parse error on line %i: %s, options in configuration file must be specified without leading -", linenr, str);
|
||||
return false;
|
||||
} else if ((pos = str.find('=')) != std::string::npos) {
|
||||
std::string name = prefix + TrimString(str.substr(0, pos), pattern);
|
||||
std::string value = TrimString(str.substr(pos + 1), pattern);
|
||||
std::string name = prefix + TrimString(std::string_view{str}.substr(0, pos), pattern);
|
||||
std::string_view value = TrimStringView(std::string_view{str}.substr(pos + 1), pattern);
|
||||
if (used_hash && name.find("rpcpassword") != std::string::npos) {
|
||||
error = strprintf("parse error on line %i, using # in rpcpassword can be ambiguous and should be avoided", linenr);
|
||||
return false;
|
||||
|
|
Loading…
Add table
Reference in a new issue