001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one or more
003 *  contributor license agreements.  See the NOTICE file distributed with
004 *  this work for additional information regarding copyright ownership.
005 *  The ASF licenses this file to You under the Apache License, Version 2.0
006 *  (the "License"); you may not use this file except in compliance with
007 *  the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 *  Unless required by applicable law or agreed to in writing, software
012 *  distributed under the License is distributed on an "AS IS" BASIS,
013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 *  See the License for the specific language governing permissions and
015 *  limitations under the License.
016 */
017package org.apache.commons.compress.harmony.unpack200.bytecode;
018
019import java.io.DataOutputStream;
020import java.io.IOException;
021import java.util.ArrayList;
022import java.util.List;
023
024/**
025 * Abstract superclass for Annotations attributes
026 */
027public abstract class AnnotationsAttribute extends Attribute {
028
029    /**
030     * Class to represent the annotation structure for class file attributes
031     */
032    public static class Annotation {
033
034        private final int num_pairs;
035        private final CPUTF8[] element_names;
036        private final ElementValue[] element_values;
037        private final CPUTF8 type;
038
039        // Resolved values
040        private int type_index;
041        private int[] name_indexes;
042
043        public Annotation(final int num_pairs, final CPUTF8 type, final CPUTF8[] element_names,
044            final ElementValue[] element_values) {
045            this.num_pairs = num_pairs;
046            this.type = type;
047            this.element_names = element_names;
048            this.element_values = element_values;
049        }
050
051        public int getLength() {
052            int length = 4;
053            for (int i = 0; i < num_pairs; i++) {
054                length += 2;
055                length += element_values[i].getLength();
056            }
057            return length;
058        }
059
060        public void resolve(final ClassConstantPool pool) {
061            type.resolve(pool);
062            type_index = pool.indexOf(type);
063            name_indexes = new int[num_pairs];
064            for (int i = 0; i < element_names.length; i++) {
065                element_names[i].resolve(pool);
066                name_indexes[i] = pool.indexOf(element_names[i]);
067                element_values[i].resolve(pool);
068            }
069        }
070
071        public void writeBody(final DataOutputStream dos) throws IOException {
072            dos.writeShort(type_index);
073            dos.writeShort(num_pairs);
074            for (int i = 0; i < num_pairs; i++) {
075                dos.writeShort(name_indexes[i]);
076                element_values[i].writeBody(dos);
077            }
078        }
079
080        public List getClassFileEntries() {
081            final List entries = new ArrayList();
082            for (int i = 0; i < element_names.length; i++) {
083                entries.add(element_names[i]);
084                entries.addAll(element_values[i].getClassFileEntries());
085            }
086            entries.add(type);
087            return entries;
088        }
089    }
090
091    public static class ElementValue {
092
093        private final Object value;
094        private final int tag;
095
096        // resolved value index if it's a constant
097        private int constant_value_index = -1;
098
099        public ElementValue(final int tag, final Object value) {
100            this.tag = tag;
101            this.value = value;
102        }
103
104        public List getClassFileEntries() {
105            final List entries = new ArrayList(1);
106            if (value instanceof CPNameAndType) {
107                // used to represent enum, so don't include the actual CPNameAndType
108                entries.add(((CPNameAndType) value).name);
109                entries.add(((CPNameAndType) value).descriptor);
110            } else if (value instanceof ClassFileEntry) {
111                entries.add(value);
112            } else if (value instanceof ElementValue[]) {
113                final ElementValue[] values = (ElementValue[]) value;
114                for (int i = 0; i < values.length; i++) {
115                    entries.addAll(values[i].getClassFileEntries());
116                }
117            } else if (value instanceof Annotation) {
118                entries.addAll(((Annotation) value).getClassFileEntries());
119            }
120            return entries;
121        }
122
123        public void resolve(final ClassConstantPool pool) {
124            if (value instanceof CPConstant) {
125                ((CPConstant) value).resolve(pool);
126                constant_value_index = pool.indexOf((CPConstant) value);
127            } else if (value instanceof CPClass) {
128                ((CPClass) value).resolve(pool);
129                constant_value_index = pool.indexOf((CPClass) value);
130            } else if (value instanceof CPUTF8) {
131                ((CPUTF8) value).resolve(pool);
132                constant_value_index = pool.indexOf((CPUTF8) value);
133            } else if (value instanceof CPNameAndType) {
134                ((CPNameAndType) value).resolve(pool);
135            } else if (value instanceof Annotation) {
136                ((Annotation) value).resolve(pool);
137            } else if (value instanceof ElementValue[]) {
138                final ElementValue[] nestedValues = (ElementValue[]) value;
139                for (int i = 0; i < nestedValues.length; i++) {
140                    nestedValues[i].resolve(pool);
141                }
142            }
143        }
144
145        public void writeBody(final DataOutputStream dos) throws IOException {
146            dos.writeByte(tag);
147            if (constant_value_index != -1) {
148                dos.writeShort(constant_value_index);
149            } else if (value instanceof CPNameAndType) {
150                ((CPNameAndType) value).writeBody(dos);
151            } else if (value instanceof Annotation) {
152                ((Annotation) value).writeBody(dos);
153            } else if (value instanceof ElementValue[]) {
154                final ElementValue[] nestedValues = (ElementValue[]) value;
155                dos.writeShort(nestedValues.length);
156                for (int i = 0; i < nestedValues.length; i++) {
157                    nestedValues[i].writeBody(dos);
158                }
159            } else {
160                throw new Error("");
161            }
162        }
163
164        public int getLength() {
165            switch (tag) {
166            case 'B':
167            case 'C':
168            case 'D':
169            case 'F':
170            case 'I':
171            case 'J':
172            case 'S':
173            case 'Z':
174            case 'c':
175            case 's':
176                return 3;
177            case 'e':
178                return 5;
179            case '[':
180                int length = 3;
181                final ElementValue[] nestedValues = (ElementValue[]) value;
182                for (int i = 0; i < nestedValues.length; i++) {
183                    length += nestedValues[i].getLength();
184                }
185                return length;
186            case '@':
187                return (1 + ((Annotation) value).getLength());
188            }
189            return 0;
190        }
191    }
192
193    public AnnotationsAttribute(final CPUTF8 attributeName) {
194        super(attributeName);
195    }
196
197}