| 13746 | |
| 13747 | template <typename chartype> |
| 13748 | simdutf_warn_unused simdutf_constexpr23 result base64_to_binary_safe_impl( |
| 13749 | const chartype *input, size_t length, char *output, size_t &outlen, |
| 13750 | base64_options options, |
| 13751 | last_chunk_handling_options last_chunk_handling_options, |
| 13752 | bool decode_up_to_bad_char) noexcept { |
| 13753 | static_assert(std::is_same<chartype, char>::value || |
| 13754 | std::is_same<chartype, char16_t>::value, |
| 13755 | "Only char and char16_t are supported."); |
| 13756 | size_t remaining_input_length = length; |
| 13757 | size_t remaining_output_length = outlen; |
| 13758 | size_t input_position = 0; |
| 13759 | size_t output_position = 0; |
| 13760 | |
| 13761 | // We also do a first pass using the fast path to decode as much as possible |
| 13762 | size_t safe_input = (std::min)( |
| 13763 | remaining_input_length, |
| 13764 | base64_length_from_binary(remaining_output_length / 3 * 3, options)); |
| 13765 | bool done_with_partial = (safe_input == remaining_input_length); |
| 13766 | simdutf::full_result r; |
| 13767 | |
| 13768 | #if SIMDUTF_CPLUSPLUS23 |
| 13769 | if consteval { |
| 13770 | r = scalar::base64::base64_to_binary_details_impl( |
| 13771 | input + input_position, safe_input, output + output_position, options, |
| 13772 | done_with_partial |
| 13773 | ? last_chunk_handling_options |
| 13774 | : simdutf::last_chunk_handling_options::only_full_chunks); |
| 13775 | } else |
| 13776 | #endif |
| 13777 | { |
| 13778 | r = get_active_implementation()->base64_to_binary_details( |
| 13779 | input + input_position, safe_input, output + output_position, options, |
| 13780 | done_with_partial |
| 13781 | ? last_chunk_handling_options |
| 13782 | : simdutf::last_chunk_handling_options::only_full_chunks); |
| 13783 | } |
| 13784 | simdutf_log_assert(r.input_count <= safe_input, |
| 13785 | "You should not read more than safe_input"); |
| 13786 | simdutf_log_assert(r.output_count <= remaining_output_length, |
| 13787 | "You should not write more than remaining_output_length"); |
| 13788 | // Technically redundant, but we want to be explicit about it. |
| 13789 | input_position += r.input_count; |
| 13790 | output_position += r.output_count; |
| 13791 | remaining_input_length -= r.input_count; |
| 13792 | remaining_output_length -= r.output_count; |
| 13793 | if (r.error != simdutf::error_code::SUCCESS) { |
| 13794 | // There is an error. We return. |
| 13795 | if (decode_up_to_bad_char && |
| 13796 | r.error == error_code::INVALID_BASE64_CHARACTER) { |
| 13797 | return slow_base64_to_binary_safe_impl( |
| 13798 | input, length, output, outlen, options, last_chunk_handling_options); |
| 13799 | } |
| 13800 | outlen = output_position; |
| 13801 | return {r.error, input_position}; |
| 13802 | } |
| 13803 | |
| 13804 | if (done_with_partial) { |
| 13805 | // We are done. We have decoded everything. |
no test coverage detected