feat(base64): decode

This commit is contained in:
2024-09-17 15:51:42 +03:00
parent 65a618639f
commit 5c8a211f46
2 changed files with 63 additions and 18 deletions

View File

@ -55,10 +55,13 @@ namespace base64
str_size = str_size * 4 + (data.size() % 3 ? 4 : 0);
return str_size;
}
// uint64_t sizeDecoded(std::string_view str) noexcept
// {
// }
uint64_t sizeDecoded(std::string_view str) noexcept
{
auto size = std::distance(str.begin(), std::find_if(str.rbegin(), str.rend(), [](char ch)
{ return ch != '='; })
.base());
return size / 4 * 3 + (size % 4 ? size % 4 - 1 : 0);
}
void encode(const uint8_t *data, uint64_t data_size, char *str, uint64_t str_size)
{
if (str_size < base64::sizeEncoded(std::span<const uint8_t>(data, data_size)))
@ -100,10 +103,48 @@ namespace base64
base64::encode(data.data(), data.size(), str.data(), str.size());
return str;
}
// void decode(const char *str, uint8_t *data, uint64_t data_size)
// {
// }
// std::vector<uint8_t> decode(std::string_view str)
// {
// }
void decode(const char *str, uint64_t str_size, uint8_t *data, uint64_t data_size)
{
std::string_view sv(str, str_size);
if (data_size < base64::sizeDecoded(sv))
{
throw std::logic_error("base64::decode: not enough allocated length");
}
if (!base64::isValid(sv))
{
throw std::logic_error("base64::decode: out of digits map");
}
auto size = std::distance(sv.begin(), std::find_if(sv.rbegin(), sv.rend(), [](char ch)
{ return ch != '='; })
.base());
if (sv.size() % 4 != 0 || sv.size() - size > 2)
{
throw std::logic_error("base64::decode: incorrect padding");
}
for (auto i = 0; i < size / 4; i++)
{
data[i * 3] = b64map[(int8_t)str[i * 4]] << 2 | b64map[(int8_t)str[i * 4 + 1]] >> 4;
data[i * 3 + 1] = b64map[(int8_t)str[i * 4 + 1]] << 4 | b64map[(int8_t)str[i * 4 + 2]] >> 2;
data[i * 3 + 2] = b64map[(int8_t)str[i * 4 + 2]] << 6 | b64map[(int8_t)str[i * 4 + 3]];
}
uint64_t last_idx = size / 4 * 3;
switch (size % 4)
{
case 2:
data[last_idx] = b64map[(int8_t)str[size - 2]] << 2 | b64map[(int8_t)str[size - 1]] >> 4;
break;
case 3:
data[last_idx] = b64map[(int8_t)str[size - 3]] << 2 | b64map[(int8_t)str[size - 2]] >> 4;
data[last_idx + 1] = b64map[(int8_t)str[size - 2]] << 4 | b64map[(int8_t)str[size - 1]] >> 2;
break;
default:
break;
}
}
std::vector<uint8_t> decode(std::string_view str) noexcept
{
std::vector<uint8_t> data(base64::sizeDecoded(str));
base64::decode(str.data(), str.size(), data.data(), data.size());
return data;
}
}

View File

@ -25,14 +25,18 @@ TEST(base64, encode_1e7)
std::vector<uint8_t> data(1e7);
encode(data);
}
// TEST(base64, decode)
// {
// }
// TEST(base64, decode_1e6)
// {
// std::string str(1e6, '0');
// decode(str);
// }
TEST(base64, decode)
{
EXPECT_EQ(hex::encode(decode("")), "");
EXPECT_EQ(hex::encode(decode("BKUEpQ==")), "04a504a5");
EXPECT_EQ(hex::encode(decode("BKUEpQA=")), "04a504a500");
EXPECT_EQ(hex::encode(decode("BKUEpQAA")), "04a504a50000");
}
TEST(base64, decode_1e7)
{
std::string str(1e7, '0');
decode(str);
}
int main(int argc, char **argv)
{