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-2010, 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 
00028 namespace Barry {
00029 
00030 //////////////////////////////////////////////////////////////////////////////
00031 // IConvHandle class
00032 
00033 IConvHandle::IConvHandle(const char *fromcode, const char *tocode)
00034 {
00035         m_handle = iconv_open(tocode, fromcode);
00036         if( m_handle == (iconv_t)(-1) ) {
00037                 throw ErrnoError(std::string("iconv_open failed: from ") + fromcode + " to " + tocode, errno);
00038         }
00039 }
00040 
00041 IConvHandle::IConvHandle(const char *fromcode, const IConverter &ic)
00042 {
00043         m_handle = iconv_open(ic.m_tocode.c_str(), fromcode);
00044         if( m_handle == (iconv_t)(-1) ) {
00045                 throw ErrnoError(std::string("iconv_open failed: from ") + fromcode + " to " + ic.m_tocode, errno);
00046         }
00047 }
00048 
00049 IConvHandle::IConvHandle(const IConverter &ic, const char *tocode)
00050 {
00051         m_handle = iconv_open(tocode, ic.m_tocode.c_str());
00052         if( m_handle == (iconv_t)(-1) ) {
00053                 throw ErrnoError(std::string("iconv_open failed: from ") + ic.m_tocode + " to " + tocode, errno);
00054         }
00055 }
00056 
00057 IConvHandle::~IConvHandle()
00058 {
00059         iconv_close(m_handle);
00060 }
00061 
00062 
00063 //////////////////////////////////////////////////////////////////////////////
00064 // IConvHandle class
00065 
00066 IConverter::IConverter(const char *tocode, bool throw_on_conv_err)
00067         : m_from(BLACKBERRY_CHARSET, tocode)
00068         , m_to(tocode, BLACKBERRY_CHARSET)
00069         , m_tocode(tocode)
00070         , m_throw_on_conv_err(throw_on_conv_err)
00071 {
00072 }
00073 
00074 IConverter::~IConverter()
00075 {
00076 }
00077 
00078 std::string IConverter::Convert(iconv_t cd, const std::string &str) const
00079 {
00080         size_t target = str.size() * 2;
00081         char *out = 0, *outstart = 0;
00082         size_t outbytesleft = 0;
00083         std::string ret;
00084 
00085         // this loop is for the very odd case that the output string
00086         // needs more than twice the input size
00087         for( int tries = 0; ; tries++ ) {
00088 
00089                 const char *in = str.data();
00090                 size_t inbytesleft = str.size();
00091                 out = outstart = (char*) m_buffer.GetBuffer(target);
00092                 outbytesleft = m_buffer.GetBufSize();
00093 
00094                 iconv(cd, NULL, NULL, NULL, NULL);      // reset cd's state
00095                 size_t status = iconv(cd, (ICONV_CONST char**) &in, &inbytesleft, &out, &outbytesleft);
00096 
00097                 if( status == (size_t)(-1) ) {
00098                         if( errno == E2BIG && tries < 2 ) {
00099                                 target += inbytesleft * 2;
00100                                 // try again with more memory...
00101                                 continue;
00102                         }
00103 
00104                         // should never happen :-)
00105                         // but if it does, and we get here, check
00106                         // whether the user wants to be notified by
00107                         // exception... if not, just fall through and
00108                         // store as much converted data as possible
00109                         if( m_throw_on_conv_err ) {
00110                                 throw ErrnoError("iconv failed", errno);
00111                         }
00112                 }
00113                 else {
00114                         // success
00115                         break;
00116                 }
00117         }
00118 
00119         // store any available converted data
00120         ret.assign(outstart, out - outstart);
00121         return ret;
00122 }
00123 
00124 std::string IConverter::FromBB(const std::string &str) const
00125 {
00126         return Convert(m_from.m_handle, str);
00127 }
00128 
00129 std::string IConverter::ToBB(const std::string &str) const
00130 {
00131         return Convert(m_to.m_handle, str);
00132 }
00133 
00134 std::string IConverter::Convert(const IConvHandle &custom, const std::string &str) const
00135 {
00136         return Convert(custom.m_handle, str);
00137 }
00138 
00139 } // namespace Barry
00140 
Generated by  doxygen 1.6.2-20100208