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