/* 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 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. */ #include "jcf.h" #include "zipfile.h" static int get_attribute PARAMS ((JCF *)); static int jcf_parse_preamble PARAMS ((JCF *)); static int jcf_parse_constant_pool PARAMS ((JCF *)); static void jcf_parse_class PARAMS ((JCF *)); static int jcf_parse_fields PARAMS ((JCF *)); static int jcf_parse_one_method PARAMS ((JCF *)); static int jcf_parse_methods PARAMS ((JCF *)); static int jcf_parse_final_attributes PARAMS ((JCF *)); #ifdef NEED_PEEK_ATTRIBUTE static int peek_attribute PARAMS ((JCF *, int, const char *, int)); #endif #ifdef NEED_SKIP_ATTRIBUTE static void skip_attribute PARAMS ((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, attribute_number, peeked_name, peeked_name_length) 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, number_of_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 DEFUN(get_attribute, (jcf), 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 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 DEFUN(jcf_parse_preamble, (jcf), 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 DEFUN(jcf_parse_constant_pool, (jcf), JCF* jcf) { int i, n; JPOOL_SIZE (jcf) = (JCF_FILL (jcf, 2), JCF_readu2 (jcf)); jcf->cpool.tags = ALLOC (JPOOL_SIZE (jcf)); jcf->cpool.data = 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] = JCF_readu2 (jcf); break; case CONSTANT_Fieldref: case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: case CONSTANT_NameAndType: jcf->cpool.data[i] = JCF_readu2 (jcf); jcf->cpool.data[i] |= JCF_readu2 (jcf) << 16; break; case CONSTANT_Integer: case CONSTANT_Float: jcf->cpool.data[i] = JCF_readu4 (jcf); break; case CONSTANT_Long: case CONSTANT_Double: jcf->cpool.data[i] = JCF_readu4 (jcf); i++; /* These take up two spots in the constant pool */ jcf->cpool.tags[i] = 0; jcf->cpool.data[i] = 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] = JCF_TELL(jcf) - 2; JCF_SKIP (jcf, n); #endif break; default: return i; } } return 0; } /* Read various class flags and numbers. */ static void DEFUN(jcf_parse_class, (jcf), 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 DEFUN(jcf_parse_fields, (jcf), 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 DEFUN(jcf_parse_one_method, (jcf), 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 DEFUN(jcf_parse_methods, (jcf), 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 DEFUN(jcf_parse_final_attributes, (jcf), 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; }