# iconv.cc

Go to the documentation of this file.

    00001 ///
    00002 /// \file       iconv.cc
    00003 ///             iconv wrapper class, and pluggable interface for records
    00004 ///
    00005
    00006 /*
    00007     Copyright (C) 2008-2011, Net Direct Inc. (http://www.netdirect.ca/)
    00008
    00009     This program is free software; you can redistribute it and/or modify
    00010     it under the terms of the GNU General Public License as published by
    00011     the Free Software Foundation; either version 2 of the License, or
    00012     (at your option) any later version.
    00013
    00014     This program is distributed in the hope that it will be useful,
    00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00017
    00018     See the GNU General Public License in the COPYING file at the
    00019     root directory of this project for more details.
    00020 */
    00021
    00022 #include "iconv.h"
    00023 #include "common.h"
    00024 #include "error.h"
    00025 #include "config.h"
    00026 #include <errno.h>
    00027 #include <string>
    00028
    00029 using namespace std;
    00030
    00031 namespace Barry {
    00032
    00033 //////////////////////////////////////////////////////////////////////////////
    00034 // IConvHandle class
    00035
    00036 IConvHandle::IConvHandle(const char *fromcode, const char *tocode)
    00037 {
    00038         m_handle = iconv_open(tocode, fromcode);
    00039         if( m_handle == (iconv_t)(-1) ) {
    00040                 throw ErrnoError(std::string("iconv_open failed: from ") + fromcode + " to " + tocode, errno);
    00041         }
    00042 }
    00043
    00044 IConvHandle::IConvHandle(const char *fromcode, const IConverter &ic)
    00045 {
    00046         m_handle = iconv_open(ic.m_tocode.c_str(), fromcode);
    00047         if( m_handle == (iconv_t)(-1) ) {
    00048                 throw ErrnoError(std::string("iconv_open failed: from ") + fromcode + " to " + ic.m_tocode, errno);
    00049         }
    00050 }
    00051
    00052 IConvHandle::IConvHandle(const IConverter &ic, const char *tocode)
    00053 {
    00054         m_handle = iconv_open(tocode, ic.m_tocode.c_str());
    00055         if( m_handle == (iconv_t)(-1) ) {
    00056                 throw ErrnoError(std::string("iconv_open failed: from ") + ic.m_tocode + " to " + tocode, errno);
    00057         }
    00058 }
    00059
    00060 IConvHandle::~IConvHandle()
    00061 {
    00062         iconv_close(m_handle);
    00063 }
    00064
    00065
    00066 //////////////////////////////////////////////////////////////////////////////
    00067 // IConvHandle class
    00068
    00069 IConverter::IConverter(const char *tocode, bool throw_on_conv_err)
    00070         : m_from(BLACKBERRY_CHARSET, tocode)
    00071         , m_to(tocode, BLACKBERRY_CHARSET)
    00072         , m_tocode(tocode)
    00073         , m_throw_on_conv_err(throw_on_conv_err)
    00074 {
    00075 }
    00076
    00077 IConverter::~IConverter()
    00078 {
    00079 }
    00080
    00081 std::string IConverter::Convert(iconv_t cd, const std::string &str) const
    00082 {
    00083         size_t target = str.size() * 2;
    00084         char *out = 0, *outstart = 0;
    00085         size_t outbytesleft = 0;
    00086         std::string ret;
    00087
    00088         // this loop is for the very odd case that the output string
    00089         // needs more than twice the input size
    00090         for( int tries = 0; ; tries++ ) {
    00091
    00092                 const char *in = str.data();
    00093                 size_t inbytesleft = str.size();
    00094                 out = outstart = (char*) m_buffer.GetBuffer(target);
    00095                 outbytesleft = m_buffer.GetBufSize();
    00096
    00097                 iconv(cd, NULL, NULL, NULL, NULL);      // reset cd's state
    00098                 size_t status = iconv(cd, (ICONV_CONST char**) &in, &inbytesleft, &out, &outbytesleft);
    00099
    00100                 if( status == (size_t)(-1) ) {
    00101                         if( errno == E2BIG && tries < 2 ) {
    00102                                 target += inbytesleft * 2;
    00103                                 // try again with more memory...
    00104                                 continue;
    00105                         }
    00106
    00107                         // should never happen :-)
    00108                         // but if it does, and we get here, check
    00109                         // whether the user wants to be notified by
    00110                         // exception... if not, just fall through and
    00111                         // store as much converted data as possible
    00112                         ErrnoError e(string("iconv failed with string '") + str + "'", errno);
    00113                         if( m_throw_on_conv_err ) {
    00114                                 throw e;
    00115                         }
    00116                         else {
    00117                                 cerr << e.what();
    00118                                 // return the unconverted string
    00119                                 return str;
    00120                         }
    00121                 }
    00122                 else {
    00123                         // success
    00124                         break;
    00125                 }
    00126         }
    00127
    00128         // store any available converted data
    00129         ret.assign(outstart, out - outstart);
    00130         return ret;
    00131 }
    00132
    00133 std::string IConverter::FromBB(const std::string &str) const
    00134 {
    00135         return Convert(m_from.m_handle, str);
    00136 }
    00137
    00138 std::string IConverter::ToBB(const std::string &str) const
    00139 {
    00140         return Convert(m_to.m_handle, str);
    00141 }
    00142
    00143 std::string IConverter::Convert(const IConvHandle &custom, const std::string &str) const
    00144 {
    00145         return Convert(custom.m_handle, str);
    00146 }
    00147
    00148 } // namespace Barry
    00149