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 numPairs; 035 private final CPUTF8[] elementNames; 036 private final ElementValue[] elementValues; 037 private final CPUTF8 type; 038 039 // Resolved values 040 private int typeIndex; 041 private int[] nameIndexes; 042 043 public Annotation(final int numPairs, final CPUTF8 type, final CPUTF8[] elementNames, 044 final ElementValue[] elementValues) { 045 this.numPairs = numPairs; 046 this.type = type; 047 this.elementNames = elementNames; 048 this.elementValues = elementValues; 049 } 050 051 public List<Object> getClassFileEntries() { 052 final List<Object> entries = new ArrayList<>(); 053 for (int i = 0; i < elementNames.length; i++) { 054 entries.add(elementNames[i]); 055 entries.addAll(elementValues[i].getClassFileEntries()); 056 } 057 entries.add(type); 058 return entries; 059 } 060 061 public int getLength() { 062 int length = 4; 063 for (int i = 0; i < numPairs; i++) { 064 length += 2; 065 length += elementValues[i].getLength(); 066 } 067 return length; 068 } 069 070 public void resolve(final ClassConstantPool pool) { 071 type.resolve(pool); 072 typeIndex = pool.indexOf(type); 073 nameIndexes = new int[numPairs]; 074 for (int i = 0; i < elementNames.length; i++) { 075 elementNames[i].resolve(pool); 076 nameIndexes[i] = pool.indexOf(elementNames[i]); 077 elementValues[i].resolve(pool); 078 } 079 } 080 081 public void writeBody(final DataOutputStream dos) throws IOException { 082 dos.writeShort(typeIndex); 083 dos.writeShort(numPairs); 084 for (int i = 0; i < numPairs; i++) { 085 dos.writeShort(nameIndexes[i]); 086 elementValues[i].writeBody(dos); 087 } 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 constantValueIndex = -1; 098 099 public ElementValue(final int tag, final Object value) { 100 this.tag = tag; 101 this.value = value; 102 } 103 104 public List<Object> getClassFileEntries() { 105 final List<Object> 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 // TODO? ClassFileEntry is an Object 112 entries.add(value); 113 } else if (value instanceof ElementValue[]) { 114 final ElementValue[] values = (ElementValue[]) value; 115 for (final ElementValue value2 : values) { 116 entries.addAll(value2.getClassFileEntries()); 117 } 118 } else if (value instanceof Annotation) { 119 entries.addAll(((Annotation) value).getClassFileEntries()); 120 } 121 return entries; 122 } 123 124 public int getLength() { 125 switch (tag) { 126 case 'B': 127 case 'C': 128 case 'D': 129 case 'F': 130 case 'I': 131 case 'J': 132 case 'S': 133 case 'Z': 134 case 'c': 135 case 's': 136 return 3; 137 case 'e': 138 return 5; 139 case '[': 140 int length = 3; 141 final ElementValue[] nestedValues = (ElementValue[]) value; 142 for (final ElementValue nestedValue : nestedValues) { 143 length += nestedValue.getLength(); 144 } 145 return length; 146 case '@': 147 return 1 + ((Annotation) value).getLength(); 148 } 149 return 0; 150 } 151 152 public void resolve(final ClassConstantPool pool) { 153 if (value instanceof CPConstant) { 154 ((CPConstant) value).resolve(pool); 155 constantValueIndex = pool.indexOf((CPConstant) value); 156 } else if (value instanceof CPClass) { 157 ((CPClass) value).resolve(pool); 158 constantValueIndex = pool.indexOf((CPClass) value); 159 } else if (value instanceof CPUTF8) { 160 ((CPUTF8) value).resolve(pool); 161 constantValueIndex = pool.indexOf((CPUTF8) value); 162 } else if (value instanceof CPNameAndType) { 163 ((CPNameAndType) value).resolve(pool); 164 } else if (value instanceof Annotation) { 165 ((Annotation) value).resolve(pool); 166 } else if (value instanceof ElementValue[]) { 167 final ElementValue[] nestedValues = (ElementValue[]) value; 168 for (final ElementValue nestedValue : nestedValues) { 169 nestedValue.resolve(pool); 170 } 171 } 172 } 173 174 public void writeBody(final DataOutputStream dos) throws IOException { 175 dos.writeByte(tag); 176 if (constantValueIndex != -1) { 177 dos.writeShort(constantValueIndex); 178 } else if (value instanceof CPNameAndType) { 179 ((CPNameAndType) value).writeBody(dos); 180 } else if (value instanceof Annotation) { 181 ((Annotation) value).writeBody(dos); 182 } else if (value instanceof ElementValue[]) { 183 final ElementValue[] nestedValues = (ElementValue[]) value; 184 dos.writeShort(nestedValues.length); 185 for (final ElementValue nestedValue : nestedValues) { 186 nestedValue.writeBody(dos); 187 } 188 } else { 189 throw new Error(""); 190 } 191 } 192 } 193 194 public AnnotationsAttribute(final CPUTF8 attributeName) { 195 super(attributeName); 196 } 197 198}