1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.commons.compress.harmony.unpack200;
20
21 import java.util.List;
22
23 import org.apache.commons.compress.harmony.pack200.Pack200Exception;
24 import org.apache.commons.compress.harmony.unpack200.bytecode.ClassFileEntry;
25 import org.apache.commons.compress.harmony.unpack200.bytecode.ConstantPoolEntry;
26
27
28
29
30 public class SegmentConstantPool {
31
32
33
34
35 public static final int ALL = 0;
36
37
38
39
40 public static final int UTF_8 = 1;
41
42
43
44
45 public static final int CP_INT = 2;
46
47
48
49
50
51
52 public static final int CP_FLOAT = 3;
53
54
55
56
57 public static final int CP_LONG = 4;
58
59
60
61
62 public static final int CP_DOUBLE = 5;
63
64
65
66
67 public static final int CP_STRING = 6;
68
69
70
71
72 public static final int CP_CLASS = 7;
73
74
75
76
77 public static final int SIGNATURE = 8;
78
79
80
81
82 public static final int CP_DESCR = 9;
83
84
85
86
87 public static final int CP_FIELD = 10;
88
89
90
91
92 public static final int CP_METHOD = 11;
93
94
95
96
97 public static final int CP_IMETHOD = 12;
98
99
100
101
102 protected static final String REGEX_MATCH_ALL = ".*";
103
104
105
106
107 protected static final String INITSTRING = "<init>";
108
109
110
111
112 protected static final String REGEX_MATCH_INIT = "^" + INITSTRING + ".*";
113
114
115
116
117
118
119
120
121
122
123 protected static boolean regexMatches(final String regexString, final String compareString) {
124 if (REGEX_MATCH_ALL.equals(regexString)) {
125 return true;
126 }
127 if (REGEX_MATCH_INIT.equals(regexString)) {
128 if (compareString.length() < INITSTRING.length()) {
129 return false;
130 }
131 return INITSTRING.equals(compareString.substring(0, INITSTRING.length()));
132 }
133 throw new Error("regex trying to match a pattern I don't know: " + regexString);
134 }
135
136 static int toIndex(final long index) throws Pack200Exception {
137 if (index < 0) {
138 throw new Pack200Exception("Cannot have a negative index.");
139 }
140 return toIntExact(index);
141 }
142
143 static int toIntExact(final long index) throws Pack200Exception {
144 try {
145 return Math.toIntExact(index);
146 } catch (final ArithmeticException e) {
147 throw new Pack200Exception("index", e);
148 }
149 }
150
151 private final CpBands bands;
152
153 private final SegmentConstantPoolArrayCache arrayCache = new SegmentConstantPoolArrayCache();
154
155
156
157
158
159
160 public SegmentConstantPool(final CpBands bands) {
161 this.bands = bands;
162 }
163
164
165
166
167
168
169
170
171 public ConstantPoolEntry getClassPoolEntry(final String name) throws Pack200Exception {
172 final int index = matchSpecificPoolEntryIndex(bands.getCpClass(), name, 0);
173 return index == -1 ? null : getConstantPoolEntry(CP_CLASS, index);
174 }
175
176
177
178
179
180
181
182
183
184
185
186 public ConstantPoolEntry getClassSpecificPoolEntry(final int cp, final long desiredIndex, final String desiredClassName) throws Pack200Exception {
187 final String[] array;
188 switch (cp) {
189 case CP_FIELD:
190 array = bands.getCpFieldClass();
191 break;
192 case CP_METHOD:
193 array = bands.getCpMethodClass();
194 break;
195 case CP_IMETHOD:
196 array = bands.getCpIMethodClass();
197 break;
198 default:
199 throw new Pack200Exception("Type is not supported yet: " + cp);
200 }
201 return getConstantPoolEntry(cp, matchSpecificPoolEntryIndex(array, desiredClassName, toIndex(desiredIndex)));
202 }
203
204
205
206
207
208
209
210
211
212 public ConstantPoolEntry getConstantPoolEntry(final int type, final long index) throws Pack200Exception {
213 if (index == -1) {
214 return null;
215 }
216 final int actualIndex = toIndex(index);
217 switch (type) {
218 case UTF_8:
219 return bands.cpUTF8Value(actualIndex);
220 case CP_INT:
221 return bands.cpIntegerValue(actualIndex);
222 case CP_FLOAT:
223 return bands.cpFloatValue(actualIndex);
224 case CP_LONG:
225 return bands.cpLongValue(actualIndex);
226 case CP_DOUBLE:
227 return bands.cpDoubleValue(actualIndex);
228 case CP_STRING:
229 return bands.cpStringValue(actualIndex);
230 case CP_CLASS:
231 return bands.cpClassValue(actualIndex);
232 case SIGNATURE:
233 throw new Pack200Exception("Type SIGNATURE is not supported yet: " + SIGNATURE);
234
235 case CP_DESCR:
236 throw new Pack200Exception("Type CP_DESCR is not supported yet: " + CP_DESCR);
237
238
239 case CP_FIELD:
240 return bands.cpFieldValue(actualIndex);
241 case CP_METHOD:
242 return bands.cpMethodValue(actualIndex);
243 case CP_IMETHOD:
244 return bands.cpIMethodValue(actualIndex);
245 default:
246 break;
247 }
248
249 throw new Pack200Exception("Type is not supported yet: " + type);
250 }
251
252
253
254
255
256
257
258
259
260
261 public ConstantPoolEntry getInitMethodPoolEntry(final int cp, final long value, final String desiredClassName) throws Pack200Exception {
262 if (cp != CP_METHOD) {
263 throw new Pack200Exception("Nothing but CP_METHOD can be an <init>");
264 }
265 final int realIndex = matchSpecificPoolEntryIndex(bands.getCpMethodClass(), bands.getCpMethodDescriptor(), desiredClassName, REGEX_MATCH_INIT,
266 toIndex(value));
267 return getConstantPoolEntry(cp, realIndex);
268 }
269
270 public ClassFileEntry getValue(final int cp, final long longIndex) throws Pack200Exception {
271 final int index = (int) longIndex;
272 if (index == -1) {
273 return null;
274 }
275 if (index < 0) {
276 throw new Pack200Exception("Cannot have a negative range");
277 }
278 switch (cp) {
279 case UTF_8:
280 return bands.cpUTF8Value(index);
281 case CP_INT:
282 return bands.cpIntegerValue(index);
283 case CP_FLOAT:
284 return bands.cpFloatValue(index);
285 case CP_LONG:
286 return bands.cpLongValue(index);
287 case CP_DOUBLE:
288 return bands.cpDoubleValue(index);
289 case CP_STRING:
290 return bands.cpStringValue(index);
291 case CP_CLASS:
292 return bands.cpClassValue(index);
293 case SIGNATURE:
294 return bands.cpSignatureValue(index);
295 case CP_DESCR:
296 return bands.cpNameAndTypeValue(index);
297 default:
298 break;
299 }
300 throw new Error("Tried to get a value I don't know about: " + cp);
301 }
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322 protected int matchSpecificPoolEntryIndex(final String[] nameArray, final String compareString, final int desiredIndex) {
323 return matchSpecificPoolEntryIndex(nameArray, nameArray, compareString, REGEX_MATCH_ALL, desiredIndex);
324 }
325
326
327
328
329
330
331
332
333
334
335
336
337
338 protected int matchSpecificPoolEntryIndex(final String[] primaryArray, final String[] secondaryArray, final String primaryCompareString,
339 final String secondaryCompareRegex, final int desiredIndex) {
340 int instanceCount = -1;
341 final List<Integer> indexList = arrayCache.indexesForArrayKey(primaryArray, primaryCompareString);
342 if (indexList.isEmpty()) {
343
344 return -1;
345 }
346
347 for (final Integer element : indexList) {
348 final int arrayIndex = element.intValue();
349 if (regexMatches(secondaryCompareRegex, secondaryArray[arrayIndex])) {
350 instanceCount++;
351 if (instanceCount == desiredIndex) {
352 return arrayIndex;
353 }
354 }
355 }
356
357
358 return -1;
359 }
360 }