001 package serp.bytecode.lowlevel; 002 003 import java.io.*; 004 005 /** 006 * Efficient representation of the constant pool as a table. This class 007 * can be used to parse out bits of information from bytecode without 008 * instantiating a full {@link serp.bytecode.BCClass}. 009 * 010 * @author Abe White 011 */ 012 public class ConstantPoolTable { 013 private byte[] _bytecode = null; 014 private int[] _table = null; 015 private int _idx = 0; 016 017 /** 018 * Constructor; supply class bytecode. 019 */ 020 public ConstantPoolTable(byte[] b) { 021 _bytecode = b; 022 _table = new int[readUnsignedShort(b, 8)]; 023 _idx = parse(b, _table); 024 } 025 026 /** 027 * Constructor; supply input stream to bytecode. 028 */ 029 public ConstantPoolTable(InputStream in) throws IOException { 030 this(toByteArray(in)); 031 } 032 033 /** 034 * Allows static computation of the byte index after the constant 035 * pool without caching constant pool information. 036 */ 037 public static int getEndIndex(byte[] b) { 038 return parse(b, null); 039 } 040 041 /** 042 * Parse class bytecode, returning end index of pool. 043 */ 044 private static int parse(byte[] b, int[] table) { 045 // each entry is the index in the byte array of the data for a const 046 // pool entry 047 int entries = (table == null) ? readUnsignedShort(b, 8) : table.length; 048 int idx = 10; 049 for (int i = 1; i < entries; i++) { 050 if (table != null) 051 table[i] = idx + 1; // skip entry type 052 053 switch (b[idx]) { 054 case 1: // utf8 055 idx += (3 + readUnsignedShort(b, idx + 1)); 056 break; 057 case 3: // integer 058 case 4: // float 059 case 9: // field 060 case 10: // method 061 case 11: // interface method 062 case 12: // name 063 idx += 5; 064 break; 065 case 5: // long 066 case 6: // double 067 idx += 9; 068 i++; // wide entry 069 break; 070 default: 071 idx += 3; 072 } 073 } 074 return idx; 075 } 076 077 /** 078 * Read a byte value at the given offset into the given bytecode. 079 */ 080 public static int readByte(byte[] b, int idx) { 081 return b[idx] & 0xFF; 082 } 083 084 /** 085 * Read an unsigned short value at the given offset into the given bytecode. 086 */ 087 public static int readUnsignedShort(byte[] b, int idx) { 088 return (readByte(b, idx) << 8) | readByte(b, idx + 1); 089 } 090 091 /** 092 * Read an int value at the given offset into the given bytecode. 093 */ 094 public static int readInt(byte[] b, int idx) { 095 return (readByte(b, idx) << 24) | (readByte(b, idx + 1) << 16) 096 | (readByte(b, idx + 2) << 8) | readByte(b, idx + 3); 097 } 098 099 /** 100 * Read a long value at the given offset into the given bytecode. 101 */ 102 public static long readLong(byte[] b, int idx) { 103 return (readInt(b, idx) << 32) | readInt(b, idx + 4); 104 } 105 106 /** 107 * Read a UTF-8 string value at the given offset into the given bytecode. 108 */ 109 public static String readString(byte[] b, int idx) { 110 int len = readUnsignedShort(b, idx); 111 try { 112 return new String(b, idx + 2, len, "UTF-8"); 113 } catch (UnsupportedEncodingException uee) { 114 throw new ClassFormatError(uee.toString()); 115 } 116 } 117 118 /** 119 * Read the contents of the given stream. 120 */ 121 private static byte[] toByteArray(InputStream in) throws IOException { 122 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 123 byte[] buf = new byte[1024]; 124 for (int r; (r = in.read(buf)) != -1; bout.write(buf, 0, r)); 125 return bout.toByteArray(); 126 } 127 128 /** 129 * Return the index into the bytecode of the end of the constant pool. 130 */ 131 public int getEndIndex() { 132 return _idx; 133 } 134 135 /** 136 * Return the given table entry. 137 */ 138 public int get(int idx) { 139 return _table[idx]; 140 } 141 142 /** 143 * Read a byte value at the given offset. 144 */ 145 public int readByte(int idx) { 146 return readByte(_bytecode, idx); 147 } 148 149 /** 150 * Read an unsigned short value at the given offset. 151 */ 152 public int readUnsignedShort(int idx) { 153 return readUnsignedShort(_bytecode, idx); 154 } 155 156 /** 157 * Read an int value at the given offset. 158 */ 159 public int readInt(int idx) { 160 return readInt(_bytecode, idx); 161 } 162 163 /** 164 * Read a long value at the given offset. 165 */ 166 public long readLong(int idx) { 167 return readLong(_bytecode, idx); 168 } 169 170 /** 171 * Read a UTF-8 string value at the given offset. 172 */ 173 public String readString(int idx) { 174 return readString(_bytecode, idx); 175 } 176 }