1 /* src/vm/suck.c - functions to read LE ordered types from a buffer
3 Copyright (C) 1996-2005 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
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., 59 Temple Place - Suite 330, Boston, MA
25 Contact: cacao@complang.tuwien.ac.at
27 Authors: Christian Thalinger
31 $Id: suck.c 4007 2005-12-22 16:26:03Z twisti $
43 #include "mm/memory.h"
44 #include "toolbox/list.h"
45 #include "toolbox/logging.h"
46 #include "toolbox/util.h"
47 #include "vm/exceptions.h"
48 #include "vm/loader.h"
49 #include "vm/options.h"
50 #include "vm/properties.h"
51 #include "vm/stringlocal.h"
56 /* global variables ***********************************************************/
58 char *bootclasspath; /* contains the boot classpath */
59 char *classpath; /* contains the classpath */
61 list *list_classpath_entries;
64 /* suck_init *******************************************************************
66 Initializes the suck subsystem like initializing the classpath
69 *******************************************************************************/
73 list_classpath_entries = NEW(list);
75 list_init(list_classpath_entries, OFFSET(list_classpath_entry, linkage));
83 /* scandir_filter **************************************************************
85 Filters for zip/jar files.
87 *******************************************************************************/
89 static int scandir_filter(const struct dirent *a)
93 #if defined(_DIRENT_HAVE_D_NAMLEN)
96 namlen = strlen(a->d_name);
99 if ((strncasecmp(a->d_name + namlen - 4, ".zip", 4) == 0) ||
100 (strncasecmp(a->d_name + namlen - 4, ".jar", 4) == 0))
107 /* suck_add ********************************************************************
109 Adds a classpath to the global classpath entries list.
111 *******************************************************************************/
113 void suck_add(char *classpath)
115 list_classpath_entry *lce;
125 /* parse the classpath string */
127 for (start = classpath; (*start) != '\0'; ) {
129 /* search for ':' delimiter to get the end of the current entry */
130 for (end = start; ((*end) != '\0') && ((*end) != ':'); end++);
134 filenamelen = end - start;
136 if (filenamelen > 4) {
137 if ((strncasecmp(end - 4, ".zip", 4) == 0) ||
138 (strncasecmp(end - 4, ".jar", 4) == 0)) {
143 /* save classpath entries as absolute pathnames */
148 if (*start != '/') { /* XXX fix me for win32 */
150 cwdlen = strlen(cwd) + strlen("/");
153 /* allocate memory for filename and fill it */
155 filename = MNEW(char, filenamelen + cwdlen + strlen("/") +
159 strcpy(filename, cwd);
160 strcat(filename, "/");
161 strncat(filename, start, filenamelen);
163 /* add cwd length to file length */
164 filenamelen += cwdlen;
167 strncpy(filename, start, filenamelen);
168 filename[filenamelen] = '\0';
174 #if defined(ENABLE_ZLIB)
175 ht = zip_open(filename);
178 lce = NEW(list_classpath_entry);
180 lce->type = CLASSPATH_ARCHIVE;
182 lce->path = filename;
183 lce->pathlen = filenamelen;
185 /* SUN compatible -verbose:class output */
187 if (opt_verboseclass)
188 printf("[Opened %s]\n", filename);
192 throw_cacao_exception_exit(string_java_lang_InternalError,
193 "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 */
212 list_addlast(list_classpath_entries, lce);
215 /* goto next classpath entry, skip ':' delimiter */
227 /* suck_add_from_property ******************************************************
229 Adds a classpath form a property entry to the global classpath
232 *******************************************************************************/
234 void suck_add_from_property(char *key)
241 struct dirent **namelist;
245 char *tmpbootclasspath;
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 /* scan the directory found for zip/jar files */
277 n = scandir(path, &namelist, scandir_filter, alphasort);
279 /* on error, just continue, this should be ok */
282 for (i = 0; i < n; i++) {
283 #if defined(_DIRENT_HAVE_D_NAMLEN)
284 namlen = namelist[i]->d_namlen;
286 namlen = strlen(namelist[i]->d_name);
289 /* reallocate memory for bootclasspath */
291 tmpbootclasspath = MNEW(char,
292 pathlen + strlen("/") + namlen +
294 strlen(bootclasspath) +
297 /* prepend the file found to bootclasspath */
299 strcpy(tmpbootclasspath, path);
300 strcat(tmpbootclasspath, "/");
301 strcat(tmpbootclasspath, namelist[i]->d_name);
302 strcat(tmpbootclasspath, ":");
304 strcat(tmpbootclasspath, bootclasspath);
306 /* free old bootclasspath memory */
308 MFREE(bootclasspath, u1, strlen(bootclasspath));
310 /* and set the new bootclasspath */
312 bootclasspath = tmpbootclasspath;
314 /* free the memory allocated by scandir */
316 FREE(namelist[i], struct dirent);
319 FREE(namelist, struct dirent);
322 MFREE(path, char, pathlen + strlen("0"));
325 /* goto next entry, skip ':' delimiter */
337 /* suck_check_classbuffer_size *************************************************
339 Assert that at least <len> bytes are left to read <len> is limited
340 to the range of non-negative s4 values.
342 *******************************************************************************/
344 bool suck_check_classbuffer_size(classbuffer *cb, s4 len)
346 #ifdef ENABLE_VERIFIER
347 if (len < 0 || ((cb->data + cb->size) - cb->pos) < len) {
349 new_classformaterror((cb)->class, "Truncated class file");
353 #endif /* ENABLE_VERIFIER */
359 u1 suck_u1(classbuffer *cb)
363 a = SUCK_BE_U1(cb->pos);
370 u2 suck_u2(classbuffer *cb)
374 a = SUCK_BE_U2(cb->pos);
381 u4 suck_u4(classbuffer *cb)
385 a = SUCK_BE_U4(cb->pos);
392 u8 suck_u8(classbuffer *cb)
394 #if U8_AVAILABLE == 1
397 a = SUCK_BE_U8(cb->pos);
404 v.high = suck_u4(cb);
412 float suck_float(classbuffer *cb)
416 #if WORDS_BIGENDIAN == 0
420 for (i = 0; i < 4; i++)
421 buffer[3 - i] = suck_u1(cb);
423 MCOPY((u1 *) (&f), buffer, u1, 4);
425 suck_nbytes((u1*) (&f), cb, 4);
428 if (sizeof(float) != 4) {
429 *exceptionptr = new_internalerror("Incompatible float-format");
431 /* XXX should we exit in such a case? */
432 throw_exception_exit();
439 double suck_double(classbuffer *cb)
443 #if WORDS_BIGENDIAN == 0
447 #if defined(__ARM__) && defined(__ARMEL__) && !defined(__VFP_FP__)
449 * On little endian ARM processors when using FPA, word order
450 * of doubles is still big endian. So take that into account
451 * here. When using VFP, word order of doubles follows byte
452 * order. (michi 2005/07/24)
454 for (i = 0; i < 4; i++)
455 buffer[3 - i] = suck_u1(cb);
456 for (i = 0; i < 4; i++)
457 buffer[7 - i] = suck_u1(cb);
459 for (i = 0; i < 8; i++)
460 buffer[7 - i] = suck_u1(cb);
461 #endif /* defined(__ARM__) && ... */
463 MCOPY((u1 *) (&d), buffer, u1, 8);
465 suck_nbytes((u1*) (&d), cb, 8);
468 if (sizeof(double) != 8) {
469 *exceptionptr = new_internalerror("Incompatible double-format");
471 /* XXX should we exit in such a case? */
472 throw_exception_exit();
479 /* suck_nbytes *****************************************************************
481 Transfer block of classfile data into a buffer.
483 *******************************************************************************/
485 void suck_nbytes(u1 *buffer, classbuffer *cb, s4 len)
487 MCOPY(buffer, cb->pos, u1, len);
492 /* suck_skip_nbytes ************************************************************
494 Skip block of classfile data.
496 *******************************************************************************/
498 void suck_skip_nbytes(classbuffer *cb, s4 len)
504 /* suck_start ******************************************************************
506 Returns true if classbuffer is already loaded or a file for the
507 specified class has succussfully been read in. All directories of
508 the searchpath are used to find the classfile (<classname>.class).
509 Returns NULL if no classfile is found and writes an error message.
511 *******************************************************************************/
513 classbuffer *suck_start(classinfo *c)
515 list_classpath_entry *lce;
524 /* initialize return value */
528 /* get the classname as char string (do it here for the warning at
529 the and of the function) */
531 filenamelen = utf_strlen(c->name) + strlen(".class") + strlen("0");
532 filename = MNEW(char, filenamelen);
534 utf_sprint(filename, c->name);
535 strcat(filename, ".class");
537 /* walk through all classpath entries */
539 for (lce = list_first(list_classpath_entries); lce != NULL && cb == NULL;
540 lce = list_next(list_classpath_entries, lce)) {
541 #if defined(ENABLE_ZLIB)
542 if (lce->type == CLASSPATH_ARCHIVE) {
544 #if defined(USE_THREADS)
545 /* enter a monitor on zip/jar archives */
547 builtin_monitorenter((java_objectheader *) lce);
550 /* try to get the file in current archive */
552 cb = zip_get(lce, c);
554 #if defined(USE_THREADS)
555 /* leave the monitor */
557 builtin_monitorexit((java_objectheader *) lce);
561 #endif /* defined(ENABLE_ZLIB) */
562 path = MNEW(char, lce->pathlen + filenamelen);
563 strcpy(path, lce->path);
564 strcat(path, filename);
566 classfile = fopen(path, "r");
568 if (classfile) { /* file exists */
569 if (!stat(path, &buffer)) { /* read classfile data */
570 cb = NEW(classbuffer);
572 cb->size = buffer.st_size;
573 cb->data = MNEW(u1, cb->size);
575 cb->path = lce->path;
577 /* read class data */
578 len = fread(cb->data, 1, cb->size, classfile);
580 if (len != buffer.st_size) {
582 /* if (ferror(classfile)) { */
588 MFREE(path, char, lce->pathlen + filenamelen);
589 #if defined(ENABLE_ZLIB)
596 dolog("Warning: Can not open class file '%s'", filename);
598 MFREE(filename, char, filenamelen);
604 /* suck_stop *******************************************************************
606 Frees memory for buffer with classfile data.
608 CAUTION: This function may only be called if buffer has been
609 allocated by suck_start with reading a file.
611 *******************************************************************************/
613 void suck_stop(classbuffer *cb)
617 MFREE(cb->data, u1, cb->size);
618 FREE(cb, classbuffer);
623 * These are local overrides for various environment variables in Emacs.
624 * Please do not remove this and leave it at the end of the file, where
625 * Emacs will automagically detect them.
626 * ---------------------------------------------------------------------
629 * indent-tabs-mode: t