fluxbox/src/FbTk/FbString.cc

386 lines
9 KiB
C++
Raw Normal View History

2006-05-07 03:45:43 +00:00
// 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.
2007-12-30 15:32:53 +00:00
#include "FbString.hh"
2006-05-07 03:45:43 +00:00
#ifdef HAVE_CERRNO
#include <cerrno>
#else
#include <errno.h>
#endif
2007-06-29 17:25:24 +00:00
#ifdef HAVE_CSTRING
#include <cstring>
#else
#include <string.h>
#endif
#ifdef HAVE_CSTDLIB
#include <cstdlib>
#else
#include <stdlib.h>
#endif
2006-05-07 03:45:43 +00:00
2010-09-05 08:47:12 +00:00
#ifdef HAVE_CSTDIO
#include <cstdio>
#else
#include <stdio.h>
#endif
2006-05-20 15:27:40 +00:00
2006-05-07 03:45:43 +00:00
#include <langinfo.h>
#include <locale.h>
#include <iostream>
#include <vector>
2010-09-04 13:01:33 +00:00
#ifdef HAVE_FRIBIDI
2010-09-05 08:47:12 +00:00
#include <fribidi/fribidi.h>
2010-09-04 13:01:33 +00:00
#endif
using std::string;
#ifdef DEBUG
using std::cerr;
using std::endl;
#endif // DEBUG
2006-05-07 03:45:43 +00:00
namespace {
#ifdef HAVE_FRIBIDI
FbTk::FbString makeVisualFromLogical(const FbTk::FbString& src) {
FriBidiCharType base = FRIBIDI_TYPE_N;
// reuse allocated memory for reencoding / reordering
static std::vector<FriBidiChar> us;
static std::vector<FriBidiChar> out_us;
static FbTk::FbString result;
const size_t S = src.size() + 1;
const size_t S4 = S * 4;
if (us.capacity() < S)
us.reserve(S);
if (out_us.capacity() < S)
out_us.reserve(S);
if (result.capacity() < S4)
result.reserve(S4);
us.resize(S);
FriBidiStrIndex len = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8,
const_cast<char*>(src.c_str()), S - 1,
&us[0]);
out_us.resize(S);
fribidi_log2vis(&us[0], len, &base, &out_us[0], NULL, NULL, NULL);
result.resize(S4);
len = fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8, &out_us[0], len, &result[0]);
result.resize(len); // trim to currently used chars
return result;
}
#endif
} // end of anonymous namespace
2006-05-07 03:45:43 +00:00
namespace FbTk {
BiDiString::BiDiString(const FbString& logical)
#ifdef HAVE_FRIBIDI
: m_visual_dirty(false)
#endif
{
if (!logical.empty())
setLogical(logical);
}
const FbString& BiDiString::setLogical(const FbString& logical) {
m_logical = logical;
#if HAVE_FRIBIDI
if (m_logical.empty()) {
m_visual_dirty = false;
m_visual.clear();
} else {
m_visual_dirty = true;
}
#endif
return m_logical;
}
const FbString& BiDiString::visual() const {
#if HAVE_FRIBIDI
if (m_visual_dirty) {
m_visual = ::makeVisualFromLogical(logical());
}
m_visual_dirty = false;
return m_visual;
#else
return m_logical;
#endif
}
2006-05-07 03:45:43 +00:00
namespace FbStringUtil {
enum ConvType { FB2X = 0, X2FB, LOCALE2FB, FB2LOCALE, CONVSIZE };
#ifdef HAVE_ICONV
static iconv_t *iconv_convs = 0;
#else
typedef int iconv_t;
2006-05-07 03:45:43 +00:00
static int iconv_convs[CONVSIZE];
#endif // HAVE_ICONV
static string locale_codeset;
2006-06-25 09:05:58 +00:00
2006-05-07 03:45:43 +00:00
/// Initialise all of the iconv conversion descriptors
void init() {
setlocale(LC_CTYPE, "");
#ifdef HAVE_ICONV
if (iconv_convs != 0)
return;
2006-05-07 03:45:43 +00:00
iconv_convs = new iconv_t[CONVSIZE];
#ifdef CODESET
2006-06-25 09:05:58 +00:00
locale_codeset = nl_langinfo(CODESET);
2006-05-07 03:45:43 +00:00
#else // openbsd doesnt have this (yet?)
2006-06-25 09:05:58 +00:00
locale_codeset = "";
string locale = setlocale(LC_CTYPE, NULL);
2006-05-07 03:45:43 +00:00
size_t pos = locale.find('.');
if (pos != string::npos)
locale_codeset = locale.substr(pos+1);
2006-05-07 03:45:43 +00:00
#endif // CODESET
#ifdef DEBUG
cerr<<"FbTk::FbString: setup converts for local codeset = "<<locale_codeset<<endl;
#endif // DEBUG
iconv_convs[FB2X] = iconv_open("ISO8859-1", "UTF-8");
iconv_convs[X2FB] = iconv_open("UTF-8", "ISO8859-1");
iconv_convs[FB2LOCALE] = iconv_open(locale_codeset.c_str(), "UTF-8");
iconv_convs[LOCALE2FB] = iconv_open("UTF-8", locale_codeset.c_str());
#else
for (int i=0; i < CONVSIZE; ++i)
2006-05-07 03:45:43 +00:00
iconv_convs[i] = 0;
#endif // HAVE_ICONV
}
void shutdown() {
#ifdef HAVE_ICONV
if (iconv_convs == 0)
return;
for (int i=0; i < CONVSIZE; ++i)
2006-05-07 03:45:43 +00:00
if (iconv_convs[i] != (iconv_t)(-1))
iconv_close(iconv_convs[i]);
delete[] iconv_convs;
iconv_convs = 0;
#endif // HAVE_ICONV
2006-05-07 03:45:43 +00:00
}
/**
Recodes the text from one encoding to another
assuming cd is correct
@param cd the iconv type
@param msg text to be converted, **NOT** necessarily NULL terminated
@param size number of BYTES to convert
@return the recoded string, or 0 on failure
*/
string recode(iconv_t cd, const string &in) {
#ifdef HAVE_ICONV
/**
--NOTE--
In the "C" locale, this will strip any high-bit characters
because C means 7-bit ASCII charset. If you don't want this
then you need to set your locale to something UTF-8, OR something
ISO8859-1.
*/
2006-05-07 03:45:43 +00:00
// If empty message, yes this can happen, return
if (in.empty())
2006-05-07 03:45:43 +00:00
return "";
if (cd == ((iconv_t)(-1)))
return in; // can't convert
2006-05-07 03:45:43 +00:00
size_t insize = in.size();
size_t outsize = insize;
char * out = (char *) malloc(outsize * sizeof(char)); // need realloc
2006-05-22 07:34:25 +00:00
char * out_ptr = out;
2006-05-07 03:45:43 +00:00
size_t inbytesleft = insize;
size_t outbytesleft = outsize;
#ifdef HAVE_CONST_ICONV
const char* in_ptr = in.data();
#else
2006-05-07 03:45:43 +00:00
char * in_ptr = const_cast<char *>(in.data());
#endif
2006-05-07 03:45:43 +00:00
size_t result = (size_t)(-1);
bool again = true;
while (again) {
again = false;
2006-05-22 07:34:25 +00:00
result = iconv(cd, &in_ptr, &inbytesleft, &out_ptr, &outbytesleft);
2006-05-07 03:45:43 +00:00
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;
2006-05-22 07:34:25 +00:00
out_ptr = out + outsize - outbytesleft;
2006-05-07 03:45:43 +00:00
break;
default:
// something else broke
perror("iconv");
break;
}
}
}
// copy to our return string
string ret;
2006-05-07 03:45:43 +00:00
ret.append(out, outsize - outbytesleft);
// reset the conversion descriptor
iconv(cd, NULL, NULL, NULL, NULL);
if (out)
free(out);
return ret;
#else
return in;
2006-05-07 03:45:43 +00:00
#endif // HAVE_ICONV
}
2006-05-07 03:45:43 +00:00
FbString XStrToFb(const string &src) {
2006-05-07 03:45:43 +00:00
return recode(iconv_convs[X2FB], src);
}
string FbStrToX(const FbString &src) {
2006-05-07 03:45:43 +00:00
return recode(iconv_convs[FB2X], src);
}
/// Handle thislocale string encodings (strings coming from userspace)
FbString LocaleStrToFb(const string &src) {
2006-05-07 03:45:43 +00:00
return recode(iconv_convs[LOCALE2FB], src);
}
string FbStrToLocale(const FbString &src) {
2006-05-07 03:45:43 +00:00
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;
}
2008-04-21 22:43:10 +00:00
} // end namespace StringUtil
2006-05-07 03:45:43 +00:00
2006-06-25 09:05:58 +00:00
#ifdef HAVE_ICONV
StringConvertor::StringConvertor(EncodingTarget target) : m_iconv((iconv_t)(-1)) {
2006-06-25 09:05:58 +00:00
if (target == ToLocaleStr)
m_destencoding = FbStringUtil::locale_codeset;
else
m_destencoding = "UTF-8";
}
#else
StringConvertor::StringConvertor(EncodingTarget target) { }
#endif
2006-06-25 09:05:58 +00:00
StringConvertor::~StringConvertor() {
#ifdef HAVE_ICONV
if (m_iconv != ((iconv_t)-1))
iconv_close(m_iconv);
#endif
}
bool StringConvertor::setSource(const string &encoding) {
2006-06-25 09:05:58 +00:00
#ifdef HAVE_ICONV
string tempenc = encoding;
2006-06-25 09:05:58 +00:00
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);
2006-06-25 09:05:58 +00:00
m_iconv = newiconv;
return true;
}
#else
return false;
#endif
}
FbString StringConvertor::recode(const string &src) {
2006-06-25 09:05:58 +00:00
#ifdef HAVE_ICONV
return FbStringUtil::recode(m_iconv, src);
#else
return src;
#endif
}
void StringConvertor::reset() {
#ifdef HAVE_ICONV
if (m_iconv != ((iconv_t)-1))
iconv_close(m_iconv);
m_iconv = ((iconv_t)(-1));
#endif
}
2010-09-04 13:01:33 +00:00
2008-04-21 22:43:10 +00:00
} // end namespace FbTk