001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.compiler;
012:
013: /**
014: * Utility methods for getting info from a class file.
015: */
016: public class ClassFileUtils {
017:
018: private static final int CONSTANT_Class = 7;
019: private static final int CONSTANT_Fieldref = 9;
020: private static final int CONSTANT_Methodref = 10;
021: private static final int CONSTANT_InterfaceMethodref = 11;
022: private static final int CONSTANT_String = 8;
023: private static final int CONSTANT_Integer = 3;
024: private static final int CONSTANT_Float = 4;
025: private static final int CONSTANT_Long = 5;
026: private static final int CONSTANT_Double = 6;
027: private static final int CONSTANT_NameAndType = 12;
028: private static final int CONSTANT_Utf8 = 1;
029:
030: /**
031: * Get the name of the class represented by bytecode.
032: */
033: public static String getClassName(byte[] bytecode) {
034: int magic = getU4(bytecode, 0);
035: if (magic != 0xCAFEBABE) {
036: throw new IllegalArgumentException(
037: "Not a class file: Magic 0xCAFEBABE bad: "
038: + Integer.toHexString(magic));
039: }
040: int constantPoolCount = getU2(bytecode, 8);
041: int[] cpOffset = new int[constantPoolCount - 1];
042: int offset = 10;
043: for (int i = 0; i < constantPoolCount - 1; i++) {
044: cpOffset[i] = offset;
045: int tag = bytecode[offset] & 0xFF;
046: if (tag == CONSTANT_Long || tag == CONSTANT_Double) {
047: ++i;
048: }
049: offset += getConstantPoolEntryLength(bytecode, offset);
050: }
051: offset += 2;
052: int this Class = getU2(bytecode, offset);
053: int nameCpIndex = getU2(bytecode, cpOffset[this Class - 1] + 1);
054: return getConstantPoolString(bytecode, cpOffset, nameCpIndex);
055: }
056:
057: /**
058: * Get the constant pool entry number i which is must be a UTF8
059: * string.
060: */
061: private static String getConstantPoolString(byte[] bytecode,
062: int[] cpOffset, int i) {
063: int offset = cpOffset[i - 1];
064: if (bytecode[offset] != CONSTANT_Utf8) {
065: throw new IllegalArgumentException("Not a UTF8 pool entry "
066: + i + " at offset " + offset);
067: }
068: int len = getU2(bytecode, offset + 1);
069: return new String(bytecode, offset + 3, len);
070: }
071:
072: private static int getU4(byte[] bytecode, int offset) {
073: int b0 = (bytecode[offset] & 0xFF);
074: int b1 = (bytecode[offset + 1] & 0xFF);
075: int b2 = (bytecode[offset + 2] & 0xFF);
076: int b3 = (bytecode[offset + 3] & 0xFF);
077: return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
078: }
079:
080: private static int getU2(byte[] bytecode, int offset) {
081: int b0 = (bytecode[offset] & 0xFF);
082: int b1 = (bytecode[offset + 1] & 0xFF);
083: return (b0 << 8) + b1;
084: }
085:
086: /**
087: * Get the length in bytes of an entry in the constant pool.
088: */
089: private static int getConstantPoolEntryLength(byte[] bytecode,
090: int offset) {
091: int tag = bytecode[offset] & 0xFF;
092: switch (tag) {
093: case CONSTANT_Class:
094: case CONSTANT_String:
095: return 3;
096: case CONSTANT_Fieldref:
097: case CONSTANT_Methodref:
098: case CONSTANT_InterfaceMethodref:
099: case CONSTANT_Integer:
100: case CONSTANT_Float:
101: case CONSTANT_NameAndType:
102: return 5;
103: case CONSTANT_Long:
104: case CONSTANT_Double:
105: return 9;
106: case CONSTANT_Utf8:
107: return 3 + getU2(bytecode, offset + 1);
108: case 0:
109: return 0;
110: }
111: throw new IllegalArgumentException(
112: "Unknown constant pool entry type " + tag + " at "
113: + Integer.toHexString(offset));
114: }
115:
116: }
|