001package serp.bytecode.lowlevel; 002 003import 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 */ 012public 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 18: // invoke dynamic 063 case 12: // name 064 idx += 5; 065 break; 066 case 5: // long 067 case 6: // double 068 idx += 9; 069 i++; // wide entry 070 break; 071 case 15: // method handle 072 idx += 4; 073 break; 074 case 16: // method type 075 default: 076 idx += 3; 077 } 078 } 079 return idx; 080 } 081 082 /** 083 * Read a byte value at the given offset into the given bytecode. 084 */ 085 public static int readByte(byte[] b, int idx) { 086 return b[idx] & 0xFF; 087 } 088 089 /** 090 * Read an unsigned short value at the given offset into the given bytecode. 091 */ 092 public static int readUnsignedShort(byte[] b, int idx) { 093 return (readByte(b, idx) << 8) | readByte(b, idx + 1); 094 } 095 096 /** 097 * Read an int value at the given offset into the given bytecode. 098 */ 099 public static int readInt(byte[] b, int idx) { 100 return (readByte(b, idx) << 24) | (readByte(b, idx + 1) << 16) 101 | (readByte(b, idx + 2) << 8) | readByte(b, idx + 3); 102 } 103 104 /** 105 * Read a long value at the given offset into the given bytecode. 106 */ 107 public static long readLong(byte[] b, int idx) { 108 return (readInt(b, idx) << 32) | readInt(b, idx + 4); 109 } 110 111 /** 112 * Read a UTF-8 string value at the given offset into the given bytecode. 113 */ 114 public static String readString(byte[] b, int idx) { 115 int len = readUnsignedShort(b, idx); 116 try { 117 return new String(b, idx + 2, len, "UTF-8"); 118 } catch (UnsupportedEncodingException uee) { 119 throw new ClassFormatError(uee.toString()); 120 } 121 } 122 123 /** 124 * Read the contents of the given stream. 125 */ 126 private static byte[] toByteArray(InputStream in) throws IOException { 127 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 128 byte[] buf = new byte[1024]; 129 for (int r; (r = in.read(buf)) != -1; bout.write(buf, 0, r)); 130 return bout.toByteArray(); 131 } 132 133 /** 134 * Return the index into the bytecode of the end of the constant pool. 135 */ 136 public int getEndIndex() { 137 return _idx; 138 } 139 140 /** 141 * Return the given table entry. 142 */ 143 public int get(int idx) { 144 return _table[idx]; 145 } 146 147 /** 148 * Read a byte value at the given offset. 149 */ 150 public int readByte(int idx) { 151 return readByte(_bytecode, idx); 152 } 153 154 /** 155 * Read an unsigned short value at the given offset. 156 */ 157 public int readUnsignedShort(int idx) { 158 return readUnsignedShort(_bytecode, idx); 159 } 160 161 /** 162 * Read an int value at the given offset. 163 */ 164 public int readInt(int idx) { 165 return readInt(_bytecode, idx); 166 } 167 168 /** 169 * Read a long value at the given offset. 170 */ 171 public long readLong(int idx) { 172 return readLong(_bytecode, idx); 173 } 174 175 /** 176 * Read a UTF-8 string value at the given offset. 177 */ 178 public String readString(int idx) { 179 return readString(_bytecode, idx); 180 } 181}