diff --git a/include/etl/base64.h b/include/etl/base64.h index 32217a96..220632c7 100644 --- a/include/etl/base64.h +++ b/include/etl/base64.h @@ -46,6 +46,8 @@ SOFTWARE. #include #endif +#define ETL_IS_8_BIT_INTEGRAL(Type) (etl::is_integral::value && (etl::integral_limits::bits == 8U)) + namespace etl { //*************************************************************************** @@ -87,7 +89,7 @@ namespace etl template ETL_CONSTEXPR14 static - typename etl::enable_if::value && (etl::integral_limits::bits == 8U), size_t>::type + typename etl::enable_if::type encode(const T* input, size_t input_length, char* output, size_t output_length) { if (input_length == 0U) @@ -96,7 +98,7 @@ namespace etl } // Figure out if the output buffer is large enough. - size_t required_output_length = encode_size(input_length); + size_t required_output_length = encoded_size(input_length); ETL_ASSERT_OR_RETURN_VALUE(output_length >= required_output_length, ETL_ERROR(base64_overflow), 0U); @@ -190,8 +192,8 @@ namespace etl //************************************************************************* template ETL_CONSTEXPR14 - static - typename etl::enable_if::value && (etl::integral_limits::bits == 8U), size_t>::type + static + typename etl::enable_if::type encode(const T* input_begin, const T* input_end, char* output_begin, char* output_end) { return encode(input_begin, static_cast(etl::distance(input_begin, input_end)), @@ -204,7 +206,7 @@ namespace etl template ETL_CONSTEXPR14 static - typename etl::enable_if::value && (etl::integral_limits::bits == 8U), size_t>::type + typename etl::enable_if::type encode(const etl::span& input_span, const etl::span& output_span) { @@ -218,11 +220,11 @@ namespace etl template ETL_CONSTEXPR14 static - typename etl::enable_if::value && (etl::integral_limits::bits == 8U), size_t>::type + typename etl::enable_if::type encode(const T* input_begin, size_t input_length, etl::istring& output) { - output.resize(etl::base64::encode_size(input_length)); + output.resize(etl::base64::encoded_size(input_length)); return encode(input_begin, input_length, output.data(), output.size()); @@ -234,11 +236,11 @@ namespace etl template ETL_CONSTEXPR14 static - typename etl::enable_if::value && (etl::integral_limits::bits == 8U), size_t>::type + typename etl::enable_if::type encode(const T* input_begin, const T* input_end, etl::istring& output) { - output.resize(etl::base64::encode_size(etl::distance(input_begin, input_end))); + output.resize(etl::base64::encoded_size(etl::distance(input_begin, input_end))); return encode(input_begin, static_cast(etl::distance(input_begin, input_end)), output.data(), output.size()); @@ -250,11 +252,11 @@ namespace etl template ETL_CONSTEXPR14 static - typename etl::enable_if::value && (etl::integral_limits::bits == 8U), size_t>::type + typename etl::enable_if::type encode(const etl::span& input_span, etl::istring& output) { - output.resize(etl::base64::encode_size(Length1)); + output.resize(etl::base64::encoded_size(Length1)); return encode(input_span.begin(), input_span.size(), output.data(), output.size()); @@ -266,16 +268,13 @@ namespace etl ETL_NODISCARD ETL_CONSTEXPR14 static - size_t encode_size(size_t input_length) + size_t encoded_size(size_t input_length) { size_t required_output_length = (input_length * 8U) / 6U; - if ((input_length % 3U) != 0U) + while ((required_output_length % 4U) != 0) { - while ((required_output_length % 4U) != 0) - { - ++required_output_length; - } + ++required_output_length; } return required_output_length; @@ -287,7 +286,7 @@ namespace etl template ETL_CONSTEXPR14 static - typename etl::enable_if::value && (etl::integral_limits::bits == 8U), size_t>::type + typename etl::enable_if::type decode(const char* input, size_t input_length, T* output, size_t output_length) { if (input_length == 0) @@ -296,7 +295,7 @@ namespace etl } // Figure out if the output buffer is large enough. - size_t required_output_length = etl::base64::decode_size(input, input_length); + size_t required_output_length = etl::base64::decoded_size(input, input_length); ETL_ASSERT_OR_RETURN_VALUE(output_length >= required_output_length, ETL_ERROR(base64_overflow), 0U); @@ -378,7 +377,7 @@ namespace etl template ETL_CONSTEXPR14 static - typename etl::enable_if::value && (etl::integral_limits::bits == 8U), size_t>::type + typename etl::enable_if::type decode(const char* input_begin, const char* input_end, T* output_begin, T* output_end) { return decode(input_begin, static_cast(etl::distance(input_begin, input_end)), @@ -390,8 +389,8 @@ namespace etl //************************************************************************* template ETL_CONSTEXPR14 - static - typename etl::enable_if::value && (etl::integral_limits::bits == 8U), size_t>::type + static + typename etl::enable_if::type decode(const etl::span& input_span, const etl::span& output_span) { @@ -404,7 +403,7 @@ namespace etl //************************************************************************* ETL_NODISCARD ETL_CONSTEXPR14 - static size_t decode_size(const char* input, size_t input_length) + static size_t decoded_size(const char* input, size_t input_length) { if (input_length == 0U) { @@ -418,6 +417,27 @@ namespace etl return required_output_length; } + //************************************************************************* + /// Calculates the buffer size required to decode from Base64 + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + static size_t decoded_size(const char* input_begin, const char* input_end) + { + return decoded_size(input_begin, static_cast(etl::distance(input_begin, input_end))); + } + + //************************************************************************* + /// Calculates the buffer size required to decode from Base64 + //************************************************************************* + template + ETL_NODISCARD + ETL_CONSTEXPR14 + static size_t decoded_size(etl::span sp) + { + return decoded_size(sp.begin(), sp.size()); + } + private: //************************************************************************* @@ -520,4 +540,6 @@ namespace etl }; } +#undef ETL_IS_8_BIT_INTEGRAL + #endif diff --git a/test/test_base64.cpp b/test/test_base64.cpp index b26423e4..409a6c63 100644 --- a/test/test_base64.cpp +++ b/test/test_base64.cpp @@ -359,7 +359,7 @@ namespace std::string actual(encoded_output.data(), size); CHECK_EQUAL(expected, actual); - CHECK_EQUAL(etl::base64::encode_size(i), size); + CHECK_EQUAL(etl::base64::encoded_size(i), size); } } @@ -379,7 +379,7 @@ namespace std::string actual(encoded_output.data(), size); CHECK_EQUAL(expected, actual); - CHECK_EQUAL(etl::base64::encode_size(i), size); + CHECK_EQUAL(etl::base64::encoded_size(i), size); } } @@ -401,7 +401,7 @@ namespace std::string actual(encoded_output.data(), size); CHECK_EQUAL(expected, actual); - CHECK_EQUAL(etl::base64::encode_size(i), size); + CHECK_EQUAL(etl::base64::encoded_size(i), size); } } @@ -421,7 +421,7 @@ namespace std::string actual(encoded_output.data(), size); CHECK_EQUAL(expected, actual); - CHECK_EQUAL(etl::base64::encode_size(i), size); + CHECK_EQUAL(etl::base64::encoded_size(i), size); } } @@ -441,7 +441,7 @@ namespace std::string actual(encoded_output.data(), size); CHECK_EQUAL(expected, actual); - CHECK_EQUAL(etl::base64::encode_size(i), size); + CHECK_EQUAL(etl::base64::encoded_size(i), size); } } @@ -463,7 +463,7 @@ namespace std::string actual(encoded_output.data(), size); CHECK_EQUAL(expected, actual); - CHECK_EQUAL(etl::base64::encode_size(i), size); + CHECK_EQUAL(etl::base64::encoded_size(i), size); } } @@ -483,7 +483,7 @@ namespace std::string actual(encoded_output.data(), size); CHECK_EQUAL(expected, actual); - CHECK_EQUAL(etl::base64::encode_size(i), size); + CHECK_EQUAL(etl::base64::encoded_size(i), size); } } @@ -503,7 +503,7 @@ namespace std::string actual(encoded_output.data(), size); CHECK_EQUAL(expected, actual); - CHECK_EQUAL(etl::base64::encode_size(i), size); + CHECK_EQUAL(etl::base64::encoded_size(i), size); } } @@ -525,7 +525,7 @@ namespace std::string actual(encoded_output.data(), size); CHECK_EQUAL(expected, actual); - CHECK_EQUAL(etl::base64::encode_size(i), size); + CHECK_EQUAL(etl::base64::encoded_size(i), size); } } @@ -545,7 +545,7 @@ namespace std::string actual(encoded_output.data(), size); CHECK_EQUAL(expected, actual); - CHECK_EQUAL(etl::base64::encode_size(i), size); + CHECK_EQUAL(etl::base64::encoded_size(i), size); } } @@ -565,7 +565,7 @@ namespace std::string actual(encoded_output.data(), size); CHECK_EQUAL(expected, actual); - CHECK_EQUAL(etl::base64::encode_size(i), size); + CHECK_EQUAL(etl::base64::encoded_size(i), size); } } @@ -587,7 +587,7 @@ namespace std::string actual(encoded_output.data(), size); CHECK_EQUAL(expected, actual); - CHECK_EQUAL(etl::base64::encode_size(i), size); + CHECK_EQUAL(etl::base64::encoded_size(i), size); } } @@ -596,11 +596,11 @@ namespace template constexpr auto GetConstexprBase64(const etl::array input) noexcept { - constexpr size_t encode_size = etl::base64::encode_size(Size); - etl::array output{ 0 }; + constexpr size_t encoded_size = etl::base64::encoded_size(Size); + etl::array output{ 0 }; etl::base64::encode(input.begin(), Size, - output._buffer, encode_size); + output._buffer, encoded_size); return output; } @@ -615,7 +615,7 @@ namespace std::string actual(output.data(), output.size()); CHECK_EQUAL(expected, actual); - CHECK_EQUAL(etl::base64::encode_size(10), output.size()); + CHECK_EQUAL(etl::base64::encoded_size(10), output.size()); } #endif @@ -649,7 +649,7 @@ namespace decoded_output.data(), decoded_output.size()); CHECK_ARRAY_EQUAL(input_data_unsigned_char.data(), decoded_output.data(), i); - CHECK_EQUAL(i, etl::base64::decode_size(encoded[i].data(), encoded[i].size())); + CHECK_EQUAL(i, etl::base64::decoded_size(encoded[i].data(), encoded[i].size())); CHECK_EQUAL(i, decoded_size); } } @@ -664,10 +664,10 @@ namespace decoded_output.fill(0); auto decoded_size = etl::base64::decode(encoded[i].data(), encoded[i].size(), - decoded_output.data(), decoded_output.size()); + decoded_output.data(), decoded_output.size()); CHECK_ARRAY_EQUAL(input_data_int8_t.data(), decoded_output.data(), i); - CHECK_EQUAL(i, etl::base64::decode_size(encoded[i].data(), encoded[i].size())); + CHECK_EQUAL(i, etl::base64::decoded_size(encoded[i].data(), encoded[i].size())); CHECK_EQUAL(i, decoded_size); } } @@ -678,7 +678,21 @@ namespace std::array decoded_output{ 0 }; CHECK_THROW((etl::base64::decode(encoded[10].data(), encoded[10].size(), - decoded_output.data(), decoded_output.size())), etl::base64_overflow); + decoded_output.data(), decoded_output.size())), etl::base64_overflow); + } + + //************************************************************************* + TEST(test_decoded_size) + { + for (size_t i = 0; i < 256; ++i) + { + size_t length = etl::base64::decoded_size(encoded[i].data(), encoded[i].size()); + + CHECK_EQUAL(length, etl::base64::decoded_size(encoded[i].data(), encoded[i].data() + encoded[i].size())); + + etl::span sp(encoded[i].data(), encoded[i].size()); + CHECK_EQUAL(length, etl::base64::decoded_size(sp)); + } } }; }