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 static final ElementValue[] EMPTY_ARRAY = {}; 067 068 /** 069 * Reads an {@code element_value} as an {@code ElementValue}. 070 * 071 * @param input Raw data input. 072 * @param cpool Constant pool. 073 * @return a new ElementValue. 074 * @throws IOException if an I/O error occurs. 075 */ 076 public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool) throws IOException { 077 return readElementValue(input, cpool, 0); 078 } 079 080 /** 081 * Reads an {@code element_value} as an {@code ElementValue}. 082 * 083 * @param input Raw data input. 084 * @param cpool Constant pool. 085 * @param arrayNesting level of current array nesting. 086 * @return a new ElementValue. 087 * @throws IOException if an I/O error occurs. 088 * @since 6.7.0 089 */ 090 public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool, int arrayNesting) 091 throws IOException { 092 final byte tag = input.readByte(); 093 switch (tag) { 094 case PRIMITIVE_BYTE: 095 case PRIMITIVE_CHAR: 096 case PRIMITIVE_DOUBLE: 097 case PRIMITIVE_FLOAT: 098 case PRIMITIVE_INT: 099 case PRIMITIVE_LONG: 100 case PRIMITIVE_SHORT: 101 case PRIMITIVE_BOOLEAN: 102 case STRING: 103 return new SimpleElementValue(tag, input.readUnsignedShort(), cpool); 104 105 case ENUM_CONSTANT: 106 return new EnumElementValue(ENUM_CONSTANT, input.readUnsignedShort(), input.readUnsignedShort(), cpool); 107 108 case CLASS: 109 return new ClassElementValue(CLASS, input.readUnsignedShort(), cpool); 110 111 case ANNOTATION: 112 // TODO isRuntimeVisible 113 return new AnnotationElementValue(ANNOTATION, AnnotationEntry.read(input, cpool, false), cpool); 114 115 case ARRAY: 116 arrayNesting++; 117 if (arrayNesting > Const.MAX_ARRAY_DIMENSIONS) { 118 // JVM spec 4.4.1 119 throw new ClassFormatException(String.format("Arrays are only valid if they represent %,d or fewer dimensions.", Const.MAX_ARRAY_DIMENSIONS)); 120 } 121 final int numArrayVals = input.readUnsignedShort(); 122 final ElementValue[] evalues = new ElementValue[numArrayVals]; 123 for (int j = 0; j < numArrayVals; j++) { 124 evalues[j] = readElementValue(input, cpool, arrayNesting); 125 } 126 return new ArrayElementValue(ARRAY, evalues, cpool); 127 128 default: 129 throw new ClassFormatException("Unexpected element value tag in annotation: " + tag); 130 } 131 } 132 133 /** 134 * @deprecated (since 6.0) will be made private and final; do not access directly, use getter 135 */ 136 @java.lang.Deprecated 137 protected int type; // TODO should be final 138 /** 139 * @deprecated (since 6.0) will be made private and final; do not access directly, use getter 140 */ 141 @java.lang.Deprecated 142 protected ConstantPool cpool; // TODO should be final 143 144 protected ElementValue(final int type, final ConstantPool cpool) { 145 this.type = type; 146 this.cpool = cpool; 147 } 148 149 public abstract void dump(DataOutputStream dos) throws IOException; 150 151 /** @since 6.0 */ 152 final ConstantPool getConstantPool() { 153 return cpool; 154 } 155 156 public int getElementValueType() { 157 return type; 158 } 159 160 /** @since 6.0 */ 161 final int getType() { 162 return type; 163 } 164 165 public abstract String stringifyValue(); 166 167 public String toShortString() { 168 return stringifyValue(); 169 } 170 171 @Override 172 public String toString() { 173 return stringifyValue(); 174 } 175}