1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 05:27:46 +00:00

AK+Everywhere: Make Base64 decoding fallible

This commit is contained in:
Ben Wiederhake 2021-10-23 15:43:59 +02:00 committed by Linus Groh
parent 3bf1f7ae87
commit cb868cfa41
11 changed files with 73 additions and 32 deletions

View file

@ -6,10 +6,7 @@
#include <AK/Array.h>
#include <AK/Base64.h>
#include <AK/ByteBuffer.h>
#include <AK/String.h>
#include <AK/StringBuilder.h>
#include <AK/StringView.h>
#include <AK/Types.h>
#include <AK/Vector.h>
@ -33,7 +30,8 @@ static constexpr auto make_alphabet()
static constexpr auto make_lookup_table()
{
constexpr auto alphabet = make_alphabet();
Array<u8, 256> table {};
Array<i16, 256> table;
table.fill(-1);
for (size_t i = 0; i < alphabet.size(); ++i) {
table[alphabet[i]] = i;
}
@ -50,19 +48,31 @@ size_t calculate_base64_encoded_length(ReadonlyBytes input)
return ((4 * input.size() / 3) + 3) & ~3;
}
ByteBuffer decode_base64(const StringView& input)
Optional<ByteBuffer> decode_base64(const StringView& input)
{
auto get = [&](const size_t offset, bool* is_padding = nullptr) -> u8 {
auto get = [&](const size_t offset, bool* is_padding) -> Optional<u8> {
constexpr auto table = make_lookup_table();
if (offset >= input.length())
return 0;
if (input[offset] == '=') {
if (is_padding)
*is_padding = true;
if (!is_padding)
return {};
*is_padding = true;
return 0;
}
return table[static_cast<unsigned char>(input[offset])];
i16 result = table[static_cast<unsigned char>(input[offset])];
if (result < 0)
return {};
VERIFY(result < 256);
return { result };
};
#define TRY_GET(index, is_padding) \
({ \
auto _temporary_result = get(index, is_padding); \
if (!_temporary_result.has_value()) \
return {}; \
_temporary_result.value(); \
})
Vector<u8> output;
output.ensure_capacity(calculate_base64_decoded_length(input));
@ -71,10 +81,10 @@ ByteBuffer decode_base64(const StringView& input)
bool in2_is_padding = false;
bool in3_is_padding = false;
const u8 in0 = get(i);
const u8 in1 = get(i + 1);
const u8 in2 = get(i + 2, &in2_is_padding);
const u8 in3 = get(i + 3, &in3_is_padding);
const u8 in0 = TRY_GET(i, nullptr);
const u8 in1 = TRY_GET(i + 1, nullptr);
const u8 in2 = TRY_GET(i + 2, &in2_is_padding);
const u8 in3 = TRY_GET(i + 3, &in3_is_padding);
const u8 out0 = (in0 << 2) | ((in1 >> 4) & 3);
const u8 out1 = ((in1 & 0xf) << 4) | ((in2 >> 2) & 0xf);
@ -87,8 +97,7 @@ ByteBuffer decode_base64(const StringView& input)
output.append(out2);
}
// FIXME: Handle OOM failure.
return ByteBuffer::copy(output).release_value();
return ByteBuffer::copy(output);
}
String encode_base64(ReadonlyBytes input)