/*
* Decompiled with CFR 0.152.
*/
package org.apache.bcel.util;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.util.BitSet;
import org.apache.bcel.Const;
import org.apache.bcel.classfile.Attribute;
import org.apache.bcel.classfile.Code;
import org.apache.bcel.classfile.CodeException;
import org.apache.bcel.classfile.ConstantCP;
import org.apache.bcel.classfile.ConstantFieldref;
import org.apache.bcel.classfile.ConstantInterfaceMethodref;
import org.apache.bcel.classfile.ConstantInvokeDynamic;
import org.apache.bcel.classfile.ConstantMethodref;
import org.apache.bcel.classfile.ConstantNameAndType;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.LocalVariableTable;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.classfile.Utility;
import org.apache.bcel.util.ByteSequence;
import org.apache.bcel.util.Class2HTML;
import org.apache.bcel.util.ConstantHTML;
final class CodeHTML {
private static boolean wide;
private final String className;
private final PrintWriter printWriter;
private BitSet gotoSet;
private final ConstantPool constantPool;
private final ConstantHTML constantHtml;
CodeHTML(String dir, String className, Method[] methods, ConstantPool constantPool, ConstantHTML constantHtml, Charset charset) throws IOException {
this.className = className;
this.constantPool = constantPool;
this.constantHtml = constantHtml;
try (PrintWriter newPrintWriter = new PrintWriter(dir + className + "_code.html", charset.name());){
this.printWriter = newPrintWriter;
this.printWriter.print("
");
this.printWriter.println("");
for (int i = 0; i < methods.length; ++i) {
this.writeMethod(methods[i], i);
}
this.printWriter.println("");
}
}
private String codeToHTML(ByteSequence bytes, int methodNumber) throws IOException {
int i;
short opcode = (short)bytes.readUnsignedByte();
int defaultOffset = 0;
int noPadBytes = 0;
StringBuilder buf = new StringBuilder(256);
buf.append("").append(Const.getOpcodeName(opcode)).append("");
if (opcode == 170 || opcode == 171) {
int remainder = bytes.getIndex() % 4;
noPadBytes = remainder == 0 ? 0 : 4 - remainder;
for (i = 0; i < noPadBytes; ++i) {
bytes.readByte();
}
defaultOffset = bytes.readInt();
}
switch (opcode) {
case 170: {
int low = bytes.readInt();
int high = bytes.readInt();
int offset = bytes.getIndex() - 12 - noPadBytes - 1;
defaultOffset += offset;
buf.append("");
int[] jumpTable = new int[high - low + 1];
for (int i2 = 0; i2 < jumpTable.length; ++i2) {
jumpTable[i2] = offset + bytes.readInt();
buf.append("").append(low + i2).append(" | ");
}
buf.append("default | \n");
for (int element : jumpTable) {
buf.append("").append(element).append(" | ");
}
buf.append("").append(defaultOffset).append(" | \n \n");
break;
}
case 171: {
int npairs = bytes.readInt();
int offset = bytes.getIndex() - 8 - noPadBytes - 1;
int[] jumpTable = new int[npairs];
defaultOffset += offset;
buf.append("\n");
break;
}
case 153:
case 154:
case 155:
case 156:
case 157:
case 158:
case 159:
case 160:
case 161:
case 162:
case 163:
case 164:
case 165:
case 166:
case 167:
case 168:
case 198:
case 199: {
int index = bytes.getIndex() + bytes.readShort() - 1;
buf.append("").append(index).append("");
break;
}
case 200:
case 201: {
int windex = bytes.getIndex() + bytes.readInt() - 1;
buf.append("").append(windex).append("");
break;
}
case 21:
case 22:
case 23:
case 24:
case 25:
case 54:
case 55:
case 56:
case 57:
case 58:
case 169: {
int vindex;
if (wide) {
vindex = bytes.readShort();
wide = false;
} else {
vindex = bytes.readUnsignedByte();
}
buf.append("%").append(vindex);
break;
}
case 196: {
wide = true;
buf.append("(wide)");
break;
}
case 188: {
buf.append("").append(Const.getTypeName(bytes.readByte())).append("");
break;
}
case 178:
case 179:
case 180:
case 181: {
int index = bytes.readShort();
ConstantFieldref c1 = (ConstantFieldref)this.constantPool.getConstant(index, (byte)9, ConstantFieldref.class);
int classIndex = c1.getClassIndex();
String name = this.constantPool.getConstantString(classIndex, (byte)7);
name = Utility.compactClassName(name, false);
index = c1.getNameAndTypeIndex();
String fieldName = this.constantPool.constantToString(index, (byte)12);
if (name.equals(this.className)) {
buf.append("").append(fieldName).append("\n");
break;
}
buf.append(this.constantHtml.referenceConstant(classIndex)).append(".").append(fieldName);
break;
}
case 187:
case 192:
case 193: {
short index = bytes.readShort();
buf.append(this.constantHtml.referenceConstant(index));
break;
}
case 182:
case 183:
case 184:
case 185:
case 186: {
String name;
int index;
int classIndex;
ConstantCP c;
short mIndex = bytes.readShort();
if (opcode == 185) {
bytes.readUnsignedByte();
bytes.readUnsignedByte();
c = (ConstantInterfaceMethodref)this.constantPool.getConstant(mIndex, (byte)11, ConstantInterfaceMethodref.class);
classIndex = c.getClassIndex();
index = c.getNameAndTypeIndex();
name = Class2HTML.referenceClass(classIndex);
} else if (opcode == 186) {
bytes.readUnsignedByte();
bytes.readUnsignedByte();
c = (ConstantInvokeDynamic)this.constantPool.getConstant(mIndex, (byte)18, ConstantInvokeDynamic.class);
index = c.getNameAndTypeIndex();
name = "#" + ((ConstantInvokeDynamic)c).getBootstrapMethodAttrIndex();
} else {
c = (ConstantMethodref)this.constantPool.getConstant(mIndex, (byte)10, ConstantMethodref.class);
classIndex = c.getClassIndex();
index = c.getNameAndTypeIndex();
name = Class2HTML.referenceClass(classIndex);
}
String str = Class2HTML.toHTML(this.constantPool.constantToString(this.constantPool.getConstant(index, (byte)12)));
ConstantNameAndType c2 = (ConstantNameAndType)this.constantPool.getConstant(index, (byte)12, ConstantNameAndType.class);
String signature = this.constantPool.constantToString(c2.getSignatureIndex(), (byte)1);
String[] args = Utility.methodSignatureArgumentTypes(signature, false);
String type = Utility.methodSignatureReturnType(signature, false);
buf.append(name).append(".").append(str).append("").append("(");
for (int i3 = 0; i3 < args.length; ++i3) {
buf.append(Class2HTML.referenceType(args[i3]));
if (i3 >= args.length - 1) continue;
buf.append(", ");
}
buf.append("):").append(Class2HTML.referenceType(type));
break;
}
case 19:
case 20: {
short index = bytes.readShort();
buf.append("").append(Class2HTML.toHTML(this.constantPool.constantToString(index, this.constantPool.getConstant(index).getTag()))).append("");
break;
}
case 18: {
int index = bytes.readUnsignedByte();
buf.append("").append(Class2HTML.toHTML(this.constantPool.constantToString(index, this.constantPool.getConstant(index).getTag()))).append("");
break;
}
case 189: {
short index = bytes.readShort();
buf.append(this.constantHtml.referenceConstant(index));
break;
}
case 197: {
short index = bytes.readShort();
byte dimensions = bytes.readByte();
buf.append(this.constantHtml.referenceConstant(index)).append(":").append(dimensions).append("-dimensional");
break;
}
case 132: {
short constant;
int vindex;
if (wide) {
vindex = bytes.readShort();
constant = bytes.readShort();
wide = false;
} else {
vindex = bytes.readUnsignedByte();
constant = bytes.readByte();
}
buf.append("%").append(vindex).append(" ").append(constant);
break;
}
default: {
if (Const.getNoOfOperands(opcode) <= 0) break;
int i4 = 0;
while ((long)i4 < Const.getOperandTypeCount(opcode)) {
switch (Const.getOperandType(opcode, i4)) {
case 8: {
buf.append(bytes.readUnsignedByte());
break;
}
case 9: {
buf.append(bytes.readShort());
break;
}
case 10: {
buf.append(bytes.readInt());
break;
}
default: {
throw new IllegalStateException("Unreachable default case reached! " + Const.getOperandType(opcode, i4));
}
}
buf.append(" ");
++i4;
}
break block0;
}
}
buf.append(" | ");
return buf.toString();
}
private void findGotos(ByteSequence bytes, Code code) throws IOException {
this.gotoSet = new BitSet(bytes.available());
if (code != null) {
Attribute[] attributes;
CodeException[] ce;
for (CodeException cex : ce = code.getExceptionTable()) {
this.gotoSet.set(cex.getStartPC());
this.gotoSet.set(cex.getEndPC());
this.gotoSet.set(cex.getHandlerPC());
}
for (Attribute attribute : attributes = code.getAttributes()) {
if (attribute.getTag() != 5) continue;
((LocalVariableTable)attribute).forEach(var -> {
int start = var.getStartPC();
this.gotoSet.set(start);
this.gotoSet.set(start + var.getLength());
});
break;
}
}
block7: while (bytes.available() > 0) {
int opcode = bytes.readUnsignedByte();
switch (opcode) {
case 170:
case 171: {
int index;
int offset;
int remainder = bytes.getIndex() % 4;
int noPadBytes = remainder == 0 ? 0 : 4 - remainder;
for (int j = 0; j < noPadBytes; ++j) {
bytes.readByte();
}
int defaultOffset = bytes.readInt();
if (opcode == 170) {
int low = bytes.readInt();
int high = bytes.readInt();
offset = bytes.getIndex() - 12 - noPadBytes - 1;
this.gotoSet.set(defaultOffset += offset);
for (int j = 0; j < high - low + 1; ++j) {
index = offset + bytes.readInt();
this.gotoSet.set(index);
}
continue block7;
}
int npairs = bytes.readInt();
offset = bytes.getIndex() - 8 - noPadBytes - 1;
this.gotoSet.set(defaultOffset += offset);
for (int j = 0; j < npairs; ++j) {
bytes.readInt();
index = offset + bytes.readInt();
this.gotoSet.set(index);
}
continue block7;
}
case 153:
case 154:
case 155:
case 156:
case 157:
case 158:
case 159:
case 160:
case 161:
case 162:
case 163:
case 164:
case 165:
case 166:
case 167:
case 168:
case 198:
case 199: {
int index = bytes.getIndex() + bytes.readShort() - 1;
this.gotoSet.set(index);
continue block7;
}
case 200:
case 201: {
int index = bytes.getIndex() + bytes.readInt() - 1;
this.gotoSet.set(index);
continue block7;
}
}
bytes.unreadByte();
this.codeToHTML(bytes, 0);
}
}
private void writeMethod(Method method, int methodNumber) throws IOException {
String signature = method.getSignature();
String[] args = Utility.methodSignatureArgumentTypes(signature, false);
String type = Utility.methodSignatureReturnType(signature, false);
String name = method.getName();
String htmlName = Class2HTML.toHTML(name);
String access = Utility.accessToString(method.getAccessFlags());
access = Utility.replace(access, " ", " ");
Attribute[] attributes = method.getAttributes();
this.printWriter.print("" + access + " " + Class2HTML.referenceType(type) + " " + htmlName + "(");
for (int i = 0; i < args.length; ++i) {
this.printWriter.print(Class2HTML.referenceType(args[i]));
if (i >= args.length - 1) continue;
this.printWriter.print(", ");
}
this.printWriter.println(")
");
Code c = null;
byte[] code = null;
if (attributes.length > 0) {
this.printWriter.print("Attributes
\n");
for (int i = 0; i < attributes.length; ++i) {
byte tag = attributes[i].getTag();
if (tag != -1) {
this.printWriter.print("- " + Const.getAttributeName(tag) + "
\n");
} else {
this.printWriter.print("- " + attributes[i] + "
");
}
if (tag != 2) continue;
c = (Code)attributes[i];
Attribute[] attributes2 = c.getAttributes();
code = c.getCode();
this.printWriter.print("");
}
this.printWriter.println("
");
}
if (code != null) {
try (ByteSequence stream = new ByteSequence(code);){
stream.mark(stream.available());
this.findGotos(stream, c);
stream.reset();
this.printWriter.println("Byte offset | Instruction | Argument | ");
while (stream.available() > 0) {
int offset = stream.getIndex();
String str = this.codeToHTML(stream, methodNumber);
String anchor = "";
if (this.gotoSet.get(offset)) {
anchor = "";
}
String anchor2 = stream.getIndex() == code.length ? "" + offset + "" : "" + offset;
this.printWriter.println("
---|
" + anchor2 + " | " + anchor + str + " |
");
}
}
this.printWriter.println(" |
");
this.printWriter.println("
");
}
}
}