1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * https://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 package org.apache.bcel.classfile;
21
22 import java.io.DataInput;
23 import java.io.DataOutputStream;
24 import java.io.IOException;
25 import java.util.Arrays;
26
27 import org.apache.bcel.Const;
28 import org.apache.bcel.util.Args;
29 import org.apache.commons.lang3.ArrayUtils;
30
31 /**
32 * This class is derived from <em>Attribute</em> and represents the list of packages that are exported or opened by the
33 * Module attribute. There may be at most one ModulePackages attribute in a ClassFile structure.
34 *
35 * @see Attribute
36 */
37 public final class ModulePackages extends Attribute {
38
39 private int[] packageIndexTable;
40
41 /**
42 * Constructs object from input stream.
43 *
44 * @param nameIndex Index in constant pool.
45 * @param length Content length in bytes.
46 * @param dataInput Input stream.
47 * @param constantPool Array of constants.
48 * @throws IOException Thrown if an I/O error occurs.
49 */
50 ModulePackages(final int nameIndex, final int length, final DataInput dataInput, final ConstantPool constantPool) throws IOException {
51 this(nameIndex, length, (int[]) null, constantPool);
52 packageIndexTable = ClassParser.readU2U2Table(dataInput);
53 }
54
55 /**
56 * Constructs a new ModulePackages.
57 *
58 * @param nameIndex Index in constant pool.
59 * @param length Content length in bytes.
60 * @param packageIndexTable Table of indices in constant pool.
61 * @param constantPool Array of constants.
62 */
63 public ModulePackages(final int nameIndex, final int length, final int[] packageIndexTable, final ConstantPool constantPool) {
64 super(Const.ATTR_MODULE_PACKAGES, nameIndex, length, constantPool);
65 this.packageIndexTable = ArrayUtils.nullToEmpty(packageIndexTable);
66 Args.requireU2(this.packageIndexTable.length, "packageIndexTable.length");
67 }
68
69 /**
70 * Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
71 * physical copy.
72 *
73 * @param c Source to copy.
74 */
75 public ModulePackages(final ModulePackages c) {
76 this(c.getNameIndex(), c.getLength(), c.getPackageIndexTable(), c.getConstantPool());
77 }
78
79 /**
80 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
81 * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
82 *
83 * @param v Visitor object.
84 */
85 @Override
86 public void accept(final Visitor v) {
87 v.visitModulePackages(this);
88 }
89
90 /**
91 * @return deep copy of this attribute.
92 */
93 @Override
94 public Attribute copy(final ConstantPool constantPool) {
95 final ModulePackages c = (ModulePackages) clone();
96 if (packageIndexTable != null) {
97 c.packageIndexTable = packageIndexTable.clone();
98 }
99 c.setConstantPool(constantPool);
100 return c;
101 }
102
103 /**
104 * Dumps ModulePackages attribute to file stream in binary format.
105 *
106 * @param file Output file stream.
107 * @throws IOException Thrown if an I/O error occurs.
108 */
109 @Override
110 public void dump(final DataOutputStream file) throws IOException {
111 super.dump(file);
112 file.writeShort(Args.requireU2(packageIndexTable.length, "packageIndexTable.length"));
113 for (final int index : packageIndexTable) {
114 file.writeShort(index);
115 }
116 }
117
118 /**
119 * Gets the number of packages.
120 *
121 * @return Length of package table.
122 */
123 public int getNumberOfPackages() {
124 return packageIndexTable == null ? 0 : packageIndexTable.length;
125 }
126
127 /**
128 * Gets the package index table.
129 *
130 * @return array of indices into constant pool of package names.
131 */
132 public int[] getPackageIndexTable() {
133 return packageIndexTable;
134 }
135
136 /**
137 * Gets the package names.
138 *
139 * @return string array of package names.
140 */
141 public String[] getPackageNames() {
142 final String[] names = new String[packageIndexTable.length];
143 Arrays.setAll(names, i -> Utility.pathToPackage(super.getConstantPool().getConstantString(packageIndexTable[i], Const.CONSTANT_Package)));
144 return names;
145 }
146
147 /**
148 * Sets the package index table.
149 *
150 * @param packageIndexTable The list of package indexes Also redefines number_of_packages according to table length.
151 */
152 public void setPackageIndexTable(final int[] packageIndexTable) {
153 this.packageIndexTable = ArrayUtils.nullToEmpty(packageIndexTable);
154 }
155
156 /**
157 * @return String representation, that is, a list of packages.
158 */
159 @Override
160 public String toString() {
161 final StringBuilder buf = new StringBuilder();
162 buf.append("ModulePackages(");
163 buf.append(packageIndexTable.length);
164 buf.append("):\n");
165 for (final int index : packageIndexTable) {
166 final String packageName = super.getConstantPool().getConstantString(index, Const.CONSTANT_Package);
167 buf.append(" ").append(Utility.compactClassName(packageName, false)).append("\n");
168 }
169 return buf.substring(0, buf.length() - 1); // remove the last newline
170 }
171 }