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