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 #if defined(HAVE_ICONV)
52 static void createRawData (JNIEnv * env, jobject obj, void *ptr);
53 static void *getData (JNIEnv * env, jobject obj);
54 
55 static jfieldID infid = NULL;
56 static jfieldID outfid = NULL;
57 #endif
58 
59 /* Union used for type punning. */
60 union char_union
61 {
62   jbyte **jb;
63   jchar **jc;
64   char **c;
65 };
66 
67 JNIEXPORT void JNICALL
Java_gnu_java_nio_charset_iconv_IconvDecoder_openIconv(JNIEnv * env UNUSED,jobject obj UNUSED,jstring jname UNUSED)68 Java_gnu_java_nio_charset_iconv_IconvDecoder_openIconv (JNIEnv * env UNUSED,
69 							jobject obj UNUSED,
70 							jstring jname UNUSED)
71 {
72 #if defined(HAVE_ICONV)
73   iconv_t iconv_object;
74   jclass cls;
75 
76   const char *name = JCL_jstring_to_cstring (env, jname);
77   if (name == NULL)
78     return;
79 
80   /* Cache fieldIDs for use in decode function. */
81   if (infid == NULL || outfid == NULL)
82     {
83       cls = (*env)->GetObjectClass (env, obj);
84       infid = (*env)->GetFieldID (env, cls, "inremaining", "I");
85       assert (infid != 0);
86       outfid = (*env)->GetFieldID (env, cls, "outremaining", "I");
87       assert (outfid != 0);
88     }
89 
90   /* to java from "name", native java format depends on endianness */
91 #ifdef WORDS_BIGENDIAN
92   iconv_object = iconv_open ("UTF-16BE", name);
93 #else
94   iconv_object = iconv_open ("UTF-16LE", name);
95 #endif
96 
97   JCL_free_cstring (env, jname, name);
98   if ((long) iconv_object == -1L)
99     {
100       JCL_ThrowException (env, "java/lang/IllegalArgumentException",
101 			  "Charset not available");
102       return;
103     }
104   createRawData (env, obj, (void *) iconv_object);
105 #else
106   JCL_ThrowException (env, "java/lang/IllegalArgumentException",
107 		      "iconv not available");
108 #endif
109 }
110 
111 JNIEXPORT jint JNICALL
Java_gnu_java_nio_charset_iconv_IconvDecoder_decode(JNIEnv * env UNUSED,jobject obj UNUSED,jbyteArray inArr UNUSED,jcharArray outArr UNUSED,jint posIn UNUSED,jint remIn UNUSED,jint posOut UNUSED,jint remOut UNUSED)112 Java_gnu_java_nio_charset_iconv_IconvDecoder_decode (JNIEnv * env UNUSED,
113 						     jobject obj UNUSED,
114 						     jbyteArray inArr UNUSED,
115 						     jcharArray outArr UNUSED,
116 						     jint posIn UNUSED,
117                                                      jint remIn UNUSED,
118 						     jint posOut UNUSED,
119                                                      jint remOut UNUSED)
120 {
121 #if defined(HAVE_ICONV)
122   iconv_t iconv_object = getData (env, obj);
123   size_t retval;
124   union char_union in, out;
125   jbyte *input, *inputcopy;
126   jchar *output, *outputcopy;
127   size_t lenIn = (size_t) remIn;
128   size_t lenOut = (size_t) remOut * 2;
129 
130   inputcopy = input = (*env)->GetByteArrayElements (env, inArr, 0);
131   outputcopy = output = (*env)->GetCharArrayElements (env, outArr, 0);
132 
133   input += posIn;
134   output += posOut;
135 
136   in.jb = &input;
137   out.jc = &output;
138   retval = iconv (iconv_object, (ICONV_CONST char **) in.c, &lenIn,
139 		  out.c, &lenOut);
140 
141   /* XXX: Do we need to relase the input array? It's not modified. */
142   (*env)->ReleaseByteArrayElements (env, inArr, inputcopy, 0);
143   (*env)->ReleaseCharArrayElements (env, outArr, outputcopy, 0);
144 
145   if (retval == (size_t) (-1))
146     {
147       if (errno == EILSEQ)
148 	retval = 1;
149       else
150 	retval = 0;
151     }
152   else
153     retval = 0;
154 
155   (*env)->SetIntField (env, obj, infid, (jint) lenIn);
156   (*env)->SetIntField (env, obj, outfid, (jint) (lenOut >> 1));
157 
158   return (jint) retval;
159 #else
160   return -1;
161 #endif
162 }
163 
164 JNIEXPORT void JNICALL
Java_gnu_java_nio_charset_iconv_IconvDecoder_closeIconv(JNIEnv * env UNUSED,jobject obj UNUSED)165 Java_gnu_java_nio_charset_iconv_IconvDecoder_closeIconv (JNIEnv * env UNUSED,
166 							 jobject obj UNUSED)
167 {
168 #if defined(HAVE_ICONV)
169   iconv_t iconv_object;
170   iconv_object = getData (env, obj);
171   iconv_close (iconv_object);
172 #endif
173 }
174 
175 
176 #if defined(HAVE_ICONV)
177 static void
createRawData(JNIEnv * env,jobject obj,void * ptr)178 createRawData (JNIEnv * env, jobject obj, void *ptr)
179 {
180   jclass cls;
181   jobject data;
182   jfieldID data_fid;
183 
184   cls = (*env)->GetObjectClass (env, obj);
185   data_fid = (*env)->GetFieldID (env, cls, "data", "Lgnu/classpath/Pointer;");
186   assert (data_fid != 0);
187 
188   data = JCL_NewRawDataObject(env, ptr);
189 
190   (*env)->SetObjectField (env, obj, data_fid, data);
191 }
192 
193 static void *
getData(JNIEnv * env,jobject obj)194 getData (JNIEnv * env, jobject obj)
195 {
196   jclass cls;
197   jfieldID data_fid;
198   jobject data;
199 
200   cls = (*env)->GetObjectClass (env, obj);
201   data_fid = (*env)->GetFieldID (env, cls, "data", "Lgnu/classpath/Pointer;");
202   assert (data_fid != 0);
203   data = (*env)->GetObjectField (env, obj, data_fid);
204 
205   return JCL_GetRawData(env, data);
206 }
207 #endif
208 
209