1 /* src/vmcore/suck.c - functions to read LE ordered types from a buffer
3 Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
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.
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.
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
25 $Id: suck.c 8399 2007-08-22 18:24:23Z twisti $
41 #include "mm/memory.h"
43 #include "threads/lock-common.h"
45 #include "toolbox/list.h"
46 #include "toolbox/logging.h"
47 #include "toolbox/util.h"
49 #include "vm/exceptions.h"
50 #include "vm/properties.h"
53 #include "vmcore/loader.h"
54 #include "vmcore/options.h"
55 #include "vmcore/suck.h"
56 #include "vmcore/zip.h"
59 /* global variables ***********************************************************/
61 list_t *list_classpath_entries;
64 /* suck_init *******************************************************************
66 Initializes the suck subsystem like initializing the classpath
69 *******************************************************************************/
73 list_classpath_entries = list_create(OFFSET(list_classpath_entry, linkage));
81 /* scandir_filter **************************************************************
83 Filters for zip/jar files.
85 *******************************************************************************/
87 #if defined(__LINUX__)
88 static int scandir_filter(const struct dirent *a)
90 static int scandir_filter(struct dirent *a)
95 #if defined(_DIRENT_HAVE_D_NAMLEN)
98 namlen = strlen(a->d_name);
101 if ((strncasecmp(a->d_name + namlen - 4, ".zip", 4) == 0) ||
102 (strncasecmp(a->d_name + namlen - 4, ".jar", 4) == 0))
109 /* suck_add ********************************************************************
111 Adds a classpath to the global classpath entries list.
113 *******************************************************************************/
115 void suck_add(char *classpath)
117 list_classpath_entry *lce;
125 #if defined(ENABLE_ZLIB)
129 /* parse the classpath string */
131 for (start = classpath; (*start) != '\0'; ) {
133 /* search for ':' delimiter to get the end of the current entry */
134 for (end = start; ((*end) != '\0') && ((*end) != ':'); end++);
138 filenamelen = end - start;
140 if (filenamelen > 4) {
141 if ((strncasecmp(end - 4, ".zip", 4) == 0) ||
142 (strncasecmp(end - 4, ".jar", 4) == 0)) {
147 /* save classpath entries as absolute pathnames */
152 if (*start != '/') { /* XXX fix me for win32 */
154 cwdlen = strlen(cwd) + strlen("/");
157 /* allocate memory for filename and fill it */
159 filename = MNEW(char, filenamelen + cwdlen + strlen("/") +
163 strcpy(filename, cwd);
164 strcat(filename, "/");
165 strncat(filename, start, filenamelen);
167 /* add cwd length to file length */
168 filenamelen += cwdlen;
171 strncpy(filename, start, filenamelen);
172 filename[filenamelen] = '\0';
178 #if defined(ENABLE_ZLIB)
179 ht = zip_open(filename);
182 lce = NEW(list_classpath_entry);
184 lce->type = CLASSPATH_ARCHIVE;
186 lce->path = filename;
187 lce->pathlen = filenamelen;
189 /* SUN compatible -verbose:class output */
191 if (opt_verboseclass)
192 printf("[Opened %s]\n", filename);
196 vm_abort("suck_add: zip/jar files not supported");
200 if (filename[filenamelen - 1] != '/') {/* XXX fixme for win32 */
201 filename[filenamelen] = '/';
202 filename[filenamelen + 1] = '\0';
206 lce = NEW(list_classpath_entry);
208 lce->type = CLASSPATH_PATH;
209 lce->path = filename;
210 lce->pathlen = filenamelen;
213 /* add current classpath entry, if no error */
216 list_add_last(list_classpath_entries, lce);
219 /* goto next classpath entry, skip ':' delimiter */
229 /* suck_add_from_property ******************************************************
231 Adds a classpath form a property entry to the global classpath
234 *******************************************************************************/
236 void suck_add_from_property(char *key)
243 struct dirent **namelist;
247 char *boot_class_path;
250 /* get the property value */
252 value = properties_get(key);
257 /* get the directory entries of the property */
259 for (start = value; (*start) != '\0'; ) {
261 /* search for ':' delimiter to get the end of the current entry */
263 for (end = start; ((*end) != '\0') && ((*end) != ':'); end++);
268 /* allocate memory for the path entry */
270 pathlen = end - start;
271 path = MNEW(char, pathlen + strlen("0"));
273 /* copy and terminate the string */
275 strncpy(path, start, pathlen);
276 path[pathlen] = '\0';
278 /* Reset namelist to NULL for the freeing in an error case
283 /* scan the directory found for zip/jar files */
285 n = scandir(path, &namelist, scandir_filter, alphasort);
287 /* On error, just continue, this should be ok. */
290 for (i = 0; i < n; i++) {
291 #if defined(_DIRENT_HAVE_D_NAMLEN)
292 namlen = namelist[i]->d_namlen;
294 namlen = strlen(namelist[i]->d_name);
297 /* Allocate memory for bootclasspath. */
299 boot_class_path = properties_get("sun.boot.class.path");
302 pathlen + strlen("/") + namlen +
304 strlen(boot_class_path) +
307 /* Prepend the file found to the bootclasspath. */
311 strcat(p, namelist[i]->d_name);
313 strcat(p, boot_class_path);
315 MFREE(boot_class_path, u1, strlen(boot_class_path));
317 #if defined(ENABLE_JAVASE)
318 properties_add("sun.boot.class.path", p);
319 properties_add("java.boot.class.path", p);
322 /* free the memory allocated by scandir */
323 /* (We use `free` as the memory came from the C library.) */
329 /* On some systems (like Linux) when n == 0, then namelist
330 returned from scnadir is NULL, thus we don't have to
332 (Use `free` as the memory came from the C library.) */
334 if (namelist != NULL)
337 MFREE(path, char, pathlen + strlen("0"));
340 /* goto next entry, skip ':' delimiter */
350 /* suck_check_classbuffer_size *************************************************
352 Assert that at least <len> bytes are left to read <len> is limited
353 to the range of non-negative s4 values.
355 *******************************************************************************/
357 bool suck_check_classbuffer_size(classbuffer *cb, s4 len)
359 #ifdef ENABLE_VERIFIER
360 if (len < 0 || ((cb->data + cb->size) - cb->pos) < len) {
361 exceptions_throw_classformaterror((cb)->class, "Truncated class file");
364 #endif /* ENABLE_VERIFIER */
370 u1 suck_u1(classbuffer *cb)
374 a = SUCK_BE_U1(cb->pos);
381 u2 suck_u2(classbuffer *cb)
385 a = SUCK_BE_U2(cb->pos);
392 u4 suck_u4(classbuffer *cb)
396 a = SUCK_BE_U4(cb->pos);
403 u8 suck_u8(classbuffer *cb)
405 #if U8_AVAILABLE == 1
408 a = SUCK_BE_U8(cb->pos);
415 v.high = suck_u4(cb);
423 float suck_float(classbuffer *cb)
427 #if WORDS_BIGENDIAN == 0
431 for (i = 0; i < 4; i++)
432 buffer[3 - i] = suck_u1(cb);
434 MCOPY((u1 *) (&f), buffer, u1, 4);
436 suck_nbytes((u1*) (&f), cb, 4);
439 assert(sizeof(float) == 4);
445 double suck_double(classbuffer *cb)
449 #if WORDS_BIGENDIAN == 0
453 # if defined(__ARM__) && defined(__ARMEL__) && !defined(__VFP_FP__)
455 * On little endian ARM processors when using FPA, word order
456 * of doubles is still big endian. So take that into account
457 * here. When using VFP, word order of doubles follows byte
458 * order. (michi 2005/07/24)
460 for (i = 0; i < 4; i++)
461 buffer[3 - i] = suck_u1(cb);
462 for (i = 0; i < 4; i++)
463 buffer[7 - i] = suck_u1(cb);
465 for (i = 0; i < 8; i++)
466 buffer[7 - i] = suck_u1(cb);
467 # endif /* defined(__ARM__) && ... */
469 MCOPY((u1 *) (&d), buffer, u1, 8);
471 suck_nbytes((u1*) (&d), cb, 8);
474 assert(sizeof(double) == 8);
480 /* suck_nbytes *****************************************************************
482 Transfer block of classfile data into a buffer.
484 *******************************************************************************/
486 void suck_nbytes(u1 *buffer, classbuffer *cb, s4 len)
488 MCOPY(buffer, cb->pos, u1, len);
493 /* suck_skip_nbytes ************************************************************
495 Skip block of classfile data.
497 *******************************************************************************/
499 void suck_skip_nbytes(classbuffer *cb, s4 len)
505 /* suck_start ******************************************************************
507 Returns true if classbuffer is already loaded or a file for the
508 specified class has succussfully been read in. All directories of
509 the searchpath are used to find the classfile (<classname>.class).
510 Returns NULL if no classfile is found and writes an error message.
512 *******************************************************************************/
514 classbuffer *suck_start(classinfo *c)
516 list_classpath_entry *lce;
525 /* initialize return value */
529 /* get the classname as char string (do it here for the warning at
530 the end of the function) */
532 filenamelen = utf_bytes(c->name) + strlen(".class") + strlen("0");
533 filename = MNEW(char, filenamelen);
535 utf_copy(filename, c->name);
536 strcat(filename, ".class");
538 /* walk through all classpath entries */
540 for (lce = list_first(list_classpath_entries); lce != NULL && cb == NULL;
541 lce = list_next(list_classpath_entries, lce)) {
542 #if defined(ENABLE_ZLIB)
543 if (lce->type == CLASSPATH_ARCHIVE) {
545 /* enter a monitor on zip/jar archives */
547 LOCK_MONITOR_ENTER(lce);
549 /* try to get the file in current archive */
551 cb = zip_get(lce, c);
553 /* leave the monitor */
555 LOCK_MONITOR_EXIT(lce);
558 #endif /* defined(ENABLE_ZLIB) */
559 path = MNEW(char, lce->pathlen + filenamelen);
560 strcpy(path, lce->path);
561 strcat(path, filename);
563 classfile = fopen(path, "r");
565 if (classfile) { /* file exists */
566 if (!stat(path, &buffer)) { /* read classfile data */
567 cb = NEW(classbuffer);
569 cb->size = buffer.st_size;
570 cb->data = MNEW(u1, cb->size);
572 cb->path = lce->path;
574 /* read class data */
576 len = fread(cb->data, 1, cb->size, classfile);
578 if (len != buffer.st_size) {
580 /* if (ferror(classfile)) { */
584 /* close the class file */
590 MFREE(path, char, lce->pathlen + filenamelen);
591 #if defined(ENABLE_ZLIB)
598 dolog("Warning: Can not open class file '%s'", filename);
600 MFREE(filename, char, filenamelen);
606 /* suck_stop *******************************************************************
608 Frees memory for buffer with classfile data.
610 CAUTION: This function may only be called if buffer has been
611 allocated by suck_start with reading a file.
613 *******************************************************************************/
615 void suck_stop(classbuffer *cb)
619 MFREE(cb->data, u1, cb->size);
620 FREE(cb, classbuffer);
625 * These are local overrides for various environment variables in Emacs.
626 * Please do not remove this and leave it at the end of the file, where
627 * Emacs will automagically detect them.
628 * ---------------------------------------------------------------------
631 * indent-tabs-mode: t