1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * https://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 package org.apache.bcel.classfile;
21
22 import java.io.DataInput;
23 import java.io.DataOutputStream;
24 import java.io.IOException;
25
26 import org.apache.bcel.Const;
27
28 /**
29 * The element_value structure is documented at https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7.16.1
30 *
31 * <pre>
32 * element_value {
33 * u1 tag;
34 * union {
35 * u2 const_value_index;
36 *
37 * { u2 type_name_index;
38 * u2 const_name_index;
39 * } enum_const_value;
40 *
41 * u2 class_info_index;
42 *
43 * annotation annotation_value;
44 *
45 * { u2 num_values;
46 * element_value values[num_values];
47 * } array_value;
48 * } value;
49 *}
50 *</pre>
51 *
52 * @since 6.0
53 */
54 public abstract class ElementValue {
55
56 /** Element value type: string. */
57 public static final byte STRING = 's';
58
59 /** Element value type: enum constant. */
60 public static final byte ENUM_CONSTANT = 'e';
61
62 /** Element value type: class. */
63 public static final byte CLASS = 'c';
64
65 /** Element value type: annotation. */
66 public static final byte ANNOTATION = '@';
67
68 /** Element value type: array. */
69 public static final byte ARRAY = '[';
70
71 /** Element value type: primitive int. */
72 public static final byte PRIMITIVE_INT = 'I';
73
74 /** Element value type: primitive byte. */
75 public static final byte PRIMITIVE_BYTE = 'B';
76
77 /** Element value type: primitive char. */
78 public static final byte PRIMITIVE_CHAR = 'C';
79
80 /** Element value type: primitive double. */
81 public static final byte PRIMITIVE_DOUBLE = 'D';
82
83 /** Element value type: primitive float. */
84 public static final byte PRIMITIVE_FLOAT = 'F';
85
86 /** Element value type: primitive long. */
87 public static final byte PRIMITIVE_LONG = 'J';
88
89 /** Element value type: primitive short. */
90 public static final byte PRIMITIVE_SHORT = 'S';
91
92 /** Element value type: primitive boolean. */
93 public static final byte PRIMITIVE_BOOLEAN = 'Z';
94
95 /** Empty array constant. */
96 static final ElementValue[] EMPTY_ARRAY = {};
97
98 /**
99 * Reads an {@code element_value} as an {@code ElementValue}.
100 *
101 * @param input Raw data input.
102 * @param cpool Constant pool.
103 * @return a new ElementValue.
104 * @throws IOException if an I/O error occurs.
105 */
106 public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool) throws IOException {
107 return readElementValue(input, cpool, 0);
108 }
109
110 /**
111 * Reads an {@code element_value} as an {@code ElementValue}.
112 *
113 * @param input Raw data input.
114 * @param cpool Constant pool.
115 * @param arrayNesting level of current array nesting.
116 * @return a new ElementValue.
117 * @throws IOException if an I/O error occurs.
118 * @since 6.7.0
119 */
120 public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool, int arrayNesting)
121 throws IOException {
122 final byte tag = input.readByte();
123 switch (tag) {
124 case PRIMITIVE_BYTE:
125 case PRIMITIVE_CHAR:
126 case PRIMITIVE_DOUBLE:
127 case PRIMITIVE_FLOAT:
128 case PRIMITIVE_INT:
129 case PRIMITIVE_LONG:
130 case PRIMITIVE_SHORT:
131 case PRIMITIVE_BOOLEAN:
132 case STRING:
133 return new SimpleElementValue(tag, input.readUnsignedShort(), cpool);
134
135 case ENUM_CONSTANT:
136 return new EnumElementValue(ENUM_CONSTANT, input.readUnsignedShort(), input.readUnsignedShort(), cpool);
137
138 case CLASS:
139 return new ClassElementValue(CLASS, input.readUnsignedShort(), cpool);
140
141 case ANNOTATION:
142 // TODO isRuntimeVisible
143 return new AnnotationElementValue(ANNOTATION, AnnotationEntry.read(input, cpool, false), cpool);
144
145 case ARRAY:
146 arrayNesting++;
147 if (arrayNesting > Const.MAX_ARRAY_DIMENSIONS) {
148 // JVM spec 4.4.1
149 throw new ClassFormatException(String.format("Arrays are only valid if they represent %,d or fewer dimensions.", Const.MAX_ARRAY_DIMENSIONS));
150 }
151 final int numArrayVals = input.readUnsignedShort();
152 final ElementValue[] evalues = new ElementValue[numArrayVals];
153 for (int j = 0; j < numArrayVals; j++) {
154 evalues[j] = readElementValue(input, cpool, arrayNesting);
155 }
156 return new ArrayElementValue(ARRAY, evalues, cpool);
157
158 default:
159 throw new ClassFormatException("Unexpected element value tag in annotation: " + tag);
160 }
161 }
162
163 /**
164 * @deprecated (since 6.0) will be made private and final; do not access directly, use getter.
165 */
166 @java.lang.Deprecated
167 protected int type; // TODO should be final
168
169 /**
170 * @deprecated (since 6.0) will be made private and final; do not access directly, use getter.
171 */
172 @java.lang.Deprecated
173 protected ConstantPool cpool; // TODO should be final
174
175 /**
176 * Constructs an ElementValue.
177 *
178 * @param type the element value type.
179 * @param cpool the constant pool.
180 */
181 protected ElementValue(final int type, final ConstantPool cpool) {
182 this.type = type;
183 this.cpool = cpool;
184 }
185
186 /**
187 * Dumps this element value to a DataOutputStream.
188 *
189 * @param dos the output stream.
190 * @throws IOException if an I/O error occurs.
191 */
192 public abstract void dump(DataOutputStream dos) throws IOException;
193
194 /**
195 * Gets the constant pool.
196 *
197 * @return the constant pool.
198 * @since 6.0
199 */
200 final ConstantPool getConstantPool() {
201 return cpool;
202 }
203
204 /**
205 * Gets the element value type.
206 *
207 * @return the element value type.
208 */
209 public int getElementValueType() {
210 return type;
211 }
212
213 /**
214 * Gets the type.
215 *
216 * @return the type.
217 * @since 6.0
218 */
219 final int getType() {
220 return type;
221 }
222
223 /**
224 * Returns a string representation of the element value.
225 *
226 * @return a string representation of the element value.
227 */
228 public abstract String stringifyValue();
229
230 /**
231 * Returns a short string representation of the element value.
232 *
233 * @return a short string representation of the element value.
234 */
235 public String toShortString() {
236 return stringifyValue();
237 }
238
239 /**
240 * Returns a string representation of the element value.
241 *
242 * @return a string representation of the element value.
243 */
244 @Override
245 public String toString() {
246 return stringifyValue();
247 }
248 }