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.classfile;
019
020import java.io.DataInput;
021import java.io.DataOutputStream;
022import java.io.IOException;
023
024import org.apache.bcel.Const;
025
026/**
027 * This class represents the type of a local variable or item on stack used in the StackMap entries.
028 *
029 * @see StackMapEntry
030 * @see StackMap
031 * @see Const
032 */
033public final class StackMapType implements Cloneable {
034
035    private byte type;
036    private int index = -1; // Index to CONSTANT_Class or offset
037    private ConstantPool constantPool;
038
039    /**
040     * @param type type tag as defined in the Constants interface
041     * @param index index to constant pool, or byte code offset
042     */
043    public StackMapType(final byte type, final int index, final ConstantPool constant_pool) {
044        if (type < Const.ITEM_Bogus || type > Const.ITEM_NewObject) {
045            throw new IllegalArgumentException("Illegal type for StackMapType: " + type);
046        }
047        this.type = type;
048        this.index = index;
049        this.constantPool = constant_pool;
050    }
051
052    /**
053     * Construct object from file stream.
054     *
055     * @param file Input stream
056     * @throws IOException if an I/O error occurs.
057     */
058    StackMapType(final DataInput file, final ConstantPool constant_pool) throws IOException {
059        this(file.readByte(), -1, constant_pool);
060        if (hasIndex()) {
061            this.index = file.readShort();
062        }
063        this.constantPool = constant_pool;
064    }
065
066    /**
067     * @return deep copy of this object
068     */
069    public StackMapType copy() {
070        try {
071            return (StackMapType) clone();
072        } catch (final CloneNotSupportedException e) {
073            // TODO should this throw?
074        }
075        return null;
076    }
077
078    /**
079     * Dump type entries to file.
080     *
081     * @param file Output file stream
082     * @throws IOException if an I/O error occurs.
083     */
084    public void dump(final DataOutputStream file) throws IOException {
085        file.writeByte(type);
086        if (hasIndex()) {
087            file.writeShort(getIndex());
088        }
089    }
090
091    /**
092     * @return Constant pool used by this object.
093     */
094    public ConstantPool getConstantPool() {
095        return constantPool;
096    }
097
098    /**
099     * @return index to constant pool if type == ITEM_Object, or offset in byte code, if type == ITEM_NewObject, and -1
100     *         otherwise
101     */
102    public int getIndex() {
103        return index;
104    }
105
106    public byte getType() {
107        return type;
108    }
109
110    /**
111     * @return true, if type is either ITEM_Object or ITEM_NewObject
112     */
113    public boolean hasIndex() {
114        return type == Const.ITEM_Object || type == Const.ITEM_NewObject;
115    }
116
117    private String printIndex() {
118        if (type == Const.ITEM_Object) {
119            if (index < 0) {
120                return ", class=<unknown>";
121            }
122            return ", class=" + constantPool.constantToString(index, Const.CONSTANT_Class);
123        }
124        if (type == Const.ITEM_NewObject) {
125            return ", offset=" + index;
126        }
127        return "";
128    }
129
130    /**
131     * @param constantPool Constant pool to be used for this object.
132     */
133    public void setConstantPool(final ConstantPool constantPool) {
134        this.constantPool = constantPool;
135    }
136
137    public void setIndex(final int t) {
138        index = t;
139    }
140
141    public void setType(final byte t) {
142        if (t < Const.ITEM_Bogus || t > Const.ITEM_NewObject) {
143            throw new IllegalArgumentException("Illegal type for StackMapType: " + t);
144        }
145        type = t;
146    }
147
148    /**
149     * @return String representation
150     */
151    @Override
152    public String toString() {
153        return "(type=" + Const.getItemName(type) + printIndex() + ")";
154    }
155}