1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.shared.dependency.analyzer.asm;
20
21 import java.nio.Buffer;
22 import java.nio.ByteBuffer;
23 import java.nio.ByteOrder;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.Map;
28 import java.util.Set;
29
30 import org.objectweb.asm.Type;
31
32
33
34
35
36
37
38
39
40
41
42
43 public class ConstantPoolParser {
44
45 public static final int HEAD = 0xcafebabe;
46
47
48
49
50 public static final byte CONSTANT_UTF8 = 1;
51
52
53 public static final byte CONSTANT_INTEGER = 3;
54
55
56 public static final byte CONSTANT_FLOAT = 4;
57
58
59 public static final byte CONSTANT_LONG = 5;
60
61
62 public static final byte CONSTANT_DOUBLE = 6;
63
64
65 public static final byte CONSTANT_CLASS = 7;
66
67
68 public static final byte CONSTANT_STRING = 8;
69
70
71 public static final byte CONSTANT_FIELDREF = 9;
72
73
74 public static final byte CONSTANT_METHODREF = 10;
75
76
77 public static final byte CONSTANT_INTERFACEMETHODREF = 11;
78
79
80 public static final byte CONSTANT_NAME_AND_TYPE = 12;
81
82
83 public static final byte CONSTANT_METHODHANDLE = 15;
84
85
86 public static final byte CONSTANT_METHOD_TYPE = 16;
87
88
89 public static final byte CONSTANT_INVOKE_DYNAMIC = 18;
90
91
92 public static final byte CONSTANT_MODULE = 19;
93
94
95 public static final byte CONSTANT_PACKAGE = 20;
96
97 private static final int OXF0 = 0xf0;
98
99 private static final int OXE0 = 0xe0;
100
101 private static final int OX3F = 0x3F;
102
103 static Set<String> getConstantPoolClassReferences(byte[] b) {
104 return parseConstantPoolClassReferences(ByteBuffer.wrap(b));
105 }
106
107 static Set<String> parseConstantPoolClassReferences(ByteBuffer buf) {
108 if (buf.order(ByteOrder.BIG_ENDIAN).getInt() != HEAD) {
109 return Collections.emptySet();
110 }
111 buf.getChar();
112 buf.getChar();
113 Set<Integer> classReferences = new HashSet<>();
114 Set<Integer> typeReferences = new HashSet<>();
115 Map<Integer, String> stringConstants = new HashMap<>();
116 for (int ix = 1, num = buf.getChar(); ix < num; ix++) {
117 byte tag = buf.get();
118 switch (tag) {
119 default:
120 throw new RuntimeException("Unknown constant pool type '" + tag + "'");
121 case CONSTANT_UTF8:
122 stringConstants.put(ix, decodeString(buf));
123 break;
124 case CONSTANT_CLASS:
125 classReferences.add((int) buf.getChar());
126 break;
127 case CONSTANT_METHOD_TYPE:
128 consumeMethodType(buf);
129 break;
130 case CONSTANT_FIELDREF:
131 case CONSTANT_METHODREF:
132 case CONSTANT_INTERFACEMETHODREF:
133 consumeReference(buf);
134 break;
135 case CONSTANT_NAME_AND_TYPE:
136 buf.getChar();
137 typeReferences.add((int) buf.getChar());
138 break;
139 case CONSTANT_INTEGER:
140 consumeInt(buf);
141 break;
142 case CONSTANT_FLOAT:
143 consumeFloat(buf);
144 break;
145 case CONSTANT_DOUBLE:
146 consumeDouble(buf);
147 ix++;
148 break;
149 case CONSTANT_LONG:
150 consumeLong(buf);
151 ix++;
152 break;
153 case CONSTANT_STRING:
154 consumeString(buf);
155 break;
156 case CONSTANT_METHODHANDLE:
157 consumeMethodHandle(buf);
158 break;
159 case CONSTANT_INVOKE_DYNAMIC:
160 consumeInvokeDynamic(buf);
161 break;
162 case CONSTANT_MODULE:
163 consumeModule(buf);
164 break;
165 case CONSTANT_PACKAGE:
166 consumePackage(buf);
167 break;
168 }
169 }
170
171 Set<String> result = new HashSet<>();
172
173 for (Integer classRef : classReferences) {
174 addClassToResult(result, stringConstants.get(classRef));
175 }
176
177 for (Integer typeRef : typeReferences) {
178 String typeName = stringConstants.get(typeRef);
179
180 if (Type.getType(typeName).getSort() == Type.METHOD) {
181 addClassToResult(result, Type.getReturnType(typeName).getInternalName());
182 Type[] argumentTypes = Type.getArgumentTypes(typeName);
183 for (Type argumentType : argumentTypes) {
184 addClassToResult(result, argumentType.getInternalName());
185 }
186 }
187 }
188
189 return result;
190 }
191
192 private static void addClassToResult(Set<String> result, String className) {
193
194 if (isImportableClass(className)) {
195 result.add(className);
196 }
197 }
198
199 private static String decodeString(ByteBuffer buf) {
200 int size = buf.getChar();
201
202 @SuppressWarnings("RedundantCast")
203 int oldLimit = ((Buffer) buf).limit();
204 ((Buffer) buf).limit(buf.position() + size);
205 StringBuilder sb = new StringBuilder(size + (size >> 1) + 16);
206 while (buf.hasRemaining()) {
207 byte b = buf.get();
208 if (b > 0) {
209 sb.append((char) b);
210 } else {
211 int b2 = buf.get();
212 if ((b & OXF0) != OXE0) {
213 sb.append((char) ((b & 0x1F) << 6 | b2 & OX3F));
214 } else {
215 int b3 = buf.get();
216 sb.append((char) ((b & 0x0F) << 12 | (b2 & OX3F) << 6 | b3 & OX3F));
217 }
218 }
219 }
220 ((Buffer) buf).limit(oldLimit);
221 return sb.toString();
222 }
223
224 private static boolean isImportableClass(String className) {
225
226 return className.indexOf('/') != -1;
227 }
228
229 private static void consumeMethodType(ByteBuffer buf) {
230 buf.getChar();
231 }
232
233 private static void consumeReference(ByteBuffer buf) {
234 buf.getChar();
235 buf.getChar();
236 }
237
238 private static void consumeInt(ByteBuffer buf) {
239 buf.getInt();
240 }
241
242 private static void consumeFloat(ByteBuffer buf) {
243 buf.getFloat();
244 }
245
246 private static void consumeDouble(ByteBuffer buf) {
247 buf.getDouble();
248 }
249
250 private static void consumeLong(ByteBuffer buf) {
251 buf.getLong();
252 }
253
254 private static void consumeString(ByteBuffer buf) {
255 buf.getChar();
256 }
257
258 private static void consumeMethodHandle(ByteBuffer buf) {
259 buf.get();
260 buf.getChar();
261 }
262
263 private static void consumeInvokeDynamic(ByteBuffer buf) {
264 buf.getChar();
265 buf.getChar();
266 }
267
268 private static void consumeModule(ByteBuffer buf) {
269 buf.getChar();
270 }
271
272 private static void consumePackage(ByteBuffer buf) {
273 buf.getChar();
274 }
275 }