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}