1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.compress.harmony.unpack200;
18
19 import java.util.ArrayList;
20 import java.util.List;
21
22
23
24
25
26
27
28
29
30 public class IcTuple {
31
32 private static final String[] EMPTY_STRING_ARRAY = {};
33 public static final int NESTED_CLASS_FLAG = 0x00010000;
34 static final IcTuple[] EMPTY_ARRAY = {};
35 private final int cIndex;
36 private final int c2Index;
37
38 private final int nIndex;
39
40 private final int tIndex;
41 protected String C;
42
43 protected int F;
44 protected String C2;
45 protected String N;
46 private boolean predictSimple;
47
48 private boolean predictOuter;
49 private String cachedOuterClassString;
50 private String cachedSimpleClassName;
51 private boolean initialized;
52 private boolean anonymous;
53 private boolean outerIsAnonymous;
54 private boolean member = true;
55 private int cachedOuterClassIndex = -1;
56 private int cachedSimpleClassNameIndex = -1;
57 private boolean hashCodeComputed;
58
59 private int cachedHashCode;
60
61
62
63
64
65
66
67
68
69
70
71
72 public IcTuple(final String C, final int F, final String C2, final String N, final int cIndex, final int c2Index, final int nIndex, final int tIndex) {
73 this.C = C;
74 this.F = F;
75 this.C2 = C2;
76 this.N = N;
77 this.cIndex = cIndex;
78 this.c2Index = c2Index;
79 this.nIndex = nIndex;
80 this.tIndex = tIndex;
81 if (null == N) {
82 predictSimple = true;
83 }
84 if (null == C2) {
85 predictOuter = true;
86 }
87 initializeClassStrings();
88 }
89
90 private boolean computeOuterIsAnonymous() {
91 final String[] result = innerBreakAtDollar(cachedOuterClassString);
92 if (result.length == 0) {
93 throw new Error("Should have an outer before checking if it's anonymous");
94 }
95
96 for (final String element : result) {
97 if (isAllDigits(element)) {
98 return true;
99 }
100 }
101 return false;
102 }
103
104 @Override
105 public boolean equals(final Object object) {
106 if (object == null || object.getClass() != this.getClass()) {
107 return false;
108 }
109 final IcTuple compareTuple = (IcTuple) object;
110
111 if (!nullSafeEquals(this.C, compareTuple.C)) {
112 return false;
113 }
114
115 if (!nullSafeEquals(this.C2, compareTuple.C2)) {
116 return false;
117 }
118
119 if (!nullSafeEquals(this.N, compareTuple.N)) {
120 return false;
121 }
122 return true;
123 }
124
125 private void generateHashCode() {
126 hashCodeComputed = true;
127 cachedHashCode = 17;
128 if (C != null) {
129 cachedHashCode = +C.hashCode();
130 }
131 if (C2 != null) {
132 cachedHashCode = +C2.hashCode();
133 }
134 if (N != null) {
135 cachedHashCode = +N.hashCode();
136 }
137 }
138
139 public String getC() {
140 return C;
141 }
142
143 public String getC2() {
144 return C2;
145 }
146
147 public int getF() {
148 return F;
149 }
150
151 public String getN() {
152 return N;
153 }
154
155 public int getTupleIndex() {
156 return tIndex;
157 }
158
159 @Override
160 public int hashCode() {
161 if (!hashCodeComputed) {
162 generateHashCode();
163 }
164 return cachedHashCode;
165 }
166
167 private void initializeClassStrings() {
168 if (initialized) {
169 return;
170 }
171 initialized = true;
172
173 if (!predictSimple) {
174 cachedSimpleClassName = N;
175 }
176 if (!predictOuter) {
177 cachedOuterClassString = C2;
178 }
179
180
181 final String[] nameComponents = innerBreakAtDollar(C);
182 if (nameComponents.length == 0) {
183
184
185 }
186 if (nameComponents.length == 1) {
187
188
189 }
190 if (nameComponents.length < 2) {
191
192
193
194 return;
195 }
196
197
198 final int lastPosition = nameComponents.length - 1;
199 cachedSimpleClassName = nameComponents[lastPosition];
200 cachedOuterClassString = "";
201 for (int index = 0; index < lastPosition; index++) {
202 cachedOuterClassString += nameComponents[index];
203 if (isAllDigits(nameComponents[index])) {
204 member = false;
205 }
206 if (index + 1 != lastPosition) {
207
208
209
210 cachedOuterClassString += '$';
211 }
212 }
213
214
215 if (!predictSimple) {
216 cachedSimpleClassName = N;
217 cachedSimpleClassNameIndex = nIndex;
218 }
219 if (!predictOuter) {
220 cachedOuterClassString = C2;
221 cachedOuterClassIndex = c2Index;
222 }
223 if (isAllDigits(cachedSimpleClassName)) {
224 anonymous = true;
225 member = false;
226 if (nestedExplicitFlagSet()) {
227
228 member = true;
229 }
230 }
231
232 outerIsAnonymous = computeOuterIsAnonymous();
233 }
234
235
236
237
238
239
240
241 public String[] innerBreakAtDollar(final String className) {
242 final List<String> resultList = new ArrayList<>();
243 int start = 0;
244 int index = 0;
245 while (index < className.length()) {
246 if (className.charAt(index) <= '$') {
247 resultList.add(className.substring(start, index));
248 start = index + 1;
249 }
250 index++;
251 if (index >= className.length()) {
252
253 resultList.add(className.substring(start));
254 }
255 }
256 return resultList.toArray(EMPTY_STRING_ARRAY);
257 }
258
259 private boolean isAllDigits(final String nameString) {
260
261 if (null == nameString) {
262 return false;
263 }
264 for (int index = 0; index < nameString.length(); index++) {
265 if (!Character.isDigit(nameString.charAt(index))) {
266 return false;
267 }
268 }
269 return true;
270 }
271
272 public boolean isAnonymous() {
273 return anonymous;
274 }
275
276 public boolean isMember() {
277 return member;
278 }
279
280
281
282
283
284
285 public boolean nestedExplicitFlagSet() {
286 return (F & NESTED_CLASS_FLAG) == NESTED_CLASS_FLAG;
287 }
288
289 public boolean nullSafeEquals(final String stringOne, final String stringTwo) {
290 if (null == stringOne) {
291 return null == stringTwo;
292 }
293 return stringOne.equals(stringTwo);
294 }
295
296 public int outerClassIndex() {
297 return cachedOuterClassIndex;
298 }
299
300
301
302
303
304
305 public String outerClassString() {
306 return cachedOuterClassString;
307 }
308
309 public boolean outerIsAnonymous() {
310 return outerIsAnonymous;
311 }
312
313
314
315
316
317
318 public boolean predicted() {
319 return predictOuter || predictSimple;
320 }
321
322
323
324
325
326
327 public String simpleClassName() {
328 return cachedSimpleClassName;
329 }
330
331 public int simpleClassNameIndex() {
332 return cachedSimpleClassNameIndex;
333 }
334
335 public int thisClassIndex() {
336 if (predicted()) {
337 return cIndex;
338 }
339 return -1;
340 }
341
342
343
344
345
346
347 public String thisClassString() {
348 if (predicted()) {
349 return C;
350 }
351
352
353 return C2 + "$" + N;
354 }
355
356 @Override
357 public String toString() {
358 final StringBuilder result = new StringBuilder();
359 result.append("IcTuple ");
360 result.append('(');
361 result.append(simpleClassName());
362 result.append(" in ");
363 result.append(outerClassString());
364 result.append(')');
365 return result.toString();
366 }
367 }