Use an unsigned accumulator in base64_encode (#2477)

* use an unsigned accumulator in base64_encode

* Forward-declare detail::base64_encode for split builds
This commit is contained in:
metsw24-max
2026-07-01 20:12:00 -04:00
committed by GitHub
parent 9d159bb412
commit a7b886b9cb
2 changed files with 29 additions and 1 deletions
+3 -1
View File
@@ -4665,7 +4665,9 @@ inline std::string base64_encode(const std::string &in) {
std::string out;
out.reserve(in.size());
auto val = 0;
// Unsigned: once four bytes are folded in the top bit is set, so the next
// `val << 8` would left-shift a negative int (undefined behaviour).
uint32_t val = 0;
auto valb = -6;
for (auto c : in) {
+26
View File
@@ -420,6 +420,32 @@ TEST(SanitizeFilenameTest, VariousPatterns) {
EXPECT_EQ("", httplib::sanitize_filename(" "));
}
// Forward declaration: in split builds split.py strips `inline` and moves the
// definition into httplib.cc, so detail::base64_encode is not visible from the
// public httplib.h. Re-declaring it here lets the tests link against the symbol
// in both header-only and split builds.
namespace httplib {
namespace detail {
std::string base64_encode(const std::string &in);
} // namespace detail
} // namespace httplib
TEST(Base64EncodeTest, KnownAnswers) {
// RFC 4648 test vectors. Inputs of four bytes or more exercise the round
// where the accumulator's top bit is already set before the next shift.
EXPECT_EQ("", detail::base64_encode(""));
EXPECT_EQ("Zg==", detail::base64_encode("f"));
EXPECT_EQ("Zm8=", detail::base64_encode("fo"));
EXPECT_EQ("Zm9v", detail::base64_encode("foo"));
EXPECT_EQ("Zm9vYg==", detail::base64_encode("foob"));
EXPECT_EQ("Zm9vYmE=", detail::base64_encode("fooba"));
EXPECT_EQ("Zm9vYmFy", detail::base64_encode("foobar"));
// High bytes keep the top bit set across several rounds.
EXPECT_EQ("AAECA//+wIB/", detail::base64_encode(std::string(
"\x00\x01\x02\x03\xff\xfe\xc0\x80\x7f", 9)));
}
TEST(EncodeQueryParamTest, ParseUnescapedChararactersTest) {
string unescapedCharacters = "-_.!~*'()";