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