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 exports table of the Module attribute. Each entry describes a package which may
028 * open the parent module.
029 *
030 * @see Module
031 * @since 6.4.0
032 */
033public final class ModuleExports implements Cloneable, Node {
034
035    private final int exportsIndex; // points to CONSTANT_Package_info
036    private final int exportsFlags;
037    private final int exportsToCount;
038    private final int[] exportsToIndex; // 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    ModuleExports(final DataInput file) throws IOException {
047        exportsIndex = file.readUnsignedShort();
048        exportsFlags = file.readUnsignedShort();
049        exportsToCount = file.readUnsignedShort();
050        exportsToIndex = new int[exportsToCount];
051        for (int i = 0; i < exportsToCount; i++) {
052            exportsToIndex[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.visitModuleExports(this);
065    }
066
067    // TODO add more getters and setters?
068
069    /**
070     * @return deep copy of this object
071     */
072    public ModuleExports copy() {
073        try {
074            return (ModuleExports) 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(exportsIndex);
089        file.writeShort(exportsFlags);
090        file.writeShort(exportsToCount);
091        for (final int entry : exportsToIndex) {
092            file.writeShort(entry);
093        }
094    }
095
096    /**
097     * @return String representation
098     */
099    @Override
100    public String toString() {
101        return "exports(" + exportsIndex + ", " + exportsFlags + ", " + exportsToCount + ", ...)";
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(exportsIndex, Const.CONSTANT_Package);
110        buf.append(Utility.compactClassName(packageName, false));
111        buf.append(", ").append(String.format("%04x", exportsFlags));
112        buf.append(", to(").append(exportsToCount).append("):\n");
113        for (final int index : exportsToIndex) {
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}