1ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba/** 2ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba * Copyright 2007 Google Inc. 3ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba * 4ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba * Licensed under the Apache License, Version 2.0 (the "License"); 5ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba * you may not use this file except in compliance with the License. 6ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba * You may obtain a copy of the License at 7ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba * 8ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba * http://www.apache.org/licenses/LICENSE-2.0 9ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba * 10ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba * Unless required by applicable law or agreed to in writing, software 11ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba * distributed under the License is distributed on an "AS IS" BASIS, 12ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba * See the License for the specific language governing permissions and 14ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba * limitations under the License. 15ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba */ 16ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba 17ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosibapackage com.tonicsystems.jarjar.util; 18ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba 19ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosibaimport java.io.*; 20ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosibaimport java.lang.reflect.Array; 21ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosibaimport java.util.*; 22ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba 23ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosibapublic class ClassHeaderReader 24ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba{ 25ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba private int access; 26ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba private String thisClass; 27ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba private String superClass; 28ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba private String[] interfaces; 29ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba 30ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba private InputStream in; 31ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba private byte[] b = new byte[0x2000]; 32ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba private int[] items = new int[1000]; 33ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba private int bsize = 0; 34ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba private MyByteArrayInputStream bin = new MyByteArrayInputStream(); 35ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba private DataInputStream data = new DataInputStream(bin); 36ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba 37ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba public int getAccess() { 38ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba return access; 39ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 40ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba 41ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba public String getClassName() { 42ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba return thisClass; 43ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 44ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba 45ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba public String getSuperName() { 46ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba return superClass; 47ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 48ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba 49ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba public String[] getInterfaces() { 50ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba return interfaces; 51ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 52ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba 53ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba public void read(InputStream in) throws IOException { 54ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba try { 55ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba this.in = in; 56ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba bsize = 0; 57ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba access = 0; 58ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba thisClass = superClass = null; 59ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba interfaces = null; 60ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba 61ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba try { 62ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba buffer(4); 63ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } catch (IOException e) { 64ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba // ignore 65ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 66ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba if (b[0] != (byte)0xCA || b[1] != (byte)0xFE || b[2] != (byte)0xBA || b[3] != (byte)0xBE) 67ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba throw new ClassFormatError("Bad magic number"); 68ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba 69ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba buffer(6); 70ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba readUnsignedShort(4); // minorVersion 71ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba readUnsignedShort(6); // majorVersion 72ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba // TODO: check version 73ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba int constant_pool_count = readUnsignedShort(8); 74ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba items = (int[])resizeArray(items, constant_pool_count); 75ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba 76ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba int index = 10; 77ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba for (int i = 1; i < constant_pool_count; i++) { 78ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba int size; 79ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba buffer(index + 3); // TODO: reduce calls to buffer 80ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba int tag = b[index]; 81ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba items[i] = index + 1; 82ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba switch (tag) { 83ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba case 9: // Fieldref 84ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba case 10: // Methodref 85ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba case 11: // InterfaceMethodref 86ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba case 3: // Integer 87ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba case 4: // Float 88ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba case 12: // NameAndType 89ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba size = 4; 90ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba break; 91ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba case 5: // Long 92ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba case 6: // Double 93ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba size = 8; 94ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba i++; 95ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba break; 96ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba case 1: // Utf8 97ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba size = 2 + readUnsignedShort(index + 1); 98ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba break; 99ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba case 7: // Class 100ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba case 8: // String 101ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba size = 2; 102ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba break; 103ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba default: 104ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba throw new IllegalStateException("Unknown constant pool tag " + tag); 105ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 106ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba index += size + 1; 107ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 108ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba buffer(index + 8); 109ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba access = readUnsignedShort(index); 110ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba thisClass = readClass(index + 2); 111ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba superClass = readClass(index + 4); 112ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba int interfaces_count = readUnsignedShort(index + 6); 113ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba 114ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba index += 8; 115ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba buffer(index + interfaces_count * 2); 116ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba interfaces = new String[interfaces_count]; 117ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba for (int i = 0; i < interfaces_count; i++) { 118ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba interfaces[i] = readClass(index); 119ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba index += 2; 120ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 121ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } finally { 122ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba in.close(); 123ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 124ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 125ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba 126ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba private String readClass(int index) throws IOException { 127ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba index = readUnsignedShort(index); 128ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba if (index == 0) 129ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba return null; 130ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba index = readUnsignedShort(items[index]); 131ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba bin.readFrom(b, items[index]); 132ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba return data.readUTF(); 133ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 134ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba 135ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba private int readUnsignedShort(int index) { 136ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba byte[] b = this.b; 137ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); 138ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 139ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba 140ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba private static final int CHUNK = 2048; 141ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba private void buffer(int amount) throws IOException { 142ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba if (amount > b.length) 143ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba b = (byte[])resizeArray(b, b.length * 2); 144ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba if (amount > bsize) { 145ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba int rounded = (int)(CHUNK * Math.ceil((float)amount / CHUNK)); 146ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba bsize += read(in, b, bsize, rounded - bsize); 147ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba if (amount > bsize) 148ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba throw new EOFException(); 149ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 150ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 151ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba 152ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba private static int read(InputStream in, byte[] b, int off, int len) throws IOException { 153ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba int total = 0; 154ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba while (total < len) { 155ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba int result = in.read(b, off + total, len - total); 156ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba if (result == -1) 157ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba break; 158ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba total += result; 159ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 160ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba return total; 161ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 162ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba 163ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba private static Object resizeArray(Object array, int length) 164ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba { 165ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba if (Array.getLength(array) < length) { 166ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba Object newArray = Array.newInstance(array.getClass().getComponentType(), length); 167ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba System.arraycopy(array, 0, newArray, 0, Array.getLength(array)); 168ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba return newArray; 169ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } else { 170ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba return array; 171ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 172ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 173ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba 174ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba private static class MyByteArrayInputStream extends ByteArrayInputStream 175ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba { 176ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba public MyByteArrayInputStream() { 177ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba super(new byte[0]); 178ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 179ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba 180ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba public void readFrom(byte[] buf, int pos) { 181ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba this.buf = buf; 182ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba this.pos = pos; 183ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba count = buf.length; 184ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 185ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba } 186ab61347a2cb3254688c42c993278cefd43e5d99dMarcin Kosiba} 187