/******************************************************************************* * Copyright (c) 2001, 2010 Mathew A. Nelson and Robocode contributors * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://robocode.sourceforge.net/license/epl-v10.html * * Contributors: * Mathew A. Nelson * - Initial API and implementation * Flemming N. Larsen * - Updated to use methods from the Logger, which replaces logger methods * that have been (re)moved from the robocode.util.Utils class * - Code cleanup * Robert D. Maupin * - Replaced old collection types like Vector and Hashtable with * synchronized List and HashMap *******************************************************************************/ package net.sf.robocode.host.security; import net.sf.robocode.io.Logger; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import java.util.Set; /** * @author Mathew A. Nelson (original) * @author Flemming N. Larsen (contributor) * @author Robert D. Maupin (contributor) */ public class ClassAnalyzer { private final static byte CONSTANT_Class = 7; private final static byte CONSTANT_Fieldref = 9; private final static byte CONSTANT_Methodref = 10; private final static byte CONSTANT_InterfaceMethodref = 11; private final static byte CONSTANT_String = 8; private final static byte CONSTANT_Integer = 3; private final static byte CONSTANT_Float = 4; private final static byte CONSTANT_Long = 5; private final static byte CONSTANT_Double = 6; private final static byte CONSTANT_NameAndType = 12; private final static byte CONSTANT_Utf8 = 1; /** * ClassAnalyzer constructor comment. */ public ClassAnalyzer() { super(); } public static void getReferencedClasses(ByteBuffer classFile, Set<String> collection) { /* http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html 4.1 The ClassFile Structure A class file consists of a single ClassFile structure: ClassFile { u4 magic; u2 minor_version; u2 major_version; u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1]; u2 access_flags; u2 this_class; u2 super_class; u2 interfaces_count; u2 interfaces[interfaces_count]; u2 fields_count; field_info fields[fields_count]; u2 methods_count; method_info methods[methods_count]; u2 attributes_count; attribute_info attributes[attributes_count]; } */ String strings[]; List<Integer> classNameIndexes = new ArrayList<Integer>(); try { DataInputStream in = new DataInputStream(new ByteArrayInputStream(classFile.array(), 0, classFile.limit())); long magic = in.readInt(); if (magic != 0xCAFEBABE) { Logger.logError("Not a class file!"); return; } in.readUnsignedShort(); // minor version in.readUnsignedShort(); // major version int constant_pool_count = in.readUnsignedShort(); strings = new String[constant_pool_count]; /* All constant_pool table entries have the following general format: cp_info { u1 tag; u1 info[]; } Constant Type Value CONSTANT_Class 7 CONSTANT_Fieldref 9 CONSTANT_Methodref 10 CONSTANT_InterfaceMethodref 11 CONSTANT_String 8 CONSTANT_Integer 3 CONSTANT_Float 4 CONSTANT_Long 5 CONSTANT_Double 6 CONSTANT_NameAndType 12 CONSTANT_Utf8 1 */ for (int i = 1; i < constant_pool_count; i++) { byte tag = in.readByte(); switch (tag) { /* CONSTANT_Class_info { u1 tag; u2 name_index; } */ case CONSTANT_Class: { int name_index = in.readUnsignedShort(); classNameIndexes.add(name_index); } break; /* CONSTANT_Fieldref_info { u1 tag; u2 class_index; u2 name_and_type_index; } CONSTANT_Methodref_info { u1 tag; u2 class_index; u2 name_and_type_index; } CONSTANT_InterfaceMethodref_info { u1 tag; u2 class_index; u2 name_and_type_index; } */ case CONSTANT_Fieldref: case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: { in.readUnsignedShort(); // class index in.readUnsignedShort(); // name and type index } break; /* CONSTANT_String_info { u1 tag; u2 string_index; } */ case CONSTANT_String: { in.readUnsignedShort(); // string index } break; /* CONSTANT_Integer_info { u1 tag; u4 bytes; } CONSTANT_Float_info { u1 tag; u4 bytes; } */ case CONSTANT_Integer: case CONSTANT_Float: { in.readInt(); // bytes } break; /* CONSTANT_Long_info { u1 tag; u4 high_bytes; u4 low_bytes; } CONSTANT_Double_info { u1 tag; u4 high_bytes; u4 low_bytes; } All 8-byte constants take up two entries in the constant_pool table of the class file. If a CONSTANT_Long_info or CONSTANT_Double_info structure is the item in the constant_pool table at index n, then the next usable item in the pool is located at index n+2. The constant_pool index n+1 must be valid but is considered unusable.2 */ case CONSTANT_Long: case CONSTANT_Double: { in.readInt(); // high bytes in.readInt(); // low bytes i++; // see "all 8-byte..." comment above. } break; /* CONSTANT_NameAndType_info { u1 tag; u2 name_index; u2 descriptor_index; } */ case CONSTANT_NameAndType: { in.readUnsignedShort(); // name index in.readUnsignedShort(); // descriptor index } break; /* CONSTANT_Utf8_info { u1 tag; u2 length; u1 bytes[length]; } */ case CONSTANT_Utf8: { String utf8_string = in.readUTF(); strings[i] = utf8_string; } break; } // switch } // for i } catch (IOException e) { return; } for (Integer classNameIndex : classNameIndexes) { String className = strings[classNameIndex].replace('\\', '.').replace('/', '.'); if (className.indexOf("[") != 0 && !collection.contains(className)) { collection.add(className); } } } }