1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.compress.harmony.pack200;
18
19 import java.io.IOException;
20 import java.io.OutputStream;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26
27 import org.objectweb.asm.Attribute;
28
29
30
31
32 public class AttributeDefinitionBands extends BandSet {
33
34 public static class AttributeDefinition {
35
36 public int index;
37 public int contextType;
38 public CPUTF8 name;
39 public CPUTF8 layout;
40
41 public AttributeDefinition(final int index, final int contextType, final CPUTF8 name, final CPUTF8 layout) {
42 this.index = index;
43 this.contextType = contextType;
44 this.name = name;
45 this.layout = layout;
46 }
47
48 }
49
50
51
52
53 public static final int CONTEXT_CLASS = 0;
54
55
56
57
58 public static final int CONTEXT_CODE = 3;
59
60
61
62
63 public static final int CONTEXT_FIELD = 1;
64
65
66
67
68 public static final int CONTEXT_METHOD = 2;
69
70 private final List<AttributeDefinition> classAttributeLayouts = new ArrayList<>();
71 private final List<AttributeDefinition> methodAttributeLayouts = new ArrayList<>();
72 private final List<AttributeDefinition> fieldAttributeLayouts = new ArrayList<>();
73
74 private final List<AttributeDefinition> codeAttributeLayouts = new ArrayList<>();
75
76 private final List<AttributeDefinition> attributeDefinitions = new ArrayList<>();
77 private final CpBands cpBands;
78
79 private final Segment segment;
80
81 public AttributeDefinitionBands(final Segment segment, final int effort, final Attribute[] attributePrototypes) {
82 super(effort, segment.getSegmentHeader());
83 this.cpBands = segment.getCpBands();
84 this.segment = segment;
85 final Map<String, String> classLayouts = new HashMap<>();
86 final Map<String, String> methodLayouts = new HashMap<>();
87 final Map<String, String> fieldLayouts = new HashMap<>();
88 final Map<String, String> codeLayouts = new HashMap<>();
89
90 for (final Attribute attributePrototype : attributePrototypes) {
91 final NewAttribute newAttribute = (NewAttribute) attributePrototype;
92 if (!(newAttribute instanceof NewAttribute.ErrorAttribute) && !(newAttribute instanceof NewAttribute.PassAttribute)
93 && !(newAttribute instanceof NewAttribute.StripAttribute)) {
94 if (newAttribute.isContextClass()) {
95 classLayouts.put(newAttribute.type, newAttribute.getLayout());
96 }
97 if (newAttribute.isContextMethod()) {
98 methodLayouts.put(newAttribute.type, newAttribute.getLayout());
99 }
100 if (newAttribute.isContextField()) {
101 fieldLayouts.put(newAttribute.type, newAttribute.getLayout());
102 }
103 if (newAttribute.isContextCode()) {
104 codeLayouts.put(newAttribute.type, newAttribute.getLayout());
105 }
106 }
107 }
108 if (classLayouts.size() > 7) {
109 segmentHeader.setHave_class_flags_hi(true);
110 }
111 if (methodLayouts.size() > 6) {
112 segmentHeader.setHave_method_flags_hi(true);
113 }
114 if (fieldLayouts.size() > 10) {
115 segmentHeader.setHave_field_flags_hi(true);
116 }
117 if (codeLayouts.size() > 15) {
118 segmentHeader.setHave_code_flags_hi(true);
119 }
120 int[] availableClassIndices = { 25, 26, 27, 28, 29, 30, 31 };
121 if (classLayouts.size() > 7) {
122 availableClassIndices = addHighIndices(availableClassIndices);
123 }
124 addAttributeDefinitions(classLayouts, availableClassIndices, CONTEXT_CLASS);
125 int[] availableMethodIndices = { 26, 27, 28, 29, 30, 31 };
126 if (methodAttributeLayouts.size() > 6) {
127 availableMethodIndices = addHighIndices(availableMethodIndices);
128 }
129 addAttributeDefinitions(methodLayouts, availableMethodIndices, CONTEXT_METHOD);
130 int[] availableFieldIndices = { 18, 23, 24, 25, 26, 27, 28, 29, 30, 31 };
131 if (fieldAttributeLayouts.size() > 10) {
132 availableFieldIndices = addHighIndices(availableFieldIndices);
133 }
134 addAttributeDefinitions(fieldLayouts, availableFieldIndices, CONTEXT_FIELD);
135 int[] availableCodeIndices = { 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 };
136 if (codeAttributeLayouts.size() > 15) {
137 availableCodeIndices = addHighIndices(availableCodeIndices);
138 }
139 addAttributeDefinitions(codeLayouts, availableCodeIndices, CONTEXT_CODE);
140 }
141
142 private void addAttributeDefinitions(final Map<String, String> layoutMap, final int[] availableIndices, final int contextType) {
143 final int i = 0;
144 layoutMap.forEach((name, layout) -> {
145 final int index = availableIndices[i];
146 final AttributeDefinition definition = new AttributeDefinition(index, contextType, cpBands.getCPUtf8(name), cpBands.getCPUtf8(layout));
147 attributeDefinitions.add(definition);
148 switch (contextType) {
149 case CONTEXT_CLASS:
150 classAttributeLayouts.add(definition);
151 break;
152 case CONTEXT_METHOD:
153 methodAttributeLayouts.add(definition);
154 break;
155 case CONTEXT_FIELD:
156 fieldAttributeLayouts.add(definition);
157 break;
158 case CONTEXT_CODE:
159 codeAttributeLayouts.add(definition);
160 }
161 });
162 }
163
164 private int[] addHighIndices(final int[] availableIndices) {
165 final int[] temp = Arrays.copyOf(availableIndices, availableIndices.length + 32);
166 int j = 32;
167 for (int i = availableIndices.length; i < temp.length; i++) {
168 temp[i] = j;
169 j++;
170 }
171 return temp;
172 }
173
174 private void addSyntheticDefinitions() {
175 final boolean anySytheticClasses = segment.getClassBands().isAnySyntheticClasses();
176 final boolean anySyntheticMethods = segment.getClassBands().isAnySyntheticMethods();
177 final boolean anySyntheticFields = segment.getClassBands().isAnySyntheticFields();
178 if (anySytheticClasses || anySyntheticMethods || anySyntheticFields) {
179 final CPUTF8 syntheticUTF = cpBands.getCPUtf8("Synthetic");
180 final CPUTF8 emptyUTF = cpBands.getCPUtf8("");
181 if (anySytheticClasses) {
182 attributeDefinitions.add(new AttributeDefinition(12, CONTEXT_CLASS, syntheticUTF, emptyUTF));
183 }
184 if (anySyntheticMethods) {
185 attributeDefinitions.add(new AttributeDefinition(12, CONTEXT_METHOD, syntheticUTF, emptyUTF));
186 }
187 if (anySyntheticFields) {
188 attributeDefinitions.add(new AttributeDefinition(12, CONTEXT_FIELD, syntheticUTF, emptyUTF));
189 }
190 }
191 }
192
193
194
195
196
197 public void finaliseBands() {
198 addSyntheticDefinitions();
199 segmentHeader.setAttribute_definition_count(attributeDefinitions.size());
200 }
201
202 public List<AttributeDefinition> getClassAttributeLayouts() {
203 return classAttributeLayouts;
204 }
205
206 public List<AttributeDefinition> getCodeAttributeLayouts() {
207 return codeAttributeLayouts;
208 }
209
210 public List<AttributeDefinition> getFieldAttributeLayouts() {
211 return fieldAttributeLayouts;
212 }
213
214 public List<AttributeDefinition> getMethodAttributeLayouts() {
215 return methodAttributeLayouts;
216 }
217
218 @Override
219 public void pack(final OutputStream out) throws IOException, Pack200Exception {
220 PackingUtils.log("Writing attribute definition bands...");
221 final int[] attributeDefinitionHeader = new int[attributeDefinitions.size()];
222 final int[] attributeDefinitionName = new int[attributeDefinitions.size()];
223 final int[] attributeDefinitionLayout = new int[attributeDefinitions.size()];
224 for (int i = 0; i < attributeDefinitionLayout.length; i++) {
225 final AttributeDefinition def = attributeDefinitions.get(i);
226 attributeDefinitionHeader[i] = def.contextType | def.index + 1 << 2;
227 attributeDefinitionName[i] = def.name.getIndex();
228 attributeDefinitionLayout[i] = def.layout.getIndex();
229 }
230
231 byte[] encodedBand = encodeBandInt("attributeDefinitionHeader", attributeDefinitionHeader, Codec.BYTE1);
232 out.write(encodedBand);
233 PackingUtils.log("Wrote " + encodedBand.length + " bytes from attributeDefinitionHeader[" + attributeDefinitionHeader.length + "]");
234
235 encodedBand = encodeBandInt("attributeDefinitionName", attributeDefinitionName, Codec.UNSIGNED5);
236 out.write(encodedBand);
237 PackingUtils.log("Wrote " + encodedBand.length + " bytes from attributeDefinitionName[" + attributeDefinitionName.length + "]");
238
239 encodedBand = encodeBandInt("attributeDefinitionLayout", attributeDefinitionLayout, Codec.UNSIGNED5);
240 out.write(encodedBand);
241 PackingUtils.log("Wrote " + encodedBand.length + " bytes from attributeDefinitionLayout[" + attributeDefinitionLayout.length + "]");
242 }
243 }