001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   https://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019
020package org.apache.bcel.classfile;
021
022import java.io.DataInput;
023import java.io.DataOutputStream;
024import java.io.IOException;
025import java.util.Arrays;
026
027import org.apache.bcel.Const;
028import org.apache.commons.lang3.ArrayUtils;
029
030/**
031 * This class represents a bootstrap method attribute, that is, the bootstrap method ref, the number of bootstrap arguments
032 * and an array of the bootstrap arguments.
033 *
034 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23"> The class File Format :
035 *      The BootstrapMethods Attribute</a>
036 * @since 6.0
037 */
038public class BootstrapMethod implements Cloneable {
039
040    static final BootstrapMethod[] EMPTY_ARRAY = {};
041
042    /** Index of the CONSTANT_MethodHandle_info structure in the constant_pool table */
043    private int bootstrapMethodRef;
044
045    /** Array of references to the constant_pool table */
046    private int[] bootstrapArguments;
047
048    /**
049     * Initialize from another object.
050     *
051     * @param c Source to copy.
052     */
053    public BootstrapMethod(final BootstrapMethod c) {
054        this(c.getBootstrapMethodRef(), c.getBootstrapArguments());
055    }
056
057    /**
058     * Constructs object from input stream.
059     *
060     * @param input Input stream.
061     * @throws IOException if an I/O error occurs.
062     */
063    BootstrapMethod(final DataInput input) throws IOException {
064        this(input.readUnsignedShort(), input.readUnsignedShort());
065
066        for (int i = 0; i < bootstrapArguments.length; i++) {
067            bootstrapArguments[i] = input.readUnsignedShort();
068        }
069    }
070
071    // helper method
072    private BootstrapMethod(final int bootstrapMethodRef, final int numBootstrapArguments) {
073        this(bootstrapMethodRef, new int[numBootstrapArguments]);
074    }
075
076    /**
077     * Constructs a BootstrapMethod.
078     *
079     * @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle.
080     * @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info.
081     */
082    public BootstrapMethod(final int bootstrapMethodRef, final int[] bootstrapArguments) {
083        this.bootstrapMethodRef = bootstrapMethodRef;
084        setBootstrapArguments(bootstrapArguments);
085    }
086
087    /**
088     * Creates a deep copy of this object.
089     *
090     * @return deep copy of this object.
091     */
092    public BootstrapMethod copy() {
093        try {
094            return (BootstrapMethod) clone();
095        } catch (final CloneNotSupportedException ignore) {
096            // TODO should this throw?
097        }
098        return null;
099    }
100
101    /**
102     * Dumps object to file stream in binary format.
103     *
104     * @param file Output file stream.
105     * @throws IOException if an I/O error occurs.
106     */
107    public final void dump(final DataOutputStream file) throws IOException {
108        file.writeShort(bootstrapMethodRef);
109        file.writeShort(bootstrapArguments.length);
110        for (final int bootstrapArgument : bootstrapArguments) {
111            file.writeShort(bootstrapArgument);
112        }
113    }
114
115    /**
116     * Gets the bootstrap arguments.
117     *
118     * @return int[] of bootstrap_method indices into constant_pool of CONSTANT_[type]_info.
119     */
120    public int[] getBootstrapArguments() {
121        return bootstrapArguments;
122    }
123
124    /**
125     * Gets the bootstrap method reference.
126     *
127     * @return index into constant_pool of bootstrap_method.
128     */
129    public int getBootstrapMethodRef() {
130        return bootstrapMethodRef;
131    }
132
133    /**
134     * Gets the count of number of bootstrap arguments.
135     *
136     * @return count of number of bootstrap arguments.
137     */
138    public int getNumBootstrapArguments() {
139        return bootstrapArguments.length;
140    }
141
142    /**
143     * Sets the bootstrap arguments.
144     *
145     * @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info.
146     */
147    public void setBootstrapArguments(final int[] bootstrapArguments) {
148        this.bootstrapArguments = ArrayUtils.nullToEmpty(bootstrapArguments);
149    }
150
151    /**
152     * Sets the bootstrap method reference.
153     *
154     * @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle.
155     */
156    public void setBootstrapMethodRef(final int bootstrapMethodRef) {
157        this.bootstrapMethodRef = bootstrapMethodRef;
158    }
159
160    /**
161     * Gets a string representation.
162     *
163     * @return String representation.
164     */
165    @Override
166    public final String toString() {
167        return "BootstrapMethod(" + bootstrapMethodRef + ", " + bootstrapArguments.length + ", " + Arrays.toString(bootstrapArguments) + ")";
168    }
169
170    /**
171     * Gets a resolved string representation.
172     *
173     * @param constantPool the constant pool.
174     * @return Resolved string representation.
175     */
176    public final String toString(final ConstantPool constantPool) {
177        final StringBuilder buf = new StringBuilder();
178        final String bootstrapMethodName = constantPool.constantToString(bootstrapMethodRef, Const.CONSTANT_MethodHandle);
179        buf.append(Utility.compactClassName(bootstrapMethodName, false));
180        final int bootstrapArgumentsLen = bootstrapArguments.length;
181        if (bootstrapArgumentsLen > 0) {
182            buf.append("\nMethod Arguments:");
183            for (int i = 0; i < bootstrapArgumentsLen; i++) {
184                buf.append("\n  ").append(i).append(": ");
185                buf.append(constantPool.constantToString(constantPool.getConstant(bootstrapArguments[i])));
186            }
187        }
188        return buf.toString();
189    }
190}