summaryrefslogtreecommitdiffstats
path: root/src/main/com/tonicsystems/jarjar/util/ClassHeaderReader.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/com/tonicsystems/jarjar/util/ClassHeaderReader.java')
-rw-r--r--src/main/com/tonicsystems/jarjar/util/ClassHeaderReader.java186
1 files changed, 186 insertions, 0 deletions
diff --git a/src/main/com/tonicsystems/jarjar/util/ClassHeaderReader.java b/src/main/com/tonicsystems/jarjar/util/ClassHeaderReader.java
new file mode 100644
index 0000000..6e448be
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/util/ClassHeaderReader.java
@@ -0,0 +1,186 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar.util;
+
+import java.io.*;
+import java.lang.reflect.Array;
+import java.util.*;
+
+public class ClassHeaderReader
+{
+ private int access;
+ private String thisClass;
+ private String superClass;
+ private String[] interfaces;
+
+ private InputStream in;
+ private byte[] b = new byte[0x2000];
+ private int[] items = new int[1000];
+ private int bsize = 0;
+ private MyByteArrayInputStream bin = new MyByteArrayInputStream();
+ private DataInputStream data = new DataInputStream(bin);
+
+ public int getAccess() {
+ return access;
+ }
+
+ public String getClassName() {
+ return thisClass;
+ }
+
+ public String getSuperName() {
+ return superClass;
+ }
+
+ public String[] getInterfaces() {
+ return interfaces;
+ }
+
+ public void read(InputStream in) throws IOException {
+ try {
+ this.in = in;
+ bsize = 0;
+ access = 0;
+ thisClass = superClass = null;
+ interfaces = null;
+
+ try {
+ buffer(4);
+ } catch (IOException e) {
+ // ignore
+ }
+ if (b[0] != (byte)0xCA || b[1] != (byte)0xFE || b[2] != (byte)0xBA || b[3] != (byte)0xBE)
+ throw new ClassFormatError("Bad magic number");
+
+ buffer(6);
+ readUnsignedShort(4); // minorVersion
+ readUnsignedShort(6); // majorVersion
+ // TODO: check version
+ int constant_pool_count = readUnsignedShort(8);
+ items = (int[])resizeArray(items, constant_pool_count);
+
+ int index = 10;
+ for (int i = 1; i < constant_pool_count; i++) {
+ int size;
+ buffer(index + 3); // TODO: reduce calls to buffer
+ int tag = b[index];
+ items[i] = index + 1;
+ switch (tag) {
+ case 9: // Fieldref
+ case 10: // Methodref
+ case 11: // InterfaceMethodref
+ case 3: // Integer
+ case 4: // Float
+ case 12: // NameAndType
+ size = 4;
+ break;
+ case 5: // Long
+ case 6: // Double
+ size = 8;
+ i++;
+ break;
+ case 1: // Utf8
+ size = 2 + readUnsignedShort(index + 1);
+ break;
+ case 7: // Class
+ case 8: // String
+ size = 2;
+ break;
+ default:
+ throw new IllegalStateException("Unknown constant pool tag " + tag);
+ }
+ index += size + 1;
+ }
+ buffer(index + 8);
+ access = readUnsignedShort(index);
+ thisClass = readClass(index + 2);
+ superClass = readClass(index + 4);
+ int interfaces_count = readUnsignedShort(index + 6);
+
+ index += 8;
+ buffer(index + interfaces_count * 2);
+ interfaces = new String[interfaces_count];
+ for (int i = 0; i < interfaces_count; i++) {
+ interfaces[i] = readClass(index);
+ index += 2;
+ }
+ } finally {
+ in.close();
+ }
+ }
+
+ private String readClass(int index) throws IOException {
+ index = readUnsignedShort(index);
+ if (index == 0)
+ return null;
+ index = readUnsignedShort(items[index]);
+ bin.readFrom(b, items[index]);
+ return data.readUTF();
+ }
+
+ private int readUnsignedShort(int index) {
+ byte[] b = this.b;
+ return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
+ }
+
+ private static final int CHUNK = 2048;
+ private void buffer(int amount) throws IOException {
+ if (amount > b.length)
+ b = (byte[])resizeArray(b, b.length * 2);
+ if (amount > bsize) {
+ int rounded = (int)(CHUNK * Math.ceil((float)amount / CHUNK));
+ bsize += read(in, b, bsize, rounded - bsize);
+ if (amount > bsize)
+ throw new EOFException();
+ }
+ }
+
+ private static int read(InputStream in, byte[] b, int off, int len) throws IOException {
+ int total = 0;
+ while (total < len) {
+ int result = in.read(b, off + total, len - total);
+ if (result == -1)
+ break;
+ total += result;
+ }
+ return total;
+ }
+
+ private static Object resizeArray(Object array, int length)
+ {
+ if (Array.getLength(array) < length) {
+ Object newArray = Array.newInstance(array.getClass().getComponentType(), length);
+ System.arraycopy(array, 0, newArray, 0, Array.getLength(array));
+ return newArray;
+ } else {
+ return array;
+ }
+ }
+
+ private static class MyByteArrayInputStream extends ByteArrayInputStream
+ {
+ public MyByteArrayInputStream() {
+ super(new byte[0]);
+ }
+
+ public void readFrom(byte[] buf, int pos) {
+ this.buf = buf;
+ this.pos = pos;
+ count = buf.length;
+ }
+ }
+}