// // One header file iconv wrapper for C++11 2022-09-29.12 GPL // https://github.com/trueroad/iconv_wrapper // // Copyright (C) 2016, 2019, 2022 Masamichi Hosoda. All rights reserved. // // One header file iconv wrapper for C++11 is free software: // you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // One header file iconv wrapper for C++11 is distributed // in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with One header file Commandline Parse for C++11. // If not, see . // #ifndef INCLUDE_GUARD_ICONV_WRAPPER_H #define INCLUDE_GUARD_ICONV_WRAPPER_H #include #include #include namespace iconv_wrapper { class iconv { public: // Open void open (const std::string &fromcode, const std::string &tocode); // Close void close () noexcept; // Convert std::string convert (const std::string &in); // Convert (with getting the incomplete input / output // when an exception occurs) std::string &convert (const std::string &in, std::string::size_type *pinpos, std::string *pout); // Get initial sequence std::string get_initial_sequence (void); // Get initial sequence std::string &get_initial_sequence (std::string *pout); // Reset conversion state void reset (void) const noexcept; // Constructor / destructor iconv () = default; iconv (const std::string &fromcode, const std::string &tocode) { open (fromcode, tocode); } ~iconv () noexcept { close (); } // Enable move iconv (iconv &&) = default; iconv& operator = (iconv &&) = default; private: // Internal class // There is two different implements for the second argument of iconv (). // `const char**' and `char **' // This class is for automatic type cast switching. class iconv_const_cast { public: iconv_const_cast (const char **in) noexcept: t (in) { } operator char** () const noexcept { return const_cast(t); } operator const char ** () const noexcept { return t; } private: const char ** t; }; // Internal function void do_iconv (std::string *pout, const char *inbuf, size_t *pinleft, std::string::size_type *pinpos = nullptr); // Disable copy // Since iconv_t cannot duplicate. iconv (iconv const &) = delete; iconv& operator = (iconv const &) = delete; // Const // Here is C cast instead of C++ cast. // C++ reinterpret_cast (pointer) and static_cast (integer) cannot be used. // Since it depends on the implementation of iconv_t. const iconv_t invalid_cd = (iconv_t)-1; // Conversion descriptor iconv_t convdesc = invalid_cd; }; inline void iconv::open (const std::string &fromcode, const std::string &tocode) { if (convdesc == invalid_cd) { close (); } convdesc = iconv_open (tocode.c_str (), fromcode.c_str ()); if (convdesc == invalid_cd) { throw std::system_error (errno, std::system_category ()); } } inline void iconv::close () noexcept { if (convdesc != invalid_cd) { iconv_close (convdesc); convdesc = invalid_cd; } } inline std::string iconv::convert (const std::string &in) { std::string out (in.size (), '\0'); convert (in, nullptr, &out); return out; } inline std::string &iconv::convert (const std::string &in, std::string::size_type *pinpos, std::string *pout) { size_t inleft {in.size ()}; if (inleft) do_iconv (pout, &in.at (0), &inleft, pinpos); else pout->clear(); return *pout; } inline std::string iconv::get_initial_sequence (void) { std::string out (1, '\0'); get_initial_sequence (&out); return out; } inline std::string &iconv::get_initial_sequence (std::string *pout) { do_iconv (pout, nullptr, nullptr); return *pout; } inline void iconv::reset (void) const noexcept { ::iconv (convdesc, nullptr, nullptr, nullptr, nullptr); } inline void iconv::do_iconv (std::string *pout, const char *inbuf, size_t *pinleft, std::string::size_type *pinpos) { if (pout->empty ()) { pout->resize (1); } const char *inbuf_tmp {inbuf}; char *outbuf {&pout->at (0)}; size_t outleft {pout->size ()}; size_t s; while ((s = ::iconv (convdesc, iconv_const_cast(&inbuf_tmp), pinleft, &outbuf, &outleft)) == static_cast(-1)) { if (errno != E2BIG) { if (pinpos && inbuf) { *pinpos = (inbuf_tmp - inbuf); } pout->resize (outbuf - &pout->at (0)); throw std::system_error (errno, std::system_category ()); } std::string::size_type pos = (outbuf - &pout->at (0)); pout->resize (pout->size () * 2); outbuf = &pout->at (pos); outleft = pout->size () - pos; } pout->resize (outbuf - &pout->at (0)); } } #endif // INCLUDE_GUARD_ICONV_WRAPPER_H