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.io.IOException;
22 import java.io.InputStream;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29
30 import org.apache.commons.compress.harmony.pack200.Codec;
31 import org.apache.commons.compress.harmony.pack200.Pack200Exception;
32 import org.apache.commons.compress.harmony.unpack200.bytecode.CPClass;
33 import org.apache.commons.compress.harmony.unpack200.bytecode.ClassConstantPool;
34 import org.apache.commons.compress.harmony.unpack200.bytecode.ClassFileEntry;
35 import org.apache.commons.compress.harmony.unpack200.bytecode.ConstantPoolEntry;
36
37
38
39
40 public class IcBands extends BandSet {
41
42 private IcTuple[] icAll;
43
44 private final String[] cpUTF8;
45
46 private final String[] cpClass;
47
48 private Map<String, IcTuple> thisClassToTuple;
49 private Map<String, List<IcTuple>> outerClassToTuples;
50
51
52
53
54 public IcBands(final Segment segment) {
55 super(segment);
56 this.cpClass = segment.getCpBands().getCpClass();
57 this.cpUTF8 = segment.getCpBands().getCpUTF8();
58 }
59
60 public IcTuple[] getIcTuples() {
61 return icAll;
62 }
63
64
65
66
67
68
69
70
71 public IcTuple[] getRelevantIcTuples(final String className, final ClassConstantPool cp) {
72 final Set<IcTuple> relevantTuplesContains = new HashSet<>();
73 final List<IcTuple> relevantTuples = new ArrayList<>();
74
75 final List<IcTuple> relevantCandidates = outerClassToTuples.get(className);
76 if (relevantCandidates != null) {
77 for (int index = 0; index < relevantCandidates.size(); index++) {
78 final IcTuple tuple = relevantCandidates.get(index);
79 relevantTuplesContains.add(tuple);
80 relevantTuples.add(tuple);
81 }
82 }
83
84 final List<ClassFileEntry> entries = cp.entries();
85
86
87
88
89
90 for (int eIndex = 0; eIndex < entries.size(); eIndex++) {
91 final ConstantPoolEntry entry = (ConstantPoolEntry) entries.get(eIndex);
92 if (entry instanceof CPClass) {
93 final CPClass clazz = (CPClass) entry;
94 final IcTuple relevant = thisClassToTuple.get(clazz.name);
95 if (relevant != null && relevantTuplesContains.add(relevant)) {
96 relevantTuples.add(relevant);
97 }
98 }
99 }
100
101
102
103
104
105
106
107 final List<IcTuple> tuplesToScan = new ArrayList<>(relevantTuples);
108 final List<IcTuple> tuplesToAdd = new ArrayList<>();
109
110 while (tuplesToScan.size() > 0) {
111
112 tuplesToAdd.clear();
113 for (int index = 0; index < tuplesToScan.size(); index++) {
114 final IcTuple aRelevantTuple = tuplesToScan.get(index);
115 final IcTuple relevant = thisClassToTuple.get(aRelevantTuple.outerClassString());
116 if (relevant != null && !aRelevantTuple.outerIsAnonymous()) {
117 tuplesToAdd.add(relevant);
118 }
119 }
120
121 tuplesToScan.clear();
122 for (int index = 0; index < tuplesToAdd.size(); index++) {
123 final IcTuple tuple = tuplesToAdd.get(index);
124 if (relevantTuplesContains.add(tuple)) {
125 relevantTuples.add(tuple);
126 tuplesToScan.add(tuple);
127 }
128 }
129
130 }
131
132
133
134
135 relevantTuples.sort((arg0, arg1) -> {
136 final int index1 = arg0.getTupleIndex();
137 final Integer index2 = Integer.valueOf(arg1.getTupleIndex());
138 return Integer.compare(index1, index2);
139 });
140
141 return relevantTuples.toArray(IcTuple.EMPTY_ARRAY);
142 }
143
144
145
146
147
148
149 @Override
150 public void read(final InputStream in) throws IOException, Pack200Exception {
151
152 final int innerClassCount = header.getInnerClassCount();
153 final int[] icThisClassInts = decodeBandInt("ic_this_class", in, Codec.UDELTA5, innerClassCount);
154 final String[] icThisClass = getReferences(icThisClassInts, cpClass);
155 final int[] icFlags = decodeBandInt("ic_flags", in, Codec.UNSIGNED5, innerClassCount);
156 final int outerClasses = SegmentUtils.countBit16(icFlags);
157 final int[] icOuterClassInts = decodeBandInt("ic_outer_class", in, Codec.DELTA5, outerClasses);
158 final String[] icOuterClass = new String[outerClasses];
159 for (int i = 0; i < icOuterClass.length; i++) {
160 if (icOuterClassInts[i] == 0) {
161 icOuterClass[i] = null;
162 } else {
163 icOuterClass[i] = cpClass[icOuterClassInts[i] - 1];
164 }
165 }
166 final int[] icNameInts = decodeBandInt("ic_name", in, Codec.DELTA5, outerClasses);
167 final String[] icName = new String[outerClasses];
168 for (int i = 0; i < icName.length; i++) {
169 if (icNameInts[i] == 0) {
170 icName[i] = null;
171 } else {
172 icName[i] = cpUTF8[icNameInts[i] - 1];
173 }
174 }
175
176
177 icAll = new IcTuple[icThisClass.length];
178 int index = 0;
179 for (int i = 0; i < icThisClass.length; i++) {
180 final String icTupleC = icThisClass[i];
181 final int icTupleF = icFlags[i];
182 String icTupleC2 = null;
183 String icTupleN = null;
184 final int cIndex = icThisClassInts[i];
185 int c2Index = -1;
186 int nIndex = -1;
187 if ((icFlags[i] & 1 << 16) != 0) {
188 icTupleC2 = icOuterClass[index];
189 icTupleN = icName[index];
190 c2Index = icOuterClassInts[index] - 1;
191 nIndex = icNameInts[index] - 1;
192 index++;
193 }
194 icAll[i] = new IcTuple(icTupleC, icTupleF, icTupleC2, icTupleN, cIndex, c2Index, nIndex, i);
195 }
196 }
197
198 @Override
199 public void unpack() throws IOException, Pack200Exception {
200 final IcTuple[] allTuples = getIcTuples();
201 thisClassToTuple = new HashMap<>(allTuples.length);
202 outerClassToTuples = new HashMap<>(allTuples.length);
203 for (final IcTuple tuple : allTuples) {
204
205
206
207
208 final Object result = thisClassToTuple.put(tuple.thisClassString(), tuple);
209 if (result != null) {
210 throw new Error("Collision detected in <thisClassString, IcTuple> mapping. There are at least two inner clases with the same name.");
211 }
212
213
214
215
216
217 if (!tuple.isAnonymous() && !tuple.outerIsAnonymous() || tuple.nestedExplicitFlagSet()) {
218
219
220 final String key = tuple.outerClassString();
221 outerClassToTuples.computeIfAbsent(key, k -> new ArrayList<>()).add(tuple);
222 }
223 }
224 }
225
226 }