1 // Copyright (C) 2010, Vaclav Haisman. All rights reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without modifica-
4 // tion, are permitted provided that the following conditions are met:
5 //
6 // 1. Redistributions of source code must retain the above copyright notice,
7 // this list of conditions and the following disclaimer.
8 //
9 // 2. Redistributions in binary form must reproduce the above copyright notice,
10 // this list of conditions and the following disclaimer in the documentation
11 // and/or other materials provided with the distribution.
12 //
13 // THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
14 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
15 // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
16 // APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
17 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
18 // DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
19 // OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
24
25 #include "dcmtk/oflog/helpers/strhelp.h"
26
27 #if defined (DCMTK_LOG4CPLUS_WITH_ICONV)
28
29 #ifdef DCMTK_LOG4CPLUS_HAVE_ICONV_H
30 #include <iconv.h>
31 #endif
32
33 #include "dcmtk/ofstd/ofstream.h"
34 #include <stdexcept>
35 #include <iostream>
36 #include <sstream>
37 #include <cassert>
38 #include <cerrno>
39 #include <cstring>
40
41
42 // This is here because some compilers (Sun CC) think that there is a
43 // difference if the typedefs are not in an extern "C" block.
44 extern "C"
45 {
46
47 //! SUSv3 iconv() type.
48 typedef size_t (& iconv_func_type_1) (iconv_t cd, char * * inbuf,
49 size_t * inbytesleft, char * * outbuf, size_t * outbytesleft);
50
51
52 //! GNU iconv() type.
53 typedef size_t (& iconv_func_type_2) (iconv_t cd, const char * * inbuf,
54 size_t * inbytesleft, char * * outbuf, size_t * outbytesleft);
55
56 } // extern "C"
57
58
59 namespace dcmtk
60 {
61 namespace log4cplus
62 {
63
64 namespace helpers
65 {
66
67 namespace
68 {
69
70
71 static iconv_t const iconv_error_handle = OFreinterpret_cast(iconv_t, -1);
72
73
74 struct iconv_handle
75 {
iconv_handledcmtk::log4cplus::helpers::__anon12a10e960111::iconv_handle76 iconv_handle (char const * to, char const * from)
77 : handle (iconv_open (to, from))
78 {
79 }
80
~iconv_handledcmtk::log4cplus::helpers::__anon12a10e960111::iconv_handle81 ~iconv_handle ()
82 {
83 if (handle != iconv_error_handle)
84 {
85 int ret = iconv_close (handle);
86 if (ret == -1)
87 {
88 STD_NAMESPACE ostringstream oss;
89 oss << "iconv_close failed: " << errno;
90 STD_NAMESPACE cerr << oss.str () << OFendl;
91 }
92 }
93 }
94
95 size_t
call_iconvdcmtk::log4cplus::helpers::__anon12a10e960111::iconv_handle96 call_iconv (iconv_func_type_1 iconv_func, char * * inbuf,
97 size_t * inbytesleft, char * * outbuf, size_t * outbytesleft)
98 {
99 return iconv_func (handle, inbuf, inbytesleft, outbuf, outbytesleft);
100 }
101
102 size_t
call_iconvdcmtk::log4cplus::helpers::__anon12a10e960111::iconv_handle103 call_iconv (iconv_func_type_2 iconv_func, char * * inbuf,
104 size_t * inbytesleft, char * * outbuf, size_t * outbytesleft)
105 {
106 return iconv_func (handle, OFconst_cast(const char * *, inbuf),
107 inbytesleft, outbuf, outbytesleft);
108 }
109
110 size_t
do_iconvdcmtk::log4cplus::helpers::__anon12a10e960111::iconv_handle111 do_iconv (char * * inbuf, size_t * inbytesleft, char * * outbuf,
112 size_t * outbytesleft)
113 {
114 return call_iconv (iconv, inbuf, inbytesleft, outbuf, outbytesleft);
115 }
116
117 iconv_t handle;
118
119 // to silence warnings
120 private:
121 iconv_handle(const iconv_handle&);
122 iconv_handle& operator=(const iconv_handle&);
123 };
124
125
126 template <typename T>
127 struct question_mark;
128
129
130 template <>
131 struct question_mark<char>
132 {
133 static char const value = '?';
134 };
135
136
137 template <>
138 struct question_mark<wchar_t>
139 {
140 static wchar_t const value = L'?';
141 };
142
143
144 char const question_mark<char>::value;
145
146
147 wchar_t const question_mark<wchar_t>::value;
148
149
150 template <typename DestType, typename SrcType>
151 static
152 void
iconv_conv(STD_NAMESPACE basic_string<DestType> & result,char const * destenc,SrcType const * src,size_t size,char const * srcenc)153 iconv_conv (STD_NAMESPACE basic_string<DestType> & result, char const * destenc,
154 SrcType const * src, size_t size, char const * srcenc)
155 {
156 iconv_handle cvt (destenc, srcenc);
157 if (cvt.handle == iconv_error_handle)
158 {
159 // TODO: Better error handling.
160 result.resize (0);
161 return;
162 }
163
164 typedef DestType outbuf_type;
165 typedef SrcType inbuf_type;
166
167 size_t result_size = size + size / 3 + 1;
168 result.resize (result_size);
169
170 char * inbuf = OFconst_cast(char *, OFreinterpret_cast(char const *, src));
171 size_t inbytesleft = size * sizeof (inbuf_type);
172
173 char * outbuf = OFreinterpret_cast(char *, &result[0]);
174 size_t outbytesleft = result_size * sizeof (outbuf_type);
175
176 size_t res;
177 size_t const error_retval = OFstatic_cast(size_t, -1);
178
179 while (inbytesleft != 0)
180 {
181 res = cvt.do_iconv (&inbuf, &inbytesleft, &outbuf, &outbytesleft);
182 if (res == error_retval)
183 {
184 switch (errno)
185 {
186 case EILSEQ:
187 case EINVAL:
188 if (outbytesleft >= sizeof (outbuf_type))
189 {
190 if (inbytesleft > 0)
191 {
192 ++inbuf;
193 inbytesleft -= sizeof (inbuf_type);
194 }
195
196 *outbuf = question_mark<outbuf_type>::value;
197 ++outbuf;
198 outbytesleft -= sizeof (outbuf_type);
199
200 continue;
201 }
202
203 // Fall through.
204
205 case E2BIG:;
206 // Fall through.
207 }
208
209 size_t const outbuf_index = result_size;
210 result_size *= 2;
211 result.resize (result_size);
212 outbuf = OFreinterpret_cast(char *, &result[0] + outbuf_index);
213 outbytesleft = (result_size - outbuf_index) * sizeof (outbuf_type);
214 }
215 else
216 result.resize (result_size - outbytesleft / sizeof (outbuf_type));
217 }
218 }
219
220
221 } // namespace
222
223
224 OFString
tostring(const STD_NAMESPACE wstring & src)225 tostring (const STD_NAMESPACE wstring & src)
226 {
227 STD_NAMESPACE string ret;
228 iconv_conv (ret, "UTF-8", src.c_str (), src.size (), "WCHAR_T");
229 return OFString(ret.c_str(), ret.size());
230 }
231
232
233 OFString
tostring(wchar_t const * src)234 tostring (wchar_t const * src)
235 {
236 assert (src);
237 STD_NAMESPACE string ret;
238 iconv_conv (ret, "UTF-8", src, STD_NAMESPACE wcslen (src), "WCHAR_T");
239 return OFString(ret.c_str(), ret.size());
240 }
241
242
243 STD_NAMESPACE wstring
towstring(const OFString & osrc)244 towstring (const OFString& osrc)
245 {
246 STD_NAMESPACE wstring ret;
247 STD_NAMESPACE string src(osrc.c_str(), osrc.size());
248 iconv_conv (ret, "WCHAR_T", src.c_str (), src.size (), "UTF-8");
249 return ret;
250 }
251
252
253 STD_NAMESPACE wstring
towstring(char const * src)254 towstring (char const * src)
255 {
256 assert (src);
257 STD_NAMESPACE wstring ret;
258 iconv_conv (ret, "WCHAR_T", src, STD_NAMESPACE strlen (src), "UTF-8");
259 return ret;
260 }
261
262
263 } // namespace helpers
264
265 } // namespace log4cplus
266
267
268 } // end namespace dcmtk
269
270 #else
271
272 int striconv_cc_dummy_to_keep_linker_from_moaning = 0;
273
274 #endif // DCMTK_LOG4CPLUS_WITH_ICONV
275