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 

Generated on Tue Mar 1 17:50:15 2011 for Barry by  doxygen 1.5.6