// FbString.cc for fluxbox // Copyright (c) 2006 Henrik Kinnunen (fluxgen at fluxbox dot org) // Copyright (c) 2006 Simon Bowden (rathnor at fluxbox dot org) // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. #include "FbString.hh" #ifdef HAVE_CERRNO #include #else #include #endif #ifdef HAVE_CSTRING #include #else #include #endif #ifdef HAVE_CSTDLIB #include #else #include #endif #include #include #include #include #ifdef HAVE_FRIBIDI #include #endif using std::string; #ifdef DEBUG using std::cerr; using std::endl; #endif // DEBUG namespace FbTk { namespace FbStringUtil { enum ConvType { FB2X = 0, X2FB, LOCALE2FB, FB2LOCALE, CONVSIZE }; #ifdef HAVE_ICONV static iconv_t *iconv_convs = 0; #else static int iconv_convs[CONVSIZE]; #endif // HAVE_ICONV static string locale_codeset; /// Initialise all of the iconv conversion descriptors void init() { setlocale(LC_CTYPE, ""); #ifdef HAVE_ICONV if (iconv_convs != 0) return; iconv_convs = new iconv_t[CONVSIZE]; #ifdef CODESET locale_codeset = nl_langinfo(CODESET); #else // openbsd doesnt have this (yet?) locale_codeset = ""; string locale = setlocale(LC_CTYPE, NULL); size_t pos = locale.find('.'); if (pos != string::npos) locale_codeset = locale.substr(pos+1); #endif // CODESET #ifdef DEBUG cerr<<"FbTk::FbString: setup converts for local codeset = "<(in.data()); size_t result = (size_t)(-1); bool again = true; while (again) { again = false; #ifdef HAVE_CONST_ICONV result = iconv(cd, (const char**)(&in_ptr), &inbytesleft, &out_ptr, &outbytesleft); #else result = iconv(cd, &in_ptr, &inbytesleft, &out_ptr, &outbytesleft); #endif // HAVE_CONST_ICONV if (result == (size_t)(-1)) { switch(errno) { case EILSEQ: // Try skipping a byte in_ptr++; inbytesleft--; again = true; case EINVAL: break; case E2BIG: // need more space! outsize += insize; out = (char *) realloc(out, outsize*sizeof(char)); if (out != NULL) again = true; outbytesleft += insize; out_ptr = out + outsize - outbytesleft; break; default: // something else broke perror("iconv"); break; } } } // copy to our return string string ret; ret.append(out, outsize - outbytesleft); // reset the conversion descriptor iconv(cd, NULL, NULL, NULL, NULL); if (out) free(out); return ret; } #else string recode(int cd, const string &str) { return str; } #endif // HAVE_ICONV FbString XStrToFb(const string &src) { return recode(iconv_convs[X2FB], src); } string FbStrToX(const FbString &src) { return recode(iconv_convs[FB2X], src); } /// Handle thislocale string encodings (strings coming from userspace) FbString LocaleStrToFb(const string &src) { return recode(iconv_convs[LOCALE2FB], src); } string FbStrToLocale(const FbString &src) { return recode(iconv_convs[FB2LOCALE], src); } bool haveUTF8() { #ifdef HAVE_ICONV if (iconv_convs[LOCALE2FB] != ((iconv_t)(-1))) return true; #endif // HAVE_ICONV return false; } #ifdef HAVE_FRIBIDI FbString BidiLog2Vis (const FbString& src){ FriBidiChar * us, * out_us; FriBidiCharType base; FbString r; char * out; us = new FriBidiChar[src.size()+1]; out_us = new FriBidiChar[src.size()+1]; unsigned int len = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8, const_cast(src.c_str()), src.length(), us); base = FRIBIDI_TYPE_N; fribidi_log2vis(us, len, &base, out_us, NULL, NULL, NULL); out = new char[4*src.size()+1]; fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8, out_us, len, out); r = out; delete[] out_us; delete[] us; delete[] out; return r; } #endif } // end namespace StringUtil StringConvertor::StringConvertor(EncodingTarget target): #ifdef HAVE_ICONV m_iconv((iconv_t)(-1)) { if (target == ToLocaleStr) m_destencoding = FbStringUtil::locale_codeset; else m_destencoding = "UTF-8"; } #else m_iconv(-1) {} #endif StringConvertor::~StringConvertor() { #ifdef HAVE_ICONV if (m_iconv != ((iconv_t)-1)) iconv_close(m_iconv); #endif } bool StringConvertor::setSource(const string &encoding) { #ifdef HAVE_ICONV string tempenc = encoding; if (encoding == "") tempenc = FbStringUtil::locale_codeset; iconv_t newiconv = iconv_open(m_destencoding.c_str(), tempenc.c_str()); if (newiconv == ((iconv_t)(-1))) return false; else { if (m_iconv != ((iconv_t)-1)) iconv_close(m_iconv); m_iconv = newiconv; return true; } #else return false; #endif } string StringConvertor::recode(const string &src) { #ifdef HAVE_ICONV return FbStringUtil::recode(m_iconv, src); #else return src; #endif } } // end namespace FbTk