1 // tinygettext - A gettext replacement that works directly on .po files
2 // Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 #include "log_stream.hpp"
29 namespace tinygettext {
31 #ifndef tinygettext_ICONV_CONST
32 # define tinygettext_ICONV_CONST
41 IConv::IConv(const std::string& from_charset_, const std::string& to_charset_)
46 set_charsets(from_charset_, to_charset_);
52 tinygettext_iconv_close(cd);
56 IConv::set_charsets(const std::string& from_charset_, const std::string& to_charset_)
59 tinygettext_iconv_close(cd);
61 from_charset = from_charset_;
62 to_charset = to_charset_;
64 for(std::string::iterator i = to_charset.begin(); i != to_charset.end(); ++i)
65 *i = static_cast<char>(toupper(*i));
67 for(std::string::iterator i = from_charset.begin(); i != from_charset.end(); ++i)
68 *i = static_cast<char>(toupper(*i));
70 if (to_charset == from_charset)
76 cd = tinygettext_iconv_open(to_charset.c_str(), from_charset.c_str());
77 if (cd == reinterpret_cast<tinygettext_iconv_t>(-1))
81 std::ostringstream str;
82 str << "IConv construction failed: conversion from '" << from_charset
83 << "' to '" << to_charset << "' not available";
84 throw std::runtime_error(str.str());
88 std::ostringstream str;
89 str << "IConv: construction failed: " << strerror(errno);
90 throw std::runtime_error(str.str());
96 /// Convert a string from encoding to another.
98 IConv::convert(const std::string& text)
106 size_t inbytesleft = text.size();
107 size_t outbytesleft = 4*inbytesleft; // Worst case scenario: ASCII -> UTF-32?
109 // We try to avoid to much copying around, so we write directly into
111 tinygettext_ICONV_CONST char* inbuf = const_cast<char*>(&text[0]);
112 std::string result(outbytesleft, 'X');
113 char* outbuf = &result[0];
115 // Try to convert the text.
116 size_t ret = tinygettext_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
117 if (ret == static_cast<size_t>(-1))
119 if (errno == EILSEQ || errno == EINVAL)
120 { // invalid multibyte sequence
121 tinygettext_iconv(cd, NULL, NULL, NULL, NULL); // reset state
123 // FIXME: Could try to skip the invalid byte and continue
124 log_error << "error: tinygettext:iconv: invalid multibyte sequence in: \"" << text << "\"" << std::endl;
126 else if (errno == E2BIG)
127 { // output buffer to small
128 assert(!"tinygettext/iconv.cpp: E2BIG: This should never be reached");
130 else if (errno == EBADF)
132 assert(!"tinygettext/iconv.cpp: EBADF: This should never be reached");
136 assert(!"tinygettext/iconv.cpp: <unknown>: This should never be reached");
140 result.resize(4*text.size() - outbytesleft);
146 } // namespace tinygettext