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}