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 */ 017 018package org.apache.bcel.classfile; 019 020import java.io.DataInput; 021import java.io.DataOutputStream; 022import java.io.IOException; 023 024import org.apache.bcel.Const; 025 026/** 027 * The element_value structure is documented at https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7.16.1 028 * 029 * <pre> 030 * element_value { 031 * u1 tag; 032 * union { 033 * u2 const_value_index; 034 * 035 * { u2 type_name_index; 036 * u2 const_name_index; 037 * } enum_const_value; 038 * 039 * u2 class_info_index; 040 * 041 * annotation annotation_value; 042 * 043 * { u2 num_values; 044 * element_value values[num_values]; 045 * } array_value; 046 * } value; 047 *} 048 *</pre> 049 * @since 6.0 050 */ 051public abstract class ElementValue { 052 053 public static final byte STRING = 's'; 054 public static final byte ENUM_CONSTANT = 'e'; 055 public static final byte CLASS = 'c'; 056 public static final byte ANNOTATION = '@'; 057 public static final byte ARRAY = '['; 058 public static final byte PRIMITIVE_INT = 'I'; 059 public static final byte PRIMITIVE_BYTE = 'B'; 060 public static final byte PRIMITIVE_CHAR = 'C'; 061 public static final byte PRIMITIVE_DOUBLE = 'D'; 062 public static final byte PRIMITIVE_FLOAT = 'F'; 063 public static final byte PRIMITIVE_LONG = 'J'; 064 public static final byte PRIMITIVE_SHORT = 'S'; 065 public static final byte PRIMITIVE_BOOLEAN = 'Z'; 066 067 /** 068 * Reads an {@code element_value} as an {@code ElementValue}. 069 * 070 * @param input Raw data input. 071 * @param cpool Constant pool. 072 * @return a new ElementValue. 073 * @throws IOException if an I/O error occurs. 074 */ 075 public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool) throws IOException { 076 return readElementValue(input, cpool, 0); 077 } 078 079 /** 080 * Reads an {@code element_value} as an {@code ElementValue}. 081 * 082 * @param input Raw data input. 083 * @param cpool Constant pool. 084 * @param arrayNesting level of current array nesting. 085 * @return a new ElementValue. 086 * @throws IOException if an I/O error occurs. 087 * @since 6.7.0 088 */ 089 public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool, int arrayNesting) 090 throws IOException { 091 final byte tag = input.readByte(); 092 switch (tag) { 093 case PRIMITIVE_BYTE: 094 case PRIMITIVE_CHAR: 095 case PRIMITIVE_DOUBLE: 096 case PRIMITIVE_FLOAT: 097 case PRIMITIVE_INT: 098 case PRIMITIVE_LONG: 099 case PRIMITIVE_SHORT: 100 case PRIMITIVE_BOOLEAN: 101 case STRING: 102 return new SimpleElementValue(tag, input.readUnsignedShort(), cpool); 103 104 case ENUM_CONSTANT: 105 return new EnumElementValue(ENUM_CONSTANT, input.readUnsignedShort(), input.readUnsignedShort(), cpool); 106 107 case CLASS: 108 return new ClassElementValue(CLASS, input.readUnsignedShort(), cpool); 109 110 case ANNOTATION: 111 // TODO isRuntimeVisible 112 return new AnnotationElementValue(ANNOTATION, AnnotationEntry.read(input, cpool, false), cpool); 113 114 case ARRAY: 115 arrayNesting++; 116 if (arrayNesting > Const.MAX_ARRAY_DIMENSIONS) { 117 // JVM spec 4.4.1 118 throw new ClassFormatException(String.format("Arrays are only valid if they represent %,d or fewer dimensions.", Const.MAX_ARRAY_DIMENSIONS)); 119 } 120 final int numArrayVals = input.readUnsignedShort(); 121 final ElementValue[] evalues = new ElementValue[numArrayVals]; 122 for (int j = 0; j < numArrayVals; j++) { 123 evalues[j] = ElementValue.readElementValue(input, cpool, arrayNesting); 124 } 125 return new ArrayElementValue(ARRAY, evalues, cpool); 126 127 default: 128 throw new ClassFormatException("Unexpected element value tag in annotation: " + tag); 129 } 130 } 131 132 /** 133 * @deprecated (since 6.0) will be made private and final; do not access directly, use getter 134 */ 135 @java.lang.Deprecated 136 protected int type; // TODO should be final 137 /** 138 * @deprecated (since 6.0) will be made private and final; do not access directly, use getter 139 */ 140 @java.lang.Deprecated 141 protected ConstantPool cpool; // TODO should be final 142 143 protected ElementValue(final int type, final ConstantPool cpool) { 144 this.type = type; 145 this.cpool = cpool; 146 } 147 148 public abstract void dump(DataOutputStream dos) throws IOException; 149 150 /** @since 6.0 */ 151 final ConstantPool getConstantPool() { 152 return cpool; 153 } 154 155 public int getElementValueType() { 156 return type; 157 } 158 159 /** @since 6.0 */ 160 final int getType() { 161 return type; 162 } 163 164 public abstract String stringifyValue(); 165 166 public String toShortString() { 167 return stringifyValue(); 168 } 169 170 @Override 171 public String toString() { 172 return stringifyValue(); 173 } 174}