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 */
019package org.apache.bcel.generic;
020
021import java.io.DataOutputStream;
022import java.io.IOException;
023
024import org.apache.bcel.classfile.ConstantDouble;
025import org.apache.bcel.classfile.ConstantFloat;
026import org.apache.bcel.classfile.ConstantInteger;
027import org.apache.bcel.classfile.ConstantLong;
028import org.apache.bcel.classfile.ConstantUtf8;
029import org.apache.bcel.classfile.ElementValue;
030import org.apache.bcel.classfile.SimpleElementValue;
031
032/**
033 * Generates simple element values in annotations.
034 *
035 * @since 6.0
036 */
037public class SimpleElementValueGen extends ElementValueGen {
038    // For primitive types and string type, this points to the value entry in
039    // the cpGen
040    // For 'class' this points to the class entry in the cpGen
041    private final int idx;
042
043    public SimpleElementValueGen(final int type, final ConstantPoolGen cpGen, final boolean value) {
044        super(type, cpGen);
045        if (value) {
046            idx = getConstantPool().addInteger(1);
047        } else {
048            idx = getConstantPool().addInteger(0);
049        }
050    }
051
052    public SimpleElementValueGen(final int type, final ConstantPoolGen cpGen, final byte value) {
053        super(type, cpGen);
054        idx = getConstantPool().addInteger(value);
055    }
056
057    public SimpleElementValueGen(final int type, final ConstantPoolGen cpGen, final char value) {
058        super(type, cpGen);
059        idx = getConstantPool().addInteger(value);
060    }
061
062    public SimpleElementValueGen(final int type, final ConstantPoolGen cpGen, final double value) {
063        super(type, cpGen);
064        idx = getConstantPool().addDouble(value);
065    }
066
067    public SimpleElementValueGen(final int type, final ConstantPoolGen cpGen, final float value) {
068        super(type, cpGen);
069        idx = getConstantPool().addFloat(value);
070    }
071
072    public SimpleElementValueGen(final int type, final ConstantPoolGen cpGen, final int value) {
073        super(type, cpGen);
074        idx = getConstantPool().addInteger(value);
075    }
076
077    public SimpleElementValueGen(final int type, final ConstantPoolGen cpGen, final long value) {
078        super(type, cpGen);
079        idx = getConstantPool().addLong(value);
080    }
081
082    public SimpleElementValueGen(final int type, final ConstantPoolGen cpGen, final short value) {
083        super(type, cpGen);
084        idx = getConstantPool().addInteger(value);
085    }
086
087    public SimpleElementValueGen(final int type, final ConstantPoolGen cpGen, final String value) {
088        super(type, cpGen);
089        idx = getConstantPool().addUtf8(value);
090    }
091
092    // ctors for each supported type... type could be inferred but for now lets
093    // force it to be passed
094
095    /**
096     * Protected ctor used for deserialization, doesn't *put* an entry in the constant pool, assumes the one at the supplied
097     * index is correct.
098     */
099    protected SimpleElementValueGen(final int type, final int idx, final ConstantPoolGen cpGen) {
100        super(type, cpGen);
101        this.idx = idx;
102    }
103
104    /**
105     * The boolean controls whether we copy info from the 'old' constant pool to the 'new'. You need to use this ctor if the
106     * annotation is being copied from one file to another.
107     */
108    public SimpleElementValueGen(final SimpleElementValue value, final ConstantPoolGen cpool, final boolean copyPoolEntries) {
109        super(value.getElementValueType(), cpool);
110        if (!copyPoolEntries) {
111            // J5ASSERT: Could assert value.stringifyValue() is the same as
112            // cpool.getConstant(SimpleElementValuevalue.getIndex())
113            idx = value.getIndex();
114        } else {
115            switch (value.getElementValueType()) {
116            case STRING:
117                idx = cpool.addUtf8(value.getValueString());
118                break;
119            case PRIMITIVE_INT:
120                idx = cpool.addInteger(value.getValueInt());
121                break;
122            case PRIMITIVE_BYTE:
123                idx = cpool.addInteger(value.getValueByte());
124                break;
125            case PRIMITIVE_CHAR:
126                idx = cpool.addInteger(value.getValueChar());
127                break;
128            case PRIMITIVE_LONG:
129                idx = cpool.addLong(value.getValueLong());
130                break;
131            case PRIMITIVE_FLOAT:
132                idx = cpool.addFloat(value.getValueFloat());
133                break;
134            case PRIMITIVE_DOUBLE:
135                idx = cpool.addDouble(value.getValueDouble());
136                break;
137            case PRIMITIVE_BOOLEAN:
138                if (value.getValueBoolean()) {
139                    idx = cpool.addInteger(1);
140                } else {
141                    idx = cpool.addInteger(0);
142                }
143                break;
144            case PRIMITIVE_SHORT:
145                idx = cpool.addInteger(value.getValueShort());
146                break;
147            default:
148                throw new IllegalArgumentException("SimpleElementValueGen class does not know how to copy this type " + super.getElementValueType());
149            }
150        }
151    }
152
153    @Override
154    public void dump(final DataOutputStream dos) throws IOException {
155        dos.writeByte(super.getElementValueType()); // u1 kind of value
156        switch (super.getElementValueType()) {
157        case PRIMITIVE_INT:
158        case PRIMITIVE_BYTE:
159        case PRIMITIVE_CHAR:
160        case PRIMITIVE_FLOAT:
161        case PRIMITIVE_LONG:
162        case PRIMITIVE_BOOLEAN:
163        case PRIMITIVE_SHORT:
164        case PRIMITIVE_DOUBLE:
165        case STRING:
166            dos.writeShort(idx);
167            break;
168        default:
169            throw new IllegalStateException("SimpleElementValueGen doesn't know how to write out type " + super.getElementValueType());
170        }
171    }
172
173    /**
174     * Return immutable variant
175     */
176    @Override
177    public ElementValue getElementValue() {
178        return new SimpleElementValue(super.getElementValueType(), idx, getConstantPool().getConstantPool());
179    }
180
181    public int getIndex() {
182        return idx;
183    }
184
185    public int getValueInt() {
186        if (super.getElementValueType() != PRIMITIVE_INT) {
187            throw new IllegalStateException("Don't call getValueString() on a non STRING ElementValue");
188        }
189        final ConstantInteger c = (ConstantInteger) getConstantPool().getConstant(idx);
190        return c.getBytes();
191    }
192
193    public String getValueString() {
194        if (super.getElementValueType() != STRING) {
195            throw new IllegalStateException("Don't call getValueString() on a non STRING ElementValue");
196        }
197        final ConstantUtf8 c = (ConstantUtf8) getConstantPool().getConstant(idx);
198        return c.getBytes();
199    }
200
201    // Whatever kind of value it is, return it as a string
202    @Override
203    public String stringifyValue() {
204        switch (super.getElementValueType()) {
205        case PRIMITIVE_INT:
206            final ConstantInteger c = (ConstantInteger) getConstantPool().getConstant(idx);
207            return Integer.toString(c.getBytes());
208        case PRIMITIVE_LONG:
209            final ConstantLong j = (ConstantLong) getConstantPool().getConstant(idx);
210            return Long.toString(j.getBytes());
211        case PRIMITIVE_DOUBLE:
212            final ConstantDouble d = (ConstantDouble) getConstantPool().getConstant(idx);
213            return Double.toString(d.getBytes());
214        case PRIMITIVE_FLOAT:
215            final ConstantFloat f = (ConstantFloat) getConstantPool().getConstant(idx);
216            return Float.toString(f.getBytes());
217        case PRIMITIVE_SHORT:
218            final ConstantInteger s = (ConstantInteger) getConstantPool().getConstant(idx);
219            return Integer.toString(s.getBytes());
220        case PRIMITIVE_BYTE:
221            final ConstantInteger b = (ConstantInteger) getConstantPool().getConstant(idx);
222            return Integer.toString(b.getBytes());
223        case PRIMITIVE_CHAR:
224            final ConstantInteger ch = (ConstantInteger) getConstantPool().getConstant(idx);
225            return Integer.toString(ch.getBytes());
226        case PRIMITIVE_BOOLEAN:
227            final ConstantInteger bo = (ConstantInteger) getConstantPool().getConstant(idx);
228            if (bo.getBytes() == 0) {
229                return "false";
230            }
231            return "true";
232        case STRING:
233            final ConstantUtf8 cu8 = (ConstantUtf8) getConstantPool().getConstant(idx);
234            return cu8.getBytes();
235        default:
236            throw new IllegalStateException("SimpleElementValueGen class does not know how to stringify type " + super.getElementValueType());
237        }
238    }
239}