1 /* gnu_java_nio_charset_iconv_IconvDecoder.c --
2    Copyright (C) 2005 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 #include <config.h>
39 #include <jcl.h>
40 
41 #include <stdio.h>
42 #include <assert.h>
43 #include <errno.h>
44 
45 #if defined(HAVE_ICONV)
46 #include <iconv.h>
47 #endif
48 
49 #include "gnu_java_nio_charset_iconv_IconvDecoder.h"
50 
51 static void createRawData (JNIEnv * env, jobject obj, void *ptr);
52 static void *getData (JNIEnv * env, jobject obj);
53 
54 static jfieldID infid = NULL;
55 static jfieldID outfid = NULL;
56 
57 /* Union used for type punning. */
58 union char_union
59 {
60   jbyte **jb;
61   jchar **jc;
62   char **c;
63 };
64 
65 JNIEXPORT void JNICALL
Java_gnu_java_nio_charset_iconv_IconvDecoder_openIconv(JNIEnv * env,jobject obj,jstring jname)66 Java_gnu_java_nio_charset_iconv_IconvDecoder_openIconv (JNIEnv * env,
67 							jobject obj,
68 							jstring jname)
69 {
70 #if defined(HAVE_ICONV)
71   iconv_t iconv_object;
72   jclass cls;
73 
74   const char *name = JCL_jstring_to_cstring (env, jname);
75   if (name == NULL)
76     return;
77 
78   /* Cache fieldIDs for use in decode function. */
79   if (infid == NULL || outfid == NULL)
80     {
81       cls = (*env)->GetObjectClass (env, obj);
82       infid = (*env)->GetFieldID (env, cls, "inremaining", "I");
83       assert (infid != 0);
84       outfid = (*env)->GetFieldID (env, cls, "outremaining", "I");
85       assert (outfid != 0);
86     }
87 
88   /* to java from "name", native java format depends on endianness */
89 #ifdef WORDS_BIGENDIAN
90   iconv_object = iconv_open ("UTF-16BE", name);
91 #else
92   iconv_object = iconv_open ("UTF-16LE", name);
93 #endif
94 
95   JCL_free_cstring (env, jname, name);
96   if ((long) iconv_object == -1L)
97     {
98       JCL_ThrowException (env, "java/lang/IllegalArgumentException",
99 			  "Charset not available");
100       return;
101     }
102   createRawData (env, obj, (void *) iconv_object);
103 #else
104   JCL_ThrowException (env, "java/lang/IllegalArgumentException",
105 		      "iconv not available");
106 #endif
107 }
108 
109 JNIEXPORT jint JNICALL
Java_gnu_java_nio_charset_iconv_IconvDecoder_decode(JNIEnv * env,jobject obj,jbyteArray inArr,jcharArray outArr,jint posIn,jint remIn,jint posOut,jint remOut)110 Java_gnu_java_nio_charset_iconv_IconvDecoder_decode (JNIEnv * env,
111 						     jobject obj,
112 						     jbyteArray inArr,
113 						     jcharArray outArr,
114 						     jint posIn, jint remIn,
115 						     jint posOut, jint remOut)
116 {
117 #if defined(HAVE_ICONV)
118   iconv_t iconv_object = getData (env, obj);
119   size_t retval;
120   union char_union in, out;
121   jbyte *input, *inputcopy;
122   jchar *output, *outputcopy;
123   size_t lenIn = (size_t) remIn;
124   size_t lenOut = (size_t) remOut * 2;
125 
126   inputcopy = input = (*env)->GetByteArrayElements (env, inArr, 0);
127   outputcopy = output = (*env)->GetCharArrayElements (env, outArr, 0);
128 
129   input += posIn;
130   output += posOut;
131 
132   in.jb = &input;
133   out.jc = &output;
134   retval = iconv (iconv_object, (ICONV_CONST char **) in.c, &lenIn,
135 		  out.c, &lenOut);
136 
137   /* XXX: Do we need to relase the input array? It's not modified. */
138   (*env)->ReleaseByteArrayElements (env, inArr, inputcopy, 0);
139   (*env)->ReleaseCharArrayElements (env, outArr, outputcopy, 0);
140 
141   if (retval == (size_t) (-1))
142     {
143       if (errno == EILSEQ || errno == EINVAL)
144 	retval = 1;
145       else
146 	retval = 0;
147     }
148   else
149     retval = 0;
150 
151   (*env)->SetIntField (env, obj, infid, (jint) lenIn);
152   (*env)->SetIntField (env, obj, outfid, (jint) (lenOut >> 1));
153 
154   return (jint) retval;
155 #else
156   return -1;
157 #endif
158 }
159 
160 JNIEXPORT void JNICALL
Java_gnu_java_nio_charset_iconv_IconvDecoder_closeIconv(JNIEnv * env,jobject obj)161 Java_gnu_java_nio_charset_iconv_IconvDecoder_closeIconv (JNIEnv * env,
162 							 jobject obj)
163 {
164 #if defined(HAVE_ICONV)
165   iconv_t iconv_object;
166   iconv_object = getData (env, obj);
167   iconv_close (iconv_object);
168 #endif
169 }
170 
171 
172 static void
createRawData(JNIEnv * env,jobject obj,void * ptr)173 createRawData (JNIEnv * env, jobject obj, void *ptr)
174 {
175   jclass cls;
176   jobject data;
177   jfieldID data_fid;
178 
179   cls = (*env)->GetObjectClass (env, obj);
180   data_fid = (*env)->GetFieldID (env, cls, "data", "Lgnu/classpath/Pointer;");
181   assert (data_fid != 0);
182 
183   data = JCL_NewRawDataObject(env, ptr);
184 
185   (*env)->SetObjectField (env, obj, data_fid, data);
186 }
187 
188 static void *
getData(JNIEnv * env,jobject obj)189 getData (JNIEnv * env, jobject obj)
190 {
191   jclass cls;
192   jfieldID data_fid;
193   jobject data;
194 
195   cls = (*env)->GetObjectClass (env, obj);
196   data_fid = (*env)->GetFieldID (env, cls, "data", "Lgnu/classpath/Pointer;");
197   assert (data_fid != 0);
198   data = (*env)->GetObjectField (env, obj, data_fid);
199 
200   return JCL_GetRawData(env, data);
201 }
202