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) throws UnknownConstantPoolTypeException {
108 return parseConstantPoolClassReferences(ByteBuffer.wrap(b));
109 }
110
111 private static Set<String> parseConstantPoolClassReferences(ByteBuffer buf)
112 throws UnknownConstantPoolTypeException {
113 if (buf.order(ByteOrder.BIG_ENDIAN).getInt() != HEAD) {
114 return Collections.emptySet();
115 }
116 buf.getChar();
117 buf.getChar();
118 Set<Integer> classReferences = new HashSet<>();
119 Set<Integer> typeReferences = new HashSet<>();
120 Map<Integer, String> stringConstants = new HashMap<>();
121 for (int ix = 1, num = buf.getChar(); ix < num; ix++) {
122 byte tag = buf.get();
123 switch (tag) {
124 case CONSTANT_UTF8:
125 stringConstants.put(ix, decodeString(buf));
126 break;
127 case CONSTANT_CLASS:
128 classReferences.add((int) buf.getChar());
129 break;
130 case CONSTANT_METHOD_TYPE:
131 consumeMethodType(buf);
132 break;
133 case CONSTANT_FIELDREF:
134 case CONSTANT_METHODREF:
135 case CONSTANT_INTERFACEMETHODREF:
136 consumeReference(buf);
137 break;
138 case CONSTANT_NAME_AND_TYPE:
139 buf.getChar();
140 typeReferences.add((int) buf.getChar());
141 break;
142 case CONSTANT_INTEGER:
143 consumeInt(buf);
144 break;
145 case CONSTANT_FLOAT:
146 consumeFloat(buf);
147 break;
148 case CONSTANT_DOUBLE:
149 consumeDouble(buf);
150 ix++;
151 break;
152 case CONSTANT_LONG:
153 consumeLong(buf);
154 ix++;
155 break;
156 case CONSTANT_STRING:
157 consumeString(buf);
158 break;
159 case CONSTANT_METHODHANDLE:
160 consumeMethodHandle(buf);
161 break;
162 case CONSTANT_INVOKE:
163 consumeDynamic(buf);
164 break;
165 case CONSTANT_INVOKE_DYNAMIC:
166 consumeInvokeDynamic(buf);
167 break;
168 case CONSTANT_MODULE:
169 consumeModule(buf);
170 break;
171 case CONSTANT_PACKAGE:
172 consumePackage(buf);
173 break;
174 default:
175 throw new UnknownConstantPoolTypeException("Unknown constant pool type '" + tag + "'");
176 }
177 }
178
179 Set<String> result = new HashSet<>();
180
181 for (Integer classRef : classReferences) {
182 addClassToResult(result, stringConstants.get(classRef));
183 }
184
185 for (Integer typeRef : typeReferences) {
186 String typeName = stringConstants.get(typeRef);
187
188 if (Type.getType(typeName).getSort() == Type.METHOD) {
189 addClassToResult(result, Type.getReturnType(typeName).getInternalName());
190 Type[] argumentTypes = Type.getArgumentTypes(typeName);
191 for (Type argumentType : argumentTypes) {
192 addClassToResult(result, argumentType.getInternalName());
193 }
194 }
195 }
196
197 return result;
198 }
199
200 private static void addClassToResult(Set<String> result, String className) {
201
202 if (isImportableClass(className)) {
203 result.add(className);
204 }
205 }
206
207 @SuppressWarnings("RedundantCast")
208 private static String decodeString(ByteBuffer buf) {
209 int size = buf.getChar();
210 int oldLimit = buf.limit();
211
212 ((Buffer) buf).limit(buf.position() + size);
213 StringBuilder sb = new StringBuilder(size + (size >> 1) + 16);
214 while (buf.hasRemaining()) {
215 byte b = buf.get();
216 if (b > 0) {
217 sb.append((char) b);
218 } else {
219 int b2 = buf.get();
220 if ((b & OXF0) != OXE0) {
221 sb.append((char) ((b & 0x1F) << 6 | b2 & OX3F));
222 } else {
223 int b3 = buf.get();
224 sb.append((char) ((b & 0x0F) << 12 | (b2 & OX3F) << 6 | b3 & OX3F));
225 }
226 }
227 }
228 ((Buffer) buf).limit(oldLimit);
229 return sb.toString();
230 }
231
232 private static boolean isImportableClass(String className) {
233
234 return className.indexOf('/') != -1;
235 }
236
237 private static void consumeMethodType(ByteBuffer buf) {
238 buf.getChar();
239 }
240
241 private static void consumeReference(ByteBuffer buf) {
242 buf.getChar();
243 buf.getChar();
244 }
245
246 private static void consumeInt(ByteBuffer buf) {
247 buf.getInt();
248 }
249
250 private static void consumeFloat(ByteBuffer buf) {
251 buf.getFloat();
252 }
253
254 private static void consumeDouble(ByteBuffer buf) {
255 buf.getDouble();
256 }
257
258 private static void consumeLong(ByteBuffer buf) {
259 buf.getLong();
260 }
261
262 private static void consumeString(ByteBuffer buf) {
263 buf.getChar();
264 }
265
266 private static void consumeMethodHandle(ByteBuffer buf) {
267 buf.get();
268 buf.getChar();
269 }
270
271 private static void consumeDynamic(ByteBuffer buf) {
272 buf.getChar();
273 buf.getChar();
274 }
275
276 private static void consumeInvokeDynamic(ByteBuffer buf) {
277 buf.getChar();
278 buf.getChar();
279 }
280
281 private static void consumeModule(ByteBuffer buf) {
282 buf.getChar();
283 }
284
285 private static void consumePackage(ByteBuffer buf) {
286 buf.getChar();
287 }
288 }