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