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.bytecode;
20
21 import java.io.DataOutputStream;
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.List;
25
26
27
28
29 public class NewAttribute extends BCIRenumberedAttribute {
30
31
32 private abstract static class AbstractBcValue {
33
34 int actualValue;
35
36 public void setActualValue(final int value) {
37 this.actualValue = value;
38 }
39
40 }
41
42 private static final class BCIndex extends AbstractBcValue {
43
44 private final int index;
45
46 BCIndex(final int index) {
47 this.index = index;
48 }
49 }
50
51 private static final class BCLength extends AbstractBcValue {
52
53 private final int length;
54
55 BCLength(final int length) {
56 this.length = length;
57 }
58 }
59
60 private static final class BCOffset extends AbstractBcValue {
61
62 private final int offset;
63 private int index;
64
65 BCOffset(final int offset) {
66 this.offset = offset;
67 }
68
69 public void setIndex(final int index) {
70 this.index = index;
71 }
72
73 }
74
75 private final List<Integer> lengths = new ArrayList<>();
76
77 private final List<Object> body = new ArrayList<>();
78
79 private ClassConstantPool pool;
80
81 private final int layoutIndex;
82
83 public NewAttribute(final CPUTF8 attributeName, final int layoutIndex) {
84 super(attributeName);
85 this.layoutIndex = layoutIndex;
86 }
87
88 public void addBCIndex(final int length, final int value) {
89 lengths.add(Integer.valueOf(length));
90 body.add(new BCIndex(value));
91 }
92
93 public void addBCLength(final int length, final int value) {
94 lengths.add(Integer.valueOf(length));
95 body.add(new BCLength(value));
96 }
97
98 public void addBCOffset(final int length, final int value) {
99 lengths.add(Integer.valueOf(length));
100 body.add(new BCOffset(value));
101 }
102
103 public void addInteger(final int length, final long value) {
104 lengths.add(Integer.valueOf(length));
105 body.add(Long.valueOf(value));
106 }
107
108 public void addToBody(final int length, final Object value) {
109 lengths.add(Integer.valueOf(length));
110 body.add(value);
111 }
112
113 public int getLayoutIndex() {
114 return layoutIndex;
115 }
116
117
118
119
120
121
122 @Override
123 protected int getLength() {
124 int length = 0;
125 for (final Integer len : lengths) {
126 length += len.intValue();
127 }
128 return length;
129 }
130
131 @Override
132 protected ClassFileEntry[] getNestedClassFileEntries() {
133 int total = 1;
134 for (final Object element : body) {
135 if (element instanceof ClassFileEntry) {
136 total++;
137 }
138 }
139 final ClassFileEntry[] nested = new ClassFileEntry[total];
140 nested[0] = getAttributeName();
141 int i = 1;
142 for (final Object element : body) {
143 if (element instanceof ClassFileEntry) {
144 nested[i] = (ClassFileEntry) element;
145 i++;
146 }
147 }
148 return nested;
149 }
150
151 @Override
152 protected int[] getStartPCs() {
153
154 return null;
155 }
156
157 @Override
158 public void renumber(final List<Integer> byteCodeOffsets) {
159 if (!renumbered) {
160 Object previous = null;
161 for (final Object obj : body) {
162 if (obj instanceof BCIndex) {
163 final BCIndex bcIndex = (BCIndex) obj;
164 bcIndex.setActualValue(byteCodeOffsets.get(bcIndex.index).intValue());
165 } else if (obj instanceof BCOffset) {
166 final BCOffset bcOffset = (BCOffset) obj;
167 if (previous instanceof BCIndex) {
168 final int index = ((BCIndex) previous).index + bcOffset.offset;
169 bcOffset.setIndex(index);
170 bcOffset.setActualValue(byteCodeOffsets.get(index).intValue());
171 } else if (previous instanceof BCOffset) {
172 final int index = ((BCOffset) previous).index + bcOffset.offset;
173 bcOffset.setIndex(index);
174 bcOffset.setActualValue(byteCodeOffsets.get(index).intValue());
175 } else {
176
177 bcOffset.setActualValue(byteCodeOffsets.get(bcOffset.offset).intValue());
178 }
179 } else if (obj instanceof BCLength) {
180
181 final BCLength bcLength = (BCLength) obj;
182 final BCIndex prevIndex = (BCIndex) previous;
183 final int index = prevIndex.index + bcLength.length;
184 final int actualLength = byteCodeOffsets.get(index).intValue() - prevIndex.actualValue;
185 bcLength.setActualValue(actualLength);
186 }
187 previous = obj;
188 }
189 renumbered = true;
190 }
191 }
192
193 @Override
194 protected void resolve(final ClassConstantPool pool) {
195 super.resolve(pool);
196 for (final Object element : body) {
197 if (element instanceof ClassFileEntry) {
198 ((ClassFileEntry) element).resolve(pool);
199 }
200 }
201 this.pool = pool;
202 }
203
204
205
206
207
208
209 @Override
210 public String toString() {
211 return attributeName.underlyingString();
212 }
213
214
215
216
217
218
219 @Override
220 protected void writeBody(final DataOutputStream dos) throws IOException {
221 for (int i = 0; i < lengths.size(); i++) {
222 final int length = lengths.get(i).intValue();
223 final Object obj = body.get(i);
224 long value = 0;
225 if (obj instanceof Long) {
226 value = ((Long) obj).longValue();
227 } else if (obj instanceof ClassFileEntry) {
228 value = pool.indexOf((ClassFileEntry) obj);
229 } else if (obj instanceof AbstractBcValue) {
230 value = ((AbstractBcValue) obj).actualValue;
231 }
232
233 switch (length) {
234 case 1:
235 dos.writeByte((int) value);
236 break;
237 case 2:
238 dos.writeShort((int) value);
239 break;
240 case 4:
241 dos.writeInt((int) value);
242 break;
243 case 8:
244 dos.writeLong(value);
245 break;
246 default:
247 break;
248 }
249 }
250 }
251
252 }