* builtins.c (expand_builtin_setjmp_receiver): Const-ify. * c-common.c (fname_var_t, c_tree_code_type, c_tree_code_length): Likewise. * c-dump.c (dump_option_value_info): Likewise. * c-format.c (format_length_info, format_char_info, format_flag_spec, format_flag_pair, format_kind_info): Likewise. * collect2.c (names): Likewise. * cppdefault.h (default_include): Likewise. * cppexp.c (suffix, vsuf_1, vsuf_2, vsuf_3): Likewise. * flow.c (life_analysis): Likewise. * gcc.c (dir_separator_str, modify_target, option_map, target_option_translations, spec_list_1, extra_specs_1, init_spec): Likewise. * gcov.c (gcov_version_string): Likewise. * genattr.c (write_units): Likewise. * genattrtab.c (make_length_attrs, write_function_unit_info): Likewise. * gengenrtl.c (rtx_definition, defs): Likewise. * genrecog.c (pred_table): Likewise. * global.c (global_alloc): Likewise. * lcm.c (optimize_mode_switching): Likewise. * local-alloc.c (find_free_reg): Likewise. * params.h (param_info): Likewise. * predict.c (predictor_info): Likewise. * protoize.c (unexpansion_struct): Likewise. * real.c (bmask): Likewise. * recog.h (insn_operand_data, insn_data): Likewise. * regclass.c (initial_fixed_regs, initial_call_used_regs): Likewise. * stmt.c (expand_nl_goto_receiver): Likewise. * toplev.c (da, debug_args, lang_opt, documented_lang_options, target_switches, target_options): Likewise. * tradcif.y (token, tokentab2, yylex): Likewise. * tree.h (attribute_spec): Likewise. * alpha.c (override_options, alpha_lookup_xfloating_lib_func): Likewise. * arc.c (arc_output_function_epilogue): Likewise. * arm.c (processors, all_cores, all_architectures, arm_override_options, isr_attribute_arg, isr_attribute_args, arm_isr_value): Likewise. * avr.c (mcu_type_s, reg_class_tab, order_regs_for_local_alloc): Likewise. * c4x.c (c4x_int_reglist): Likewise. * d30v.c (override_options): Likewise. * h8300.c (shift_insn): Likewise. * i386.c (size_cost, i386_cost, i486_cost, pentium_cost, pentiumpro_cost, k6_cost, athlon_cost, pentium4_cost, ix86_cost, ix86_expand_sse_comi, ix86_expand_sse_compare, override_options, builtin_description, bdesc_comi, bdesc_2arg, bdesc_1arg, ix86_init_mmx_sse_builtins, ix86_expand_builtin): Likewise. * i386.h (processor_costs, ix86_cost): Likewise. * m68hc11.c (m68hc11_cost, m6811_cost, m6812_cost): Likewise. * m68hc11.h (processor_costs, m68hc11_cost): Likewise. * m68k.c (codes_68881, codes_FPA): Likewise. * m88k.c (mode_from_align, max_from_align, all_from_align, best_from_align, m_options): Likewise. * m88k.h (ORDER_REGS_FOR_LOCAL_ALLOC): Likewise. * mcore.c (mode_from_align): Likewise. * mips/elf64.h (UNIQUE_SECTION): Likewise. * mips/iris6gld.h (UNIQUE_SECTION): Likewise. * mips.c (mips_sw_reg_names, mips_regno_to_class): Likewise. * mips.h (mips_regno_to_class): Likewise. * ns32k.c (scales): Likewise. * pa.c (import_string, magic_milli): Likewise. * rs6000.c (alt_reg_names, rs6000_override_options): Likewise. * sparc.c (leaf_reg_remap, sparc_override_options, reg_leaf_alloc_order, reg_nonleaf_alloc_order, reg_alloc_orders): Likewise. * sparc.h (sparc_cpu_select, leaf_reg_remap): Likewise. cp: * class.c (build_vtable_entry_ref): Const-ify. * decl.c (predefined_identifier, initialize_predefined_identifiers): Likewise. * init.c (build_new_1): Likewise. * lex.c (cplus_tree_code_type, cplus_tree_code_length, resword): Likewise. f: * bad.c (_ffebad_message_, ffebad_messages_): Const-ify. * bld.c (ffebld_arity_op_): Likewise. * bld.h (ffebld_arity_op_): Likewise. * com.c (ffecom_init_0): Likewise. * intdoc.c (_ffeintrin_name_, _ffeintrin_gen_, _ffeintrin_spec_, _ffeintrin_imp_, names, gens, imps, specs, cc_pair, cc_descriptions, cc_summaries): Likewise. * intrin.c (_ffeintrin_name_, _ffeintrin_gen_, _ffeintrin_spec_, _ffeintrin_imp_, ffeintrin_names_, ffeintrin_gens_, ffeintrin_imps_, ffeintrin_specs_): Likewise. java: * jcf-io.c (format_uint): Const-ify. * lang.c (java_tree_code_type, java_tree_code_length): Likewise. * lex.c (java_get_line_col): Likewise. * parse.y (build_incdec): Likewise. From-SVN: r46062
653 lines
17 KiB
C
653 lines
17 KiB
C
/* Utility routines for finding and reading Java(TM) .class files.
|
|
Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GNU CC; see the file COPYING. If not, write to
|
|
the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
Boston, MA 02111-1307, USA.
|
|
|
|
Java and all Java-based marks are trademarks or registered trademarks
|
|
of Sun Microsystems, Inc. in the United States and other countries.
|
|
The Free Software Foundation is independent of Sun Microsystems, Inc. */
|
|
|
|
/* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
|
|
|
|
#include "config.h"
|
|
#include "system.h"
|
|
|
|
#include "jcf.h"
|
|
#include "tree.h"
|
|
#include "toplev.h"
|
|
#include "java-tree.h"
|
|
|
|
#include "zlib.h"
|
|
|
|
/* DOS brain-damage */
|
|
#ifndef O_BINARY
|
|
#define O_BINARY 0 /* MS-DOS brain-damage */
|
|
#endif
|
|
|
|
int
|
|
DEFUN(jcf_unexpected_eof, (jcf, count),
|
|
JCF *jcf AND int count ATTRIBUTE_UNUSED)
|
|
{
|
|
if (jcf->filename)
|
|
fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename);
|
|
else
|
|
fprintf (stderr, "Premature end of .class file <stdin>.\n");
|
|
exit (-1);
|
|
}
|
|
|
|
void
|
|
DEFUN(jcf_trim_old_input, (jcf),
|
|
JCF *jcf)
|
|
{
|
|
int count = jcf->read_ptr - jcf->buffer;
|
|
if (count > 0)
|
|
{
|
|
memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr);
|
|
jcf->read_ptr -= count;
|
|
jcf->read_end -= count;
|
|
}
|
|
}
|
|
|
|
int
|
|
DEFUN(jcf_filbuf_from_stdio, (jcf, count),
|
|
JCF *jcf AND int count)
|
|
{
|
|
FILE *file = (FILE*) (jcf->read_state);
|
|
if (count > jcf->buffer_end - jcf->read_ptr)
|
|
{
|
|
JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer;
|
|
JCF_u4 old_read_end = jcf->read_end - jcf->buffer;
|
|
JCF_u4 old_size = jcf->buffer_end - jcf->buffer;
|
|
JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count;
|
|
unsigned char *new_buffer = jcf->buffer == NULL ? ALLOC (new_size)
|
|
: REALLOC (jcf->buffer, new_size);
|
|
jcf->buffer = new_buffer;
|
|
jcf->buffer_end = new_buffer + new_size;
|
|
jcf->read_ptr = new_buffer + old_read_ptr;
|
|
jcf->read_end = new_buffer + old_read_end;
|
|
}
|
|
count -= jcf->read_end - jcf->read_ptr;
|
|
if (count <= 0)
|
|
return 0;
|
|
if ((int) fread (jcf->read_end, 1, count, file) != count)
|
|
jcf_unexpected_eof (jcf, count);
|
|
jcf->read_end += count;
|
|
return 0;
|
|
}
|
|
|
|
#include "zipfile.h"
|
|
|
|
struct ZipFile *SeenZipFiles = NULL;
|
|
|
|
/* Open a zip file with the given name, and cache directory and file
|
|
descriptor. If the file is missing, treat it as an empty archive.
|
|
Return NULL if the .zip file is malformed.
|
|
*/
|
|
|
|
ZipFile *
|
|
DEFUN(opendir_in_zip, (zipfile, is_system),
|
|
const char *zipfile AND int is_system)
|
|
{
|
|
struct ZipFile* zipf;
|
|
char magic [4];
|
|
int fd;
|
|
for (zipf = SeenZipFiles; zipf != NULL; zipf = zipf->next)
|
|
{
|
|
if (strcmp (zipf->name, zipfile) == 0)
|
|
return zipf;
|
|
}
|
|
|
|
zipf = ALLOC (sizeof (struct ZipFile) + strlen (zipfile) + 1);
|
|
zipf->next = SeenZipFiles;
|
|
zipf->name = (char*)(zipf+1);
|
|
strcpy (zipf->name, zipfile);
|
|
SeenZipFiles = zipf;
|
|
fd = open (zipfile, O_RDONLY | O_BINARY);
|
|
zipf->fd = fd;
|
|
if (fd < 0)
|
|
{
|
|
/* A missing zip file is not considered an error.
|
|
We may want to re-consider that. FIXME. */
|
|
zipf->count = 0;
|
|
zipf->dir_size = 0;
|
|
zipf->central_directory = NULL;
|
|
}
|
|
else
|
|
{
|
|
jcf_dependency_add_file (zipfile, is_system);
|
|
if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC)
|
|
return NULL;
|
|
lseek (fd, 0L, SEEK_SET);
|
|
if (read_zip_archive (zipf) != 0)
|
|
return NULL;
|
|
}
|
|
return zipf;
|
|
}
|
|
|
|
/* Returns:
|
|
0: OK - zipmember found.
|
|
-1: Not found.
|
|
-2: Malformed archive.
|
|
*/
|
|
|
|
int
|
|
DEFUN(open_in_zip, (jcf, zipfile, zipmember, is_system),
|
|
JCF *jcf AND const char *zipfile AND const char *zipmember
|
|
AND int is_system)
|
|
{
|
|
ZipDirectory *zipd;
|
|
int i, len;
|
|
ZipFile *zipf = opendir_in_zip (zipfile, is_system);
|
|
|
|
if (zipf == NULL)
|
|
return -2;
|
|
|
|
if (!zipmember)
|
|
return 0;
|
|
|
|
len = strlen (zipmember);
|
|
|
|
zipd = (struct ZipDirectory*) zipf->central_directory;
|
|
for (i = 0; i < zipf->count; i++, zipd = ZIPDIR_NEXT (zipd))
|
|
{
|
|
if (len == zipd->filename_length &&
|
|
strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0)
|
|
{
|
|
JCF_ZERO (jcf);
|
|
|
|
jcf->filename = xstrdup (zipfile);
|
|
jcf->classname = xstrdup (zipmember);
|
|
return read_zip_member(jcf, zipd, zipf);
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/* Read data from zip archive member. */
|
|
|
|
int
|
|
DEFUN(read_zip_member, (jcf, zipd, zipf),
|
|
JCF *jcf AND ZipDirectory *zipd AND ZipFile *zipf)
|
|
{
|
|
jcf->filbuf = jcf_unexpected_eof;
|
|
jcf->zipd = (void *)zipd;
|
|
|
|
if (zipd->compression_method == Z_NO_COMPRESSION)
|
|
{
|
|
jcf->buffer = ALLOC (zipd->size);
|
|
jcf->buffer_end = jcf->buffer + zipd->size;
|
|
jcf->read_ptr = jcf->buffer;
|
|
jcf->read_end = jcf->buffer_end;
|
|
if (lseek (zipf->fd, zipd->filestart, 0) < 0
|
|
|| read (zipf->fd, jcf->buffer, zipd->size) != (long) zipd->size)
|
|
return -2;
|
|
}
|
|
else
|
|
{
|
|
char *buffer;
|
|
z_stream d_stream; /* decompression stream */
|
|
d_stream.zalloc = (alloc_func) 0;
|
|
d_stream.zfree = (free_func) 0;
|
|
d_stream.opaque = (voidpf) 0;
|
|
|
|
jcf->buffer = ALLOC (zipd->uncompressed_size);
|
|
d_stream.next_out = jcf->buffer;
|
|
d_stream.avail_out = zipd->uncompressed_size;
|
|
jcf->buffer_end = jcf->buffer + zipd->uncompressed_size;
|
|
jcf->read_ptr = jcf->buffer;
|
|
jcf->read_end = jcf->buffer_end;
|
|
buffer = ALLOC (zipd->size);
|
|
d_stream.next_in = buffer;
|
|
d_stream.avail_in = zipd->size;
|
|
if (lseek (zipf->fd, zipd->filestart, 0) < 0
|
|
|| read (zipf->fd, buffer, zipd->size) != (long) zipd->size)
|
|
return -2;
|
|
/* Handle NO_HEADER using undocumented zlib feature.
|
|
This is a very common hack. */
|
|
inflateInit2 (&d_stream, -MAX_WBITS);
|
|
inflate (&d_stream, Z_NO_FLUSH);
|
|
inflateEnd (&d_stream);
|
|
FREE (buffer);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if JCF_USE_STDIO
|
|
const char *
|
|
DEFUN(open_class, (filename, jcf, stream, dep_name),
|
|
const char *filename AND JCF *jcf AND FILE* stream
|
|
AND const char *dep_name)
|
|
{
|
|
if (jcf)
|
|
{
|
|
if (dep_name != NULL)
|
|
jcf_dependency_add_file (dep_name, 0);
|
|
JCF_ZERO (jcf);
|
|
jcf->buffer = NULL;
|
|
jcf->buffer_end = NULL;
|
|
jcf->read_ptr = NULL;
|
|
jcf->read_end = NULL;
|
|
jcf->read_state = stream;
|
|
jcf->filename = filename;
|
|
jcf->filbuf = jcf_filbuf_from_stdio;
|
|
}
|
|
else
|
|
fclose (stream);
|
|
return filename;
|
|
}
|
|
#else
|
|
const char *
|
|
DEFUN(open_class, (filename, jcf, fd, dep_name),
|
|
const char *filename AND JCF *jcf AND int fd AND const char *dep_name)
|
|
{
|
|
if (jcf)
|
|
{
|
|
struct stat stat_buf;
|
|
if (fstat (fd, &stat_buf) != 0
|
|
|| ! S_ISREG (stat_buf.st_mode))
|
|
{
|
|
perror ("Could not figure length of .class file");
|
|
return NULL;
|
|
}
|
|
if (dep_name != NULL)
|
|
jcf_dependency_add_file (dep_name, 0);
|
|
JCF_ZERO (jcf);
|
|
jcf->buffer = ALLOC (stat_buf.st_size);
|
|
jcf->buffer_end = jcf->buffer + stat_buf.st_size;
|
|
jcf->read_ptr = jcf->buffer;
|
|
jcf->read_end = jcf->buffer_end;
|
|
jcf->read_state = NULL;
|
|
jcf->filename = filename;
|
|
if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size)
|
|
{
|
|
perror ("Failed to read .class file");
|
|
return NULL;
|
|
}
|
|
close (fd);
|
|
jcf->filbuf = jcf_unexpected_eof;
|
|
}
|
|
else
|
|
close (fd);
|
|
return filename;
|
|
}
|
|
#endif
|
|
|
|
|
|
const char *
|
|
DEFUN(find_classfile, (filename, jcf, dep_name),
|
|
char *filename AND JCF *jcf AND const char *dep_name)
|
|
{
|
|
#if JCF_USE_STDIO
|
|
FILE *stream = fopen (filename, "rb");
|
|
if (stream == NULL)
|
|
return NULL;
|
|
return open_class (arg, jcf, stream, dep_name);
|
|
#else
|
|
int fd = open (filename, O_RDONLY | O_BINARY);
|
|
if (fd < 0)
|
|
return NULL;
|
|
return open_class (filename, jcf, fd, dep_name);
|
|
#endif
|
|
}
|
|
|
|
/* Returns a freshly malloc'd string with the fully qualified pathname
|
|
of the .class file for the class CLASSNAME. Returns NULL on
|
|
failure. If JCF != NULL, it is suitably initialized.
|
|
SOURCE_OK is true if we should also look for .java file. */
|
|
|
|
const char *
|
|
DEFUN(find_class, (classname, classname_length, jcf, source_ok),
|
|
const char *classname AND int classname_length AND JCF *jcf AND int source_ok)
|
|
|
|
{
|
|
#if JCF_USE_STDIO
|
|
FILE *stream;
|
|
#else
|
|
int fd;
|
|
#endif
|
|
int i, k, java = -1, class = -1;
|
|
struct stat java_buf, class_buf;
|
|
char *dep_file;
|
|
void *entry;
|
|
char *java_buffer;
|
|
|
|
/* Allocate and zero out the buffer, since we don't explicitly put a
|
|
null pointer when we're copying it below. */
|
|
int buflen = jcf_path_max_len () + classname_length + 10;
|
|
char *buffer = (char *) ALLOC (buflen);
|
|
memset (buffer, 0, buflen);
|
|
|
|
java_buffer = (char *) alloca (buflen);
|
|
|
|
jcf->java_source = 0;
|
|
|
|
for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry))
|
|
{
|
|
const char *path_name = jcf_path_name (entry);
|
|
if (class != 0)
|
|
{
|
|
int dir_len;
|
|
|
|
strcpy (buffer, path_name);
|
|
i = strlen (buffer);
|
|
|
|
/* This is right because we know that `.zip' entries will have a
|
|
trailing slash. See jcf-path.c. */
|
|
dir_len = i - 1;
|
|
|
|
for (k = 0; k < classname_length; k++, i++)
|
|
{
|
|
char ch = classname[k];
|
|
buffer[i] = ch == '.' ? '/' : ch;
|
|
}
|
|
strcpy (buffer+i, ".class");
|
|
|
|
if (jcf_path_is_zipfile (entry))
|
|
{
|
|
int err_code;
|
|
JCF _jcf;
|
|
buffer[dir_len] = '\0';
|
|
SOURCE_FRONTEND_DEBUG
|
|
(("Trying [...%s]:%s",
|
|
&buffer[dir_len-(dir_len > 15 ? 15 : dir_len)],
|
|
buffer+dir_len+1));
|
|
if (jcf == NULL)
|
|
jcf = &_jcf;
|
|
err_code = open_in_zip (jcf, buffer, buffer+dir_len+1,
|
|
jcf_path_is_system (entry));
|
|
if (err_code == 0)
|
|
{
|
|
/* Should we check if .zip is out-of-date wrt .java? */
|
|
buffer[dir_len] = '(';
|
|
strcpy (buffer+i, ".class)");
|
|
if (jcf == &_jcf)
|
|
JCF_FINISH (jcf);
|
|
return buffer;
|
|
}
|
|
else
|
|
continue;
|
|
}
|
|
class = stat (buffer, &class_buf);
|
|
}
|
|
|
|
if (source_ok)
|
|
{
|
|
/* Compute name of .java file. */
|
|
int l, m;
|
|
strcpy (java_buffer, path_name);
|
|
l = strlen (java_buffer);
|
|
for (m = 0; m < classname_length; ++m)
|
|
java_buffer[m + l] = (classname[m] == '.' ? '/' : classname[m]);
|
|
strcpy (java_buffer + m + l, ".java");
|
|
java = stat (java_buffer, &java_buf);
|
|
if (java == 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* We preferably pick a class file if we have a chance. If the source
|
|
file is newer than the class file, we issue a warning and parse the
|
|
source file instead.
|
|
There should be a flag to allow people have the class file picked
|
|
up no matter what. FIXME. */
|
|
if (! java && ! class && java_buf.st_mtime > class_buf.st_mtime)
|
|
{
|
|
if (flag_newer)
|
|
warning ("Source file for class `%s' is newer than its matching class file. Source file `%s' used instead", classname, java_buffer);
|
|
class = -1;
|
|
}
|
|
|
|
if (! java)
|
|
dep_file = java_buffer;
|
|
else
|
|
dep_file = buffer;
|
|
#if JCF_USE_STDIO
|
|
if (!class)
|
|
{
|
|
SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
|
|
stream = fopen (buffer, "rb");
|
|
if (stream)
|
|
goto found;
|
|
}
|
|
/* Give .java a try, if necessary */
|
|
if (!java)
|
|
{
|
|
strcpy (buffer, java_buffer);
|
|
SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
|
|
stream = fopen (buffer, "r");
|
|
if (stream)
|
|
{
|
|
jcf->java_source = 1;
|
|
goto found;
|
|
}
|
|
}
|
|
#else
|
|
if (!class)
|
|
{
|
|
SOURCE_FRONTEND_DEBUG ((stderr, "[Class selected: %s]\n",
|
|
classname+classname_length-
|
|
(classname_length <= 30 ?
|
|
classname_length : 30)));
|
|
fd = open (buffer, O_RDONLY | O_BINARY);
|
|
if (fd >= 0)
|
|
goto found;
|
|
}
|
|
/* Give .java a try, if necessary */
|
|
if (!java)
|
|
{
|
|
strcpy (buffer, java_buffer);
|
|
SOURCE_FRONTEND_DEBUG ((stderr, "[Source selected: %s]\n",
|
|
classname+classname_length-
|
|
(classname_length <= 30 ?
|
|
classname_length : 30)));
|
|
fd = open (buffer, O_RDONLY);
|
|
if (fd >= 0)
|
|
{
|
|
jcf->java_source = 1;
|
|
goto found;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
free (buffer);
|
|
return NULL;
|
|
found:
|
|
#if JCF_USE_STDIO
|
|
if (jcf->java_source)
|
|
return NULL; /* FIXME */
|
|
else
|
|
return open_class (buffer, jcf, stream, dep_file);
|
|
#else
|
|
if (jcf->java_source)
|
|
{
|
|
JCF_ZERO (jcf); /* JCF_FINISH relies on this */
|
|
jcf->java_source = 1;
|
|
jcf->filename = xstrdup (buffer);
|
|
close (fd); /* We use STDIO for source file */
|
|
}
|
|
else
|
|
buffer = (char *) open_class (buffer, jcf, fd, dep_file);
|
|
jcf->classname = xstrdup (classname);
|
|
return buffer;
|
|
#endif
|
|
}
|
|
|
|
void
|
|
DEFUN(jcf_print_char, (stream, ch),
|
|
FILE *stream AND int ch)
|
|
{
|
|
switch (ch)
|
|
{
|
|
case '\'':
|
|
case '\\':
|
|
case '\"':
|
|
fprintf (stream, "\\%c", ch);
|
|
break;
|
|
case '\n':
|
|
fprintf (stream, "\\n");
|
|
break;
|
|
case '\t':
|
|
fprintf (stream, "\\t");
|
|
break;
|
|
case '\r':
|
|
fprintf (stream, "\\r");
|
|
break;
|
|
default:
|
|
if (ch >= ' ' && ch < 127)
|
|
putc (ch, stream);
|
|
else if (ch < 256)
|
|
fprintf (stream, "\\%03x", ch);
|
|
else
|
|
fprintf (stream, "\\u%04x", ch);
|
|
}
|
|
}
|
|
|
|
/* Print UTF8 string at STR of length LENGTH bytes to STREAM. */
|
|
|
|
void
|
|
DEFUN(jcf_print_utf8, (stream, str, length),
|
|
FILE *stream AND register const unsigned char *str AND int length)
|
|
{
|
|
const unsigned char * limit = str + length;
|
|
while (str < limit)
|
|
{
|
|
int ch = UTF8_GET (str, limit);
|
|
if (ch < 0)
|
|
{
|
|
fprintf (stream, "\\<invalid>");
|
|
return;
|
|
}
|
|
jcf_print_char (stream, ch);
|
|
}
|
|
}
|
|
|
|
/* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */
|
|
|
|
void
|
|
DEFUN(jcf_print_utf8_replace, (stream, str, length, in_char, out_char),
|
|
FILE *stream AND const unsigned char *str AND int length
|
|
AND int in_char AND int out_char)
|
|
{
|
|
const unsigned char *limit = str + length;
|
|
while (str < limit)
|
|
{
|
|
int ch = UTF8_GET (str, limit);
|
|
if (ch < 0)
|
|
{
|
|
fprintf (stream, "\\<invalid>");
|
|
return;
|
|
}
|
|
jcf_print_char (stream, ch == in_char ? out_char : ch);
|
|
}
|
|
}
|
|
|
|
/* Check that all the cross-references in the constant pool are
|
|
valid. Returns 0 on success.
|
|
Otherwise, returns the index of the (first) invalid entry.
|
|
Only checks internal consistency, but does not check that
|
|
any classes, fields, or methods are valid.*/
|
|
|
|
int
|
|
DEFUN(verify_constant_pool, (jcf),
|
|
JCF *jcf)
|
|
{
|
|
int i, n;
|
|
for (i = 1; i < JPOOL_SIZE (jcf); i++)
|
|
{
|
|
switch (JPOOL_TAG (jcf, i))
|
|
{
|
|
case CONSTANT_NameAndType:
|
|
n = JPOOL_USHORT2 (jcf, i);
|
|
if (n <= 0 || n >= JPOOL_SIZE(jcf)
|
|
|| JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
|
|
return i;
|
|
/* ... fall through ... */
|
|
case CONSTANT_Class:
|
|
case CONSTANT_String:
|
|
n = JPOOL_USHORT1 (jcf, i);
|
|
if (n <= 0 || n >= JPOOL_SIZE(jcf)
|
|
|| JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
|
|
return i;
|
|
break;
|
|
case CONSTANT_Fieldref:
|
|
case CONSTANT_Methodref:
|
|
case CONSTANT_InterfaceMethodref:
|
|
n = JPOOL_USHORT1 (jcf, i);
|
|
if (n <= 0 || n >= JPOOL_SIZE(jcf)
|
|
|| JPOOL_TAG (jcf, n) != CONSTANT_Class)
|
|
return i;
|
|
n = JPOOL_USHORT2 (jcf, i);
|
|
if (n <= 0 || n >= JPOOL_SIZE(jcf)
|
|
|| JPOOL_TAG (jcf, n) != CONSTANT_NameAndType)
|
|
return i;
|
|
break;
|
|
case CONSTANT_Long:
|
|
case CONSTANT_Double:
|
|
i++;
|
|
break;
|
|
case CONSTANT_Float:
|
|
case CONSTANT_Integer:
|
|
case CONSTANT_Utf8:
|
|
case CONSTANT_Unicode:
|
|
break;
|
|
default:
|
|
return i;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
DEFUN(format_uint, (buffer, value, base),
|
|
char *buffer AND uint64 value AND int base)
|
|
{
|
|
#define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8)
|
|
char buf[WRITE_BUF_SIZE];
|
|
register char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */
|
|
int chars_written;
|
|
int i;
|
|
|
|
/* Now do the actual conversion, placing the result at the *end* of buf. */
|
|
/* Note this code does not pretend to be optimized. */
|
|
do {
|
|
int digit = value % base;
|
|
static const char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
*--buf_ptr = digit_chars[digit];
|
|
value /= base;
|
|
} while (value != 0);
|
|
|
|
chars_written = buf+WRITE_BUF_SIZE - buf_ptr;
|
|
for (i = 0; i < chars_written; i++)
|
|
buffer[i] = *buf_ptr++;
|
|
buffer[i] = 0;
|
|
}
|
|
|
|
void
|
|
DEFUN(format_int, (buffer, value, base),
|
|
char *buffer AND jlong value AND int base)
|
|
{
|
|
uint64 abs_value;
|
|
if (value < 0)
|
|
{
|
|
abs_value = -(uint64)value;
|
|
*buffer++ = '-';
|
|
}
|
|
else
|
|
abs_value = (uint64) value;
|
|
format_uint (buffer, abs_value, base);
|
|
}
|