diff --git a/include/etl/base64.h b/include/etl/base64.h index bc661deb4..32217a964 100644 --- a/include/etl/base64.h +++ b/include/etl/base64.h @@ -30,6 +30,7 @@ SOFTWARE. #include "etl/platform.h" #include "etl/span.h" +#include "etl/static_assert.h" #include "etl/error_handler.h" #include "etl/exception.h" #include "etl/type_traits.h" @@ -37,9 +38,14 @@ SOFTWARE. #include "etl/algorithm.h" #include "etl/integral_limits.h" #include "etl/iterator.h" +#include "etl/string.h" #include +#if ETL_USING_STL + #include +#endif + namespace etl { //*************************************************************************** @@ -90,17 +96,9 @@ namespace etl } // Figure out if the output buffer is large enough. - size_t required_output_length = (input_length * 8U) / 6U; + size_t required_output_length = encode_size(input_length); - if ((input_length % 3U) != 0U) - { - while ((required_output_length % 4U) != 0) - { - ++required_output_length; - } - } - - ETL_ASSERT_OR_RETURN_VALUE(output_length >= required_output_length, ETL_ERROR(base64_overflow), etl::span()); + ETL_ASSERT_OR_RETURN_VALUE(output_length >= required_output_length, ETL_ERROR(base64_overflow), 0U); const T* p_in = input; const T* p_in_end = input + input_length; @@ -187,6 +185,19 @@ namespace etl return static_cast(etl::distance(output, p_out)); } + //************************************************************************* + /// Encode to Base64 from and to pointer/pointer + //************************************************************************* + template + ETL_CONSTEXPR14 + static + typename etl::enable_if::value && (etl::integral_limits::bits == 8U), size_t>::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)), + output_begin, static_cast(etl::distance(output_begin, output_end))); + } + //************************************************************************* /// Encode to Base64 from and to span/span //************************************************************************* @@ -202,16 +213,51 @@ namespace etl } //************************************************************************* - /// Encode to Base64 from and to pointer/pointer + /// Encode to Base64 from pointer/length to etl::istring //************************************************************************* template ETL_CONSTEXPR14 static typename etl::enable_if::value && (etl::integral_limits::bits == 8U), size_t>::type - encode(const T* input_begin, const T* input_end, char* output_begin, char* output_end) + encode(const T* input_begin, size_t input_length, + etl::istring& output) { - return encode(input_begin, static_cast(etl::distance(input_begin, input_end)), - output_begin, static_cast(etl::distance(output_begin, output_end))); + output.resize(etl::base64::encode_size(input_length)); + + return encode(input_begin, input_length, + output.data(), output.size()); + } + + //************************************************************************* + /// Encode to Base64 from pointer/pointer to etl::istring + //************************************************************************* + template + ETL_CONSTEXPR14 + static + typename etl::enable_if::value && (etl::integral_limits::bits == 8U), size_t>::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))); + + return encode(input_begin, static_cast(etl::distance(input_begin, input_end)), + output.data(), output.size()); + } + + //************************************************************************* + /// Encode to Base64 from span to etl::istring + //************************************************************************* + template + ETL_CONSTEXPR14 + static + typename etl::enable_if::value && (etl::integral_limits::bits == 8U), size_t>::type + encode(const etl::span& input_span, + etl::istring& output) + { + output.resize(etl::base64::encode_size(Length1)); + + return encode(input_span.begin(), input_span.size(), + output.data(), output.size()); } //************************************************************************* @@ -250,10 +296,9 @@ namespace etl } // Figure out if the output buffer is large enough. - size_t length = static_cast(etl::distance(input, etl::find(input, input + input_length, padding())) - 1); - size_t required_output_length = length - (length / 4U); + size_t required_output_length = etl::base64::decode_size(input, input_length); - ETL_ASSERT_OR_RETURN_VALUE(output_length >= required_output_length, ETL_ERROR(base64_overflow), etl::span()); + ETL_ASSERT_OR_RETURN_VALUE(output_length >= required_output_length, ETL_ERROR(base64_overflow), 0U); const char* p_in = input; const char* p_in_end = input + input_length; @@ -328,30 +373,30 @@ namespace etl } //************************************************************************* - /// Decode from Base64 from and to span/span + /// Decode from Base64 from and to pointer/pointer //************************************************************************* - template + template ETL_CONSTEXPR14 static typename etl::enable_if::value && (etl::integral_limits::bits == 8U), size_t>::type - decode(const etl::span& input_span, - const etl::span& output_span) + decode(const char* input_begin, const char* input_end, T* output_begin, T* output_end) { - return decode(input_span.begin(), input_span.size(), - output_span.begin(), output_span.size()); + return decode(input_begin, static_cast(etl::distance(input_begin, input_end)), + output_begin, static_cast(etl::distance(output_begin, output_end))); } //************************************************************************* - /// Decode from Base64 from and to pointer/pointer + /// Decode from Base64 from and to span/span //************************************************************************* - template + template ETL_CONSTEXPR14 - static - typename etl::enable_if::value && (etl::integral_limits::bits == 8U), size_t>::type - decode(const char* input_begin, const char* input_end, T* output_begin, T* output_end) + static + typename etl::enable_if::value && (etl::integral_limits::bits == 8U), size_t>::type + decode(const etl::span& input_span, + const etl::span& output_span) { - return decode(input_begin, static_cast(etl::distance(input_begin, input_end)), - output_begin, static_cast(etl::distance(output_begin, output_end))); + return decode(input_span.begin(), input_span.size(), + output_span.begin(), output_span.size()); } //************************************************************************* diff --git a/include/etl/basic_string.h b/include/etl/basic_string.h index cfeaf0717..05d79d3fe 100644 --- a/include/etl/basic_string.h +++ b/include/etl/basic_string.h @@ -173,7 +173,7 @@ namespace etl /// Gets the current size of the string. ///\return The current size of the string. //************************************************************************* - size_type size() const + ETL_CONSTEXPR size_type size() const { return current_size; } @@ -605,7 +605,7 @@ namespace etl /// Returns a const pointer to the beginning of the string data. ///\return A const pointer to the beginning of the string data. //********************************************************************* - const_pointer data() const + ETL_CONSTEXPR const_pointer data() const { return p_buffer; } diff --git a/include/etl/vector.h b/include/etl/vector.h index 23d332976..af236dc7f 100644 --- a/include/etl/vector.h +++ b/include/etl/vector.h @@ -365,7 +365,7 @@ namespace etl /// Returns a const pointer to the beginning of the vector data. ///\return A const pointer to the beginning of the vector data. //********************************************************************* - const_pointer data() const + ETL_CONSTEXPR const_pointer data() const { return p_buffer; } @@ -974,7 +974,7 @@ namespace etl /// Gets the current size of the vector. ///\return The current size of the vector. //************************************************************************* - size_type size() const + ETL_CONSTEXPR size_type size() const { return size_t(p_end - p_buffer); } diff --git a/test/test_base64.cpp b/test/test_base64.cpp index 470cbca71..b26423e4c 100644 --- a/test/test_base64.cpp +++ b/test/test_base64.cpp @@ -30,6 +30,9 @@ SOFTWARE. #include "etl/base64.h" +#include "etl/string.h" +#include "etl/vector.h" + #include #include #include @@ -349,8 +352,8 @@ namespace { encoded_output.fill(0); - auto size = etl::base64::encode(input_data_unsigned_char.data(), i, - encoded_output.data(), encoded_output.size()); + auto size = etl::base64::encode(input_data_unsigned_char.data(), i, + encoded_output.data(), encoded_output.size()); std::string expected(encoded[i]); std::string actual(encoded_output.data(), size); @@ -369,8 +372,8 @@ namespace { encoded_output.fill(0); - auto size = etl::base64::encode(input_data_unsigned_char.data(), input_data_unsigned_char.data() + i, - encoded_output.data(), encoded_output.data() + encoded_output.size()); + auto size = etl::base64::encode(input_data_unsigned_char.data(), input_data_unsigned_char.data() + i, + encoded_output.data(), encoded_output.data() + encoded_output.size()); std::string expected(encoded[i]); std::string actual(encoded_output.data(), size); @@ -402,6 +405,130 @@ namespace } } + //************************************************************************* + TEST(test_encode_unsigned_char_pointer_size_to_etl_string) + { + etl::string<344U> encoded_output; + + for (size_t i = 0; i < 256; ++i) + { + encoded_output.clear(); + + auto size = etl::base64::encode(input_data_unsigned_char.data(), i, + encoded_output); + + std::string expected(encoded[i]); + std::string actual(encoded_output.data(), size); + + CHECK_EQUAL(expected, actual); + CHECK_EQUAL(etl::base64::encode_size(i), size); + } + } + + //************************************************************************* + TEST(test_encode_unsigned_char_pointer_pointer_to_etl_string) + { + etl::string<344U> encoded_output; + + for (size_t i = 0; i < 256; ++i) + { + encoded_output.clear(); + + auto size = etl::base64::encode(input_data_unsigned_char.data(), input_data_unsigned_char.data() + i, + encoded_output); + + std::string expected(encoded[i]); + std::string actual(encoded_output.data(), size); + + CHECK_EQUAL(expected, actual); + CHECK_EQUAL(etl::base64::encode_size(i), size); + } + } + + //************************************************************************* + TEST(test_encode_unsigned_char_span_to_etl_string) + { + etl::string<344U> encoded_output; + + for (size_t i = 0; i < 256; ++i) + { + encoded_output.clear(); + + etl::span input_span(input_data_unsigned_char.data(), i); + + auto size = etl::base64::encode(input_span, + encoded_output); + + std::string expected(encoded[i]); + std::string actual(encoded_output.data(), size); + + CHECK_EQUAL(expected, actual); + CHECK_EQUAL(etl::base64::encode_size(i), size); + } + } + + //************************************************************************* + TEST(test_encode_int8_t_pointer_size_to_etl_string) + { + etl::string<344U> encoded_output; + + for (size_t i = 0; i < 256; ++i) + { + encoded_output.clear(); + + auto size = etl::base64::encode(input_data_int8_t.data(), i, + encoded_output); + + std::string expected(encoded[i]); + std::string actual(encoded_output.data(), size); + + CHECK_EQUAL(expected, actual); + CHECK_EQUAL(etl::base64::encode_size(i), size); + } + } + + //************************************************************************* + TEST(test_encode_int8_t_pointer_pointer_to_etl_string) + { + etl::string<344U> encoded_output; + + for (size_t i = 0; i < 256; ++i) + { + encoded_output.clear(); + + auto size = etl::base64::encode(input_data_int8_t.data(), input_data_int8_t.data() + i, + encoded_output); + + std::string expected(encoded[i]); + std::string actual(encoded_output.data(), size); + + CHECK_EQUAL(expected, actual); + CHECK_EQUAL(etl::base64::encode_size(i), size); + } + } + + //************************************************************************* + TEST(test_encode_int8_t_span_to_etl_string) + { + etl::string<344U> encoded_output; + + for (size_t i = 0; i < 256; ++i) + { + encoded_output.clear(); + + etl::span input_span(input_data_int8_t.data(), i); + + auto size = etl::base64::encode(input_span, + encoded_output); + + std::string expected(encoded[i]); + std::string actual(encoded_output.data(), size); + + CHECK_EQUAL(expected, actual); + CHECK_EQUAL(etl::base64::encode_size(i), size); + } + } + //************************************************************************* TEST(test_encode_int8_t_pointer_size) { @@ -411,8 +538,8 @@ namespace { encoded_output.fill(0); - auto size = etl::base64::encode(input_data_int8_t.data(), i, - encoded_output.data(), encoded_output.size()); + auto size = etl::base64::encode(input_data_int8_t.data(), i, + encoded_output.data(), encoded_output.size()); std::string expected(encoded[i]); std::string actual(encoded_output.data(), size); @@ -431,8 +558,8 @@ namespace { encoded_output.fill(0); - auto size = etl::base64::encode(input_data_int8_t.data(), input_data_int8_t.data() + i, - encoded_output.data(), encoded_output.data() + encoded_output.size()); + auto size = etl::base64::encode(input_data_int8_t.data(), input_data_int8_t.data() + i, + encoded_output.data(), encoded_output.data() + encoded_output.size()); std::string expected(encoded[i]); std::string actual(encoded_output.data(), size); @@ -472,8 +599,8 @@ namespace constexpr size_t encode_size = etl::base64::encode_size(Size); etl::array output{ 0 }; - etl::base64::encode(input.begin(), Size, - output._buffer, encode_size); + etl::base64::encode(input.begin(), Size, + output._buffer, encode_size); return output; } @@ -497,8 +624,16 @@ namespace { std::array encoded_output{ 0 }; - CHECK_THROW((etl::base64::encode(input_data_unsigned_char.data(), 10, - encoded_output.data(), encoded_output.size())), etl::base64_overflow); + CHECK_THROW((etl::base64::encode(input_data_unsigned_char.data(), 10, + encoded_output.data(), encoded_output.size())), etl::base64_overflow); + } + + //************************************************************************* + TEST(test_encode_overflow_for_etl_string) + { + etl::string<10> output; + + CHECK_THROW((etl::base64::encode(input_data_unsigned_char.data(), 10, output)), etl::base64_overflow); } //************************************************************************* @@ -510,8 +645,8 @@ namespace { decoded_output.fill(0); - auto decoded_size = etl::base64::decode(encoded[i].data(), encoded[i].size(), - decoded_output.data(), decoded_output.size()); + auto decoded_size = etl::base64::decode(encoded[i].data(), encoded[i].size(), + 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())); @@ -528,8 +663,8 @@ namespace { decoded_output.fill(0); - auto decoded_size = etl::base64::decode(encoded[i].data(), encoded[i].size(), - decoded_output.data(), decoded_output.size()); + auto decoded_size = etl::base64::decode(encoded[i].data(), encoded[i].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())); @@ -542,8 +677,8 @@ 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); + CHECK_THROW((etl::base64::decode(encoded[10].data(), encoded[10].size(), + decoded_output.data(), decoded_output.size())), etl::base64_overflow); } }; }