diff options
Diffstat (limited to 'ext/sqlite_modern_cpp/sqlite_modern_cpp/utility/utf16_utf8.h')
-rw-r--r-- | ext/sqlite_modern_cpp/sqlite_modern_cpp/utility/utf16_utf8.h | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/ext/sqlite_modern_cpp/sqlite_modern_cpp/utility/utf16_utf8.h b/ext/sqlite_modern_cpp/sqlite_modern_cpp/utility/utf16_utf8.h new file mode 100644 index 0000000..ea21723 --- /dev/null +++ b/ext/sqlite_modern_cpp/sqlite_modern_cpp/utility/utf16_utf8.h @@ -0,0 +1,42 @@ +#pragma once + +#include <locale> +#include <string> +#include <algorithm> + +#include "../errors.h" + +namespace sqlite { + namespace utility { + inline std::string utf16_to_utf8(const std::u16string &input) { + struct : std::codecvt<char16_t, char, std::mbstate_t> { + } codecvt; + std::mbstate_t state{}; + std::string result((std::max)(input.size() * 3 / 2, std::size_t(4)), '\0'); + const char16_t *remaining_input = input.data(); + std::size_t produced_output = 0; + while(true) { + char *used_output; + switch(codecvt.out(state, remaining_input, &input[input.size()], + remaining_input, &result[produced_output], + &result[result.size() - 1] + 1, used_output)) { + case std::codecvt_base::ok: + result.resize(used_output - result.data()); + return result; + case std::codecvt_base::noconv: + // This should be unreachable + case std::codecvt_base::error: + throw errors::invalid_utf16("Invalid UTF-16 input", ""); + case std::codecvt_base::partial: + if(used_output == result.data() + produced_output) + throw errors::invalid_utf16("Unexpected end of input", ""); + produced_output = used_output - result.data(); + result.resize( + result.size() + + (std::max)((&input[input.size()] - remaining_input) * 3 / 2, + std::ptrdiff_t(4))); + } + } + } + } // namespace utility +} // namespace sqlite |