// tinygettext - A gettext replacement that works directly on .po files // Copyright (C) 2009 Ingo Ruhnke // // This program 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 2 // of the License, or (at your option) any later version. // // This program 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 this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include #include #include #include #include #include #include "iconv.hpp" #include "log_stream.hpp" namespace tinygettext { #ifndef tinygettext_ICONV_CONST # define tinygettext_ICONV_CONST #endif IConv::IConv() : to_charset(), from_charset(), cd(0) {} IConv::IConv(const std::string& from_charset_, const std::string& to_charset_) : to_charset(), from_charset(), cd(0) { set_charsets(from_charset_, to_charset_); } IConv::~IConv() { if (cd) tinygettext_iconv_close(cd); } void IConv::set_charsets(const std::string& from_charset_, const std::string& to_charset_) { if (cd) tinygettext_iconv_close(cd); from_charset = from_charset_; to_charset = to_charset_; for(std::string::iterator i = to_charset.begin(); i != to_charset.end(); ++i) *i = static_cast(toupper(*i)); for(std::string::iterator i = from_charset.begin(); i != from_charset.end(); ++i) *i = static_cast(toupper(*i)); if (to_charset == from_charset) { cd = 0; } else { cd = tinygettext_iconv_open(to_charset.c_str(), from_charset.c_str()); if (cd == reinterpret_cast(-1)) { if(errno == EINVAL) { std::ostringstream str; str << "IConv construction failed: conversion from '" << from_charset << "' to '" << to_charset << "' not available"; throw std::runtime_error(str.str()); } else { std::ostringstream str; str << "IConv: construction failed: " << strerror(errno); throw std::runtime_error(str.str()); } } } } /// Convert a string from encoding to another. std::string IConv::convert(const std::string& text) { if (!cd) { return text; } else { size_t inbytesleft = text.size(); size_t outbytesleft = 4*inbytesleft; // Worst case scenario: ASCII -> UTF-32? // We try to avoid to much copying around, so we write directly into // a std::string tinygettext_ICONV_CONST char* inbuf = const_cast(&text[0]); std::string result(outbytesleft, 'X'); char* outbuf = &result[0]; // Try to convert the text. size_t ret = tinygettext_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); if (ret == static_cast(-1)) { if (errno == EILSEQ || errno == EINVAL) { // invalid multibyte sequence tinygettext_iconv(cd, NULL, NULL, NULL, NULL); // reset state // FIXME: Could try to skip the invalid byte and continue log_error << "error: tinygettext:iconv: invalid multibyte sequence in: \"" << text << "\"" << std::endl; } else if (errno == E2BIG) { // output buffer to small assert(!"tinygettext/iconv.cpp: E2BIG: This should never be reached"); } else if (errno == EBADF) { assert(!"tinygettext/iconv.cpp: EBADF: This should never be reached"); } else { assert(!"tinygettext/iconv.cpp: : This should never be reached"); } } result.resize(4*text.size() - outbytesleft); return result; } } } // namespace tinygettext /* EOF */