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