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