3 /// iconv wrapper class, and pluggable interface for records
7 Copyright (C) 2008-2011, 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.
35 //////////////////////////////////////////////////////////////////////////////
36 // IConvHandlePrivate class
37 class IConvHandlePrivate
47 //////////////////////////////////////////////////////////////////////////////
50 IConvHandle::IConvHandle(const char *fromcode
,
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
,
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
,
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;
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...
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
) {
129 // return the unconverted string
139 // store any available converted data
140 ret
.assign(outstart
, out
- outstart
);
145 //////////////////////////////////////////////////////////////////////////////
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
)
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
);