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