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