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