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.Arrays; 024 025import org.apache.bcel.Const; 026import org.apache.commons.lang3.ArrayUtils; 027 028/** 029 * This class is derived from <em>Attribute</em> and represents the list of packages that are exported or opened by the 030 * Module attribute. There may be at most one ModulePackages attribute in a ClassFile structure. 031 * 032 * @see Attribute 033 */ 034public final class ModulePackages extends Attribute { 035 036 private int[] packageIndexTable; 037 038 /** 039 * Construct object from input stream. 040 * 041 * @param name_index Index in constant pool 042 * @param length Content length in bytes 043 * @param input Input stream 044 * @param constant_pool Array of constants 045 * @throws IOException if an I/O error occurs. 046 */ 047 ModulePackages(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool) throws IOException { 048 this(name_index, length, (int[]) null, constant_pool); 049 final int number_of_packages = input.readUnsignedShort(); 050 packageIndexTable = new int[number_of_packages]; 051 for (int i = 0; i < number_of_packages; i++) { 052 packageIndexTable[i] = input.readUnsignedShort(); 053 } 054 } 055 056 /** 057 * @param nameIndex Index in constant pool 058 * @param length Content length in bytes 059 * @param packageIndexTable Table of indices in constant pool 060 * @param constantPool Array of constants 061 */ 062 public ModulePackages(final int nameIndex, final int length, final int[] packageIndexTable, final ConstantPool constantPool) { 063 super(Const.ATTR_MODULE_PACKAGES, nameIndex, length, constantPool); 064 this.packageIndexTable = packageIndexTable != null ? packageIndexTable : ArrayUtils.EMPTY_INT_ARRAY; 065 } 066 067 /** 068 * Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a 069 * physical copy. 070 */ 071 public ModulePackages(final ModulePackages c) { 072 this(c.getNameIndex(), c.getLength(), c.getPackageIndexTable(), c.getConstantPool()); 073 } 074 075 /** 076 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. 077 * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. 078 * 079 * @param v Visitor object 080 */ 081 @Override 082 public void accept(final Visitor v) { 083 v.visitModulePackages(this); 084 } 085 086 /** 087 * @return deep copy of this attribute 088 */ 089 @Override 090 public Attribute copy(final ConstantPool constantPool) { 091 final ModulePackages c = (ModulePackages) clone(); 092 if (packageIndexTable != null) { 093 c.packageIndexTable = new int[packageIndexTable.length]; 094 System.arraycopy(packageIndexTable, 0, c.packageIndexTable, 0, packageIndexTable.length); 095 } 096 c.setConstantPool(constantPool); 097 return c; 098 } 099 100 /** 101 * Dump ModulePackages 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 void dump(final DataOutputStream file) throws IOException { 108 super.dump(file); 109 file.writeShort(packageIndexTable.length); 110 for (final int index : packageIndexTable) { 111 file.writeShort(index); 112 } 113 } 114 115 /** 116 * @return Length of package table. 117 */ 118 public int getNumberOfPackages() { 119 return packageIndexTable == null ? 0 : packageIndexTable.length; 120 } 121 122 /** 123 * @return array of indices into constant pool of package names. 124 */ 125 public int[] getPackageIndexTable() { 126 return packageIndexTable; 127 } 128 129 /** 130 * @return string array of package names 131 */ 132 public String[] getPackageNames() { 133 final String[] names = new String[packageIndexTable.length]; 134 Arrays.setAll(names, i -> Utility.pathToPackage(super.getConstantPool().getConstantString(packageIndexTable[i], Const.CONSTANT_Package))); 135 return names; 136 } 137 138 /** 139 * @param packageIndexTable the list of package indexes Also redefines number_of_packages according to table length. 140 */ 141 public void setPackageIndexTable(final int[] packageIndexTable) { 142 this.packageIndexTable = packageIndexTable != null ? packageIndexTable : ArrayUtils.EMPTY_INT_ARRAY; 143 } 144 145 /** 146 * @return String representation, i.e., a list of packages. 147 */ 148 @Override 149 public String toString() { 150 final StringBuilder buf = new StringBuilder(); 151 buf.append("ModulePackages("); 152 buf.append(packageIndexTable.length); 153 buf.append("):\n"); 154 for (final int index : packageIndexTable) { 155 final String package_name = super.getConstantPool().getConstantString(index, Const.CONSTANT_Package); 156 buf.append(" ").append(Utility.compactClassName(package_name, false)).append("\n"); 157 } 158 return buf.substring(0, buf.length() - 1); // remove the last newline 159 } 160}