    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}