diff options
Diffstat (limited to 'gcc/java/jcf-parse.c')
-rw-r--r-- | gcc/java/jcf-parse.c | 917 |
1 files changed, 917 insertions, 0 deletions
diff --git a/gcc/java/jcf-parse.c b/gcc/java/jcf-parse.c new file mode 100644 index 0000000..0e8c51c --- /dev/null +++ b/gcc/java/jcf-parse.c @@ -0,0 +1,917 @@ +/* Parser for Java(TM) .class files. + Copyright (C) 1996 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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. + +GNU CC 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> */ + +#include <stdio.h> +#include <ctype.h> +#include "config.h" +#include "tree.h" +#include "obstack.h" +#include "flags.h" +#include "java-except.h" +#include "input.h" +#include "java-tree.h" + +/* A CONSTANT_Utf8 element is converted to an IDENTIFIER_NODE at parse time. */ +#define JPOOL_UTF(JCF, INDEX) CPOOL_UTF(&(JCF)->cpool, INDEX) +#define JPOOL_UTF_LENGTH(JCF, INDEX) IDENTIFIER_LENGTH (JPOOL_UTF (JCF, INDEX)) +#define JPOOL_UTF_DATA(JCF, INDEX) \ + ((unsigned char*) IDENTIFIER_POINTER (JPOOL_UTF (JCF, INDEX))) +#define HANDLE_CONSTANT_Utf8(JCF, INDEX, LENGTH) \ + do { \ + unsigned char save; unsigned char *text; \ + JCF_FILL (JCF, (LENGTH)+1); /* Make sure we read 1 byte beyond string. */ \ + text = (JCF)->read_ptr; \ + save = text[LENGTH]; \ + text[LENGTH] = 0; \ + (JCF)->cpool.data[INDEX] = (jword) get_identifier (text); \ + text[LENGTH] = save; \ + JCF_SKIP (JCF, LENGTH); } while (0) + +#include "jcf.h" +#ifdef __STDC__ +/* For getenv */ +#include <stdlib.h> +#endif + +#ifndef SEEK_SET +#include <unistd.h> +#endif + +extern struct obstack *saveable_obstack; +extern struct obstack temporary_obstack; +extern struct obstack permanent_obstack; + +/* The class we are currently processing. */ +tree current_class = NULL_TREE; + +/* The class we started with. */ +tree main_class = NULL_TREE; + +/* The FIELD_DECL for the current field. */ +static tree current_field = NULL_TREE; + +static tree current_method = NULL_TREE; + +static tree give_name_to_class PROTO ((JCF *jcf, int index)); + +void parse_zip_file_entries (void); +void process_zip_dir(); + +/* Source file compilation declarations */ +static void parse_source_file (); +extern int java_error_count; +#define java_parse_abort_on_error() \ + { \ + if (java_error_count) \ + { \ + java_report_errors (); \ + java_pop_parser_context (); \ + return; \ + } \ + } + +/* Handle "SourceFile" attribute. */ + +void +set_source_filename (jcf, index) + JCF *jcf; + int index; +{ + tree sfname_id = get_name_constant (jcf, index); + char *sfname = IDENTIFIER_POINTER (sfname_id); + if (input_filename != NULL) + { + int old_len = strlen (input_filename); + int new_len = IDENTIFIER_LENGTH (sfname_id); + /* Use the current input_filename (derived from the class name) + if it has a directory prefix, but otherwise matches sfname. */ + if (old_len > new_len + && strcmp (sfname, input_filename + old_len - new_len) == 0 + && (input_filename[old_len - new_len - 1] == '/' + || input_filename[old_len - new_len - 1] == '\\')) + return; + } + input_filename = sfname; + DECL_SOURCE_FILE (TYPE_NAME (current_class)) = sfname; + if (current_class == main_class) main_input_filename = input_filename; +} + +#define HANDLE_SOURCEFILE(INDEX) set_source_filename (jcf, INDEX) + +#define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \ +{ tree super_class = SUPER==0 ? NULL_TREE : get_class_constant (jcf, SUPER); \ + current_class = give_name_to_class (jcf, THIS); \ + set_super_info (ACCESS_FLAGS, current_class, super_class, INTERFACES_COUNT);} + +#define HANDLE_CLASS_INTERFACE(INDEX) \ + add_interface (current_class, get_class_constant (jcf, INDEX)) + +#define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \ +{ int sig_index = SIGNATURE; \ + current_field = add_field (current_class, get_name_constant (jcf, NAME), \ + parse_signature (jcf, sig_index), ACCESS_FLAGS); \ + set_java_signature (TREE_TYPE (current_field), JPOOL_UTF (jcf, sig_index)); } + +#define HANDLE_END_FIELDS() \ + (current_field = NULL_TREE) + +#define HANDLE_CONSTANTVALUE(INDEX) \ +{ tree constant; int index = INDEX; \ + if (JPOOL_TAG (jcf, index) == CONSTANT_String) { \ + tree name = get_name_constant (jcf, JPOOL_USHORT1 (jcf, index)); \ + constant = build_utf8_ref (name); \ + } \ + else \ + constant = get_constant (jcf, index); \ + set_constant_value (current_field, constant); } + +#define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \ + (current_method = add_method (current_class, ACCESS_FLAGS, \ + get_name_constant (jcf, NAME), \ + get_name_constant (jcf, SIGNATURE)), \ + DECL_LOCALVARIABLES_OFFSET (current_method) = 0, \ + DECL_LINENUMBERS_OFFSET (current_method) = 0) + +#define HANDLE_END_METHODS() \ +{ tree handle_type = CLASS_TO_HANDLE_TYPE (current_class); \ + if (handle_type != current_class) layout_type (handle_type); } + +#define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \ +{ DECL_MAX_STACK (current_method) = (MAX_STACK); \ + DECL_MAX_LOCALS (current_method) = (MAX_LOCALS); \ + DECL_CODE_LENGTH (current_method) = (CODE_LENGTH); \ + DECL_CODE_OFFSET (current_method) = JCF_TELL (jcf); } + +#define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \ +{ int n = (COUNT); \ + DECL_LOCALVARIABLES_OFFSET (current_method) = JCF_TELL (jcf) - 2; \ + JCF_SKIP (jcf, n * 10); } + +#define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \ +{ int n = (COUNT); \ + DECL_LINENUMBERS_OFFSET (current_method) = JCF_TELL (jcf) - 2; \ + JCF_SKIP (jcf, n * 4); } + +#include "jcf-reader.c" + +static int yydebug; + +tree +parse_signature (jcf, sig_index) + JCF *jcf; + int sig_index; +{ + if (sig_index <= 0 || sig_index >= JPOOL_SIZE(jcf) + || JPOOL_TAG (jcf, sig_index) != CONSTANT_Utf8) + fatal ("invalid field/method signature"); + else + { + return parse_signature_string (JPOOL_UTF_DATA (jcf, sig_index), + JPOOL_UTF_LENGTH (jcf, sig_index)); + } +} + +void +init_lex () +{ + /* Make identifier nodes long enough for the language-specific slots. */ + set_identifier_size (sizeof (struct lang_identifier)); +} + +void +set_yydebug (value) + int value; +{ + yydebug = value; +} + +tree +get_constant (jcf, index) + JCF *jcf; + int index; +{ + tree value; + int tag; + if (index <= 0 || index >= JPOOL_SIZE(jcf)) + goto bad; + tag = JPOOL_TAG (jcf, index); + if ((tag & CONSTANT_ResolvedFlag) || tag == CONSTANT_Utf8) + return (tree) jcf->cpool.data[index]; + push_obstacks (&permanent_obstack, &permanent_obstack); + switch (tag) + { + case CONSTANT_Integer: + { + jint num = JPOOL_INT(jcf, index); + value = build_int_2 (num, num < 0 ? -1 : 0); + TREE_TYPE (value) = int_type_node; + break; + } + case CONSTANT_Long: + { + jint num = JPOOL_INT (jcf, index); + HOST_WIDE_INT lo, hi; + lshift_double (num, 0, 32, 64, &lo, &hi, 0); + num = JPOOL_INT (jcf, index+1); + add_double (lo, hi, num, 0, &lo, &hi); + value = build_int_2 (lo, hi); + TREE_TYPE (value) = long_type_node; + force_fit_type (value, 0); + break; + } +#if TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT + case CONSTANT_Float: + { + jint num = JPOOL_INT(jcf, index); + REAL_VALUE_TYPE d; +#ifdef REAL_ARITHMETIC + d = REAL_VALUE_FROM_TARGET_SINGLE (num); +#else + union { float f; jint i; } u; + u.i = num; + d = u.f; +#endif + value = build_real (float_type_node, d); + break; + } + case CONSTANT_Double: + { + HOST_WIDE_INT num[2]; + REAL_VALUE_TYPE d; + HOST_WIDE_INT lo, hi; + num[0] = JPOOL_INT (jcf, index); + lshift_double (num[0], 0, 32, 64, &lo, &hi, 0); + num[0] = JPOOL_INT (jcf, index+1); + add_double (lo, hi, num[0], 0, &lo, &hi); + if (FLOAT_WORDS_BIG_ENDIAN) + { + num[0] = hi; + num[1] = lo; + } + else + { + num[0] = lo; + num[1] = hi; + } +#ifdef REAL_ARITHMETIC + d = REAL_VALUE_FROM_TARGET_DOUBLE (num); +#else + union { double d; jint i[2]; } u; + u.i[0] = (jint) num[0]; + u.i[1] = (jint) num[1]; + d = u.d; +#endif + value = build_real (double_type_node, d); + break; + } +#endif /* TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT */ + case CONSTANT_String: + { + extern struct obstack *expression_obstack; + tree name = get_name_constant (jcf, JPOOL_USHORT1 (jcf, index)); + char *utf8_ptr = IDENTIFIER_POINTER (name); + unsigned char *str_ptr; + int utf8_len = IDENTIFIER_LENGTH (name); + unsigned char *str = (unsigned char*)utf8_ptr; + int i = utf8_len; + int str_len; + + /* Count the number of Unicode characters in the string, + while checking for a malformed Utf8 string. */ + for (str_len = 0; i > 0; str_len++) + { + int char_len = UT8_CHAR_LENGTH (*str); + if (char_len < 0 || char_len > 2 || char_len > i) + fatal ("bad string constant"); + str += char_len; + i -= char_len; + } + + value = make_node (STRING_CST); + TREE_STRING_LENGTH (value) = 2 * str_len; + TREE_STRING_POINTER (value) + = obstack_alloc (expression_obstack, 2 * str_len); + str_ptr = (unsigned char *) TREE_STRING_POINTER (value); + str = (unsigned char*)utf8_ptr; + for (i = 0; i < str_len; i++) + { + int char_value; + int char_len = UT8_CHAR_LENGTH (*str); + switch (char_len) + { + case 1: + char_value = *str++; + break; + case 2: + char_value = *str++ & 0x1F; + char_value = (char_value << 6) | (*str++ & 0x3F); + break; + case 3: + char_value = *str_ptr++ & 0x0F; + char_value = (char_value << 6) | (*str++ & 0x3F); + char_value = (char_value << 6) | (*str++ & 0x3F); + break; + default: + goto bad; + } + if (BYTES_BIG_ENDIAN) + { + *str_ptr++ = char_value >> 8; + *str_ptr++ = char_value & 0xFF; + } + else + { + *str_ptr++ = char_value & 0xFF; + *str_ptr++ = char_value >> 8; + } + } + } + break; + default: + goto bad; + } + pop_obstacks (); + JPOOL_TAG(jcf, index) = tag | CONSTANT_ResolvedFlag; + jcf->cpool.data [index] = (jword) value; + return value; + bad: + fatal ("bad value constant type %d, index %d", + JPOOL_TAG( jcf, index ), index); +} + +tree +get_name_constant (jcf, index) + JCF *jcf; + int index; +{ + tree name = get_constant (jcf, index); + if (TREE_CODE (name) != IDENTIFIER_NODE) + fatal ("bad nameandtype index %d", index); + return name; +} + +static tree +give_name_to_class (jcf, i) + JCF *jcf; + int i; +{ + if (i <= 0 || i >= JPOOL_SIZE(jcf) + || JPOOL_TAG (jcf, i) != CONSTANT_Class) + fatal ("bad class index %d", i); + else + { + tree this_class; + int j = JPOOL_USHORT1 (jcf, i); + /* verify_constant_pool confirmed that j is a CONSTANT_Utf8. */ + tree class_name = unmangle_classname (JPOOL_UTF_DATA (jcf, j), + JPOOL_UTF_LENGTH (jcf, j)); + this_class = lookup_class (class_name); + input_filename = DECL_SOURCE_FILE (TYPE_NAME (this_class)); + lineno = 0; + if (main_input_filename == NULL && jcf == main_jcf) + main_input_filename = input_filename; + + jcf->cpool.data[i] = (jword) this_class; + JPOOL_TAG (jcf, i) = CONSTANT_ResolvedClass; + return this_class; + } +} + +/* Get the class of the CONSTANT_Class whose constant pool index is I. */ + +tree +get_class_constant (JCF *jcf , int i) +{ + tree type; + if (i <= 0 || i >= JPOOL_SIZE(jcf) + || (JPOOL_TAG (jcf, i) & ~CONSTANT_ResolvedFlag) != CONSTANT_Class) + fatal ("bad class index %d", i); + + if (JPOOL_TAG (jcf, i) != CONSTANT_ResolvedClass) + { + int name_index = JPOOL_USHORT1 (jcf, i); + /* verify_constant_pool confirmed that name_index is a CONSTANT_Utf8. */ + char *name = JPOOL_UTF_DATA (jcf, name_index); + int nlength = JPOOL_UTF_LENGTH (jcf, name_index); + if (name[0] == '[') /* Handle array "classes". */ + type = parse_signature_string (name, nlength); + else + { + tree cname = unmangle_classname (name, nlength); + type = lookup_class (cname); + } + jcf->cpool.data[i] = (jword) type; + JPOOL_TAG (jcf, i) = CONSTANT_ResolvedClass; + } + else + type = (tree) jcf->cpool.data[i]; + return type; +} + +void +fix_classpath () +{ + static char default_path[] = DEFAULT_CLASS_PATH; + + if (classpath == NULL) + { + classpath = (char *) getenv ("CLASSPATH"); + if (classpath == NULL) + { + warning ("CLASSPATH not set"); + classpath = default_path; + } + } +} + +void +DEFUN(jcf_out_of_synch, (jcf), + JCF *jcf) +{ + char *source = strdup (jcf->filename); + int i = strlen (source); + + while (source[i] != '.') + i--; + + source [i] = '\0'; + warning ("Class file `%s' out of synch with `%s.java'", + jcf->filename, source); + free (source); +} + +/* Load CLASS_OR_NAME. CLASS_OR_NAME can be a mere identifier if + called from the parser, otherwise it's a RECORD_TYPE node. If + VERBOSE is 1, print error message on failure to load a class. */ + +void +load_class (class_or_name, verbose) + tree class_or_name; + int verbose; +{ + JCF this_jcf, *jcf; + tree name = (TREE_CODE (class_or_name) == IDENTIFIER_NODE ? + class_or_name : DECL_NAME (TYPE_NAME (class_or_name))); + tree save_current_class = current_class; + char *save_input_filename = input_filename; + JCF *save_current_jcf = current_jcf; + long saved_pos; + if (current_jcf->read_state) + saved_pos = ftell (current_jcf->read_state); + + push_obstacks (&permanent_obstack, &permanent_obstack); + + if (!classpath) + fix_classpath (); + /* Search in current zip first. */ + if (find_in_current_zip (IDENTIFIER_POINTER (name), + IDENTIFIER_LENGTH (name), &jcf) == 0) + if (find_class (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name), + &this_jcf, 1) == 0) + { + if (verbose) + { + error ("Cannot find class file class %s.", + IDENTIFIER_POINTER (name)); + TYPE_SIZE (class_or_name) = error_mark_node; + if (!strcmp (classpath, DEFAULT_CLASS_PATH)) + fatal ("giving up"); + pop_obstacks (); /* FIXME: one pop_obstack() per function */ + } + return; + } + else + { + this_jcf.seen_in_zip = 0; + current_jcf = &this_jcf; + if (this_jcf.outofsynch) + jcf_out_of_synch (current_jcf); + } + else + current_jcf = jcf; + + if (current_jcf->java_source) + jcf_parse_source (current_jcf); + else { + int saved_lineno = lineno; + input_filename = current_jcf->filename; + jcf_parse (current_jcf); + lineno = saved_lineno; + } + + if (!current_jcf->seen_in_zip) + JCF_FINISH (current_jcf); +/* DECL_IGNORED_P (TYPE_NAME (class_or_name)) = 1;*/ + pop_obstacks (); + + current_class = save_current_class; + input_filename = save_input_filename; + current_jcf = save_current_jcf; + if (current_jcf->read_state) + fseek (current_jcf->read_state, saved_pos, SEEK_SET); +} + +/* Parse a source file when JCF refers to a source file. This piece + needs further work as far as error handling and report. */ + +int +jcf_parse_source (jcf) + JCF *jcf; +{ + java_parser_context_save_global (); + + input_filename = current_jcf->filename; + if (!(finput = fopen (input_filename, "r"))) + fatal ("input file `%s' just disappeared - jcf_parse_source", + input_filename); + + parse_source_file (1); /* Parse only */ + if (current_class && TREE_TYPE (current_class)) + CLASS_FROM_SOURCE_P (TREE_TYPE (current_class)) = 1; + + fclose (finput); + java_parser_context_restore_global (); +} + +/* Parse the .class file JCF. */ + +int +jcf_parse (jcf) + JCF* jcf; +{ + int i, code; + + if (jcf_parse_preamble (jcf) != 0) + fatal ("Not a valid Java .class file.\n"); + code = jcf_parse_constant_pool (jcf); + if (code != 0) + fatal ("error while parsing constant pool"); + code = verify_constant_pool (jcf); + if (code > 0) + fatal ("error in constant pool entry #%d\n", code); + + jcf_parse_class (jcf); + if (main_class == NULL_TREE) + main_class = current_class; + if (! quiet_flag && TYPE_NAME (current_class)) + fprintf (stderr, " class %s", + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (current_class)))); + CLASS_LOADED_P (current_class) = 1; + + for (i = 1; i < JPOOL_SIZE(jcf); i++) + { + switch (JPOOL_TAG (jcf, i)) + { + case CONSTANT_Class: + get_class_constant (jcf, i); + break; + } + } + + code = jcf_parse_fields (jcf); + if (code != 0) + fatal ("error while parsing fields"); + code = jcf_parse_methods (jcf); + if (code != 0) + fatal ("error while parsing methods"); + code = jcf_parse_final_attributes (jcf); + if (code != 0) + fatal ("error while parsing final attributes"); + + /* The fields of class_type_node are already in correct order. */ + if (current_class != class_type_node && current_class != object_type_node) + TYPE_FIELDS (current_class) = nreverse (TYPE_FIELDS (current_class)); + + push_obstacks (&permanent_obstack, &permanent_obstack); + layout_class (current_class); + pop_obstacks (); +} + +void +init_outgoing_cpool () +{ + current_constant_pool_data_ref = NULL_TREE; + if (outgoing_cpool == NULL) + { + static CPool outgoing_cpool_buffer; + outgoing_cpool = &outgoing_cpool_buffer; + CPOOL_INIT(outgoing_cpool); + } + else + { + CPOOL_REINIT(outgoing_cpool); + } +} + +void +parse_class_file () +{ + tree method; + char *save_input_filename = input_filename; + int save_lineno = lineno; + + input_filename = DECL_SOURCE_FILE (TYPE_NAME (current_class)); + lineno = 0; + debug_start_source_file (input_filename); + init_outgoing_cpool (); + + for ( method = TYPE_METHODS (CLASS_TO_HANDLE_TYPE (current_class)); + method != NULL_TREE; method = TREE_CHAIN (method)) + { + JCF *jcf = current_jcf; + + if (METHOD_NATIVE (method) || METHOD_ABSTRACT (method)) + continue; + + if (DECL_CODE_OFFSET (method) == 0) + { + error ("missing Code attribute"); + continue; + } + + lineno = 0; + if (DECL_LINENUMBERS_OFFSET (method)) + { + register int i; + register unsigned char *ptr; + JCF_SEEK (jcf, DECL_LINENUMBERS_OFFSET (method)); + linenumber_count = i = JCF_readu2 (jcf); + linenumber_table = ptr = jcf->read_ptr; + + for (ptr += 2; --i >= 0; ptr += 4) + { + int line = GET_u2 (ptr); + /* Set initial lineno lineno to smallest linenumber. + * Needs to be set before init_function_start. */ + if (lineno == 0 || line < lineno) + lineno = line; + } + } + else + { + linenumber_table = NULL; + linenumber_count = 0; + } + + start_java_method (method); + + give_name_to_locals (jcf); + + /* Actually generate code. */ + expand_byte_code (jcf, method); + + end_java_method (); + } + + if (flag_emit_class_files) + write_classfile (current_class); + make_class_data (current_class); + register_class (); + rest_of_decl_compilation (TYPE_NAME (current_class), (char*) 0, 1, 0); + + debug_end_source_file (save_lineno); + input_filename = save_input_filename; + lineno = save_lineno; +} + +/* Parse a source file, as pointed by the current JCF. If PARSE_ONLY + is non zero, we're not parsing a file found on the command line and + we skip things related to code generation. */ + +static void +parse_source_file (parse_only) + int parse_only; +{ + lang_init_source (1); /* Error msgs have no method prototypes */ + java_push_parser_context (); + java_init_lex (); /* Initialize the parser */ + java_parse_abort_on_error (); + java_parse (); /* Parse and build partial tree nodes. */ + java_parse_abort_on_error (); + java_complete_class (); /* Parse unsatisfied class decl. */ + java_parse_abort_on_error (); + java_check_circular_reference (); /* Check on circular references */ + java_parse_abort_on_error (); + java_check_methods (); /* Check the methods */ + java_parse_abort_on_error (); + java_layout_classes (); + java_parse_abort_on_error (); + if (!parse_only) + { + lang_init_source (2); /* Error msgs have method prototypes */ + java_complete_expand_methods (); /* Complete and expand method bodies */ + java_parse_abort_on_error (); + java_expand_finals (); /* Expand and check the finals */ + java_parse_abort_on_error (); + java_check_final (); /* Check unitialized final */ + java_parse_abort_on_error (); + if (! flag_emit_class_files) + emit_register_class (); + java_report_errors (); /* Final step for this file */ + } + if (flag_emit_class_files) + write_classfile (current_class); + java_pop_parser_context (); +} + +int +yyparse () +{ + /* Everything migh be enclosed within a loop processing each file after + the other one. */ + + switch (jcf_figure_file_type (current_jcf)) + { + case JCF_ZIP: + parse_zip_file_entries (); + emit_register_class (); + break; + case JCF_CLASS: + jcf_parse (current_jcf); + parse_class_file (); + emit_register_class (); + break; + case JCF_SOURCE: + parse_source_file (0); /* Parse and generate */ + break; + } + return 0; +} + +static struct ZipFileCache *localToFile; + +/* Process all class entries found in the zip file. */ +void +parse_zip_file_entries (void) +{ + struct ZipDirectory *zdir; + int i; + + for (i = 0, zdir = (ZipDirectory *)localToFile->z.central_directory; + i < localToFile->z.count; i++, zdir = ZIPDIR_NEXT (zdir)) + { + tree class; + + /* We don't need to consider those files. */ + if (!zdir->size || !zdir->filename_offset) + continue; + + class = lookup_class (get_identifier (ZIPDIR_FILENAME (zdir))); + current_jcf = TYPE_LANG_SPECIFIC (class)->jcf; + current_class = class; + + if ( !CLASS_LOADED_P (class)) + { + fseek (current_jcf->read_state, current_jcf->zip_offset, SEEK_SET); + jcf_parse (current_jcf); + } + + input_filename = current_jcf->filename; + + parse_class_file (); + FREE (current_jcf->buffer); /* No longer necessary */ + /* Note: there is a way to free this buffer right after a class seen + in a zip file has been parsed. The idea is the set its jcf in such + a way that buffer will be reallocated the time the code for the class + will be generated. FIXME. */ + } +} + +/* Read all the entries of the zip file, creates a class and a JCF. Sets the + jcf up for further processing and link it to the created class. */ + +void process_zip_dir() +{ + int i; + ZipDirectory *zdir; + + for (i = 0, zdir = (ZipDirectory *)localToFile->z.central_directory; + i < localToFile->z.count; i++, zdir = ZIPDIR_NEXT (zdir)) + { + char *class_name, *file_name, *class_name_in_zip_dir; + tree class; + JCF *jcf; + int j; + + class_name_in_zip_dir = ZIPDIR_FILENAME (zdir); + + /* We choose to not to process entries with a zero size or entries + not bearing the .class extention. */ + if (!zdir->size || !zdir->filename_offset || + strncmp (&class_name_in_zip_dir[zdir->filename_length-6], + ".class", 6)) + { + /* So it will be skipped in parse_zip_file_entries */ + zdir->size = 0; + continue; + } + + class_name = ALLOC (zdir->filename_length+1-6); + file_name = ALLOC (zdir->filename_length+1); + jcf = ALLOC (sizeof (JCF)); + JCF_ZERO (jcf); + + strncpy (class_name, class_name_in_zip_dir, zdir->filename_length-6); + class_name [zdir->filename_length-6] = '\0'; + strncpy (file_name, class_name_in_zip_dir, zdir->filename_length); + file_name [zdir->filename_length] = '\0'; + + for (j=0; class_name[j]; j++) + class_name [j] = (class_name [j] == '/' ? '.' : class_name [j]); + + /* Yes, we write back the true class name into the zip directory. */ + strcpy (class_name_in_zip_dir, class_name); + zdir->filename_length = j; + class = lookup_class (get_identifier (class_name)); + + jcf->read_state = finput; + jcf->filbuf = jcf_filbuf_from_stdio; + jcf->seen_in_zip = 1; + jcf->java_source = 0; + jcf->zip_offset = zdir->filestart; + jcf->classname = class_name; + jcf->filename = file_name; + + TYPE_LANG_SPECIFIC (class) = + (struct lang_type *) perm_calloc (1, sizeof (struct lang_type)); + TYPE_LANG_SPECIFIC (class)->jcf = jcf; + } +} + +/* Lookup class NAME and figure whether is a class already found in the current + zip file. */ +int +DEFUN(find_in_current_zip, (name, length, jcf), + char *name AND int length AND JCF **jcf) +{ + JCF *local_jcf; + tree class_name = maybe_get_identifier (name), class, icv; + + if (!class_name) + return 0; + + if (!(icv = IDENTIFIER_CLASS_VALUE (class_name))) + return 0; + + class = TREE_TYPE (icv); + + /* Doesn't have jcf specific info ? It's not ours */ + if (!TYPE_LANG_SPECIFIC (class) || !TYPE_LANG_SPECIFIC (class)->jcf) + return 0; + + *jcf = local_jcf = TYPE_LANG_SPECIFIC (class)->jcf; + fseek (local_jcf->read_state, local_jcf->zip_offset, SEEK_SET); + return 1; +} + +/* Figure what kind of file we're dealing with */ +int +DEFUN(jcf_figure_file_type, (jcf), + JCF *jcf) +{ + unsigned char magic_string[4]; + uint32 magic; + + if (fread (magic_string, 1, 4, jcf->read_state) != 4) + jcf_unexpected_eof (jcf, 4); + + fseek (jcf->read_state, 0L, SEEK_SET); + magic = GET_u4 (magic_string); + + if (magic == 0xcafebabe) + return JCF_CLASS; + + if (!open_in_zip (jcf, input_filename, NULL)) + { + localToFile = ALLOC (sizeof (struct ZipFileCache)); + bcopy (SeenZipFiles, localToFile, sizeof (struct ZipFileCache)); + process_zip_dir (); /* Register all the class defined there */ + return JCF_ZIP; + } + + return JCF_SOURCE; +} + |