From 1993ee410db04ab04efecc84bcfc4f21d60ef90c Mon Sep 17 00:00:00 2001 From: SEK1RO Date: Mon, 16 Sep 2024 20:59:12 +0300 Subject: [PATCH] feat(base64): encode --- include/base/base64.hpp | 8 +++---- src/base64.cpp | 51 ++++++++++++++++++++++++++++++++++------- test/test-base64.cpp | 20 +++++++++------- 3 files changed, 59 insertions(+), 20 deletions(-) diff --git a/include/base/base64.hpp b/include/base/base64.hpp index c745128..2e37b71 100644 --- a/include/base/base64.hpp +++ b/include/base/base64.hpp @@ -7,12 +7,12 @@ namespace base64 { - bool isValid(const char *str) noexcept; + bool isValid(const char *str, size_t str_size) noexcept; bool isValid(std::string_view str) noexcept; - void encode(const uint8_t *data, uint64_t data_size, char *str) noexcept; + void encode(const uint8_t *data, size_t data_size, char *str, size_t str_size); std::string encode(std::span data) noexcept; - void decode(const char *str, uint8_t *data, uint64_t data_size); - std::vector decode(std::string_view str); + void decode(const char *str, size_t str_size, uint8_t *data, size_t data_size); + std::vector decode(std::string_view str) noexcept; } \ No newline at end of file diff --git a/src/base64.cpp b/src/base64.cpp index aa98dbd..784cc55 100644 --- a/src/base64.cpp +++ b/src/base64.cpp @@ -29,9 +29,9 @@ static const int8_t b64map[] = { namespace base64 { - bool isValid(const char *str) noexcept + bool isValid(const char *str, size_t str_size) noexcept { - return base64::isValid(std::string_view(str)); + return base64::isValid(std::string_view(str, str_size)); } bool isValid(std::string_view str) noexcept { @@ -44,12 +44,47 @@ namespace base64 } return baseN::isValid(sv, b64map); } - // void encode(const uint8_t *data, uint64_t data_size, char *str) noexcept - // { - // } - // std::string encode(std::span data) noexcept - // { - // } + void encode(const uint8_t *data, size_t data_size, char *str, size_t str_size) + { + if (str_size < data_size / 3 * 4 + (data_size % 3 ? 4 : 0)) + { + throw std::logic_error("base64::encode: not enough allocated length"); + } + for (size_t i = 0; i < data_size / 3; i++) + { + str[i * 4] = b64digits[data[i * 3] >> 2]; + str[i * 4 + 1] = b64digits[(data[i * 3] << 4 | data[i * 3 + 1] >> 4) & 0x3F]; + str[i * 4 + 2] = b64digits[(data[i * 3 + 1] << 2 | data[i * 3 + 2] >> 6) & 0x3F]; + str[i * 4 + 3] = b64digits[data[i * 3 + 2] & 0x3F]; + } + uint64_t last_idx = data_size / 3 * 4; + if (last_idx + 3 < str_size) + { + switch (data_size % 3) + { + case 1: + str[last_idx] = b64digits[data[data_size - 1] >> 2]; + str[last_idx + 1] = b64digits[data[data_size - 1] << 4 & 0x30]; + str[last_idx + 2] = '='; + str[last_idx + 3] = '='; + break; + case 2: + str[last_idx] = b64digits[data[data_size - 2] >> 2]; + str[last_idx + 1] = b64digits[(data[data_size - 2] << 4 | data[data_size - 1] >> 4) & 0x3F]; + str[last_idx + 2] = b64digits[data[data_size - 1] & 0x0F]; + str[last_idx + 3] = '='; + break; + default: + break; + } + } + } + std::string encode(std::span data) noexcept + { + std::string str(data.size() / 3 * 4 + (data.size() % 3 ? 4 : 0), ' '); + base64::encode(data.data(), data.size(), str.data(), str.size()); + return str; + } // void decode(const char *str, uint8_t *data, uint64_t data_size) // { // } diff --git a/test/test-base64.cpp b/test/test-base64.cpp index 0e053f5..b452011 100644 --- a/test/test-base64.cpp +++ b/test/test-base64.cpp @@ -13,14 +13,18 @@ TEST(base64, isValid) EXPECT_FALSE(isValid("1===")); EXPECT_FALSE(isValid("?!*")); } -// TEST(base64, encode) -// { -// } -// TEST(base64, encode_1e6) -// { -// std::vector data(1e6); -// encode(data); -// } +TEST(base64, encode) +{ + EXPECT_EQ(encode(hex::decode("")), ""); + EXPECT_EQ(encode(hex::decode("04a504a5")), "BKUEpQ=="); + EXPECT_EQ(encode(hex::decode("04a504a500")), "BKUEpQA="); + EXPECT_EQ(encode(hex::decode("04a504a50000")), "BKUEpQAA"); +} +TEST(base64, encode_1e7) +{ + std::vector data(1e7); + encode(data); +} // TEST(base64, decode) // { // }