diff --git a/src/yycc/encoding/iconv.cpp b/src/yycc/encoding/iconv.cpp index 728c807..66407ec 100644 --- a/src/yycc/encoding/iconv.cpp +++ b/src/yycc/encoding/iconv.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #define NS_YYCC_STRING ::yycc::string @@ -104,61 +105,46 @@ namespace yycc::encoding::iconv { #pragma region Kernel - // YYC MARK: - // Use std::monostate to simulate std::expected. - constexpr const size_t ICONV_INC_LEN = 16u; constexpr size_t ICONV_ERR_RV = static_cast(-1); // Reference: https://stackoverflow.com/questions/13297458/simple-utf8-utf16-string-conversion-with-iconv - static ConvResult iconv_kernel( - const Token& token, const uint8_t* arg_inbuf, size_t arg_inbytes, uint8_t** arg_outbuf, size_t* arg_outbytes) { -#define SETUP_RV(buf, len) \ - *arg_outbuf = (buf); \ - *arg_outbytes = (len); - + static ConvResult> iconv_kernel(const Token& token, const uint8_t* str_from_buf, size_t str_from_len) { // ===== Check Requirements ===== + // Prepare return value + std::vector str_to; + // Unwrap and check iconv_t that_iconv_t cd = token.get_inner()->get_inner(); if (cd == INVALID_ICONV_TOKEN) return ConvError::InvalidCd; - // Check nullptr output variables - if (arg_outbuf == nullptr || arg_outbytes == nullptr) return ConvError::NullPointer; // Check empty input - if (arg_inbytes == 0u) { - SETUP_RV(nullptr, 0u); - return {}; - } + if (str_from_len == 0u) return str_to; // Check nullptr input variables - if (arg_inbuf == nullptr) return ConvError::NullPointer; + if (str_from_buf == nullptr) return ConvError::NullPointer; // ===== Do Iconv ===== // setup input variables - size_t inbytesleft = arg_inbytes; - const char* inbuf = reinterpret_cast(arg_inbuf); + size_t inbytesleft = str_from_len; + const char* inbuf = reinterpret_cast(str_from_buf); // pre-allocation output variables - size_t outbytesall = arg_inbytes + ICONV_INC_LEN; - char* outbufbase = static_cast(std::malloc(outbytesall)); - if (outbufbase == nullptr) throw std::bad_alloc(); - size_t outbytesleft = outbytesall; - char* outbuf = outbufbase; + str_to.resize(str_from_len + ICONV_INC_LEN); + size_t outbytesleft = str_to.size(); + char* outbuf = reinterpret_cast(str_to.data()); // conv core size_t nchars = that_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); while (nchars == ICONV_ERR_RV && errno == E2BIG) { // record the length has been converted - size_t len = outbuf - str_to.data(); + size_t len = outbuf - reinterpret_cast(str_to.data()); - // resize for variables - outbytesall += ICONV_INC_LEN; - outbytesleft += ICONV_INC_LEN; - - // resize for container - str_to.resize(outbytesall); + // resize for container and its variables + str_to.resize(str_to.size() + ICONV_INC_LEN); + outbytesleft = str_to.size(); // assign new outbuf from failed position - outbuf = str_to.data() + len; + outbuf = reinterpret_cast(str_to.data()) + len; nchars = that_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); } @@ -167,9 +153,6 @@ namespace yycc::encoding::iconv { // check error if (nchars == ICONV_ERR_RV) { - // Free allocated buffer - std::free(outbufbase); - if (errno == EILSEQ) { return ConvError::InvalidMbSeq; } else if (errno == EINVAL) { @@ -180,11 +163,9 @@ namespace yycc::encoding::iconv { } else { // success // compute result data - SETUP_RV(reinterpret_cast(outbufbase), outbytesall - outbytesleft); - return {}; + str_to.resize(str_to.size() - outbytesleft); + return str_to; } - -#undef SETUP_RV } #pragma endregion