package org.aspectj.apache.bcel.classfile;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.aspectj.apache.bcel.Constants;
public final class Module extends Attribute {
private static final String[] NO_MODULE_NAMES = {};
private int moduleNameIndex;
private int moduleFlags;
private int moduleVersionIndex;
private Require[] requires;
private Export[] exports;
private Open[] opens;
private Uses[] uses;
private Provide[] provides;
private byte[] moduleInfo;
private int ptr;
private boolean unpacked = false;
public Module(Module module) {
super(module.getTag(), module.getNameIndex(), module.getLength(), module.getConstantPool());
moduleInfo = module.getBytes();
}
public Module(int nameIndex, int length, byte[] data, ConstantPool cp) {
super(Constants.ATTR_MODULE, nameIndex, length, cp);
}
Module(int nameIndex, int length, DataInputStream stream, ConstantPool cp) throws IOException {
this(nameIndex, length, (byte[])null, cp);
moduleInfo = new byte[length];
stream.read(moduleInfo);
unpacked = false;
}
public class Require {
private final int moduleIndex;
private final int flags;
private final int versionIndex;
public Require(int moduleIndex, int flags, int versionIndex) {
this.moduleIndex = moduleIndex;
this.flags = flags;
this.versionIndex = versionIndex;
}
public String getModuleName() {
return cpool.getModuleName(moduleIndex);
}
public int getFlags() {
return flags;
}
public int getVersionIndex() {
return versionIndex;
}
public String getVersionString() {
if (versionIndex == 0) {
return null;
} else {
return cpool.getConstantUtf8(versionIndex).getValue();
}
}
public String getFlagsAsString() {
StringBuilder s = new StringBuilder();
if ((flags & Constants.MODULE_ACC_TRANSITIVE)!=0) {
s.append(" transitive");
}
if ((flags & Constants.MODULE_ACC_STATIC_PHASE)!=0) {
s.append(" static");
}
if ((flags & Constants.MODULE_ACC_SYNTHETIC)!=0) {
s.append(" synthetic");
}
if ((flags & Constants.MODULE_ACC_MANDATED)!=0) {
s.append(" mandated");
}
return s.toString();
}
public String toString() {
return "requires"+getFlagsAsString()+" "+getModuleName()+(versionIndex==0?"":" "+getVersionString());
}
}
public class Export {
private final int packageIndex;
private final int flags;
private final int[] toModuleIndices;
public Export(int packageIndex, int flags, int[] toModuleIndices) {
this.packageIndex = packageIndex;
this.flags = flags;
this.toModuleIndices = toModuleIndices;
}
public int getPackageIndex() {
return packageIndex;
}
public int getFlags() {
return flags;
}
public int[] getToModuleIndices() {
return toModuleIndices;
}
public String getPackage() {
return cpool.getPackageName(packageIndex);
}
public String getFlagsAsString() {
StringBuilder s = new StringBuilder();
if ((flags & Constants.MODULE_ACC_SYNTHETIC)!=0) {
s.append(" synthetic");
}
if ((flags & Constants.MODULE_ACC_MANDATED)!=0) {
s.append(" synthetic");
}
return s.toString();
}
public String[] getToModuleNames() {
if (toModuleIndices==null) {
return NO_MODULE_NAMES;
}
String[] toModuleNames = new String[toModuleIndices.length];
for (int i=0;i<toModuleIndices.length;i++) {
toModuleNames[i] = cpool.getModuleName(toModuleIndices[i]);
}
return toModuleNames;
}
public String toString() {
StringBuilder s =new StringBuilder();
s.append("exports").append(getFlagsAsString()).append(" ").append(getPackage().replace('/', '.'));
String[] toModules = getToModuleNames();
if (toModules.length!=0) {
s.append(" to ");
for (int i=0;i<toModules.length;i++) {
if (i>0) {
s.append(", ");
}
s.append(toModules[i]);
}
}
return s.toString().trim();
}
}
public class Open {
private final int packageIndex;
private final int flags;
private final int[] toModuleIndices;
public Open(int packageIndex, int flags, int[] toModuleIndices) {
this.packageIndex = packageIndex;
this.flags = flags;
this.toModuleIndices = toModuleIndices;
}
public int getPackageIndex() {
return packageIndex;
}
public int getFlags() {
return flags;
}
public int[] getToModuleIndices() {
return toModuleIndices;
}
public String getPackage() {
return cpool.getPackageName(packageIndex);
}
public String getFlagsAsString() {
StringBuilder s = new StringBuilder();
if ((flags & Constants.MODULE_ACC_SYNTHETIC)!=0) {
s.append(" synthetic");
}
if ((flags & Constants.MODULE_ACC_MANDATED)!=0) {
s.append(" synthetic");
}
return s.toString();
}
public String[] getToModuleNames() {
if (toModuleIndices==null) {
return NO_MODULE_NAMES;
}
String[] toModuleNames = new String[toModuleIndices.length];
for (int i=0;i<toModuleIndices.length;i++) {
toModuleNames[i] = cpool.getModuleName(toModuleIndices[i]);
}
return toModuleNames;
}
public String toString() {
StringBuilder s =new StringBuilder();
s.append("opens").append(getFlagsAsString()).append(" ").append(getPackage().replace('/', '.'));
String[] toModules = getToModuleNames();
if (toModules.length!=0) {
s.append(" to ");
for (int i=0;i<toModules.length;i++) {
if (i>0) {
s.append(", ");
}
s.append(toModules[i]);
}
}
return s.toString().trim();
}
}
public class Provide {
private final int providedTypeIndex;
private final int[] withTypeIndices;
public Provide(int providedTypeIndex, int[] withTypeIndices) {
this.providedTypeIndex = providedTypeIndex;
this.withTypeIndices = withTypeIndices;
}
public String getProvidedType() {
return cpool.getConstantString_CONSTANTClass(providedTypeIndex);
}
public int getProvidedTypeIndex() {
return providedTypeIndex;
}
public String[] getWithTypeStrings() {
String[] result = new String[withTypeIndices.length];
for (int i=0;i<withTypeIndices.length;i++) {
result[i] = cpool.getConstantString_CONSTANTClass(withTypeIndices[i]);
}
return result;
}
public int[] getWithTypeIndices() {
return withTypeIndices;
}
public String toString() {
StringBuilder s =new StringBuilder();
s.append("provides ").append(getProvidedType().replace('/', '.'));
s.append(" with ");
String[] withtypes = getWithTypeStrings();
for (int i=0;i< withtypes.length;i++) {
if (i>0) s.append(",");
s.append(withtypes[i].replace('/','.'));
}
return s.toString();
}
}
public class Uses {
private final int typeNameIndex;
public Uses(int typeNameIndex) {
this.typeNameIndex = typeNameIndex;
}
public String getTypeName() {
return cpool.getConstantString_CONSTANTClass(typeNameIndex);
}
public int getTypeNameIndex() {
return typeNameIndex;
}
public String toString() {
StringBuilder s =new StringBuilder();
s.append("uses ").append(getTypeName().replace('/', '.'));
return s.toString().trim();
}
}
private final int readInt() {
return ((moduleInfo[ptr++] & 0xFF) << 24) + ((moduleInfo[ptr++] & 0xFF) << 16)
+ ((moduleInfo[ptr++] & 0xFF) << 8) + (moduleInfo[ptr++] & 0xFF);
}
private final int readUnsignedShort() {
return ((moduleInfo[ptr++] & 0xff) << 8) + (moduleInfo[ptr++] & 0xff);
}
private final int readUnsignedShort(int offset) {
return ((moduleInfo[offset++] & 0xff) << 8) + (moduleInfo[offset] & 0xff);
}
private void ensureUnpacked() {
if (!unpacked) {
ptr = 0;
moduleNameIndex = readUnsignedShort();
moduleFlags = readUnsignedShort();
moduleVersionIndex = readUnsignedShort();
int count = readUnsignedShort();
requires = new Require[count];
for (int i = 0; i < count; i++) {
requires[i] = new Require(readUnsignedShort(), readUnsignedShort(), readUnsignedShort());
}
count = readUnsignedShort();
exports = new Export[count];
for (int i = 0; i < count; i++) {
int index = readUnsignedShort();
int flags = readUnsignedShort();
int toCount = readUnsignedShort();
int[] to = new int[toCount];
for (int j = 0; j < toCount; j++) {
to[j] = readUnsignedShort();
}
exports[i] = new Export(index, flags, to);
}
count = readUnsignedShort();
opens = new Open[count];
for (int i = 0; i < count; i++) {
int index = readUnsignedShort();
int flags = readUnsignedShort();
int toCount = readUnsignedShort();
int[] to = new int[toCount];
for (int j = 0; j < toCount; j++) {
to[j] = readUnsignedShort();
}
opens[i] = new Open(index, flags, to);
}
count = readUnsignedShort();
uses = new Uses[count];
for (int i = 0; i < count; i++) {
uses[i] = new Uses(readUnsignedShort());
}
count = readUnsignedShort();
provides = new Provide[count];
for (int i = 0; i < count; i++) {
int index = readUnsignedShort();
int toCount = readUnsignedShort();
int[] to = new int[toCount];
for (int j = 0; j < toCount; j++) {
to[j] = readUnsignedShort();
}
provides[i] = new Provide(index, to);
}
unpacked = true;
}
}
@Override
public final void dump(DataOutputStream file) throws IOException {
super.dump(file);
if (!unpacked) {
file.write(moduleInfo);
} else {
file.writeShort(moduleNameIndex);
file.writeShort(moduleFlags);
file.writeShort(moduleVersionIndex);
file.writeShort(requires.length);
for (int i = 0; i < requires.length; i++) {
file.writeShort(requires[i].moduleIndex);
file.writeShort(requires[i].flags);
file.writeShort(requires[i].versionIndex);
}
file.writeShort(exports.length);
for (Export export : exports) {
file.writeShort(export.packageIndex);
int[] toIndices = export.toModuleIndices;
file.writeShort(toIndices.length);
for (int index : toIndices) {
file.writeShort(index);
}
}
file.writeShort(opens.length);
for (Open open : opens) {
file.writeShort(open.packageIndex);
int[] toIndices = open.toModuleIndices;
file.writeShort(toIndices.length);
for (int index : toIndices) {
file.writeShort(index);
}
}
file.writeShort(uses.length);
for (Uses use : uses) {
file.writeShort(use.getTypeNameIndex());
}
file.writeShort(provides.length);
for (Provide provide : provides) {
file.writeShort(provide.providedTypeIndex);
int[] toIndices = provide.withTypeIndices;
file.writeShort(toIndices.length);
for (int index : toIndices) {
file.writeShort(index);
}
}
}
}
public String toStringRequires() {
StringBuilder s = new StringBuilder();
s.append('#').append(requires.length);
if (requires.length > 0) {
for (Require require : requires) {
s.append(' ');
s.append(require.moduleIndex).append(':').append(require.flags);
}
}
return s.toString();
}
public String toStringExports() {
StringBuilder s = new StringBuilder();
s.append('#').append(exports.length);
if (exports.length > 0) {
for (Export export : exports) {
s.append(' ');
s.append(export.packageIndex).append(":[");
int[] toIndices = export.toModuleIndices;
for (int i = 0; i < toIndices.length; i++) {
if (i > 0)
s.append(',');
s.append(toIndices[i]);
}
s.append("]");
}
}
return s.toString();
}
public String toStringOpens() {
StringBuilder s = new StringBuilder();
s.append('#').append(opens.length);
if (opens.length > 0) {
for (Open open : opens) {
s.append(' ');
s.append(open.packageIndex).append(":[");
int[] toIndices = open.toModuleIndices;
for (int i = 0; i < toIndices.length; i++) {
if (i > 0)
s.append(',');
s.append(toIndices[i]);
}
s.append("]");
}
}
return s.toString();
}
public String toStringUses() {
StringBuilder s = new StringBuilder();
s.append('#').append(uses.length);
if (uses.length > 0) {
for (Uses use : uses) {
s.append(' ');
s.append(use.getTypeName());
}
}
return s.toString();
}
public String toStringProvides() {
StringBuilder s = new StringBuilder();
s.append('#').append(provides.length);
if (provides.length > 0) {
for (Provide provide : provides) {
s.append(' ');
s.append(provide.providedTypeIndex).append(":[");
int[] indices = provide.withTypeIndices;
for (int i = 0; i < indices.length; i++) {
if (i > 0)
s.append(',');
s.append(indices[i]);
}
s.append("]");
}
}
return s.toString();
}
@Override
public final String toString() {
StringBuilder s = new StringBuilder();
ensureUnpacked();
s.append("Module(");
if (requires.length != 0) {
s.append("requires=");
s.append(toStringRequires());
s.append(" ");
}
if (exports.length != 0) {
s.append("exports=");
s.append(toStringExports());
s.append(" ");
}
if (opens.length != 0) {
s.append("opens=");
s.append(toStringOpens());
s.append(" ");
}
if (uses.length != 0) {
s.append("uses=");
s.append(toStringUses());
s.append(" ");
}
if (provides.length != 0) {
s.append("provides=");
s.append(toStringProvides());
s.append(" ");
}
return s.toString().trim()+")";
}
@Override
public void accept(ClassVisitor v) {
v.visitModule(this);
}
public Require[] getRequires() {
ensureUnpacked();
return requires;
}
public String[] getRequiredModuleNames() {
ensureUnpacked();
String[] results = new String[requires.length];
for (int i=0;i<requires.length;i++) {
results[i] = cpool.getModuleName(requires[i].moduleIndex);
}
return results;
}
public byte[] getBytes() {
return moduleInfo;
}
public Export[] getExports() {
ensureUnpacked();
return exports;
}
public Open[] getOpens() {
ensureUnpacked();
return opens;
}
public Uses[] getUses() {
ensureUnpacked();
return uses;
}
public Provide[] getProvides() {
ensureUnpacked();
return provides;
}
public String getModuleName() {
return ((ConstantModule)cpool.getConstant(moduleNameIndex)).getModuleName(cpool);
}
public int getModuleFlags() {
return moduleFlags;
}
public String getModuleVersion() {
if (moduleVersionIndex == 0) {
return null;
} else {
return cpool.getConstantUtf8(moduleVersionIndex).getValue();
}
}
}