AK: Add an option to the base64 encoder to omit padding

Will be used by an upcoming JS prototype

(cherry picked from commit 41e14e3fc3aab8417b8687df7e4242982e97ba23)

Co-authored-by: Jamie Mansfield <[email protected]>
This commit is contained in:
Timothy FlynnandJamie Mansfield authored and Nico Weber committed 2026-09-18 20:04:39 -04:00
1 parent 651f72cab4
commit bff7eccf6b
3 files changed
+55 -9

No files matched your search

+11 -7
View File
@@ -90,7 +90,7 @@ static ErrorOr<ByteBuffer> decode_base64_impl(StringView input, ReadonlySpan<i16
return output;
}
static ErrorOr<String> encode_base64_impl(ReadonlyBytes input, ReadonlySpan<char> alphabet)
static ErrorOr<String> encode_base64_impl(ReadonlyBytes input, ReadonlySpan<char> alphabet, OmitPadding omit_padding)
{
Vector<u8> output;
TRY(output.try_ensure_capacity(calculate_base64_encoded_length(input)));
@@ -119,8 +119,12 @@ static ErrorOr<String> encode_base64_impl(ReadonlyBytes input, ReadonlySpan<char
output.unchecked_append(alphabet[index0]);
output.unchecked_append(alphabet[index1]);
output.unchecked_append(is_16bit ? '=' : alphabet[index2]);
output.unchecked_append(is_8bit ? '=' : alphabet[index3]);
if (!is_16bit || omit_padding == OmitPadding::No)
output.unchecked_append(is_16bit ? '=' : alphabet[index2]);
if (!is_8bit || omit_padding == OmitPadding::No)
output.unchecked_append(is_8bit ? '=' : alphabet[index3]);
}
return String::from_utf8_without_validation(output);
@@ -138,13 +142,13 @@ ErrorOr<ByteBuffer> decode_base64url(StringView input)
return decode_base64_impl(input, lookup_table);
}
ErrorOr<String> encode_base64(ReadonlyBytes input)
ErrorOr<String> encode_base64(ReadonlyBytes input, OmitPadding omit_padding)
{
return encode_base64_impl(input, base64_alphabet);
return encode_base64_impl(input, base64_alphabet, omit_padding);
}
ErrorOr<String> encode_base64url(ReadonlyBytes input)
ErrorOr<String> encode_base64url(ReadonlyBytes input, OmitPadding omit_padding)
{
return encode_base64_impl(input, base64url_alphabet);
return encode_base64_impl(input, base64url_alphabet, omit_padding);
}
}
+7 -2
View File
@@ -65,8 +65,13 @@ consteval auto base64url_lookup_table()
[[nodiscard]] ErrorOr<ByteBuffer> decode_base64(StringView);
[[nodiscard]] ErrorOr<ByteBuffer> decode_base64url(StringView);
[[nodiscard]] ErrorOr<String> encode_base64(ReadonlyBytes);
[[nodiscard]] ErrorOr<String> encode_base64url(ReadonlyBytes);
enum class OmitPadding {
No,
Yes,
};
[[nodiscard]] ErrorOr<String> encode_base64(ReadonlyBytes, OmitPadding = OmitPadding::No);
[[nodiscard]] ErrorOr<String> encode_base64url(ReadonlyBytes, OmitPadding = OmitPadding::No);
}
#if USING_AK_GLOBALLY
+37
View File
@@ -92,6 +92,22 @@ TEST_CASE(test_encode)
encode_equal("foobar"sv, "Zm9vYmFy"sv);
}
TEST_CASE(test_encode_omit_padding)
{
auto encode_equal = [&](StringView input, StringView expected) {
auto encoded = MUST(encode_base64(input.bytes(), AK::OmitPadding::Yes));
EXPECT_EQ(encoded, expected);
};
encode_equal(""sv, ""sv);
encode_equal("f"sv, "Zg"sv);
encode_equal("fo"sv, "Zm8"sv);
encode_equal("foo"sv, "Zm9v"sv);
encode_equal("foob"sv, "Zm9vYg"sv);
encode_equal("fooba"sv, "Zm9vYmE"sv);
encode_equal("foobar"sv, "Zm9vYmFy"sv);
}
TEST_CASE(test_urldecode)
{
auto decode_equal = [&](StringView input, StringView expected) {
@@ -135,3 +151,24 @@ TEST_CASE(test_urlencode)
encode_equal("hello!!world"sv, "aGVsbG8hIXdvcmxk"sv);
}
TEST_CASE(test_urlencode_omit_padding)
{
auto encode_equal = [&](StringView input, StringView expected) {
auto encoded = MUST(encode_base64url(input.bytes(), AK::OmitPadding::Yes));
EXPECT_EQ(encoded, expected);
};
encode_equal(""sv, ""sv);
encode_equal("f"sv, "Zg"sv);
encode_equal("fo"sv, "Zm8"sv);
encode_equal("foo"sv, "Zm9v"sv);
encode_equal("foob"sv, "Zm9vYg"sv);
encode_equal("fooba"sv, "Zm9vYmE"sv);
encode_equal("foobar"sv, "Zm9vYmFy"sv);
encode_equal("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."sv, "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwgc2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYSBhbGlxdWEu"sv);
encode_equal("hello?world"sv, "aGVsbG8_d29ybGQ"sv);
encode_equal("hello!!world"sv, "aGVsbG8hIXdvcmxk"sv);
}