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 3959 2005-12-20 23:25:07Z twisti $
42 #include "mm/memory.h"
43 #include "toolbox/list.h"
44 #include "toolbox/logging.h"
45 #include "toolbox/util.h"
46 #include "vm/exceptions.h"
47 #include "vm/loader.h"
48 #include "vm/options.h"
49 #include "vm/stringlocal.h"
54 /* global variables ***********************************************************/
56 list *list_classpath_entries;
59 /* suck_init *******************************************************************
61 Initializes the suck subsystem like initializing the classpath
64 *******************************************************************************/
68 list_classpath_entries = NEW(list);
70 list_init(list_classpath_entries, OFFSET(list_classpath_entry, linkage));
78 /* suck_add ********************************************************************
80 Adds a classpath to the global classpath entries list.
82 *******************************************************************************/
84 void suck_add(char *classpath)
86 list_classpath_entry *lce;
96 /* parse the classpath string */
98 for (start = classpath; (*start) != '\0'; ) {
100 /* search for ':' delimiter to get the end of the current entry */
101 for (end = start; ((*end) != '\0') && ((*end) != ':'); end++);
105 filenamelen = end - start;
107 if (filenamelen > 3) {
108 if (strncasecmp(end - 3, "zip", 3) == 0 ||
109 strncasecmp(end - 3, "jar", 3) == 0) {
114 /* save classpath entries as absolute pathnames */
119 if (*start != '/') { /* XXX fix me for win32 */
121 cwdlen = strlen(cwd) + strlen("/");
124 /* allocate memory for filename and fill it */
126 filename = MNEW(char, filenamelen + cwdlen + strlen("/") +
130 strcpy(filename, cwd);
131 strcat(filename, "/");
132 strncat(filename, start, filenamelen);
134 /* add cwd length to file length */
135 filenamelen += cwdlen;
138 strncpy(filename, start, filenamelen);
139 filename[filenamelen] = '\0';
145 #if defined(ENABLE_ZLIB)
146 ht = zip_open(filename);
149 lce = NEW(list_classpath_entry);
151 lce->type = CLASSPATH_ARCHIVE;
153 lce->path = filename;
154 lce->pathlen = filenamelen;
156 /* SUN compatible -verbose:class output */
158 if (opt_verboseclass)
159 printf("[Opened %s]\n", filename);
163 throw_cacao_exception_exit(string_java_lang_InternalError,
164 "zip/jar files not supported");
168 if (filename[filenamelen - 1] != '/') {/* XXX fixme for win32 */
169 filename[filenamelen] = '/';
170 filename[filenamelen + 1] = '\0';
174 lce = NEW(list_classpath_entry);
176 lce->type = CLASSPATH_PATH;
177 lce->path = filename;
178 lce->pathlen = filenamelen;
181 /* add current classpath entry */
183 list_addlast(list_classpath_entries, lce);
186 /* goto next classpath entry, skip ':' delimiter */
198 /* suck_check_classbuffer_size *************************************************
200 Assert that at least <len> bytes are left to read <len> is limited
201 to the range of non-negative s4 values.
203 *******************************************************************************/
205 bool suck_check_classbuffer_size(classbuffer *cb, s4 len)
207 #ifdef ENABLE_VERIFIER
208 if (len < 0 || ((cb->data + cb->size) - cb->pos) < len) {
210 new_classformaterror((cb)->class, "Truncated class file");
214 #endif /* ENABLE_VERIFIER */
220 u1 suck_u1(classbuffer *cb)
224 a = SUCK_BE_U1(cb->pos);
231 u2 suck_u2(classbuffer *cb)
235 a = SUCK_BE_U2(cb->pos);
242 u4 suck_u4(classbuffer *cb)
246 a = SUCK_BE_U4(cb->pos);
253 u8 suck_u8(classbuffer *cb)
255 #if U8_AVAILABLE == 1
258 a = SUCK_BE_U8(cb->pos);
265 v.high = suck_u4(cb);
273 float suck_float(classbuffer *cb)
277 #if WORDS_BIGENDIAN == 0
281 for (i = 0; i < 4; i++)
282 buffer[3 - i] = suck_u1(cb);
284 MCOPY((u1 *) (&f), buffer, u1, 4);
286 suck_nbytes((u1*) (&f), cb, 4);
289 if (sizeof(float) != 4) {
290 *exceptionptr = new_internalerror("Incompatible float-format");
292 /* XXX should we exit in such a case? */
293 throw_exception_exit();
300 double suck_double(classbuffer *cb)
304 #if WORDS_BIGENDIAN == 0
308 #if defined(__ARM__) && defined(__ARMEL__) && !defined(__VFP_FP__)
310 * On little endian ARM processors when using FPA, word order
311 * of doubles is still big endian. So take that into account
312 * here. When using VFP, word order of doubles follows byte
313 * order. (michi 2005/07/24)
315 for (i = 0; i < 4; i++)
316 buffer[3 - i] = suck_u1(cb);
317 for (i = 0; i < 4; i++)
318 buffer[7 - i] = suck_u1(cb);
320 for (i = 0; i < 8; i++)
321 buffer[7 - i] = suck_u1(cb);
322 #endif /* defined(__ARM__) && ... */
324 MCOPY((u1 *) (&d), buffer, u1, 8);
326 suck_nbytes((u1*) (&d), cb, 8);
329 if (sizeof(double) != 8) {
330 *exceptionptr = new_internalerror("Incompatible double-format");
332 /* XXX should we exit in such a case? */
333 throw_exception_exit();
340 /* suck_nbytes *****************************************************************
342 Transfer block of classfile data into a buffer.
344 *******************************************************************************/
346 void suck_nbytes(u1 *buffer, classbuffer *cb, s4 len)
348 MCOPY(buffer, cb->pos, u1, len);
353 /* suck_skip_nbytes ************************************************************
355 Skip block of classfile data.
357 *******************************************************************************/
359 void suck_skip_nbytes(classbuffer *cb, s4 len)
365 /* suck_start ******************************************************************
367 Returns true if classbuffer is already loaded or a file for the
368 specified class has succussfully been read in. All directories of
369 the searchpath are used to find the classfile (<classname>.class).
370 Returns NULL if no classfile is found and writes an error message.
372 *******************************************************************************/
374 classbuffer *suck_start(classinfo *c)
376 list_classpath_entry *lce;
385 /* initialize return value */
389 /* get the classname as char string (do it here for the warning at
390 the and of the function) */
392 filenamelen = utf_strlen(c->name) + strlen(".class") + strlen("0");
393 filename = MNEW(char, filenamelen);
395 utf_sprint(filename, c->name);
396 strcat(filename, ".class");
398 /* walk through all classpath entries */
400 for (lce = list_first(list_classpath_entries); lce != NULL && cb == NULL;
401 lce = list_next(list_classpath_entries, lce)) {
402 #if defined(ENABLE_ZLIB)
403 if (lce->type == CLASSPATH_ARCHIVE) {
405 #if defined(USE_THREADS)
406 /* enter a monitor on zip/jar archives */
408 builtin_monitorenter((java_objectheader *) lce);
411 /* try to get the file in current archive */
413 cb = zip_get(lce, c);
415 #if defined(USE_THREADS)
416 /* leave the monitor */
418 builtin_monitorexit((java_objectheader *) lce);
422 #endif /* defined(ENABLE_ZLIB) */
423 path = MNEW(char, lce->pathlen + filenamelen);
424 strcpy(path, lce->path);
425 strcat(path, filename);
427 classfile = fopen(path, "r");
429 if (classfile) { /* file exists */
430 if (!stat(path, &buffer)) { /* read classfile data */
431 cb = NEW(classbuffer);
433 cb->size = buffer.st_size;
434 cb->data = MNEW(u1, cb->size);
436 cb->path = lce->path;
438 /* read class data */
439 len = fread(cb->data, 1, cb->size, classfile);
441 if (len != buffer.st_size) {
443 /* if (ferror(classfile)) { */
449 MFREE(path, char, lce->pathlen + filenamelen);
450 #if defined(ENABLE_ZLIB)
457 dolog("Warning: Can not open class file '%s'", filename);
459 MFREE(filename, char, filenamelen);
465 /* suck_stop *******************************************************************
467 Frees memory for buffer with classfile data.
469 CAUTION: This function may only be called if buffer has been
470 allocated by suck_start with reading a file.
472 *******************************************************************************/
474 void suck_stop(classbuffer *cb)
478 MFREE(cb->data, u1, cb->size);
479 FREE(cb, classbuffer);
484 * These are local overrides for various environment variables in Emacs.
485 * Please do not remove this and leave it at the end of the file, where
486 * Emacs will automagically detect them.
487 * ---------------------------------------------------------------------
490 * indent-tabs-mode: t