Remove old autovect-branch by moving to "dead" directory.
[official-gcc.git] / old-autovect-branch / libjava / gnu / gcj / convert / natIconv.cc
blob6c64e2b4bf9b3b33aaa40ce6f4555c068c2745eb
1 // natIconv.cc -- Java side of iconv() reader.
3 /* Copyright (C) 2000, 2001, 2003 Free Software Foundation
5 This file is part of libgcj.
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9 details. */
11 /* Author: Tom Tromey <tromey@redhat.com>. */
13 #include <config.h>
15 #include <gcj/cni.h>
16 #include <jvm.h>
18 #include <gnu/gcj/convert/Input_iconv.h>
19 #include <gnu/gcj/convert/Output_iconv.h>
20 #include <java/io/CharConversionException.h>
21 #include <java/io/UnsupportedEncodingException.h>
23 #include <errno.h>
25 #ifdef HAVE_ICONV
26 #include <iconv.h>
28 template<typename T>
29 static inline size_t
30 iconv_adapter (size_t (*iconv_f) (iconv_t, T, size_t *, char **, size_t *),
31 iconv_t handle, char **inbuf, size_t *inavail,
32 char **outbuf, size_t *outavail)
34 return (*iconv_f) (handle, (T) inbuf, inavail, outbuf, outavail);
37 #endif
39 void
40 gnu::gcj::convert::Input_iconv::init (jstring encoding)
42 #ifdef HAVE_ICONV
43 jsize len = _Jv_GetStringUTFLength (encoding);
44 char buffer[len + 1];
45 _Jv_GetStringUTFRegion (encoding, 0, encoding->length(), buffer);
46 buffer[len] = '\0';
48 iconv_t h = iconv_open ("UCS-2", buffer);
49 if (h == (iconv_t) -1)
50 throw new java::io::UnsupportedEncodingException (encoding);
52 JvAssert (h != NULL);
53 handle = reinterpret_cast<gnu::gcj::RawData *> (h);
54 #else /* HAVE_ICONV */
55 // If no iconv, just throw an exception.
56 throw new java::io::UnsupportedEncodingException (encoding);
57 #endif /* HAVE_ICONV */
60 void
61 gnu::gcj::convert::Input_iconv::finalize (void)
63 #ifdef HAVE_ICONV
64 if (handle != NULL)
66 iconv_close ((iconv_t) handle);
67 handle = NULL;
69 #endif /* HAVE_ICONV */
72 jint
73 gnu::gcj::convert::Input_iconv::read (jcharArray outbuffer,
74 jint outpos, jint count)
76 #ifdef HAVE_ICONV
77 jbyte *bytes = elements (inbuffer);
78 jchar *out = elements (outbuffer);
79 size_t inavail = inlength - inpos;
80 size_t old_in = inavail;
81 size_t outavail = count * sizeof (jchar);
82 size_t old_out = outavail;
84 char *inbuf = (char *) &bytes[inpos];
85 char *outbuf = (char *) &out[outpos];
87 size_t r = iconv_adapter (iconv, (iconv_t) handle,
88 &inbuf, &inavail,
89 &outbuf, &outavail);
91 if (r == (size_t) -1)
93 // If we see EINVAL then there is an incomplete sequence at the
94 // end of the input buffer. If we see E2BIG then we ran out of
95 // space in the output buffer. However, in both these cases
96 // some conversion might have taken place. So we fall through
97 // to the normal case.
98 if (errno != EINVAL && errno != E2BIG)
99 throw new java::io::CharConversionException ();
102 if (iconv_byte_swap)
104 size_t max = (old_out - outavail) / sizeof (jchar);
105 for (size_t i = 0; i < max; ++i)
107 // Byte swap.
108 jchar c = (((out[outpos + i] & 0xff) << 8)
109 | ((out[outpos + i] >> 8) & 0xff));
110 outbuf[i] = c;
114 inpos += old_in - inavail;
115 return (old_out - outavail) / sizeof (jchar);
116 #else /* HAVE_ICONV */
117 return -1;
118 #endif /* HAVE_ICONV */
121 void
122 gnu::gcj::convert::Input_iconv::done ()
124 #ifdef HAVE_ICONV
125 // 50 bytes should be enough for any reset sequence.
126 size_t avail = 50;
127 char tmp[avail];
128 char *p = tmp;
129 // Calling iconv() with a NULL INBUF pointer will cause iconv() to
130 // switch to its initial state. We don't care about the output that
131 // might be generated in that situation.
132 iconv_adapter (iconv, (iconv_t) handle, NULL, NULL, &p, &avail);
133 BytesToUnicode::done ();
134 #else /* HAVE_ICONV */
135 // If no iconv, do nothing
136 #endif /* HAVE_ICONV */
139 void
140 gnu::gcj::convert::Output_iconv::init (jstring encoding)
142 #ifdef HAVE_ICONV
143 jsize len = _Jv_GetStringUTFLength (encoding);
144 char buffer[len + 1];
145 _Jv_GetStringUTFRegion (encoding, 0, encoding->length(), buffer);
146 buffer[len] = '\0';
148 iconv_t h = iconv_open (buffer, "UCS-2");
149 if (h == (iconv_t) -1)
150 throw new java::io::UnsupportedEncodingException (encoding);
152 JvAssert (h != NULL);
153 handle = reinterpret_cast<gnu::gcj::RawData *> (h);
154 #else /* HAVE_ICONV */
155 // If no iconv, just throw an exception.
156 throw new java::io::UnsupportedEncodingException (encoding);
157 #endif /* HAVE_ICONV */
160 void
161 gnu::gcj::convert::Output_iconv::finalize (void)
163 #ifdef HAVE_ICONV
164 if (handle != NULL)
166 iconv_close ((iconv_t) handle);
167 handle = NULL;
169 #endif /* HAVE_ICONV */
172 jint
173 gnu::gcj::convert::Output_iconv::write (jcharArray inbuffer,
174 jint inpos, jint inlength)
176 #ifdef HAVE_ICONV
177 jchar *chars = elements (inbuffer);
178 jbyte *out = elements (buf);
179 jchar *temp_buffer = NULL;
181 size_t inavail = inlength * sizeof (jchar);
182 size_t old_in = inavail;
184 size_t outavail = buf->length - count;
185 size_t old_out = outavail;
187 char *inbuf = (char *) &chars[inpos];
188 char *outbuf = (char *) &out[count];
190 if (iconv_byte_swap)
192 // Ugly performance penalty -- don't use losing systems!
193 temp_buffer = (jchar *) _Jv_Malloc (inlength * sizeof (jchar));
194 for (int i = 0; i < inlength; ++i)
196 // Byte swap.
197 jchar c = (((chars[inpos + i] & 0xff) << 8)
198 | ((chars[inpos + i] >> 8) & 0xff));
199 temp_buffer[i] = c;
201 inbuf = (char *) temp_buffer;
204 size_t loop_old_in = old_in;
205 while (1)
207 size_t r = iconv_adapter (iconv, (iconv_t) handle,
208 &inbuf, &inavail,
209 &outbuf, &outavail);
210 if (r == (size_t) -1)
212 if (errno == EINVAL)
214 // Incomplete byte sequence at the end of the input
215 // buffer. This shouldn't be able to happen here.
216 break;
218 else if (errno == E2BIG)
220 // Output buffer is too small.
221 break;
223 else if (errno == EILSEQ || inavail == loop_old_in)
225 // Untranslatable sequence. Since glibc 2.1.3 doesn't
226 // properly set errno, we also assume that this is what
227 // is happening if no conversions took place. (This can
228 // be a bogus assumption if in fact the output buffer is
229 // too small.) We skip the first character and try
230 // again.
231 inavail -= 2;
232 if (inavail == 0)
233 break;
234 loop_old_in -= 2;
235 inbuf += 2;
238 else
239 break;
242 if (temp_buffer != NULL)
243 _Jv_Free (temp_buffer);
245 count += old_out - outavail;
246 return (old_in - inavail) / sizeof (jchar);
247 #else /* HAVE_ICONV */
248 return -1;
249 #endif /* HAVE_ICONV */
252 jboolean
253 gnu::gcj::convert::IOConverter::iconv_init (void)
255 // Some versions of iconv() always return their UCS-2 results in
256 // big-endian order, and they also require UCS-2 inputs to be in
257 // big-endian order. For instance, glibc 2.1.3 does this. If the
258 // UTF-8=>UCS-2 iconv converter has this feature, then we assume
259 // that all UCS-2 converters do. (This might not be the best
260 // heuristic, but is is all we've got.)
261 jboolean result = false;
262 #ifdef HAVE_ICONV
263 iconv_t handle = iconv_open ("UCS-2", "UTF-8");
264 if (handle != (iconv_t) -1)
266 jchar c;
267 unsigned char in[3];
268 char *inp, *outp;
269 size_t inc, outc, r;
271 // This is the UTF-8 encoding of \ufeff.
272 in[0] = 0xef;
273 in[1] = 0xbb;
274 in[2] = 0xbf;
276 inp = (char *) in;
277 inc = 3;
278 outp = (char *) &c;
279 outc = 2;
281 r = iconv_adapter (iconv, handle, &inp, &inc, &outp, &outc);
282 // Conversion must be complete for us to use the result.
283 if (r != (size_t) -1 && inc == 0 && outc == 0)
284 result = (c != 0xfeff);
286 // Release iconv handle.
287 iconv_close (handle);
289 #endif /* HAVE_ICONV */
290 return result;
293 void
294 gnu::gcj::convert::Output_iconv::done ()
296 #ifdef HAVE_ICONV
297 // 50 bytes should be enough for any reset sequence.
298 size_t avail = 50;
299 char tmp[avail];
300 char *p = tmp;
301 // Calling iconv() with a NULL INBUF pointer will cause iconv() to
302 // switch to its initial state. We don't care about the output that
303 // might be generated in that situation.
304 iconv_adapter (iconv, (iconv_t) handle, NULL, NULL, &p, &avail);
305 UnicodeToBytes::done ();
306 #else /* HAVE_ICONV */
307 // If no iconv, do nothing
308 #endif /* HAVE_ICONV */