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