View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one or more
3    *  contributor license agreements.  See the NOTICE file distributed with
4    *  this work for additional information regarding copyright ownership.
5    *  The ASF licenses this file to You under the Apache License, Version 2.0
6    *  (the "License"); you may not use this file except in compliance with
7    *  the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  package org.apache.commons.compress.harmony.unpack200;
18  
19  import org.apache.commons.compress.harmony.pack200.Codec;
20  import org.apache.commons.compress.harmony.pack200.Pack200Exception;
21  import org.apache.commons.compress.harmony.unpack200.bytecode.ClassFileEntry;
22  
23  /**
24   * AttributeLayout defines a layout that describes how an attribute will be transmitted.
25   */
26  public class AttributeLayout implements IMatcher {
27  
28      /**
29       * {@value}
30       */
31      public static final String ACC_ABSTRACT = "ACC_ABSTRACT"; //$NON-NLS-1$
32  
33      /**
34       * {@value}
35       */
36      public static final String ACC_ANNOTATION = "ACC_ANNOTATION"; //$NON-NLS-1$
37  
38      /**
39       * {@value}
40       */
41      public static final String ACC_ENUM = "ACC_ENUM"; //$NON-NLS-1$
42  
43      /**
44       * {@value}
45       */
46      public static final String ACC_FINAL = "ACC_FINAL"; //$NON-NLS-1$
47  
48      /**
49       * {@value}
50       */
51      public static final String ACC_INTERFACE = "ACC_INTERFACE"; //$NON-NLS-1$
52  
53      /**
54       * {@value}
55       */
56      public static final String ACC_NATIVE = "ACC_NATIVE"; //$NON-NLS-1$
57  
58      /**
59       * {@value}
60       */
61      public static final String ACC_PRIVATE = "ACC_PRIVATE"; //$NON-NLS-1$
62  
63      /**
64       * {@value}
65       */
66      public static final String ACC_PROTECTED = "ACC_PROTECTED"; //$NON-NLS-1$
67  
68      /**
69       * {@value}
70       */
71      public static final String ACC_PUBLIC = "ACC_PUBLIC"; //$NON-NLS-1$
72  
73      /**
74       * {@value}
75       */
76      public static final String ACC_STATIC = "ACC_STATIC"; //$NON-NLS-1$
77  
78      /**
79       * {@value}
80       */
81      public static final String ACC_STRICT = "ACC_STRICT"; //$NON-NLS-1$
82  
83      /**
84       * {@value}
85       */
86      public static final String ACC_SYNCHRONIZED = "ACC_SYNCHRONIZED"; //$NON-NLS-1$
87  
88      /**
89       * {@value}
90       */
91      public static final String ACC_SYNTHETIC = "ACC_SYNTHETIC"; //$NON-NLS-1$
92  
93      /**
94       * {@value}
95       */
96      public static final String ACC_TRANSIENT = "ACC_TRANSIENT"; //$NON-NLS-1$
97  
98      /**
99       * {@value}
100      */
101     public static final String ACC_VOLATILE = "ACC_VOLATILE"; //$NON-NLS-1$
102 
103     /**
104      * {@value}
105      */
106     public static final String ATTRIBUTE_ANNOTATION_DEFAULT = "AnnotationDefault"; //$NON-NLS-1$
107 
108     /**
109      * {@value}
110      */
111     public static final String ATTRIBUTE_CLASS_FILE_VERSION = "class-file version"; //$NON-NLS-1$
112 
113     /**
114      * {@value}
115      */
116     public static final String ATTRIBUTE_CODE = "Code"; //$NON-NLS-1$
117 
118     /**
119      * {@value}
120      */
121     public static final String ATTRIBUTE_CONSTANT_VALUE = "ConstantValue"; //$NON-NLS-1$
122 
123     /**
124      * {@value}
125      */
126     public static final String ATTRIBUTE_DEPRECATED = "Deprecated"; //$NON-NLS-1$
127 
128     /**
129      * {@value}
130      */
131 
132     /**
133      * {@value}
134      */
135     public static final String ATTRIBUTE_ENCLOSING_METHOD = "EnclosingMethod"; //$NON-NLS-1$
136 
137     /**
138      * {@value}
139      */
140     public static final String ATTRIBUTE_EXCEPTIONS = "Exceptions"; //$NON-NLS-1$
141 
142     /**
143      * {@value}
144      */
145     public static final String ATTRIBUTE_INNER_CLASSES = "InnerClasses"; //$NON-NLS-1$
146 
147     /**
148      * {@value}
149      */
150     public static final String ATTRIBUTE_LINE_NUMBER_TABLE = "LineNumberTable"; //$NON-NLS-1$
151 
152     /**
153      * {@value}
154      */
155     public static final String ATTRIBUTE_LOCAL_VARIABLE_TABLE = "LocalVariableTable"; //$NON-NLS-1$
156 
157     /**
158      * {@value}
159      */
160     public static final String ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable"; //$NON-NLS-1$
161 
162     /**
163      * {@value}
164      */
165     public static final String ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations"; //$NON-NLS-1$
166 
167     /**
168      * {@value}
169      */
170     public static final String ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = "RuntimeInvisibleParameterAnnotations"; //$NON-NLS-1$
171 
172     /**
173      * {@value}
174      */
175     public static final String ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations"; //$NON-NLS-1$
176 
177     /**
178      * {@value}
179      */
180     public static final String ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations"; //$NON-NLS-1$
181 
182     /**
183      * {@value}
184      */
185     public static final String ATTRIBUTE_SIGNATURE = "Signature"; //$NON-NLS-1$
186 
187     /**
188      * {@value}
189      */
190     public static final String ATTRIBUTE_SOURCE_FILE = "SourceFile"; //$NON-NLS-1$
191 
192     /**
193      * {@value}
194      */
195     public static final int CONTEXT_CLASS = 0;
196 
197     /**
198      * {@value}
199      */
200     public static final int CONTEXT_CODE = 3;
201 
202     /**
203      * {@value}
204      */
205     public static final int CONTEXT_FIELD = 1;
206 
207     /**
208      * {@value}
209      */
210     public static final int CONTEXT_METHOD = 2;
211 
212     /**
213      * Context names.
214      */
215     public static final String[] contextNames = { "Class", "Field", "Method", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
216             "Code", }; //$NON-NLS-1$
217 
218     private static ClassFileEntry getValue(final String layout, long value, final SegmentConstantPool pool) throws Pack200Exception {
219         if (layout.startsWith("R")) { //$NON-NLS-1$
220             // references
221             if (layout.indexOf('N') != -1) {
222                 value--;
223             }
224             if (layout.startsWith("RU")) { //$NON-NLS-1$
225                 return pool.getValue(SegmentConstantPool.UTF_8, value);
226             }
227             if (layout.startsWith("RS")) { //$NON-NLS-1$
228                 return pool.getValue(SegmentConstantPool.SIGNATURE, value);
229             }
230         } else if (layout.startsWith("K")) { //$NON-NLS-1$
231             final char type = layout.charAt(1);
232             switch (type) {
233             case 'S': // String
234                 return pool.getValue(SegmentConstantPool.CP_STRING, value);
235             case 'I': // Int (or byte or short)
236             case 'C': // Char
237                 return pool.getValue(SegmentConstantPool.CP_INT, value);
238             case 'F': // Float
239                 return pool.getValue(SegmentConstantPool.CP_FLOAT, value);
240             case 'J': // Long
241                 return pool.getValue(SegmentConstantPool.CP_LONG, value);
242             case 'D': // Double
243                 return pool.getValue(SegmentConstantPool.CP_DOUBLE, value);
244             }
245         }
246         throw new Pack200Exception("Unknown layout encoding: " + layout);
247     }
248 
249     private final int context;
250 
251     private final int index;
252 
253     private final String layout;
254 
255     private long mask;
256 
257     private final String name;
258     private final boolean isDefault;
259     private int backwardsCallCount;
260 
261     /**
262      * Constructs a default AttributeLayout (equivalent to {@code new AttributeLayout(name, context, layout, index, true);})
263      *
264      * @param name    TODO
265      * @param context TODO
266      * @param layout  TODO
267      * @param index   TODO
268      * @throws Pack200Exception Attribute context out of range.
269      * @throws Pack200Exception Cannot have a null layout.
270      * @throws Pack200Exception Cannot have an unnamed layout.
271      */
272     public AttributeLayout(final String name, final int context, final String layout, final int index) throws Pack200Exception {
273         this(name, context, layout, index, true);
274     }
275 
276     public AttributeLayout(final String name, final int context, final String layout, final int index, final boolean isDefault) throws Pack200Exception {
277         this.index = index;
278         this.context = context;
279         if (index >= 0) {
280             this.mask = 1L << index;
281         } else {
282             this.mask = 0;
283         }
284         if (context != CONTEXT_CLASS && context != CONTEXT_CODE && context != CONTEXT_FIELD && context != CONTEXT_METHOD) {
285             throw new Pack200Exception("Attribute context out of range: " + context);
286         }
287         if (layout == null) {
288             throw new Pack200Exception("Cannot have a null layout");
289         }
290         if (name == null || name.length() == 0) {
291             throw new Pack200Exception("Cannot have an unnamed layout");
292         }
293         this.name = name;
294         this.layout = layout;
295         this.isDefault = isDefault;
296     }
297 
298     public Codec getCodec() {
299         if (layout.indexOf('O') >= 0) {
300             return Codec.BRANCH5;
301         }
302         if (layout.indexOf('P') >= 0) {
303             return Codec.BCI5;
304         }
305         if (layout.indexOf('S') >= 0 && !layout.contains("KS") //$NON-NLS-1$
306                 && !layout.contains("RS")) { //$NON-NLS-1$
307             return Codec.SIGNED5;
308         }
309         if (layout.indexOf('B') >= 0) {
310             return Codec.BYTE1;
311         }
312         return Codec.UNSIGNED5;
313     }
314 
315     public int getContext() {
316         return context;
317     }
318 
319     public int getIndex() {
320         return index;
321     }
322 
323     public String getLayout() {
324         return layout;
325     }
326 
327     public String getName() {
328         return name;
329     }
330 
331     public ClassFileEntry getValue(final long value, final SegmentConstantPool pool) throws Pack200Exception {
332         return getValue(layout, value, pool);
333     }
334 
335     public ClassFileEntry getValue(final long value, final String type, final SegmentConstantPool pool) throws Pack200Exception {
336         // TODO This really needs to be better tested, esp. the different types
337         // TODO This should have the ability to deal with RUN stuff too, and
338         // unions
339         if (!layout.startsWith("KQ")) {
340             return getValue(layout, value, pool);
341         }
342         if (type.equals("Ljava/lang/String;")) { //$NON-NLS-1$
343             return getValue("KS", value, pool);
344         }
345         return getValue("K" + type + layout.substring(2), value, //$NON-NLS-1$
346                 pool);
347     }
348 
349     @Override
350     public int hashCode() {
351         final int PRIME = 31;
352         int r = 1;
353         if (name != null) {
354             r = r * PRIME + name.hashCode();
355         }
356         if (layout != null) {
357             r = r * PRIME + layout.hashCode();
358         }
359         r = r * PRIME + index;
360         r = r * PRIME + context;
361         return r;
362     }
363 
364     public boolean isDefaultLayout() {
365         return isDefault;
366     }
367 
368     /*
369      * (non-Javadoc)
370      *
371      * @see org.apache.commons.compress.harmony.unpack200.IMatches#matches(long)
372      */
373     @Override
374     public boolean matches(final long value) {
375         return (value & mask) != 0;
376     }
377 
378     public int numBackwardsCallables() {
379         if ("*".equals(layout)) {
380             return 1;
381         }
382         return backwardsCallCount;
383     }
384 
385     public void setBackwardsCallCount(final int backwardsCallCount) {
386         this.backwardsCallCount = backwardsCallCount;
387     }
388 
389     @Override
390     public String toString() {
391         return contextNames[context] + ": " + name;
392     }
393 
394 }