Bumped copyright dates for 2013
[barry.git] / src / iconv.cc
blob9326e2235aae3c619c3b97314186218390a542ce
1 ///
2 /// \file iconv.cc
3 /// iconv wrapper class, and pluggable interface for records
4 ///
6 /*
7 Copyright (C) 2008-2013, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
22 #include "iconv.h"
23 #include "common.h"
24 #include "error.h"
25 #include "config.h"
26 #include <iconv.h>
27 #include <iostream>
28 #include <errno.h>
29 #include <string>
31 using namespace std;
33 namespace Barry {
35 //////////////////////////////////////////////////////////////////////////////
36 // IConvHandlePrivate class
37 class IConvHandlePrivate
39 public:
40 iconv_t m_handle;
42 IConvHandlePrivate()
47 //////////////////////////////////////////////////////////////////////////////
48 // IConvHandle class
50 IConvHandle::IConvHandle(const char *fromcode,
51 const char *tocode,
52 bool throw_on_conv_err)
53 : m_priv( new IConvHandlePrivate )
54 , m_throw_on_conv_err(throw_on_conv_err)
56 m_priv->m_handle = iconv_open(tocode, fromcode);
57 if( m_priv->m_handle == (iconv_t)(-1) ) {
58 throw ErrnoError(std::string("iconv_open failed: from ") + fromcode + " to " + tocode, errno);
62 IConvHandle::IConvHandle(const char *fromcode,
63 const IConverter &ic,
64 bool throw_on_conv_err)
65 : m_priv( new IConvHandlePrivate )
66 , m_throw_on_conv_err(throw_on_conv_err)
68 m_priv->m_handle = iconv_open(ic.m_tocode.c_str(), fromcode);
69 if( m_priv->m_handle == (iconv_t)(-1) ) {
70 throw ErrnoError(std::string("iconv_open failed: from ") + fromcode + " to " + ic.m_tocode, errno);
74 IConvHandle::IConvHandle(const IConverter &ic,
75 const char *tocode,
76 bool throw_on_conv_err)
77 : m_priv( new IConvHandlePrivate )
78 , m_throw_on_conv_err(throw_on_conv_err)
80 m_priv->m_handle = iconv_open(tocode, ic.m_tocode.c_str());
81 if( m_priv->m_handle == (iconv_t)(-1) ) {
82 throw ErrnoError(std::string("iconv_open failed: from ") + ic.m_tocode + " to " + tocode, errno);
86 IConvHandle::~IConvHandle()
88 iconv_close(m_priv->m_handle);
91 std::string IConvHandle::Convert(Data &tmp, const std::string &str) const
93 size_t target = str.size() * 2;
94 char *out = 0, *outstart = 0;
95 size_t outbytesleft = 0;
96 std::string ret;
97 iconv_t cd = m_priv->m_handle;
99 // this loop is for the very odd case that the output string
100 // needs more than twice the input size
101 for( int tries = 0; ; tries++ ) {
103 const char *in = str.data();
104 size_t inbytesleft = str.size();
105 out = outstart = (char*) tmp.GetBuffer(target);
106 outbytesleft = tmp.GetBufSize();
108 iconv(cd, NULL, NULL, NULL, NULL); // reset cd's state
109 size_t status = iconv(cd, (ICONV_CONST char**) &in, &inbytesleft, &out, &outbytesleft);
111 if( status == (size_t)(-1) ) {
112 if( errno == E2BIG && tries < 2 ) {
113 target += inbytesleft * 2;
114 // try again with more memory...
115 continue;
118 // should never happen :-)
119 // but if it does, and we get here, check
120 // whether the user wants to be notified by
121 // exception... if not, just fall through and
122 // store as much converted data as possible
123 ErrnoError e(string("iconv failed with string '") + str + "'", errno);
124 if( m_throw_on_conv_err ) {
125 throw e;
127 else {
128 cerr << e.what();
129 // return the unconverted string
130 return str;
133 else {
134 // success
135 break;
139 // store any available converted data
140 ret.assign(outstart, out - outstart);
141 return ret;
145 //////////////////////////////////////////////////////////////////////////////
146 // IConvHandle class
148 IConverter::IConverter(const char *tocode, bool throw_on_conv_err)
149 : m_from(BLACKBERRY_CHARSET, tocode, throw_on_conv_err)
150 , m_to(tocode, BLACKBERRY_CHARSET, throw_on_conv_err)
151 , m_tocode(tocode)
155 IConverter::~IConverter()
159 std::string IConverter::FromBB(const std::string &str) const
161 return m_from.Convert(m_buffer, str);
164 std::string IConverter::ToBB(const std::string &str) const
166 return m_to.Convert(m_buffer, str);
169 std::string IConverter::Convert(const IConvHandle &custom, const std::string &str) const
171 return custom.Convert(m_buffer, str);
174 } // namespace Barry