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.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   * Abstract superclass for Annotations attributes
26   */
27  public abstract class AnnotationsAttribute extends Attribute {
28  
29      /**
30       * Class to represent the annotation structure for class file attributes
31       */
32      public static class Annotation {
33  
34          private final int numPairs;
35          private final CPUTF8[] elementNames;
36          private final ElementValue[] elementValues;
37          private final CPUTF8 type;
38  
39          // Resolved values
40          private int typeIndex;
41          private int[] nameIndexes;
42  
43          public Annotation(final int numPairs, final CPUTF8 type, final CPUTF8[] elementNames, final ElementValue[] elementValues) {
44              this.numPairs = numPairs;
45              this.type = type;
46              this.elementNames = elementNames;
47              this.elementValues = elementValues;
48          }
49  
50          public List<Object> getClassFileEntries() {
51              final List<Object> entries = new ArrayList<>();
52              for (int i = 0; i < elementNames.length; i++) {
53                  entries.add(elementNames[i]);
54                  entries.addAll(elementValues[i].getClassFileEntries());
55              }
56              entries.add(type);
57              return entries;
58          }
59  
60          public int getLength() {
61              int length = 4;
62              for (int i = 0; i < numPairs; i++) {
63                  length += 2;
64                  length += elementValues[i].getLength();
65              }
66              return length;
67          }
68  
69          public void resolve(final ClassConstantPool pool) {
70              type.resolve(pool);
71              typeIndex = pool.indexOf(type);
72              nameIndexes = new int[numPairs];
73              for (int i = 0; i < elementNames.length; i++) {
74                  elementNames[i].resolve(pool);
75                  nameIndexes[i] = pool.indexOf(elementNames[i]);
76                  elementValues[i].resolve(pool);
77              }
78          }
79  
80          public void writeBody(final DataOutputStream dos) throws IOException {
81              dos.writeShort(typeIndex);
82              dos.writeShort(numPairs);
83              for (int i = 0; i < numPairs; i++) {
84                  dos.writeShort(nameIndexes[i]);
85                  elementValues[i].writeBody(dos);
86              }
87          }
88      }
89  
90      public static class ElementValue {
91  
92          private final Object value;
93          private final int tag;
94  
95          // resolved value index if it's a constant
96          private int constantValueIndex = -1;
97  
98          public ElementValue(final int tag, final Object value) {
99              this.tag = tag;
100             this.value = value;
101         }
102 
103         public List<Object> getClassFileEntries() {
104             final List<Object> entries = new ArrayList<>(1);
105             if (value instanceof CPNameAndType) {
106                 // used to represent enum, so don't include the actual CPNameAndType
107                 entries.add(((CPNameAndType) value).name);
108                 entries.add(((CPNameAndType) value).descriptor);
109             } else if (value instanceof ClassFileEntry) {
110                 // TODO? ClassFileEntry is an Object
111                 entries.add(value);
112             } else if (value instanceof ElementValue[]) {
113                 final ElementValue[] values = (ElementValue[]) value;
114                 for (final ElementValue value2 : values) {
115                     entries.addAll(value2.getClassFileEntries());
116                 }
117             } else if (value instanceof Annotation) {
118                 entries.addAll(((Annotation) value).getClassFileEntries());
119             }
120             return entries;
121         }
122 
123         public int getLength() {
124             switch (tag) {
125             case 'B':
126             case 'C':
127             case 'D':
128             case 'F':
129             case 'I':
130             case 'J':
131             case 'S':
132             case 'Z':
133             case 'c':
134             case 's':
135                 return 3;
136             case 'e':
137                 return 5;
138             case '[':
139                 int length = 3;
140                 final ElementValue[] nestedValues = (ElementValue[]) value;
141                 for (final ElementValue nestedValue : nestedValues) {
142                     length += nestedValue.getLength();
143                 }
144                 return length;
145             case '@':
146                 return 1 + ((Annotation) value).getLength();
147             }
148             return 0;
149         }
150 
151         public void resolve(final ClassConstantPool pool) {
152             if (value instanceof CPConstant) {
153                 ((CPConstant) value).resolve(pool);
154                 constantValueIndex = pool.indexOf((CPConstant) value);
155             } else if (value instanceof CPClass) {
156                 ((CPClass) value).resolve(pool);
157                 constantValueIndex = pool.indexOf((CPClass) value);
158             } else if (value instanceof CPUTF8) {
159                 ((CPUTF8) value).resolve(pool);
160                 constantValueIndex = pool.indexOf((CPUTF8) value);
161             } else if (value instanceof CPNameAndType) {
162                 ((CPNameAndType) value).resolve(pool);
163             } else if (value instanceof Annotation) {
164                 ((Annotation) value).resolve(pool);
165             } else if (value instanceof ElementValue[]) {
166                 final ElementValue[] nestedValues = (ElementValue[]) value;
167                 for (final ElementValue nestedValue : nestedValues) {
168                     nestedValue.resolve(pool);
169                 }
170             }
171         }
172 
173         public void writeBody(final DataOutputStream dos) throws IOException {
174             dos.writeByte(tag);
175             if (constantValueIndex != -1) {
176                 dos.writeShort(constantValueIndex);
177             } else if (value instanceof CPNameAndType) {
178                 ((CPNameAndType) value).writeBody(dos);
179             } else if (value instanceof Annotation) {
180                 ((Annotation) value).writeBody(dos);
181             } else if (value instanceof ElementValue[]) {
182                 final ElementValue[] nestedValues = (ElementValue[]) value;
183                 dos.writeShort(nestedValues.length);
184                 for (final ElementValue nestedValue : nestedValues) {
185                     nestedValue.writeBody(dos);
186                 }
187             } else {
188                 throw new Error("");
189             }
190         }
191     }
192 
193     public AnnotationsAttribute(final CPUTF8 attributeName) {
194         super(attributeName);
195     }
196 
197 }