* src/native/vm/cldc1.1/com_sun_cldc_io_ResourceInputStream.cpp
[cacao.git] / src / native / vm / cldc1.1 / com_sun_cldc_io_ResourceInputStream.cpp
1 /* src/native/vm/cldc1.1/com_sun_cldc_io_ResourceInputStream.cpp
2
3    Copyright (C) 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <sys/stat.h>
29 #include <sys/mman.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <zlib.h>
33
34 #include "mm/memory.h"
35
36 #include "native/jni.h"
37 #include "native/llni.h"
38 #include "native/native.h"
39
40 #include "native/include/java_lang_Object.h"
41 #include "native/include/java_lang_String.h"
42 #include "native/include/com_sun_cldchi_jvm_FileDescriptor.h"
43
44 // FIXME
45 extern "C" {
46 #include "native/include/com_sun_cldc_io_ResourceInputStream.h"
47 }
48
49 #include "vm/types.h"
50 #include "vm/builtin.h"
51 #include "vm/vm.hpp" /* REMOVE ME: temporarily */
52 #include "vm/exceptions.hpp"
53 #include "vm/string.hpp"
54
55 #include "vmcore/zip.h"
56
57 #include "threads/lock-common.h"
58
59
60 /* native methods implemented by this file ************************************/
61  
62 static JNINativeMethod methods[] = {
63         { (char*) "open",        (char*) "(Ljava/lang/String;)Ljava/lang/Object;", (void*) (uintptr_t) &Java_com_sun_cldc_io_ResourceInputStream_open        },
64         { (char*) "bytesRemain", (char*) "(Ljava/lang/Object;)I",                  (void*) (uintptr_t) &Java_com_sun_cldc_io_ResourceInputStream_bytesRemain },
65         { (char*) "readByte",    (char*) "(Ljava/lang/Object;)I",                  (void*) (uintptr_t) &Java_com_sun_cldc_io_ResourceInputStream_readByte    },
66         { (char*) "readBytes",   (char*) "(Ljava/lang/Object;[BII)I",              (void*) (uintptr_t) &Java_com_sun_cldc_io_ResourceInputStream_readBytes   },
67         { (char*) "clone",       (char*) "(Ljava/lang/Object;)Ljava/lang/Object;", (void*) (uintptr_t) &Java_com_sun_cldc_io_ResourceInputStream_clone       },
68 };
69  
70
71 /* _Jv_com_sun_cldc_io_ResourceInputStream_init ********************************
72  
73    Register native functions.
74  
75 *******************************************************************************/
76  
77 // FIXME
78 extern "C" {
79 void _Jv_com_sun_cldc_io_ResourceInputStream_init(void)
80 {
81         utf *u;
82  
83         u = utf_new_char("com/sun/cldc/io/ResourceInputStream");
84  
85         native_method_register(u, methods, NATIVE_METHODS_COUNT);
86 }
87 }
88
89 static struct com_sun_cldchi_jvm_FileDescriptor* zip_read_resource(list_classpath_entry *lce, utf *name)
90 {
91         hashtable_zipfile_entry *htzfe;
92         lfh                      lfh;
93         u1                      *indata;
94         u1                      *outdata;
95         z_stream                 zs;
96         int                      err;
97         
98         classinfo *ci;
99         com_sun_cldchi_jvm_FileDescriptor *fileDescriptor = NULL;
100
101         /* try to find the class in the current archive */
102
103         htzfe = zip_find(lce, name);
104
105         if (htzfe == NULL)
106                 return NULL;
107
108         /* read stuff from local file header */
109
110         lfh.filenamelength   = SUCK_LE_U2(htzfe->data + LFH_FILE_NAME_LENGTH);
111         lfh.extrafieldlength = SUCK_LE_U2(htzfe->data + LFH_EXTRA_FIELD_LENGTH);
112
113         indata = htzfe->data +
114                 LFH_HEADER_SIZE +
115                 lfh.filenamelength +
116                 lfh.extrafieldlength;
117
118         /* allocate buffer for uncompressed data */
119
120         outdata = MNEW(u1, htzfe->uncompressedsize);
121
122         /* how is the file stored? */
123
124         switch (htzfe->compressionmethod) {
125         case Z_DEFLATED:
126                 /* fill z_stream structure */
127
128                 zs.next_in   = indata;
129                 zs.avail_in  = htzfe->compressedsize;
130                 zs.next_out  = outdata;
131                 zs.avail_out = htzfe->uncompressedsize;
132
133                 zs.zalloc = Z_NULL;
134                 zs.zfree  = Z_NULL;
135                 zs.opaque = Z_NULL;
136
137                 /* initialize this inflate run */
138
139                 if (inflateInit2(&zs, -MAX_WBITS) != Z_OK)
140                         vm_abort("zip_get: inflateInit2 failed: %s", strerror(errno));
141
142                 /* decompress the file into buffer */
143
144                 err = inflate(&zs, Z_SYNC_FLUSH);
145
146                 if ((err != Z_STREAM_END) && (err != Z_OK))
147                         vm_abort("zip_get: inflate failed: %s", strerror(errno));
148
149                 /* finish this inflate run */
150
151                 if (inflateEnd(&zs) != Z_OK)
152                         vm_abort("zip_get: inflateEnd failed: %s", strerror(errno));
153                 break;
154
155         case 0:
156                 /* uncompressed file, just copy the data */
157                 MCOPY(outdata, indata, u1, htzfe->compressedsize);
158                 break;
159
160         default:
161                 vm_abort("zip_get: unknown compression method %d",
162                                  htzfe->compressionmethod);
163         }
164                 
165         /* Create a file descriptor object */
166         ci = load_class_bootstrap(utf_new_char("com/sun/cldchi/jvm/FileDescriptor"));
167         fileDescriptor = (com_sun_cldchi_jvm_FileDescriptor *) native_new_and_init(ci);
168         LLNI_field_set_val(fileDescriptor, pointer, (int64_t)outdata);
169         LLNI_field_set_val(fileDescriptor, length, htzfe->uncompressedsize);
170         LLNI_field_set_val(fileDescriptor, position, 0);
171         return fileDescriptor;
172         
173 }
174
175 static struct com_sun_cldchi_jvm_FileDescriptor* file_read_resource(char *path) 
176 {
177         int len;
178         struct stat statBuffer;
179         u1 *filep;
180         com_sun_cldchi_jvm_FileDescriptor *fileDescriptor = NULL; 
181         classinfo *ci;
182         int fd;
183         
184         fd = open(path, O_RDONLY);
185         
186         if (fd > 0) {
187                 
188                 if (fstat(fd, &statBuffer) != -1) {
189                         len = statBuffer.st_size;
190                 } else {  
191                         return NULL;
192                 }
193                 
194                 /* Map file into the memory */
195                 filep = (u1*) mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0);
196                 
197                 /* Create a file descriptor object */
198                 ci = load_class_bootstrap(utf_new_char("com/sun/cldchi/jvm/FileDescriptor"));
199                 fileDescriptor = (com_sun_cldchi_jvm_FileDescriptor *) native_new_and_init(ci);
200                 LLNI_field_set_val(fileDescriptor, pointer, (int64_t)filep);
201                 LLNI_field_set_val(fileDescriptor, length, len);
202                 LLNI_field_set_val(fileDescriptor, position, 0);
203                 
204                 return fileDescriptor;  
205                 
206         } else {
207                 return NULL;
208         }
209         
210 }
211
212
213 // Native functions are exported as C functions.
214 extern "C" {
215
216 /*
217  * Class:     com/sun/cldc/io/ResourceInputStream
218  * Method:    open
219  * Signature: (Ljava/lang/String;)Ljava/lang/Object;
220  */
221 JNIEXPORT struct java_lang_Object* JNICALL Java_com_sun_cldc_io_ResourceInputStream_open(JNIEnv *env, jclass clazz, java_lang_String *name)
222 {
223         
224         list_classpath_entry *lce;
225         char *filename;
226         s4 filenamelen;
227         char *path;
228         utf *uname;
229         com_sun_cldchi_jvm_FileDescriptor* descriptor;
230         
231         /* get the classname as char string (do it here for the warning at
232        the end of the function) */
233
234         uname = javastring_toutf((java_handle_t *)name, false);
235         filenamelen = utf_bytes(uname) + strlen("0");
236         filename = MNEW(char, filenamelen);
237         utf_copy(filename, uname);
238         
239         /* walk through all classpath entries */
240
241         for (lce = (list_classpath_entry*) list_first(list_classpath_entries); lce != NULL;
242                  lce = (list_classpath_entry*) list_next(list_classpath_entries, lce)) {
243                         
244 #if defined(ENABLE_ZLIB)
245                 if (lce->type == CLASSPATH_ARCHIVE) {
246
247                         /* enter a monitor on zip/jar archives */
248                         LOCK_MONITOR_ENTER(lce);
249
250                         /* try to get the file in current archive */
251                         descriptor = zip_read_resource(lce, uname);
252
253                         /* leave the monitor */
254                         LOCK_MONITOR_EXIT(lce);
255                         
256                         if (descriptor != NULL) { /* file exists */
257                                 break;
258                         }
259
260                 } else {
261 #endif
262                         
263                         path = MNEW(char, lce->pathlen + filenamelen);
264                         strcpy(path, lce->path);
265                         strcat(path, filename);
266
267                         descriptor = file_read_resource(path);
268                         
269                         MFREE(path, char, lce->pathlen + filenamelen);
270
271                         if (descriptor != NULL) { /* file exists */
272                                 break;
273                         }
274                         
275 #if defined(ENABLE_ZLIB)
276                 }
277 #endif  
278                         
279         }
280
281         MFREE(filename, char, filenamelen);
282
283         return (java_lang_Object*) descriptor;
284         
285 }
286
287
288 /*
289  * Class:     com_sun_cldc_io_ResourceInputStream
290  * Method:    bytesRemain
291  * Signature: (Ljava/lang/Object;)I
292  */
293 JNIEXPORT s4 JNICALL Java_com_sun_cldc_io_ResourceInputStream_bytesRemain(JNIEnv *env, jclass clazz, struct java_lang_Object* jobj) {
294         
295         com_sun_cldchi_jvm_FileDescriptor *fileDescriptor;
296         int32_t length;
297         int32_t position;
298
299         fileDescriptor = (com_sun_cldchi_jvm_FileDescriptor *) jobj;
300         LLNI_field_get_val(fileDescriptor, position, position);
301         LLNI_field_get_val(fileDescriptor, length, length);
302         
303         return length - position;
304
305 }
306
307 /*
308  * Class:     com_sun_cldc_io_ResourceInputStream
309  * Method:    readByte
310  * Signature: (Ljava/lang/Object;)I
311  */
312 JNIEXPORT s4 JNICALL Java_com_sun_cldc_io_ResourceInputStream_readByte(JNIEnv *env, jclass clazz, struct java_lang_Object* jobj) {
313         
314         com_sun_cldchi_jvm_FileDescriptor *fileDescriptor;
315         u1 byte;
316         int32_t length;
317         int32_t position;
318         int64_t filep;
319         
320         fileDescriptor = (com_sun_cldchi_jvm_FileDescriptor *) jobj;
321         LLNI_field_get_val(fileDescriptor, position, position);
322         LLNI_field_get_val(fileDescriptor, length, length);
323         LLNI_field_get_val(fileDescriptor, pointer, filep);
324         
325         if (position < length) {
326                 byte = ((u1*)(int)filep)[position];
327                 position++;
328         } else {
329                 return -1; /* EOF */
330         }
331
332         /* Update access position */
333         LLNI_field_set_val(fileDescriptor, position, position);
334         
335         return (byte & 0xFF);
336
337 }
338
339 /*
340  * Class:     com_sun_cldc_io_ResourceInputStream
341  * Method:    readBytes
342  * Signature: (Ljava/lang/Object;[BII)I
343  */
344 JNIEXPORT s4 JNICALL Java_com_sun_cldc_io_ResourceInputStream_readBytes(JNIEnv *env, jclass clazz, struct java_lang_Object* jobj, java_handle_bytearray_t* byteArray, s4 off, s4 len) {
345         
346         com_sun_cldchi_jvm_FileDescriptor *fileDescriptor;
347         s4 readBytes = -1;
348         int32_t fileLength;
349         int32_t position;
350         s4 available;
351         int64_t filep;
352         void *buf;
353
354         /* get pointer to the buffer */
355         buf = &(LLNI_array_direct(byteArray, off));
356         
357         fileDescriptor = (com_sun_cldchi_jvm_FileDescriptor *) jobj;
358         LLNI_field_get_val(fileDescriptor, position, position);
359         LLNI_field_get_val(fileDescriptor, length, fileLength);
360         LLNI_field_get_val(fileDescriptor, pointer, filep);
361         
362         if (position < fileLength) {
363                 available = fileLength - position;
364                 if (available < len) {
365                         readBytes = available;
366                 } else {
367                         readBytes = len;
368                 }
369                 memcpy(buf, ((u1*)(int)filep) + position, readBytes * sizeof(u1));
370                 position += readBytes;
371         } else {
372                 return -1; /* EOF */
373         }
374
375         /* Update access position */
376         LLNI_field_set_val(fileDescriptor, position, position);
377         
378         return readBytes;
379 }
380
381 /*
382  * Class:     com_sun_cldc_io_ResourceInputStream
383  * Method:    clone
384  * Signature: (Ljava/lang/Object;)Ljava/lang/Object;
385  */
386 JNIEXPORT struct java_lang_Object* JNICALL Java_com_sun_cldc_io_ResourceInputStream_clone(JNIEnv *env, jclass clazz, struct java_lang_Object* jobj) {
387         
388         classinfo *ci;
389         com_sun_cldchi_jvm_FileDescriptor *srcFileDescriptor;
390         com_sun_cldchi_jvm_FileDescriptor *dstFileDescriptor;
391         int32_t srcLength;
392         int32_t srcPosition;
393         int64_t srcFilePointer;
394         
395         srcFileDescriptor = (com_sun_cldchi_jvm_FileDescriptor *) jobj;
396         LLNI_field_get_val(srcFileDescriptor, position, srcPosition);
397         LLNI_field_get_val(srcFileDescriptor, length, srcLength);
398         LLNI_field_get_val(srcFileDescriptor, pointer, srcFilePointer);
399         
400         ci = load_class_bootstrap(utf_new_char("com/sun/cldchi/jvm/FileDescriptor"));
401         dstFileDescriptor = (com_sun_cldchi_jvm_FileDescriptor *) native_new_and_init(ci);
402         LLNI_field_set_val(dstFileDescriptor, position, srcPosition);
403         LLNI_field_set_val(dstFileDescriptor, length, srcLength);
404         LLNI_field_set_val(dstFileDescriptor, pointer, srcFilePointer);
405         
406         return (java_lang_Object*) dstFileDescriptor;
407
408 }
409
410 } // extern "C"
411
412
413 /*
414  * These are local overrides for various environment variables in Emacs.
415  * Please do not remove this and leave it at the end of the file, where
416  * Emacs will automagically detect them.
417  * ---------------------------------------------------------------------
418  * Local variables:
419  * mode: c++
420  * indent-tabs-mode: t
421  * c-basic-offset: 4
422  * tab-width: 4
423  * End:
424  * vim:noexpandtab:sw=4:ts=4:
425  */