1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.tonicsystems.jarjar.util;
18
19 import java.io.*;
20 import java.lang.reflect.Array;
21 import java.util.*;
22
23 public class ClassHeaderReader
24 {
25 private int access;
26 private String thisClass;
27 private String superClass;
28 private String[] interfaces;
29
30 private InputStream in;
31 private byte[] b = new byte[0x2000];
32 private int[] items = new int[1000];
33 private int bsize = 0;
34 private MyByteArrayInputStream bin = new MyByteArrayInputStream();
35 private DataInputStream data = new DataInputStream(bin);
36
37 public int getAccess() {
38 return access;
39 }
40
41 public String getClassName() {
42 return thisClass;
43 }
44
45 public String getSuperName() {
46 return superClass;
47 }
48
49 public String[] getInterfaces() {
50 return interfaces;
51 }
52
53 public void read(InputStream in) throws IOException {
54 try {
55 this.in = in;
56 bsize = 0;
57 access = 0;
58 thisClass = superClass = null;
59 interfaces = null;
60
61 try {
62 buffer(4);
63 } catch (IOException e) {
64
65 }
66 if (b[0] != (byte)0xCA || b[1] != (byte)0xFE || b[2] != (byte)0xBA || b[3] != (byte)0xBE)
67 throw new ClassFormatError("Bad magic number");
68
69 buffer(6);
70 readUnsignedShort(4);
71 readUnsignedShort(6);
72
73 int constant_pool_count = readUnsignedShort(8);
74 items = (int[])resizeArray(items, constant_pool_count);
75
76 int index = 10;
77 for (int i = 1; i < constant_pool_count; i++) {
78 int size;
79 buffer(index + 3);
80 int tag = b[index];
81 items[i] = index + 1;
82 switch (tag) {
83 case 9:
84 case 10:
85 case 11:
86 case 3:
87 case 4:
88 case 12:
89 size = 4;
90 break;
91 case 5:
92 case 6:
93 size = 8;
94 i++;
95 break;
96 case 1:
97 size = 2 + readUnsignedShort(index + 1);
98 break;
99 case 7:
100 case 8:
101 size = 2;
102 break;
103 default:
104 throw new IllegalStateException("Unknown constant pool tag " + tag);
105 }
106 index += size + 1;
107 }
108 buffer(index + 8);
109 access = readUnsignedShort(index);
110 thisClass = readClass(index + 2);
111 superClass = readClass(index + 4);
112 int interfaces_count = readUnsignedShort(index + 6);
113
114 index += 8;
115 buffer(index + interfaces_count * 2);
116 interfaces = new String[interfaces_count];
117 for (int i = 0; i < interfaces_count; i++) {
118 interfaces[i] = readClass(index);
119 index += 2;
120 }
121 } finally {
122 in.close();
123 }
124 }
125
126 private String readClass(int index) throws IOException {
127 index = readUnsignedShort(index);
128 if (index == 0)
129 return null;
130 index = readUnsignedShort(items[index]);
131 bin.readFrom(b, items[index]);
132 return data.readUTF();
133 }
134
135 private int readUnsignedShort(int index) {
136 byte[] b = this.b;
137 return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
138 }
139
140 private static final int CHUNK = 2048;
141 private void buffer(int amount) throws IOException {
142 if (amount > b.length)
143 b = (byte[])resizeArray(b, b.length * 2);
144 if (amount > bsize) {
145 int rounded = (int)(CHUNK * Math.ceil((float)amount / CHUNK));
146 bsize += read(in, b, bsize, rounded - bsize);
147 if (amount > bsize)
148 throw new EOFException();
149 }
150 }
151
152 private static int read(InputStream in, byte[] b, int off, int len) throws IOException {
153 int total = 0;
154 while (total < len) {
155 int result = in.read(b, off + total, len - total);
156 if (result == -1)
157 break;
158 total += result;
159 }
160 return total;
161 }
162
163 private static Object resizeArray(Object array, int length)
164 {
165 if (Array.getLength(array) < length) {
166 Object newArray = Array.newInstance(array.getClass().getComponentType(), length);
167 System.arraycopy(array, 0, newArray, 0, Array.getLength(array));
168 return newArray;
169 } else {
170 return array;
171 }
172 }
173
174 private static class MyByteArrayInputStream extends ByteArrayInputStream
175 {
176 public MyByteArrayInputStream() {
177 super(new byte[0]);
178 }
179
180 public void readFrom(byte[] buf, int pos) {
181 this.buf = buf;
182 this.pos = pos;
183 count = buf.length;
184 }
185 }
186 }