| /* This file read a Java(TM) .class file. |
| It is not stand-alone: It depends on tons of macros, and the |
| intent is you #include this file after you've defined the macros. |
| Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 |
| Free Software Foundation, Inc. |
| |
| This file is part of GCC. |
| |
| GCC 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. |
| |
| GCC 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 GCC; 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. */ |
| |
| #include "jcf.h" |
| #include "zipfile.h" |
| |
| static int get_attribute (JCF *); |
| static int jcf_parse_preamble (JCF *); |
| static int jcf_parse_constant_pool (JCF *); |
| static void jcf_parse_class (JCF *); |
| static int jcf_parse_fields (JCF *); |
| static int jcf_parse_one_method (JCF *); |
| static int jcf_parse_methods (JCF *); |
| static int jcf_parse_final_attributes (JCF *); |
| #ifdef NEED_PEEK_ATTRIBUTE |
| static int peek_attribute (JCF *, int, const char *, int); |
| #endif |
| #ifdef NEED_SKIP_ATTRIBUTE |
| static void skip_attribute (JCF *, int); |
| #endif |
| |
| /* Go through all available attribute (ATTRIBUTE_NUMER) and try to |
| identify PEEKED_NAME. Return 1 if PEEKED_NAME was found, 0 |
| otherwise. JCF is restored to its initial position before |
| returning. */ |
| |
| #ifdef NEED_PEEK_ATTRIBUTE /* Not everyone uses this function */ |
| static int |
| peek_attribute (JCF *jcf, int attribute_number, const char *peeked_name, |
| int peeked_name_length) |
| { |
| int to_return = 0; |
| long absolute_offset = (long)JCF_TELL (jcf); |
| int i; |
| |
| for (i = 0; !to_return && i < attribute_number; i++) |
| { |
| uint16 attribute_name = (JCF_FILL (jcf, 6), JCF_readu2 (jcf)); |
| uint32 attribute_length = JCF_readu4 (jcf); |
| int name_length; |
| const unsigned char *name_data; |
| |
| JCF_FILL (jcf, (long) attribute_length); |
| if (attribute_name <= 0 || attribute_name >= JPOOL_SIZE(jcf) |
| || JPOOL_TAG (jcf, attribute_name) != CONSTANT_Utf8) |
| continue; |
| |
| name_length = JPOOL_UTF_LENGTH (jcf, attribute_name); |
| name_data = JPOOL_UTF_DATA (jcf, attribute_name); |
| |
| if (name_length == peeked_name_length |
| && ! memcmp (name_data, peeked_name, peeked_name_length)) |
| { |
| to_return = 1; |
| break; |
| } |
| |
| JCF_SKIP (jcf, attribute_length); |
| } |
| |
| JCF_SEEK (jcf, absolute_offset); |
| return to_return; |
| } |
| #endif |
| |
| #ifdef NEED_SKIP_ATTRIBUTE /* Not everyone uses this function */ |
| static void |
| skip_attribute (JCF *jcf, int number_of_attribute) |
| { |
| while (number_of_attribute--) |
| { |
| JCF_u4 N; |
| JCF_FILL (jcf, 6); |
| (void) JCF_readu2 (jcf); |
| N = JCF_readu4 (jcf); |
| JCF_SKIP (jcf, N); |
| } |
| } |
| #endif |
| |
| static int |
| get_attribute (JCF *jcf) |
| { |
| uint16 attribute_name = (JCF_FILL (jcf, 6), JCF_readu2 (jcf)); |
| uint32 attribute_length = JCF_readu4 (jcf); |
| uint32 start_pos = JCF_TELL(jcf); |
| int name_length; |
| const unsigned char *name_data; |
| JCF_FILL (jcf, (long) attribute_length); |
| if (attribute_name <= 0 || attribute_name >= JPOOL_SIZE(jcf)) |
| return -2; |
| if (JPOOL_TAG (jcf, attribute_name) != CONSTANT_Utf8) |
| return -2; |
| name_length = JPOOL_UTF_LENGTH (jcf, attribute_name); |
| name_data = JPOOL_UTF_DATA (jcf, attribute_name); |
| |
| #define MATCH_ATTRIBUTE(S) \ |
| (name_length == sizeof (S)-1 && memcmp (name_data, S, sizeof (S)-1) == 0) |
| |
| #ifdef IGNORE_ATTRIBUTE |
| if (IGNORE_ATTRIBUTE (jcf, attribute_name, attribute_length)) |
| { |
| JCF_SKIP (jcf, attribute_length); |
| } |
| else |
| #endif |
| #ifdef HANDLE_SOURCEFILE |
| if (MATCH_ATTRIBUTE ("SourceFile")) |
| { |
| uint16 sourcefile_index = JCF_readu2 (jcf); |
| HANDLE_SOURCEFILE(sourcefile_index); |
| } |
| else |
| #endif |
| #ifdef HANDLE_CONSTANTVALUE |
| if (MATCH_ATTRIBUTE ("ConstantValue")) |
| { |
| uint16 constantvalue_index = JCF_readu2 (jcf); |
| if (constantvalue_index <= 0 || constantvalue_index >= JPOOL_SIZE(jcf)) |
| return -2; |
| HANDLE_CONSTANTVALUE(constantvalue_index); |
| } |
| else |
| #endif |
| #ifdef HANDLE_CODE_ATTRIBUTE |
| if (MATCH_ATTRIBUTE ("Code")) |
| { |
| uint16 j; |
| uint16 max_stack ATTRIBUTE_UNUSED = JCF_readu2 (jcf); |
| uint16 max_locals ATTRIBUTE_UNUSED = JCF_readu2 (jcf); |
| uint32 code_length = JCF_readu4 (jcf); |
| uint16 exception_table_length, attributes_count; |
| if (code_length + 12 > attribute_length) |
| return -1; |
| HANDLE_CODE_ATTRIBUTE(max_stack, max_locals, code_length); |
| JCF_SKIP (jcf, code_length); |
| exception_table_length = JCF_readu2 (jcf); |
| if (code_length + 8 * exception_table_length + 12 > attribute_length) |
| return -1; |
| #ifdef HANDLE_EXCEPTION_TABLE |
| HANDLE_EXCEPTION_TABLE (jcf->read_ptr, exception_table_length); |
| #endif |
| JCF_SKIP (jcf, 2 * 4 * exception_table_length); |
| attributes_count = JCF_readu2 (jcf); |
| for (j = 0; j < attributes_count; j++) |
| { |
| int code = get_attribute (jcf); |
| if (code != 0) |
| return code; |
| } |
| } |
| else |
| #endif /* HANDLE_CODE_ATTRIBUTE */ |
| #ifdef HANDLE_EXCEPTIONS_ATTRIBUTE |
| if (MATCH_ATTRIBUTE ("Exceptions")) |
| { |
| uint16 count = JCF_readu2 (jcf); |
| HANDLE_EXCEPTIONS_ATTRIBUTE (count); |
| } |
| else |
| #endif |
| #ifdef HANDLE_LINENUMBERTABLE_ATTRIBUTE |
| if (MATCH_ATTRIBUTE ("LineNumberTable")) |
| { |
| uint16 count = JCF_readu2 (jcf); |
| HANDLE_LINENUMBERTABLE_ATTRIBUTE (count); |
| } |
| else |
| #endif |
| #ifdef HANDLE_LOCALVARIABLETABLE_ATTRIBUTE |
| if (MATCH_ATTRIBUTE ("LocalVariableTable")) |
| { |
| uint16 count = JCF_readu2 (jcf); |
| HANDLE_LOCALVARIABLETABLE_ATTRIBUTE (count); |
| } |
| else |
| #endif |
| #ifdef HANDLE_INNERCLASSES_ATTRIBUTE |
| if (MATCH_ATTRIBUTE ("InnerClasses")) |
| { |
| uint16 count = JCF_readu2 (jcf); |
| HANDLE_INNERCLASSES_ATTRIBUTE (count); |
| } |
| else |
| #endif |
| #ifdef HANDLE_SYNTHETIC_ATTRIBUTE |
| if (MATCH_ATTRIBUTE ("Synthetic")) |
| { |
| HANDLE_SYNTHETIC_ATTRIBUTE (); |
| } |
| else |
| #endif |
| #ifdef HANDLE_GCJCOMPILED_ATTRIBUTE |
| if (MATCH_ATTRIBUTE ("gnu.gcj.gcj-compiled")) |
| { |
| HANDLE_GCJCOMPILED_ATTRIBUTE (); |
| } |
| else |
| #endif |
| #ifdef HANDLE_DEPRECATED_ATTRIBUTE |
| if (MATCH_ATTRIBUTE ("Deprecated")) |
| { |
| HANDLE_DEPRECATED_ATTRIBUTE (); |
| } |
| else |
| #endif |
| { |
| #ifdef PROCESS_OTHER_ATTRIBUTE |
| PROCESS_OTHER_ATTRIBUTE(jcf, attribute_name, attribute_length); |
| #else |
| JCF_SKIP (jcf, attribute_length); |
| #endif |
| } |
| if ((long) (start_pos + attribute_length) != JCF_TELL(jcf)) |
| return -1; |
| return 0; |
| } |
| |
| /* Read and handle the pre-amble. */ |
| static int |
| jcf_parse_preamble (JCF* jcf) |
| { |
| uint32 magic = (JCF_FILL (jcf, 8), JCF_readu4 (jcf)); |
| uint16 minor_version ATTRIBUTE_UNUSED = JCF_readu2 (jcf); |
| uint16 major_version ATTRIBUTE_UNUSED = JCF_readu2 (jcf); |
| #ifdef HANDLE_MAGIC |
| HANDLE_MAGIC (magic, minor_version, major_version); |
| #endif |
| if (magic != 0xcafebabe) |
| return -1; |
| else |
| return 0; |
| } |
| |
| /* Read and handle the constant pool. |
| |
| Return 0 if OK. |
| Return -2 if a bad cross-reference (index of other constant) was seen. |
| */ |
| static int |
| jcf_parse_constant_pool (JCF* jcf) |
| { |
| int i, n; |
| JPOOL_SIZE (jcf) = (JCF_FILL (jcf, 2), JCF_readu2 (jcf)); |
| jcf->cpool.tags = ggc_alloc (JPOOL_SIZE (jcf)); |
| jcf->cpool.data = ggc_alloc (sizeof (jword) * JPOOL_SIZE (jcf)); |
| jcf->cpool.tags[0] = 0; |
| #ifdef HANDLE_START_CONSTANT_POOL |
| HANDLE_START_CONSTANT_POOL (JPOOL_SIZE (jcf)); |
| #endif |
| for (i = 1; i < (int) JPOOL_SIZE (jcf); i++) |
| { |
| int constant_kind; |
| |
| /* Make sure at least 9 bytes are available. This is enough |
| for all fixed-sized constant pool entries (so we don't need many |
| more JCF_FILL calls below), but is is small enough that |
| we are guaranteed to not hit EOF (in a valid .class file). */ |
| JCF_FILL (jcf, 9); |
| constant_kind = JCF_readu (jcf); |
| jcf->cpool.tags[i] = constant_kind; |
| switch (constant_kind) |
| { |
| case CONSTANT_String: |
| case CONSTANT_Class: |
| jcf->cpool.data[i].w = JCF_readu2 (jcf); |
| break; |
| case CONSTANT_Fieldref: |
| case CONSTANT_Methodref: |
| case CONSTANT_InterfaceMethodref: |
| case CONSTANT_NameAndType: |
| jcf->cpool.data[i].w = JCF_readu2 (jcf); |
| jcf->cpool.data[i].w |= JCF_readu2 (jcf) << 16; |
| break; |
| case CONSTANT_Integer: |
| case CONSTANT_Float: |
| jcf->cpool.data[i].w = JCF_readu4 (jcf); |
| break; |
| case CONSTANT_Long: |
| case CONSTANT_Double: |
| jcf->cpool.data[i].w = JCF_readu4 (jcf); |
| i++; /* These take up two spots in the constant pool */ |
| jcf->cpool.tags[i] = 0; |
| jcf->cpool.data[i].w = JCF_readu4 (jcf); |
| break; |
| case CONSTANT_Utf8: |
| n = JCF_readu2 (jcf); |
| JCF_FILL (jcf, n); |
| #ifdef HANDLE_CONSTANT_Utf8 |
| HANDLE_CONSTANT_Utf8(jcf, i, n); |
| #else |
| jcf->cpool.data[i].w = JCF_TELL(jcf) - 2; |
| JCF_SKIP (jcf, n); |
| #endif |
| break; |
| default: |
| return i; |
| } |
| } |
| return 0; |
| } |
| |
| /* Read various class flags and numbers. */ |
| |
| static void |
| jcf_parse_class (JCF* jcf) |
| { |
| int i; |
| uint16 interfaces_count; |
| JCF_FILL (jcf, 8); |
| jcf->access_flags = JCF_readu2 (jcf); |
| jcf->this_class = JCF_readu2 (jcf); |
| jcf->super_class = JCF_readu2 (jcf); |
| interfaces_count = JCF_readu2 (jcf); |
| |
| #ifdef HANDLE_CLASS_INFO |
| HANDLE_CLASS_INFO(jcf->access_flags, jcf->this_class, jcf->super_class, interfaces_count); |
| #endif |
| |
| JCF_FILL (jcf, 2 * interfaces_count); |
| |
| /* Read interfaces. */ |
| for (i = 0; i < interfaces_count; i++) |
| { |
| uint16 index ATTRIBUTE_UNUSED = JCF_readu2 (jcf); |
| #ifdef HANDLE_CLASS_INTERFACE |
| HANDLE_CLASS_INTERFACE (index); |
| #endif |
| } |
| } |
| |
| /* Read fields. */ |
| static int |
| jcf_parse_fields (JCF* jcf) |
| { |
| int i, j; |
| uint16 fields_count; |
| JCF_FILL (jcf, 2); |
| fields_count = JCF_readu2 (jcf); |
| |
| #ifdef HANDLE_START_FIELDS |
| HANDLE_START_FIELDS (fields_count); |
| #endif |
| for (i = 0; i < fields_count; i++) |
| { |
| uint16 access_flags = (JCF_FILL (jcf, 8), JCF_readu2 (jcf)); |
| uint16 name_index = JCF_readu2 (jcf); |
| uint16 signature_index = JCF_readu2 (jcf); |
| uint16 attribute_count = JCF_readu2 (jcf); |
| #ifdef HANDLE_START_FIELD |
| HANDLE_START_FIELD (access_flags, name_index, signature_index, |
| attribute_count); |
| #endif |
| for (j = 0; j < attribute_count; j++) |
| { |
| int code = get_attribute (jcf); |
| if (code != 0) |
| return code; |
| } |
| #ifdef HANDLE_END_FIELD |
| HANDLE_END_FIELD (); |
| #endif |
| } |
| #ifdef HANDLE_END_FIELDS |
| HANDLE_END_FIELDS (); |
| #endif |
| return 0; |
| } |
| |
| /* Read methods. */ |
| |
| static int |
| jcf_parse_one_method (JCF* jcf) |
| { |
| int i; |
| uint16 access_flags = (JCF_FILL (jcf, 8), JCF_readu2 (jcf)); |
| uint16 name_index = JCF_readu2 (jcf); |
| uint16 signature_index = JCF_readu2 (jcf); |
| uint16 attribute_count = JCF_readu2 (jcf); |
| #ifdef HANDLE_METHOD |
| HANDLE_METHOD(access_flags, name_index, signature_index, attribute_count); |
| #endif |
| for (i = 0; i < attribute_count; i++) |
| { |
| int code = get_attribute (jcf); |
| if (code != 0) |
| return code; |
| } |
| #ifdef HANDLE_END_METHOD |
| HANDLE_END_METHOD (); |
| #endif |
| return 0; |
| } |
| |
| static int |
| jcf_parse_methods (JCF* jcf) |
| { |
| int i; |
| uint16 methods_count; |
| JCF_FILL (jcf, 2); |
| methods_count = JCF_readu2 (jcf); |
| #ifdef HANDLE_START_METHODS |
| HANDLE_START_METHODS (methods_count); |
| #endif |
| for (i = 0; i < methods_count; i++) |
| { |
| int code = jcf_parse_one_method (jcf); |
| if (code != 0) |
| return code; |
| } |
| #ifdef HANDLE_END_METHODS |
| HANDLE_END_METHODS (); |
| #endif |
| return 0; |
| } |
| |
| /* Read attributes. */ |
| static int |
| jcf_parse_final_attributes (JCF *jcf) |
| { |
| int i; |
| uint16 attributes_count = (JCF_FILL (jcf, 2), JCF_readu2 (jcf)); |
| #ifdef START_FINAL_ATTRIBUTES |
| START_FINAL_ATTRIBUTES (attributes_count) |
| #endif |
| for (i = 0; i < attributes_count; i++) |
| { |
| int code = get_attribute (jcf); |
| if (code != 0) |
| return code; |
| } |
| return 0; |
| } |
| |