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.generic;
019
020import java.io.DataOutputStream;
021import java.io.IOException;
022
023import org.apache.bcel.ExceptionConst;
024import org.apache.bcel.util.ByteSequence;
025
026/** 
027 * LDC - Push item from constant pool.
028 *
029 * <PRE>Stack: ... -&gt; ..., item</PRE>
030 *
031 * @version $Id: LDC.java 1749603 2016-06-21 20:50:19Z ggregory $
032 */
033public class LDC extends CPInstruction implements PushInstruction, ExceptionThrower {
034
035    /**
036     * Empty constructor needed for the Class.newInstance() statement in
037     * Instruction.readInstruction(). Not to be used otherwise.
038     */
039    LDC() {
040    }
041
042
043    public LDC(final int index) {
044        super(org.apache.bcel.Const.LDC_W, index);
045        setSize();
046    }
047
048
049    // Adjust to proper size
050    protected final void setSize() {
051        if (super.getIndex() <= org.apache.bcel.Const.MAX_BYTE) { // Fits in one byte?
052            super.setOpcode(org.apache.bcel.Const.LDC);
053            super.setLength(2);
054        } else {
055            super.setOpcode(org.apache.bcel.Const.LDC_W);
056            super.setLength(3);
057        }
058    }
059
060
061    /**
062     * Dump instruction as byte code to stream out.
063     * @param out Output stream
064     */
065    @Override
066    public void dump( final DataOutputStream out ) throws IOException {
067        out.writeByte(super.getOpcode());
068        if (super.getLength() == 2) { // TODO useless check?
069            out.writeByte(super.getIndex());
070        } else {
071            out.writeShort(super.getIndex());
072        }
073    }
074
075
076    /**
077     * Set the index to constant pool and adjust size.
078     */
079    @Override
080    public final void setIndex( final int index ) {
081        super.setIndex(index);
082        setSize();
083    }
084
085
086    /**
087     * Read needed data (e.g. index) from file.
088     */
089    @Override
090    protected void initFromFile( final ByteSequence bytes, final boolean wide ) throws IOException {
091        super.setLength(2);
092        super.setIndex(bytes.readUnsignedByte());
093    }
094
095
096    public Object getValue( final ConstantPoolGen cpg ) {
097        org.apache.bcel.classfile.Constant c = cpg.getConstantPool().getConstant(super.getIndex());
098        switch (c.getTag()) {
099            case org.apache.bcel.Const.CONSTANT_String:
100                final int i = ((org.apache.bcel.classfile.ConstantString) c).getStringIndex();
101                c = cpg.getConstantPool().getConstant(i);
102                return ((org.apache.bcel.classfile.ConstantUtf8) c).getBytes();
103            case org.apache.bcel.Const.CONSTANT_Float:
104                return new Float(((org.apache.bcel.classfile.ConstantFloat) c).getBytes());
105            case org.apache.bcel.Const.CONSTANT_Integer:
106                return Integer.valueOf(((org.apache.bcel.classfile.ConstantInteger) c).getBytes());
107            case org.apache.bcel.Const.CONSTANT_Class:
108                final int nameIndex = ((org.apache.bcel.classfile.ConstantClass) c).getNameIndex();
109                c = cpg.getConstantPool().getConstant(nameIndex);
110                return new ObjectType(((org.apache.bcel.classfile.ConstantUtf8) c).getBytes());
111            default: // Never reached
112                throw new RuntimeException("Unknown or invalid constant type at " + super.getIndex());
113        }
114    }
115
116
117    @Override
118    public Type getType( final ConstantPoolGen cpg ) {
119        switch (cpg.getConstantPool().getConstant(super.getIndex()).getTag()) {
120            case org.apache.bcel.Const.CONSTANT_String:
121                return Type.STRING;
122            case org.apache.bcel.Const.CONSTANT_Float:
123                return Type.FLOAT;
124            case org.apache.bcel.Const.CONSTANT_Integer:
125                return Type.INT;
126            case org.apache.bcel.Const.CONSTANT_Class:
127                return Type.CLASS;
128            default: // Never reached
129                throw new RuntimeException("Unknown or invalid constant type at " + super.getIndex());
130        }
131    }
132
133
134    @Override
135    public Class<?>[] getExceptions() {
136        return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_STRING_RESOLUTION);
137    }
138
139
140    /**
141     * Call corresponding visitor method(s). The order is:
142     * Call visitor methods of implemented interfaces first, then
143     * call methods according to the class hierarchy in descending order,
144     * i.e., the most specific visitXXX() call comes last.
145     *
146     * @param v Visitor object
147     */
148    @Override
149    public void accept( final Visitor v ) {
150        v.visitStackProducer(this);
151        v.visitPushInstruction(this);
152        v.visitExceptionThrower(this);
153        v.visitTypedInstruction(this);
154        v.visitCPInstruction(this);
155        v.visitLDC(this);
156    }
157}