• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
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 
getAccess()37     public int getAccess() {
38         return access;
39     }
40 
getClassName()41     public String getClassName() {
42         return thisClass;
43     }
44 
getSuperName()45     public String getSuperName() {
46         return superClass;
47     }
48 
getInterfaces()49     public String[] getInterfaces() {
50         return interfaces;
51     }
52 
read(InputStream in)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                 // ignore
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); // minorVersion
71             readUnsignedShort(6); // majorVersion
72             // TODO: check version
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); // TODO: reduce calls to buffer
80                 int tag = b[index];
81                 items[i] = index + 1;
82                 switch (tag) {
83                 case 9:  // Fieldref
84                 case 10: // Methodref
85                 case 11: // InterfaceMethodref
86                 case 3:  // Integer
87                 case 4:  // Float
88                 case 12: // NameAndType
89                     size = 4;
90                     break;
91                 case 5:  // Long
92                 case 6:  // Double
93                     size = 8;
94                     i++;
95                     break;
96                 case 1:  // Utf8
97                     size = 2 + readUnsignedShort(index + 1);
98                     break;
99                 case 7:  // Class
100                 case 8:  // String
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 
readClass(int index)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 
readUnsignedShort(int index)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;
buffer(int amount)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 
read(InputStream in, byte[] b, int off, int len)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 
resizeArray(Object array, int length)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     {
MyByteArrayInputStream()176         public MyByteArrayInputStream() {
177             super(new byte[0]);
178         }
179 
readFrom(byte[] buf, int pos)180         public void readFrom(byte[] buf, int pos) {
181             this.buf = buf;
182             this.pos = pos;
183             count = buf.length;
184         }
185     }
186 }
187