1 /* src/vm/suck.c - functions to read LE ordered types from a buffer
3 Copyright (C) 1996-2005, 2006 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 Contact: cacao@cacaojvm.org
27 Authors: Christian Thalinger
31 $Id: suck.c 6037 2006-11-22 11:05:06Z twisti $
44 #include "mm/memory.h"
46 #if defined(ENABLE_THREADS)
47 # include "threads/native/lock.h"
49 # include "threads/none/lock.h"
52 #include "toolbox/list.h"
53 #include "toolbox/logging.h"
54 #include "toolbox/util.h"
55 #include "vm/exceptions.h"
56 #include "vm/loader.h"
57 #include "vm/options.h"
58 #include "vm/properties.h"
59 #include "vm/stringlocal.h"
65 /* global variables ***********************************************************/
67 list *list_classpath_entries;
70 /* suck_init *******************************************************************
72 Initializes the suck subsystem like initializing the classpath
75 *******************************************************************************/
79 list_classpath_entries = list_create(OFFSET(list_classpath_entry, linkage));
87 /* scandir_filter **************************************************************
89 Filters for zip/jar files.
91 *******************************************************************************/
93 #if defined(__LINUX__)
94 static int scandir_filter(const struct dirent *a)
96 static int scandir_filter(struct dirent *a)
101 #if defined(_DIRENT_HAVE_D_NAMLEN)
102 namlen = a->d_namlen;
104 namlen = strlen(a->d_name);
107 if ((strncasecmp(a->d_name + namlen - 4, ".zip", 4) == 0) ||
108 (strncasecmp(a->d_name + namlen - 4, ".jar", 4) == 0))
115 /* suck_add ********************************************************************
117 Adds a classpath to the global classpath entries list.
119 *******************************************************************************/
121 void suck_add(char *classpath)
123 list_classpath_entry *lce;
131 #if defined(ENABLE_ZLIB)
135 /* parse the classpath string */
137 for (start = classpath; (*start) != '\0'; ) {
139 /* search for ':' delimiter to get the end of the current entry */
140 for (end = start; ((*end) != '\0') && ((*end) != ':'); end++);
144 filenamelen = end - start;
146 if (filenamelen > 4) {
147 if ((strncasecmp(end - 4, ".zip", 4) == 0) ||
148 (strncasecmp(end - 4, ".jar", 4) == 0)) {
153 /* save classpath entries as absolute pathnames */
158 if (*start != '/') { /* XXX fix me for win32 */
160 cwdlen = strlen(cwd) + strlen("/");
163 /* allocate memory for filename and fill it */
165 filename = MNEW(char, filenamelen + cwdlen + strlen("/") +
169 strcpy(filename, cwd);
170 strcat(filename, "/");
171 strncat(filename, start, filenamelen);
173 /* add cwd length to file length */
174 filenamelen += cwdlen;
177 strncpy(filename, start, filenamelen);
178 filename[filenamelen] = '\0';
184 #if defined(ENABLE_ZLIB)
185 ht = zip_open(filename);
188 lce = NEW(list_classpath_entry);
190 lce->type = CLASSPATH_ARCHIVE;
192 lce->path = filename;
193 lce->pathlen = filenamelen;
195 /* SUN compatible -verbose:class output */
197 if (opt_verboseclass)
198 printf("[Opened %s]\n", filename);
202 throw_cacao_exception_exit(string_java_lang_InternalError,
203 "zip/jar files not supported");
207 if (filename[filenamelen - 1] != '/') {/* XXX fixme for win32 */
208 filename[filenamelen] = '/';
209 filename[filenamelen + 1] = '\0';
213 lce = NEW(list_classpath_entry);
215 lce->type = CLASSPATH_PATH;
216 lce->path = filename;
217 lce->pathlen = filenamelen;
220 /* add current classpath entry, if no error */
223 list_add_last(list_classpath_entries, lce);
226 /* goto next classpath entry, skip ':' delimiter */
236 /* suck_add_from_property ******************************************************
238 Adds a classpath form a property entry to the global classpath
241 *******************************************************************************/
243 void suck_add_from_property(char *key)
250 struct dirent **namelist;
254 char *tmpbootclasspath;
256 /* get the property value */
258 value = properties_get(key);
263 /* get the directory entries of the property */
265 for (start = value; (*start) != '\0'; ) {
267 /* search for ':' delimiter to get the end of the current entry */
269 for (end = start; ((*end) != '\0') && ((*end) != ':'); end++);
274 /* allocate memory for the path entry */
276 pathlen = end - start;
277 path = MNEW(char, pathlen + strlen("0"));
279 /* copy and terminate the string */
281 strncpy(path, start, pathlen);
282 path[pathlen] = '\0';
284 /* Reset namelist to NULL for the freeing in an error case
289 /* scan the directory found for zip/jar files */
291 n = scandir(path, &namelist, scandir_filter, alphasort);
293 /* On error, just continue, this should be ok. */
296 for (i = 0; i < n; i++) {
297 #if defined(_DIRENT_HAVE_D_NAMLEN)
298 namlen = namelist[i]->d_namlen;
300 namlen = strlen(namelist[i]->d_name);
303 /* reallocate memory for bootclasspath */
305 tmpbootclasspath = MNEW(char,
306 pathlen + strlen("/") + namlen +
308 strlen(_Jv_bootclasspath) +
311 /* prepend the file found to bootclasspath */
313 strcpy(tmpbootclasspath, path);
314 strcat(tmpbootclasspath, "/");
315 strcat(tmpbootclasspath, namelist[i]->d_name);
316 strcat(tmpbootclasspath, ":");
318 strcat(tmpbootclasspath, _Jv_bootclasspath);
320 /* free old bootclasspath memory */
322 MFREE(_Jv_bootclasspath, u1, strlen(_Jv_bootclasspath));
324 /* and set the new bootclasspath */
326 _Jv_bootclasspath = tmpbootclasspath;
328 /* free the memory allocated by scandir */
329 /* (We use `free` as the memory came from the C library.) */
335 /* On some systems (like Linux) when n == 0, then namelist
336 returned from scnadir is NULL, thus we don't have to
338 (Use `free` as the memory came from the C library.) */
340 if (namelist != NULL)
343 MFREE(path, char, pathlen + strlen("0"));
346 /* goto next entry, skip ':' delimiter */
356 /* suck_check_classbuffer_size *************************************************
358 Assert that at least <len> bytes are left to read <len> is limited
359 to the range of non-negative s4 values.
361 *******************************************************************************/
363 bool suck_check_classbuffer_size(classbuffer *cb, s4 len)
365 #ifdef ENABLE_VERIFIER
366 if (len < 0 || ((cb->data + cb->size) - cb->pos) < len) {
368 new_classformaterror((cb)->class, "Truncated class file");
372 #endif /* ENABLE_VERIFIER */
378 u1 suck_u1(classbuffer *cb)
382 a = SUCK_BE_U1(cb->pos);
389 u2 suck_u2(classbuffer *cb)
393 a = SUCK_BE_U2(cb->pos);
400 u4 suck_u4(classbuffer *cb)
404 a = SUCK_BE_U4(cb->pos);
411 u8 suck_u8(classbuffer *cb)
413 #if U8_AVAILABLE == 1
416 a = SUCK_BE_U8(cb->pos);
423 v.high = suck_u4(cb);
431 float suck_float(classbuffer *cb)
435 #if WORDS_BIGENDIAN == 0
439 for (i = 0; i < 4; i++)
440 buffer[3 - i] = suck_u1(cb);
442 MCOPY((u1 *) (&f), buffer, u1, 4);
444 suck_nbytes((u1*) (&f), cb, 4);
447 if (sizeof(float) != 4) {
448 *exceptionptr = new_internalerror("Incompatible float-format");
450 /* XXX should we exit in such a case? */
451 throw_exception_exit();
458 double suck_double(classbuffer *cb)
462 #if WORDS_BIGENDIAN == 0
466 #if defined(__ARM__) && defined(__ARMEL__) && !defined(__VFP_FP__)
468 * On little endian ARM processors when using FPA, word order
469 * of doubles is still big endian. So take that into account
470 * here. When using VFP, word order of doubles follows byte
471 * order. (michi 2005/07/24)
473 for (i = 0; i < 4; i++)
474 buffer[3 - i] = suck_u1(cb);
475 for (i = 0; i < 4; i++)
476 buffer[7 - i] = suck_u1(cb);
478 for (i = 0; i < 8; i++)
479 buffer[7 - i] = suck_u1(cb);
480 #endif /* defined(__ARM__) && ... */
482 MCOPY((u1 *) (&d), buffer, u1, 8);
484 suck_nbytes((u1*) (&d), cb, 8);
487 if (sizeof(double) != 8) {
488 *exceptionptr = new_internalerror("Incompatible double-format");
490 /* XXX should we exit in such a case? */
491 throw_exception_exit();
498 /* suck_nbytes *****************************************************************
500 Transfer block of classfile data into a buffer.
502 *******************************************************************************/
504 void suck_nbytes(u1 *buffer, classbuffer *cb, s4 len)
506 MCOPY(buffer, cb->pos, u1, len);
511 /* suck_skip_nbytes ************************************************************
513 Skip block of classfile data.
515 *******************************************************************************/
517 void suck_skip_nbytes(classbuffer *cb, s4 len)
523 /* suck_start ******************************************************************
525 Returns true if classbuffer is already loaded or a file for the
526 specified class has succussfully been read in. All directories of
527 the searchpath are used to find the classfile (<classname>.class).
528 Returns NULL if no classfile is found and writes an error message.
530 *******************************************************************************/
532 classbuffer *suck_start(classinfo *c)
534 list_classpath_entry *lce;
543 /* initialize return value */
547 /* get the classname as char string (do it here for the warning at
548 the end of the function) */
550 filenamelen = utf_bytes(c->name) + strlen(".class") + strlen("0");
551 filename = MNEW(char, filenamelen);
553 utf_copy(filename, c->name);
554 strcat(filename, ".class");
556 /* walk through all classpath entries */
558 for (lce = list_first(list_classpath_entries); lce != NULL && cb == NULL;
559 lce = list_next(list_classpath_entries, lce)) {
560 #if defined(ENABLE_ZLIB)
561 if (lce->type == CLASSPATH_ARCHIVE) {
563 /* enter a monitor on zip/jar archives */
565 LOCK_MONITOR_ENTER(lce);
567 /* try to get the file in current archive */
569 cb = zip_get(lce, c);
571 /* leave the monitor */
573 LOCK_MONITOR_EXIT(lce);
576 #endif /* defined(ENABLE_ZLIB) */
577 path = MNEW(char, lce->pathlen + filenamelen);
578 strcpy(path, lce->path);
579 strcat(path, filename);
581 classfile = fopen(path, "r");
583 if (classfile) { /* file exists */
584 if (!stat(path, &buffer)) { /* read classfile data */
585 cb = NEW(classbuffer);
587 cb->size = buffer.st_size;
588 cb->data = MNEW(u1, cb->size);
590 cb->path = lce->path;
592 /* read class data */
594 len = fread(cb->data, 1, cb->size, classfile);
596 if (len != buffer.st_size) {
598 /* if (ferror(classfile)) { */
602 /* close the class file */
608 MFREE(path, char, lce->pathlen + filenamelen);
609 #if defined(ENABLE_ZLIB)
616 dolog("Warning: Can not open class file '%s'", filename);
618 MFREE(filename, char, filenamelen);
624 /* suck_stop *******************************************************************
626 Frees memory for buffer with classfile data.
628 CAUTION: This function may only be called if buffer has been
629 allocated by suck_start with reading a file.
631 *******************************************************************************/
633 void suck_stop(classbuffer *cb)
637 MFREE(cb->data, u1, cb->size);
638 FREE(cb, classbuffer);
643 * These are local overrides for various environment variables in Emacs.
644 * Please do not remove this and leave it at the end of the file, where
645 * Emacs will automagically detect them.
646 * ---------------------------------------------------------------------
649 * indent-tabs-mode: t