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