1/*
2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
3 */
4/*
5 * Licensed to the Apache Software Foundation (ASF) under one or more
6 * contributor license agreements.  See the NOTICE file distributed with
7 * this work for additional information regarding copyright ownership.
8 * The ASF licenses this file to You under the Apache License, Version 2.0
9 * (the "License"); you may not use this file except in compliance with
10 * the License.  You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21package com.sun.org.apache.bcel.internal.generic;
22
23import java.io.DataInput;
24import java.io.DataOutputStream;
25import java.io.IOException;
26
27import com.sun.org.apache.bcel.internal.classfile.AnnotationElementValue;
28import com.sun.org.apache.bcel.internal.classfile.AnnotationEntry;
29import com.sun.org.apache.bcel.internal.classfile.ArrayElementValue;
30import com.sun.org.apache.bcel.internal.classfile.ClassElementValue;
31import com.sun.org.apache.bcel.internal.classfile.ElementValue;
32import com.sun.org.apache.bcel.internal.classfile.EnumElementValue;
33import com.sun.org.apache.bcel.internal.classfile.SimpleElementValue;
34
35/**
36 * @since 6.0
37 */
38public abstract class ElementValueGen
39{
40    private final int type;
41    private final ConstantPoolGen cpGen;
42
43    protected ElementValueGen(final int type, final ConstantPoolGen cpGen)
44    {
45        this.type = type;
46        this.cpGen = cpGen;
47    }
48
49    /**
50     * Subtypes return an immutable variant of the ElementValueGen
51     */
52    public abstract ElementValue getElementValue();
53
54    public int getElementValueType()
55    {
56        return type;
57    }
58
59    public abstract String stringifyValue();
60
61    public abstract void dump(DataOutputStream dos) throws IOException;
62
63    public static final int STRING = 's';
64
65    public static final int ENUM_CONSTANT = 'e';
66
67    public static final int CLASS = 'c';
68
69    public static final int ANNOTATION = '@';
70
71    public static final int ARRAY = '[';
72
73    public static final int PRIMITIVE_INT = 'I';
74
75    public static final int PRIMITIVE_BYTE = 'B';
76
77    public static final int PRIMITIVE_CHAR = 'C';
78
79    public static final int PRIMITIVE_DOUBLE = 'D';
80
81    public static final int PRIMITIVE_FLOAT = 'F';
82
83    public static final int PRIMITIVE_LONG = 'J';
84
85    public static final int PRIMITIVE_SHORT = 'S';
86
87    public static final int PRIMITIVE_BOOLEAN = 'Z';
88
89    public static ElementValueGen readElementValue(final DataInput dis,
90            final ConstantPoolGen cpGen) throws IOException
91    {
92        final int type = dis.readUnsignedByte();
93        switch (type)
94        {
95        case 'B': // byte
96            return new SimpleElementValueGen(PRIMITIVE_BYTE, dis
97                    .readUnsignedShort(), cpGen);
98        case 'C': // char
99            return new SimpleElementValueGen(PRIMITIVE_CHAR, dis
100                    .readUnsignedShort(), cpGen);
101        case 'D': // double
102            return new SimpleElementValueGen(PRIMITIVE_DOUBLE, dis
103                    .readUnsignedShort(), cpGen);
104        case 'F': // float
105            return new SimpleElementValueGen(PRIMITIVE_FLOAT, dis
106                    .readUnsignedShort(), cpGen);
107        case 'I': // int
108            return new SimpleElementValueGen(PRIMITIVE_INT, dis
109                    .readUnsignedShort(), cpGen);
110        case 'J': // long
111            return new SimpleElementValueGen(PRIMITIVE_LONG, dis
112                    .readUnsignedShort(), cpGen);
113        case 'S': // short
114            return new SimpleElementValueGen(PRIMITIVE_SHORT, dis
115                    .readUnsignedShort(), cpGen);
116        case 'Z': // boolean
117            return new SimpleElementValueGen(PRIMITIVE_BOOLEAN, dis
118                    .readUnsignedShort(), cpGen);
119        case 's': // String
120            return new SimpleElementValueGen(STRING, dis.readUnsignedShort(),
121                    cpGen);
122        case 'e': // Enum constant
123            return new EnumElementValueGen(dis.readUnsignedShort(), dis
124                    .readUnsignedShort(), cpGen);
125        case 'c': // Class
126            return new ClassElementValueGen(dis.readUnsignedShort(), cpGen);
127        case '@': // Annotation
128            // TODO: isRuntimeVisible ??????????
129            // FIXME
130            return new AnnotationElementValueGen(ANNOTATION,
131                    new AnnotationEntryGen(AnnotationEntry.read(dis, cpGen
132                            .getConstantPool(), true), cpGen, false), cpGen);
133        case '[': // Array
134            final int numArrayVals = dis.readUnsignedShort();
135            final ElementValue[] evalues = new ElementValue[numArrayVals];
136            for (int j = 0; j < numArrayVals; j++)
137            {
138                evalues[j] = ElementValue.readElementValue(dis, cpGen
139                        .getConstantPool());
140            }
141            return new ArrayElementValueGen(ARRAY, evalues, cpGen);
142        default:
143            throw new RuntimeException("Unexpected element value kind in annotation: " + type);
144        }
145    }
146
147    protected ConstantPoolGen getConstantPool()
148    {
149        return cpGen;
150    }
151
152    /**
153     * Creates an (modifiable) ElementValueGen copy of an (immutable)
154     * ElementValue - constant pool is assumed correct.
155     */
156    public static ElementValueGen copy(final ElementValue value,
157            final ConstantPoolGen cpool, final boolean copyPoolEntries)
158    {
159        switch (value.getElementValueType())
160        {
161        case 'B': // byte
162        case 'C': // char
163        case 'D': // double
164        case 'F': // float
165        case 'I': // int
166        case 'J': // long
167        case 'S': // short
168        case 'Z': // boolean
169        case 's': // String
170            return new SimpleElementValueGen((SimpleElementValue) value, cpool,
171                    copyPoolEntries);
172        case 'e': // Enum constant
173            return new EnumElementValueGen((EnumElementValue) value, cpool,
174                    copyPoolEntries);
175        case '@': // Annotation
176            return new AnnotationElementValueGen(
177                    (AnnotationElementValue) value, cpool, copyPoolEntries);
178        case '[': // Array
179            return new ArrayElementValueGen((ArrayElementValue) value, cpool,
180                    copyPoolEntries);
181        case 'c': // Class
182            return new ClassElementValueGen((ClassElementValue) value, cpool,
183                    copyPoolEntries);
184        default:
185            throw new RuntimeException("Not implemented yet! (" + value.getElementValueType() + ")");
186        }
187    }
188}
189