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