1 /* src/vm/suck.cpp - 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.hpp"
37 #include "threads/mutex.hpp"
39 #include "toolbox/list.hpp"
40 #include "toolbox/logging.hpp"
41 #include "toolbox/util.h"
43 #include "vm/exceptions.hpp"
44 #include "vm/loader.hpp"
45 #include "vm/options.h"
47 #include "vm/properties.hpp"
48 #include "vm/suck.hpp"
53 /* scandir_filter **************************************************************
55 Filters for zip/jar files.
57 *******************************************************************************/
59 static int scandir_filter(const struct dirent *a)
63 #if defined(_DIRENT_HAVE_D_NAMLEN)
66 namlen = strlen(a->d_name);
69 if ((strncasecmp(a->d_name + namlen - 4, ".zip", 4) == 0) ||
70 (strncasecmp(a->d_name + namlen - 4, ".jar", 4) == 0))
78 * Adds a classpath to the global classpath entries list.
80 void SuckClasspath::add(char *classpath)
82 list_classpath_entry *lce;
90 #if defined(ENABLE_ZLIB)
94 /* parse the classpath string */
96 for (start = classpath; (*start) != '\0'; ) {
98 /* search for ':' delimiter to get the end of the current entry */
99 for (end = start; ((*end) != '\0') && ((*end) != ':'); end++);
103 filenamelen = end - start;
105 if (filenamelen > 4) {
106 if ((strncasecmp(end - 4, ".zip", 4) == 0) ||
107 (strncasecmp(end - 4, ".jar", 4) == 0)) {
112 /* save classpath entries as absolute pathnames */
117 if (*start != '/') { /* XXX fix me for win32 */
119 cwdlen = strlen(cwd) + strlen("/");
122 /* allocate memory for filename and fill it */
124 filename = MNEW(char, filenamelen + cwdlen + strlen("/") +
128 strcpy(filename, cwd);
129 strcat(filename, "/");
130 strncat(filename, start, filenamelen);
132 /* add cwd length to file length */
133 filenamelen += cwdlen;
136 strncpy(filename, start, filenamelen);
137 filename[filenamelen] = '\0';
143 #if defined(ENABLE_ZLIB)
144 ht = zip_open(filename);
147 lce = NEW(list_classpath_entry);
149 lce->type = CLASSPATH_ARCHIVE;
151 lce->path = filename;
152 lce->pathlen = filenamelen;
154 /* SUN compatible -verbose:class output */
156 if (opt_verboseclass)
157 printf("[Opened %s]\n", filename);
161 os::abort("suck_add: zip/jar files not supported");
165 if (filename[filenamelen - 1] != '/') {/* XXX fixme for win32 */
166 filename[filenamelen] = '/';
167 filename[filenamelen + 1] = '\0';
171 lce = NEW(list_classpath_entry);
173 lce->type = CLASSPATH_PATH;
174 lce->path = filename;
175 lce->pathlen = filenamelen;
178 /* add current classpath entry, if no error */
184 /* goto next classpath entry, skip ':' delimiter */
195 * Adds a classpath form a property entry to the global classpath
198 void SuckClasspath::add_from_property(const char *key)
204 struct dirent **namelist;
210 // Get the property value.
211 Properties& properties = VM::get_current()->get_properties();
212 value = properties.get(key);
217 /* get the directory entries of the property */
219 for (start = value; (*start) != '\0'; ) {
221 /* search for ':' delimiter to get the end of the current entry */
223 for (end = start; ((*end) != '\0') && ((*end) != ':'); end++);
228 /* allocate memory for the path entry */
230 pathlen = end - start;
231 char* path = MNEW(char, pathlen + strlen("0"));
233 /* copy and terminate the string */
235 strncpy(path, start, pathlen);
236 path[pathlen] = '\0';
238 /* Reset namelist to NULL for the freeing in an error case
243 /* scan the directory found for zip/jar files */
245 n = os::scandir((const char*) path, &namelist, &scandir_filter, (int (*)(const void*, const void*)) &alphasort);
247 /* On error, just continue, this should be ok. */
250 for (i = 0; i < n; i++) {
251 #if defined(_DIRENT_HAVE_D_NAMLEN)
252 namlen = namelist[i]->d_namlen;
254 namlen = strlen(namelist[i]->d_name);
257 /* Allocate memory for bootclasspath. */
259 // FIXME Make boot_class_path const char*.
260 char* boot_class_path = (char*) properties.get("sun.boot.class.path");
263 pathlen + strlen("/") + namlen +
265 strlen(boot_class_path) +
268 /* Prepend the file found to the bootclasspath. */
272 strcat(p, namelist[i]->d_name);
274 strcat(p, boot_class_path);
276 properties.put("sun.boot.class.path", p);
277 properties.put("java.boot.class.path", p);
279 MFREE(boot_class_path, char, strlen(boot_class_path));
281 /* free the memory allocated by scandir */
282 /* (We use `free` as the memory came from the C library.) */
288 /* On some systems (like Linux) when n == 0, then namelist
289 returned from scnadir is NULL, thus we don't have to
291 (Use `free` as the memory came from the C library.) */
293 if (namelist != NULL)
296 MFREE(path, char, pathlen + strlen("0"));
299 /* goto next entry, skip ':' delimiter */
309 /* suck_check_classbuffer_size *************************************************
311 Assert that at least <len> bytes are left to read <len> is limited
312 to the range of non-negative s4 values.
314 *******************************************************************************/
316 bool suck_check_classbuffer_size(classbuffer *cb, s4 len)
318 #ifdef ENABLE_VERIFIER
319 if (len < 0 || ((cb->data + cb->size) - cb->pos) < len) {
320 exceptions_throw_classformaterror(cb->clazz, "Truncated class file");
323 #endif /* ENABLE_VERIFIER */
329 u1 suck_u1(classbuffer *cb)
333 a = SUCK_BE_U1(cb->pos);
340 u2 suck_u2(classbuffer *cb)
344 a = SUCK_BE_U2(cb->pos);
351 u4 suck_u4(classbuffer *cb)
355 a = SUCK_BE_U4(cb->pos);
362 u8 suck_u8(classbuffer *cb)
366 a = SUCK_BE_U8(cb->pos);
373 float suck_float(classbuffer *cb)
377 #if WORDS_BIGENDIAN == 0
381 for (i = 0; i < 4; i++)
382 buffer[3 - i] = suck_u1(cb);
384 MCOPY((u1 *) (&f), buffer, u1, 4);
386 suck_nbytes((u1*) (&f), cb, 4);
389 assert(sizeof(float) == 4);
395 double suck_double(classbuffer *cb)
399 #if WORDS_BIGENDIAN == 0
403 # if defined(__ARM__) && defined(__ARMEL__) && !defined(__VFP_FP__)
405 * On little endian ARM processors when using FPA, word order
406 * of doubles is still big endian. So take that into account
407 * here. When using VFP, word order of doubles follows byte
408 * order. (michi 2005/07/24)
410 for (i = 0; i < 4; i++)
411 buffer[3 - i] = suck_u1(cb);
412 for (i = 0; i < 4; i++)
413 buffer[7 - i] = suck_u1(cb);
415 for (i = 0; i < 8; i++)
416 buffer[7 - i] = suck_u1(cb);
417 # endif /* defined(__ARM__) && ... */
419 MCOPY((u1 *) (&d), buffer, u1, 8);
421 suck_nbytes((u1*) (&d), cb, 8);
424 assert(sizeof(double) == 8);
430 /* suck_nbytes *****************************************************************
432 Transfer block of classfile data into a buffer.
434 *******************************************************************************/
436 void suck_nbytes(u1 *buffer, classbuffer *cb, s4 len)
438 MCOPY(buffer, cb->pos, u1, len);
443 /* suck_skip_nbytes ************************************************************
445 Skip block of classfile data.
447 *******************************************************************************/
449 void suck_skip_nbytes(classbuffer *cb, s4 len)
455 /* suck_start ******************************************************************
457 Returns true if classbuffer is already loaded or a file for the
458 specified class has succussfully been read in. All directories of
459 the searchpath are used to find the classfile (<classname>.class).
460 Returns NULL if no classfile is found and writes an error message.
462 *******************************************************************************/
464 classbuffer *suck_start(classinfo *c)
466 list_classpath_entry *lce;
475 /* initialize return value */
479 /* get the classname as char string (do it here for the warning at
480 the end of the function) */
482 filenamelen = utf_bytes(c->name) + strlen(".class") + strlen("0");
483 filename = MNEW(char, filenamelen);
485 utf_copy(filename, c->name);
486 strcat(filename, ".class");
488 // Get current list of classpath entries.
489 SuckClasspath& suckclasspath = VM::get_current()->get_suckclasspath();
491 /* walk through all classpath entries */
493 for (SuckClasspath::iterator it = suckclasspath.begin(); it != suckclasspath.end() && cb == NULL; it++) {
496 #if defined(ENABLE_ZLIB)
497 if (lce->type == CLASSPATH_ARCHIVE) {
499 /* enter a monitor on zip/jar archives */
503 /* try to get the file in current archive */
505 cb = zip_get(lce, c);
507 /* leave the monitor */
509 lce->mutex->unlock();
512 #endif /* defined(ENABLE_ZLIB) */
513 path = MNEW(char, lce->pathlen + filenamelen);
514 strcpy(path, lce->path);
515 strcat(path, filename);
517 classfile = os::fopen(path, "r");
519 if (classfile) { /* file exists */
520 if (!os::stat(path, &buffer)) { /* read classfile data */
521 cb = NEW(classbuffer);
523 cb->size = buffer.st_size;
524 cb->data = MNEW(u1, cb->size);
526 cb->path = lce->path;
528 /* read class data */
530 len = os::fread((void *) cb->data, 1, cb->size,
533 if (len != buffer.st_size) {
535 /* if (ferror(classfile)) { */
539 /* close the class file */
541 os::fclose(classfile);
545 MFREE(path, char, lce->pathlen + filenamelen);
546 #if defined(ENABLE_ZLIB)
553 dolog("Warning: Can not open class file '%s'", filename);
555 MFREE(filename, char, filenamelen);
561 /* suck_stop *******************************************************************
563 Frees memory for buffer with classfile data.
565 CAUTION: This function may only be called if buffer has been
566 allocated by suck_start with reading a file.
568 *******************************************************************************/
570 void suck_stop(classbuffer *cb)
574 MFREE(cb->data, u1, cb->size);
575 FREE(cb, classbuffer);
580 * These are local overrides for various environment variables in Emacs.
581 * Please do not remove this and leave it at the end of the file, where
582 * Emacs will automagically detect them.
583 * ---------------------------------------------------------------------
586 * indent-tabs-mode: t
590 * vim:noexpandtab:sw=4:ts=4: