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