    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 a BootstrapMethods attribute.
    028 *
    029 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23">
    030 * The class File Format : The BootstrapMethods Attribute</a>
    031 * @since 6.0
    032 */
    033public class BootstrapMethods extends Attribute {
    034
    035    private BootstrapMethod[] bootstrapMethods;  // TODO this could be made final (setter is not used)
    036
    037    /**
    038     * Initialize from another object. Note that both objects use the same
    039     * references (shallow copy). Use clone() for a physical copy.
    040     */
    041    public BootstrapMethods(final BootstrapMethods c) {
    042        this(c.getNameIndex(), c.getLength(), c.getBootstrapMethods(), c.getConstantPool());
    043    }
    044
    045
    046    /**
    047     * @param name_index Index in constant pool to CONSTANT_Utf8
    048     * @param length Content length in bytes
    049     * @param bootstrapMethods array of bootstrap methods
    050     * @param constant_pool Array of constants
    051     */
    052    public BootstrapMethods(final int name_index, final int length, final BootstrapMethod[] bootstrapMethods, final ConstantPool constant_pool) {
    053        super(Const.ATTR_BOOTSTRAP_METHODS, name_index, length, constant_pool);
    054        this.bootstrapMethods = bootstrapMethods;
    055    }
    056
    057    /**
    058     * Construct object from Input stream.
    059     *
    060     * @param name_index Index in constant pool to CONSTANT_Utf8
    061     * @param length Content length in bytes
    062     * @param input Input stream
    063     * @param constant_pool Array of constants
    064     * @throws IOException
    065     */
    066    BootstrapMethods(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool) throws IOException {
    067        this(name_index, length, (BootstrapMethod[]) null, constant_pool);
    068
    069        final int num_bootstrap_methods = input.readUnsignedShort();
    070        bootstrapMethods = new BootstrapMethod[num_bootstrap_methods];
    071        for (int i = 0; i < num_bootstrap_methods; i++) {
    072            bootstrapMethods[i] = new BootstrapMethod(input);
    073        }
    074    }
    075
    076    /**
    077     * @return array of bootstrap method "records"
    078     */
    079    public final BootstrapMethod[] getBootstrapMethods() {
    080        return bootstrapMethods;
    081    }
    082
    083    /**
    084     * @param bootstrapMethods the array of bootstrap methods
    085     */
    086    public final void setBootstrapMethods(final BootstrapMethod[] bootstrapMethods) {
    087        this.bootstrapMethods = bootstrapMethods;
    088    }
    089
    090    /**
    091     * @param v Visitor object
    092     */
    093    @Override
    094    public void accept(final Visitor v) {
    095        v.visitBootstrapMethods(this);
    096    }
    097
    098    /**
    099     * @return deep copy of this attribute
    100     */
    101    @Override
    102    public BootstrapMethods copy(final ConstantPool _constant_pool) {
    103        final BootstrapMethods c = (BootstrapMethods) clone();
    104        c.bootstrapMethods = new BootstrapMethod[bootstrapMethods.length];
    105
    106        for (int i = 0; i < bootstrapMethods.length; i++) {
    107            c.bootstrapMethods[i] = bootstrapMethods[i].copy();
    108        }
    109        c.setConstantPool(_constant_pool);
    110        return c;
    111    }
    112
    113    /**
    114     * Dump bootstrap methods attribute to file stream in binary format.
    115     *
    116     * @param file Output file stream
    117     * @throws IOException
    118     */
    119    @Override
    120    public final void dump(final DataOutputStream file) throws IOException {
    121        super.dump(file);
    122
    123        file.writeShort(bootstrapMethods.length);
    124        for (final BootstrapMethod bootstrap_method : bootstrapMethods) {
    125            bootstrap_method.dump(file);
    126        }
    127    }
    128
    129    /**
    130     * @return String representation.
    131     */
    132    @Override
    133    public final String toString() {
    134        final StringBuilder buf = new StringBuilder();
    135        buf.append("BootstrapMethods(");
    136        buf.append(bootstrapMethods.length);
    137        buf.append("):");
    138        for (int i = 0; i < bootstrapMethods.length; i++) {
    139            buf.append("\n");
    140            final int start = buf.length();
    141            buf.append("  ").append(i).append(": ");
    142            final int indent_count = buf.length() - start;
    143            final String[] lines = (bootstrapMethods[i].toString(super.getConstantPool())).split("\\r?\\n");
    144            buf.append(lines[0]);
    145            for (int j = 1; j < lines.length; j++) {
    146                buf.append("\n").append("          ".substring(0,indent_count)).append(lines[j]);
    147            }
    148        }
    149        return buf.toString();
    150    }
    151}