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 an entry in the opens table of the Module attribute.
028 * Each entry describes a package which the parent module opens.
029 *
030 * @see   Module
031 * @since 6.4.0
032 */
033public final class ModuleOpens implements Cloneable, Node {
034
035    private final int opens_index;  // points to CONSTANT_Package_info
036    private final int opens_flags;
037    private final int opens_to_count;
038    private final int[] opens_to_index;  // points to CONSTANT_Module_info
039
040
041    /**
042     * Construct object from file stream.
043     *
044     * @param file Input stream
045     * @throws IOException if an I/O Exception occurs in readUnsignedShort
046     */
047    ModuleOpens(final DataInput file) throws IOException {
048        opens_index = file.readUnsignedShort();
049        opens_flags = file.readUnsignedShort();
050        opens_to_count = file.readUnsignedShort();
051        opens_to_index = new int[opens_to_count];
052        for (int i = 0; i < opens_to_count; i++) {
053            opens_to_index[i] = file.readUnsignedShort();
054        }
055    }
056
057
058    /**
059     * Called by objects that are traversing the nodes of the tree implicitely
060     * defined by the contents of a Java class. I.e., the hierarchy of methods,
061     * fields, attributes, etc. spawns a tree of objects.
062     *
063     * @param v Visitor object
064     */
065    @Override
066    public void accept( final Visitor v ) {
067        v.visitModuleOpens(this);
068    }
069
070    // TODO add more getters and setters?
071
072    /**
073     * Dump table entry to file stream in binary format.
074     *
075     * @param file Output file stream
076     * @throws IOException if an I/O Exception occurs in writeShort
077     */
078    public void dump( final DataOutputStream file ) throws IOException {
079        file.writeShort(opens_index);
080        file.writeShort(opens_flags);
081        file.writeShort(opens_to_count);
082        for (final int entry : opens_to_index) {
083            file.writeShort(entry);
084        }
085    }
086
087
088    /**
089     * @return String representation
090     */
091    @Override
092    public String toString() {
093        return "opens(" + opens_index + ", " + opens_flags + ", " + opens_to_count + ", ...)";
094    }
095
096
097    /**
098     * @return Resolved string representation
099     */
100    public String toString( final ConstantPool constant_pool ) {
101        final StringBuilder buf = new StringBuilder();
102        final String package_name = constant_pool.constantToString(opens_index, Const.CONSTANT_Package);
103        buf.append(Utility.compactClassName(package_name, false));
104        buf.append(", ").append(String.format("%04x", opens_flags));
105        buf.append(", to(").append(opens_to_count).append("):\n");
106        for (final int index : opens_to_index) {
107            final String module_name = constant_pool.getConstantString(index, Const.CONSTANT_Module);
108            buf.append("      ").append(Utility.compactClassName(module_name, false)).append("\n");
109        }
110        return buf.substring(0, buf.length()-1); // remove the last newline
111    }
112
113
114    /**
115     * @return deep copy of this object
116     */
117    public ModuleOpens copy() {
118        try {
119            return (ModuleOpens) clone();
120        } catch (final CloneNotSupportedException e) {
121            // TODO should this throw?
122        }
123        return null;
124    }
125}