OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [gnu/] [gcj/] [convert/] [natIconv.cc] - Blame information for rev 756

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 756 jeremybenn
// natIconv.cc -- Java side of iconv() reader.
2
 
3
/* Copyright (C) 2000, 2001, 2003, 2006, 2011  Free Software Foundation
4
 
5
   This file is part of libgcj.
6
 
7
This software is copyrighted work licensed under the terms of the
8
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
9
details.  */
10
 
11
/* Author: Tom Tromey <tromey@redhat.com>.  */
12
 
13
#include <config.h>
14
 
15
#include <gcj/cni.h>
16
#include <jvm.h>
17
 
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>
22
 
23
#include <errno.h>
24
 
25
#ifdef HAVE_ICONV
26
#include <iconv.h>
27
 
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)
33
{
34
  return (*iconv_f) (handle, (T) inbuf, inavail, outbuf, outavail);
35
}
36
 
37
#endif
38
 
39
void
40
gnu::gcj::convert::Input_iconv::init (jstring encoding)
41
{
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';
47
 
48
  iconv_t h = iconv_open ("UCS-2", buffer);
49
  if (h == (iconv_t) -1)
50
    throw new ::java::io::UnsupportedEncodingException (encoding);
51
 
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 */
58
}
59
 
60
void
61
gnu::gcj::convert::Input_iconv::finalize (void)
62
{
63
#ifdef HAVE_ICONV
64
  if (handle != NULL)
65
    {
66
      iconv_close ((iconv_t) handle);
67
      handle = NULL;
68
    }
69
#endif /* HAVE_ICONV */
70
}
71
 
72
jint
73
gnu::gcj::convert::Input_iconv::read (jcharArray outbuffer,
74
                                      jint outpos, jint count)
75
{
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;
83
 
84
  char *inbuf = (char *) &bytes[inpos];
85
  char *outbuf = (char *) &out[outpos];
86
 
87
  size_t r = iconv_adapter (iconv, (iconv_t) handle,
88
                            &inbuf, &inavail,
89
                            &outbuf, &outavail);
90
 
91
  if (r == (size_t) -1)
92
    {
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 ();
100
    }
101
 
102
  if (iconv_byte_swap)
103
    {
104
      size_t max = (old_out - outavail) / sizeof (jchar);
105
      for (size_t i = 0; i < max; ++i)
106
        {
107
          // Byte swap.
108
          jchar c = (((out[outpos + i] & 0xff) << 8)
109
                     | ((out[outpos + i] >> 8) & 0xff));
110
          outbuf[i] = c;
111
        }
112
    }
113
 
114
  inpos += old_in - inavail;
115
  return (old_out - outavail) / sizeof (jchar);
116
#else /* HAVE_ICONV */
117
  return -1;
118
#endif /* HAVE_ICONV */
119
}
120
 
121
void
122
gnu::gcj::convert::Input_iconv::done ()
123
{
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 */
137
}
138
 
139
void
140
gnu::gcj::convert::Output_iconv::init (jstring encoding)
141
{
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';
147
 
148
  iconv_t h = iconv_open (buffer, "UCS-2");
149
  if (h == (iconv_t) -1)
150
    throw new ::java::io::UnsupportedEncodingException (encoding);
151
 
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 */
158
}
159
 
160
void
161
gnu::gcj::convert::Output_iconv::finalize (void)
162
{
163
#ifdef HAVE_ICONV
164
  if (handle != NULL)
165
    {
166
      iconv_close ((iconv_t) handle);
167
      handle = NULL;
168
    }
169
#endif /* HAVE_ICONV */
170
}
171
 
172
jint
173
gnu::gcj::convert::Output_iconv::write (jcharArray inbuffer,
174
                                        jint inpos, jint inlength)
175
{
176
#ifdef HAVE_ICONV
177
  jchar *chars = elements (inbuffer);
178
  jbyte *out = elements (buf);
179
  jchar *temp_buffer = NULL;
180
 
181
  size_t inavail = inlength * sizeof (jchar);
182
  size_t old_in = inavail;
183
 
184
  size_t outavail = buf->length - count;
185
  size_t old_out = outavail;
186
 
187
  char *inbuf = (char *) &chars[inpos];
188
  char *outbuf = (char *) &out[count];
189
 
190
  if (iconv_byte_swap)
191
    {
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)
195
        {
196
          // Byte swap.
197
          jchar c = (((chars[inpos + i] & 0xff) << 8)
198
                     | ((chars[inpos + i] >> 8) & 0xff));
199
          temp_buffer[i] = c;
200
        }
201
      inbuf = (char *) temp_buffer;
202
    }
203
 
204
  size_t loop_old_in = old_in;
205
  while (1)
206
    {
207
      size_t r = iconv_adapter (iconv, (iconv_t) handle,
208
                                &inbuf, &inavail,
209
                                &outbuf, &outavail);
210
      if (r == (size_t) -1)
211
        {
212
          if (errno == EINVAL)
213
            {
214
              // Incomplete byte sequence at the end of the input
215
              // buffer.  This shouldn't be able to happen here.
216
              break;
217
            }
218
          else if (errno == E2BIG)
219
            {
220
              // Output buffer is too small.
221
              break;
222
            }
223
          else if (errno == EILSEQ || inavail == loop_old_in)
224
            {
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;
236
            }
237
        }
238
      else
239
        break;
240
    }
241
 
242
  if (temp_buffer != NULL)
243
    _Jv_Free (temp_buffer);
244
 
245
  count += old_out - outavail;
246
  return (old_in - inavail) / sizeof (jchar);
247
#else /* HAVE_ICONV */
248
  return -1;
249
#endif /* HAVE_ICONV */
250
}
251
 
252
jboolean
253
gnu::gcj::convert::IOConverter::iconv_init (void)
254
{
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)
265
    {
266
      jchar c;
267
      unsigned char in[4];
268
      char *inp, *outp;
269
      size_t inc, outc, r;
270
 
271
      // This is the UTF-8 encoding of \ufeff.  At least Tru64 UNIX libiconv
272
      // needs the trailing NUL byte, otherwise iconv fails with EINVAL.
273
      in[0] = 0xef;
274
      in[1] = 0xbb;
275
      in[2] = 0xbf;
276
      in[3] = 0x00;
277
 
278
      inp = (char *) in;
279
      inc = 4;
280
      outp = (char *) &c;
281
      outc = 2;
282
 
283
      r = iconv_adapter (iconv, handle, &inp, &inc, &outp, &outc);
284
      // Conversion must be complete for us to use the result.
285
      if (r != (size_t) -1 && inc == 0 && outc == 0)
286
        result = (c != 0xfeff);
287
 
288
      // Release iconv handle.
289
      iconv_close (handle);
290
    }
291
#endif /* HAVE_ICONV */
292
  return result;
293
}
294
 
295
void
296
gnu::gcj::convert::Output_iconv::done ()
297
{
298
#ifdef HAVE_ICONV
299
  // 50 bytes should be enough for any reset sequence.
300
  size_t avail = 50;
301
  char tmp[avail];
302
  char *p = tmp;
303
  // Calling iconv() with a NULL INBUF pointer will cause iconv() to
304
  // switch to its initial state.  We don't care about the output that
305
  // might be generated in that situation.
306
  iconv_adapter (iconv, (iconv_t) handle, NULL, NULL, &p, &avail);
307
  UnicodeToBytes::done ();
308
#else /* HAVE_ICONV */
309
  // If no iconv, do nothing
310
#endif /* HAVE_ICONV */
311
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.