1 /* src/vmcore/suck.c - functions to read LE ordered types from a buffer
3 Copyright (C) 1996-2005, 2006, 2007, 2008
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
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.
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.
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
35 #include "mm/memory.h"
37 #include "threads/lock-common.h"
39 #include "toolbox/list.h"
40 #include "toolbox/logging.h"
41 #include "toolbox/util.h"
43 #include "vm/exceptions.hpp"
44 #include "vm/properties.h"
47 #include "vmcore/loader.h"
48 #include "vmcore/options.h"
49 #include "vmcore/suck.h"
50 #include "vmcore/os.hpp"
51 #include "vmcore/zip.h"
54 /* global variables ***********************************************************/
56 list_t *list_classpath_entries;
59 /* suck_init *******************************************************************
61 Initializes the suck subsystem like initializing the classpath
64 *******************************************************************************/
68 TRACESUBSYSTEMINITIALIZATION("suck_init");
70 list_classpath_entries = list_create(OFFSET(list_classpath_entry, linkage));
78 /* scandir_filter **************************************************************
80 Filters for zip/jar files.
82 *******************************************************************************/
84 #if defined(__LINUX__)
85 static int scandir_filter(const struct dirent *a)
87 static int scandir_filter(struct dirent *a)
92 #if defined(_DIRENT_HAVE_D_NAMLEN)
95 namlen = strlen(a->d_name);
98 if ((strncasecmp(a->d_name + namlen - 4, ".zip", 4) == 0) ||
99 (strncasecmp(a->d_name + namlen - 4, ".jar", 4) == 0))
106 /* suck_add ********************************************************************
108 Adds a classpath to the global classpath entries list.
110 *******************************************************************************/
112 void suck_add(char *classpath)
114 list_classpath_entry *lce;
122 #if defined(ENABLE_ZLIB)
126 /* parse the classpath string */
128 for (start = classpath; (*start) != '\0'; ) {
130 /* search for ':' delimiter to get the end of the current entry */
131 for (end = start; ((*end) != '\0') && ((*end) != ':'); end++);
135 filenamelen = end - start;
137 if (filenamelen > 4) {
138 if ((strncasecmp(end - 4, ".zip", 4) == 0) ||
139 (strncasecmp(end - 4, ".jar", 4) == 0)) {
144 /* save classpath entries as absolute pathnames */
149 if (*start != '/') { /* XXX fix me for win32 */
151 cwdlen = strlen(cwd) + strlen("/");
154 /* allocate memory for filename and fill it */
156 filename = MNEW(char, filenamelen + cwdlen + strlen("/") +
160 strcpy(filename, cwd);
161 strcat(filename, "/");
162 strncat(filename, start, filenamelen);
164 /* add cwd length to file length */
165 filenamelen += cwdlen;
168 strncpy(filename, start, filenamelen);
169 filename[filenamelen] = '\0';
175 #if defined(ENABLE_ZLIB)
176 ht = zip_open(filename);
179 lce = NEW(list_classpath_entry);
181 lce->type = CLASSPATH_ARCHIVE;
183 lce->path = filename;
184 lce->pathlen = filenamelen;
186 /* SUN compatible -verbose:class output */
188 if (opt_verboseclass)
189 printf("[Opened %s]\n", filename);
193 vm_abort("suck_add: zip/jar files not supported");
197 if (filename[filenamelen - 1] != '/') {/* XXX fixme for win32 */
198 filename[filenamelen] = '/';
199 filename[filenamelen + 1] = '\0';
203 lce = NEW(list_classpath_entry);
205 lce->type = CLASSPATH_PATH;
206 lce->path = filename;
207 lce->pathlen = filenamelen;
210 /* add current classpath entry, if no error */
213 list_add_last(list_classpath_entries, lce);
216 /* goto next classpath entry, skip ':' delimiter */
226 /* suck_add_from_property ******************************************************
228 Adds a classpath form a property entry to the global classpath
231 *******************************************************************************/
233 void suck_add_from_property(const char *key)
240 struct dirent **namelist;
244 char *boot_class_path;
247 /* get the property value */
249 value = properties_get(key);
254 /* get the directory entries of the property */
256 for (start = value; (*start) != '\0'; ) {
258 /* search for ':' delimiter to get the end of the current entry */
260 for (end = start; ((*end) != '\0') && ((*end) != ':'); end++);
265 /* allocate memory for the path entry */
267 pathlen = end - start;
268 path = MNEW(char, pathlen + strlen("0"));
270 /* copy and terminate the string */
272 strncpy(path, start, pathlen);
273 path[pathlen] = '\0';
275 /* Reset namelist to NULL for the freeing in an error case
280 /* scan the directory found for zip/jar files */
282 n = os_scandir(path, &namelist, scandir_filter, alphasort);
284 /* On error, just continue, this should be ok. */
287 for (i = 0; i < n; i++) {
288 #if defined(_DIRENT_HAVE_D_NAMLEN)
289 namlen = namelist[i]->d_namlen;
291 namlen = strlen(namelist[i]->d_name);
294 /* Allocate memory for bootclasspath. */
296 // FIXME Make boot_class_path const char*.
297 boot_class_path = (char*) properties_get("sun.boot.class.path");
300 pathlen + strlen("/") + namlen +
302 strlen(boot_class_path) +
305 /* Prepend the file found to the bootclasspath. */
309 strcat(p, namelist[i]->d_name);
311 strcat(p, boot_class_path);
313 properties_add("sun.boot.class.path", p);
314 properties_add("java.boot.class.path", p);
316 MFREE(boot_class_path, char, strlen(boot_class_path));
318 /* free the memory allocated by scandir */
319 /* (We use `free` as the memory came from the C library.) */
325 /* On some systems (like Linux) when n == 0, then namelist
326 returned from scnadir is NULL, thus we don't have to
328 (Use `free` as the memory came from the C library.) */
330 if (namelist != NULL)
333 MFREE(path, char, pathlen + strlen("0"));
336 /* goto next entry, skip ':' delimiter */
346 /* suck_check_classbuffer_size *************************************************
348 Assert that at least <len> bytes are left to read <len> is limited
349 to the range of non-negative s4 values.
351 *******************************************************************************/
353 bool suck_check_classbuffer_size(classbuffer *cb, s4 len)
355 #ifdef ENABLE_VERIFIER
356 if (len < 0 || ((cb->data + cb->size) - cb->pos) < len) {
357 exceptions_throw_classformaterror(cb->clazz, "Truncated class file");
360 #endif /* ENABLE_VERIFIER */
366 u1 suck_u1(classbuffer *cb)
370 a = SUCK_BE_U1(cb->pos);
377 u2 suck_u2(classbuffer *cb)
381 a = SUCK_BE_U2(cb->pos);
388 u4 suck_u4(classbuffer *cb)
392 a = SUCK_BE_U4(cb->pos);
399 u8 suck_u8(classbuffer *cb)
401 #if U8_AVAILABLE == 1
404 a = SUCK_BE_U8(cb->pos);
411 v.high = suck_u4(cb);
419 float suck_float(classbuffer *cb)
423 #if WORDS_BIGENDIAN == 0
427 for (i = 0; i < 4; i++)
428 buffer[3 - i] = suck_u1(cb);
430 MCOPY((u1 *) (&f), buffer, u1, 4);
432 suck_nbytes((u1*) (&f), cb, 4);
435 assert(sizeof(float) == 4);
441 double suck_double(classbuffer *cb)
445 #if WORDS_BIGENDIAN == 0
449 # if defined(__ARM__) && defined(__ARMEL__) && !defined(__VFP_FP__)
451 * On little endian ARM processors when using FPA, word order
452 * of doubles is still big endian. So take that into account
453 * here. When using VFP, word order of doubles follows byte
454 * order. (michi 2005/07/24)
456 for (i = 0; i < 4; i++)
457 buffer[3 - i] = suck_u1(cb);
458 for (i = 0; i < 4; i++)
459 buffer[7 - i] = suck_u1(cb);
461 for (i = 0; i < 8; i++)
462 buffer[7 - i] = suck_u1(cb);
463 # endif /* defined(__ARM__) && ... */
465 MCOPY((u1 *) (&d), buffer, u1, 8);
467 suck_nbytes((u1*) (&d), cb, 8);
470 assert(sizeof(double) == 8);
476 /* suck_nbytes *****************************************************************
478 Transfer block of classfile data into a buffer.
480 *******************************************************************************/
482 void suck_nbytes(u1 *buffer, classbuffer *cb, s4 len)
484 MCOPY(buffer, cb->pos, u1, len);
489 /* suck_skip_nbytes ************************************************************
491 Skip block of classfile data.
493 *******************************************************************************/
495 void suck_skip_nbytes(classbuffer *cb, s4 len)
501 /* suck_start ******************************************************************
503 Returns true if classbuffer is already loaded or a file for the
504 specified class has succussfully been read in. All directories of
505 the searchpath are used to find the classfile (<classname>.class).
506 Returns NULL if no classfile is found and writes an error message.
508 *******************************************************************************/
510 classbuffer *suck_start(classinfo *c)
512 list_classpath_entry *lce;
521 /* initialize return value */
525 /* get the classname as char string (do it here for the warning at
526 the end of the function) */
528 filenamelen = utf_bytes(c->name) + strlen(".class") + strlen("0");
529 filename = MNEW(char, filenamelen);
531 utf_copy(filename, c->name);
532 strcat(filename, ".class");
534 /* walk through all classpath entries */
536 for (lce = list_first(list_classpath_entries); lce != NULL && cb == NULL;
537 lce = list_next(list_classpath_entries, lce)) {
538 #if defined(ENABLE_ZLIB)
539 if (lce->type == CLASSPATH_ARCHIVE) {
541 /* enter a monitor on zip/jar archives */
543 LOCK_MONITOR_ENTER(lce);
545 /* try to get the file in current archive */
547 cb = zip_get(lce, c);
549 /* leave the monitor */
551 LOCK_MONITOR_EXIT(lce);
554 #endif /* defined(ENABLE_ZLIB) */
555 path = MNEW(char, lce->pathlen + filenamelen);
556 strcpy(path, lce->path);
557 strcat(path, filename);
559 classfile = os_fopen(path, "r");
561 if (classfile) { /* file exists */
562 if (!os_stat(path, &buffer)) { /* read classfile data */
563 cb = NEW(classbuffer);
565 cb->size = buffer.st_size;
566 cb->data = MNEW(u1, cb->size);
568 cb->path = lce->path;
570 /* read class data */
572 len = os_fread((void *) cb->data, 1, cb->size,
575 if (len != buffer.st_size) {
577 /* if (ferror(classfile)) { */
581 /* close the class file */
583 os_fclose(classfile);
587 MFREE(path, char, lce->pathlen + filenamelen);
588 #if defined(ENABLE_ZLIB)
595 dolog("Warning: Can not open class file '%s'", filename);
597 MFREE(filename, char, filenamelen);
603 /* suck_stop *******************************************************************
605 Frees memory for buffer with classfile data.
607 CAUTION: This function may only be called if buffer has been
608 allocated by suck_start with reading a file.
610 *******************************************************************************/
612 void suck_stop(classbuffer *cb)
616 MFREE(cb->data, u1, cb->size);
617 FREE(cb, classbuffer);
622 * These are local overrides for various environment variables in Emacs.
623 * Please do not remove this and leave it at the end of the file, where
624 * Emacs will automagically detect them.
625 * ---------------------------------------------------------------------
628 * indent-tabs-mode: t