/* libjclass - Library for reading java class files * Copyright (C) 2003 Nicos Panayides * * 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 * of the License, 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * $Id: java_file.c,v 1.19 2003/11/28 10:34:53 anarxia Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include static uint16_t fread_uint16(FILE*); static uint32_t fread_uint32(FILE*); static ConstantPool* fread_constant_pool(FILE*); static void get_next_entry(FILE*, ConstantPoolEntry*); static uint16_t* fread_interfaces(FILE*, uint16_t); static Field* fread_fields(FILE*, uint16_t); static AttributeContainer* fread_attributes(FILE*, uint16_t); /* Reads 2 bytes from a file and converts them to native byte order. */ static uint16_t fread_uint16(FILE* classfile) { uint16_t bytes; fread(&(bytes), sizeof(uint16_t), 1, classfile); bytes = UINT16_NATIVE(bytes); return bytes; } /* Reads 4 bytes from a file and converts them to native byte order. */ static uint32_t fread_uint32(FILE* classfile) { uint32_t bytes; fread(&(bytes), sizeof(uint32_t), 1, classfile); bytes = UINT32_NATIVE(bytes); return bytes; } /** * jclass_class_new_from_file * @classfile: The file containing the class. * * Creates a JavaClass struct from the given class file. * The file must be opened with "rb" permissions. * The file will always be closed when the function returns. * * Returns: A JavaClass struct allocated with malloc. */ JavaClass* jclass_class_new_from_file(FILE* classfile) { JavaClass* class_struct; if (classfile == NULL) return NULL; if (fread_uint32(classfile) != JAVA_CLASS_MAGIC) { fclose(classfile); return NULL; } class_struct = (JavaClass*) malloc(sizeof(JavaClass)); class_struct->minor_version = fread_uint16(classfile); class_struct->major_version = fread_uint16(classfile); class_struct->constant_pool = fread_constant_pool(classfile); class_struct->access_flags = fread_uint16(classfile); class_struct->constant_pool->this_class = fread_uint16(classfile); class_struct->constant_pool->super_class = fread_uint16(classfile); class_struct->interfaces_count = fread_uint16(classfile); class_struct->interfaces = fread_interfaces(classfile, class_struct->interfaces_count); class_struct->fields_count = fread_uint16(classfile); class_struct->fields = fread_fields(classfile, class_struct->fields_count); class_struct->methods_count = fread_uint16(classfile); class_struct->methods = fread_fields(classfile, class_struct->methods_count); class_struct->attributes_count = fread_uint16(classfile); class_struct->attributes = fread_attributes(classfile, class_struct->attributes_count); fclose(classfile); return class_struct; } /** * jclass_cp_new_from_file * @classfile: The file containg the class. * * Reads the constant pool of the class from the given class file. * The file must be opened with "rb" permissions. * The file will always be closed when the function returns. * * Returns: A ConstantPool struct. */ ConstantPool* jclass_cp_new_from_file(FILE* classfile) { ConstantPool* constant_pool; int bytes; if (classfile == NULL) return NULL; if (fread_uint32(classfile) != JAVA_CLASS_MAGIC) { fclose(classfile); return NULL; } fread(&bytes, 4, 1, classfile); constant_pool = fread_constant_pool(classfile); fread(&bytes, 2, 1, classfile); constant_pool->this_class = fread_uint16(classfile); constant_pool->super_class = fread_uint16(classfile); fclose(classfile); return constant_pool; } static ConstantPool* fread_constant_pool(FILE* classfile) { ConstantPool* constant_pool; uint16_t count = 0; constant_pool = (ConstantPool*) malloc(sizeof(ConstantPool)); constant_pool->count = fread_uint16(classfile); constant_pool->entries = (ConstantPoolEntry*) malloc(sizeof(ConstantPoolEntry) * constant_pool->count); constant_pool->entries[0].tag = CONSTANT_Empty; do { count++; get_next_entry(classfile, &constant_pool->entries[count]); if (constant_pool->entries[count].tag != CONSTANT_Empty) { /* For every double or long the next entry is reserved for the VM */ if (constant_pool->entries[count].tag == CONSTANT_Long || constant_pool->entries[count].tag == CONSTANT_Double) { count++; constant_pool->entries[count].tag = CONSTANT_Empty; } } else { fputs("Unrecognised entry in the constant pool\n", stderr); } } while(count < constant_pool->count - 1); return constant_pool; } /** * get_next_entry * @classfile: The file to read from. * @info: A pointer to the ConstantPoolEntry struct to store the entry. * * Reads the next constant pool entry from the class file. */ static void get_next_entry(FILE* classfile, ConstantPoolEntry* info) { int tags_read; tags_read = fread(&(info->tag), sizeof(uint8_t), 1, classfile); if (tags_read < 1) { info->tag = 0; return; } switch(info->tag) { case CONSTANT_Class: info->info.classinfo.name_index = fread_uint16(classfile); break; case CONSTANT_Fieldref: case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: info->info.ref.class_index = fread_uint16(classfile); info->info.ref.name_and_type_index = fread_uint16(classfile); break; case CONSTANT_String: info->info.stringinfo.string_index = fread_uint16(classfile); break; case CONSTANT_Integer: case CONSTANT_Float: info->info.integer.bytes = fread_uint32(classfile); break; case CONSTANT_Long: case CONSTANT_Double: info->info.longinfo = (LongEntry*) malloc(sizeof(LongEntry)); info->info.longinfo->long_bytes = ((uint64_t) fread_uint32(classfile)) << 32; info->info.longinfo->long_bytes += fread_uint32(classfile); break; case CONSTANT_NameAndType: info->info.nameandtype.name_index = fread_uint16(classfile); info->info.nameandtype.descriptor_index = fread_uint16(classfile); break; case CONSTANT_Utf8: info->info.utf8 = (UTF8Entry*) malloc(sizeof(UTF8Entry)); info->info.utf8->length = fread_uint16(classfile); if(info->info.utf8->length) { info->info.utf8->contents = (uint8_t*) malloc(sizeof(uint8_t) * info->info.utf8->length); fread(info->info.utf8->contents, info->info.utf8->length, 1, classfile); } else info->info.utf8->contents = NULL; break; default: fprintf(stderr, "Unknown tag number: %d\n", info->tag); info->tag = CONSTANT_Empty; } } static uint16_t* fread_interfaces(FILE* classfile, uint16_t count) { uint16_t* interfaces; uint16_t i; if(count) interfaces = (uint16_t*) malloc(sizeof(uint16_t) * count); else interfaces = NULL; for(i = 0; i < count; i++) interfaces[i] = fread_uint16(classfile); return interfaces; } /** * fread_fields * @classfile: The file to read the fields from. * @count: The number of fields to read. * * Reads count number of fields from a class file. * * Returns: An array of Fields read from a file. */ static Field* fread_fields(FILE* classfile, uint16_t count) { Field* field_array; uint16_t i; if(count) { field_array = (Field*) malloc(sizeof(Field) * count); for(i=0; i < count; i++) { field_array[i].access_flags = fread_uint16(classfile); field_array[i].name_index = fread_uint16(classfile); field_array[i].descriptor_index = fread_uint16(classfile); field_array[i].attributes_count = fread_uint16(classfile); field_array[i].attributes = fread_attributes(classfile, field_array[i].attributes_count); } } else field_array = NULL; return field_array; } /** * fread_attributes * @classfile: The file to read the attributes from. * @count: Number of attributes to read. * * Helper function to read attributes from the file. * The file pointer must be where the attributes start. * * Returns: An array of AttributeContainer structs with the attributes. */ static AttributeContainer* fread_attributes(FILE* classfile, uint16_t count) { AttributeContainer* attributes; int j; if(!count) return NULL; attributes = (AttributeContainer*) malloc(sizeof(AttributeContainer) * count); for(j=0; j < count; j++) { attributes[j].name_index = fread_uint16(classfile); attributes[j].length = fread_uint32(classfile); if(attributes[j].length) { attributes[j].contents = (uint8_t*) malloc(sizeof(uint8_t) * attributes[j].length); fread(attributes[j].contents, attributes[j].length, 1, classfile); } else attributes[j].contents = NULL; } return attributes; }