package com.sun.org.apache.bcel.internal.util;
import com.sun.org.apache.bcel.internal.classfile.LocalVariable;
import com.sun.org.apache.bcel.internal.classfile.Attribute;
import com.sun.org.apache.bcel.internal.classfile.CodeException;
import com.sun.org.apache.bcel.internal.classfile.LocalVariableTable;
import com.sun.org.apache.bcel.internal.classfile.Code;
import com.sun.org.apache.bcel.internal.classfile.ConstantNameAndType;
import com.sun.org.apache.bcel.internal.classfile.ConstantInterfaceMethodref;
import com.sun.org.apache.bcel.internal.classfile.ConstantInvokeDynamic;
import com.sun.org.apache.bcel.internal.classfile.ConstantMethodref;
import com.sun.org.apache.bcel.internal.classfile.Utility;
import com.sun.org.apache.bcel.internal.classfile.ConstantFieldref;
import com.sun.org.apache.bcel.internal.Const;
import java.io.IOException;
import java.io.FileOutputStream;
import com.sun.org.apache.bcel.internal.classfile.Method;
import com.sun.org.apache.bcel.internal.classfile.ConstantPool;
import java.util.BitSet;
import java.io.PrintWriter;
final class CodeHTML
{
private final String class_name;
private final PrintWriter file;
private BitSet goto_set;
private final ConstantPool constant_pool;
private final ConstantHTML constant_html;
private static boolean wide;
CodeHTML(String dir, String class_name, Method[] methods, ConstantPool constant_pool, ConstantHTML constant_html) throws IOException {
this.class_name = class_name;
this.constant_pool = constant_pool;
this.constant_html = constant_html;
(this.file = new PrintWriter(new FileOutputStream(dir + class_name + "_code.html"))).println("
");
for (int i = 0; i < methods.length; ++i) {
this.writeMethod(methods[i], i);
}
this.file.println("");
this.file.close();
}
private String codeToHTML(ByteSequence bytes, int method_number) throws IOException {
short opcode = (short)bytes.readUnsignedByte();
int default_offset = 0;
int no_pad_bytes = 0;
StringBuilder buf = new StringBuilder(256);
buf.append("").append(Const.getOpcodeName((int)opcode)).append("");
if (opcode == 170 || opcode == 171) {
int remainder = bytes.getIndex() % 4;
no_pad_bytes = ((remainder == 0) ? 0 : (4 - remainder));
for (int i = 0; i < no_pad_bytes; ++i) {
bytes.readByte();
}
default_offset = bytes.readInt();
}
switch (opcode) {
case 170: {
int low = bytes.readInt();
int high = bytes.readInt();
int offset = bytes.getIndex() - 12 - no_pad_bytes - 1;
default_offset += offset;
buf.append("");
int[] jump_table = new int[high - low + 1];
for (int j = 0; j < jump_table.length; ++j) {
jump_table[j] = offset + bytes.readInt();
buf.append("").append(low + j).append(" | ");
}
buf.append("default | \n");
for (int element : jump_table) {
buf.append("").append(element).append(" | ");
}
buf.append("").append(default_offset).append(" | \n \n");
break;
}
case 171: {
int npairs = bytes.readInt();
int offset = bytes.getIndex() - 8 - no_pad_bytes - 1;
int[] jump_table = new int[npairs];
default_offset += 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 (CodeHTML.wide) {
vindex = bytes.readShort();
CodeHTML.wide = false;
}
else {
vindex = bytes.readUnsignedByte();
}
buf.append("%").append(vindex);
break;
}
case 196: {
CodeHTML.wide = true;
buf.append("(wide)");
break;
}
case 188: {
buf.append("").append(Const.getTypeName((int)bytes.readByte())).append("");
break;
}
case 178:
case 179:
case 180:
case 181: {
int index = bytes.readShort();
ConstantFieldref c1 = (ConstantFieldref)this.constant_pool.getConstant(index, (byte)9);
int class_index = c1.getClassIndex();
String name = this.constant_pool.getConstantString(class_index, (byte)7);
name = Utility.compactClassName(name, false);
index = c1.getNameAndTypeIndex();
String field_name = this.constant_pool.constantToString(index, (byte)12);
if (name.equals(this.class_name)) {
buf.append("").append(field_name).append("\n");
break;
}
buf.append(this.constant_html.referenceConstant(class_index)).append(".").append(field_name);
break;
}
case 187:
case 192:
case 193: {
int index = bytes.readShort();
buf.append(this.constant_html.referenceConstant(index));
break;
}
case 182:
case 183:
case 184:
case 185:
case 186: {
int m_index = bytes.readShort();
int index;
String name;
if (opcode == 185) {
bytes.readUnsignedByte();
bytes.readUnsignedByte();
ConstantInterfaceMethodref c4 = (ConstantInterfaceMethodref)this.constant_pool.getConstant(m_index, (byte)11);
int class_index = c4.getClassIndex();
index = c4.getNameAndTypeIndex();
name = Class2HTML.referenceClass(class_index);
}
else if (opcode == 186) {
bytes.readUnsignedByte();
bytes.readUnsignedByte();
ConstantInvokeDynamic c3 = (ConstantInvokeDynamic)this.constant_pool.getConstant(m_index, (byte)18);
index = c3.getNameAndTypeIndex();
name = "#" + c3.getBootstrapMethodAttrIndex();
}
else {
ConstantMethodref c2 = (ConstantMethodref)this.constant_pool.getConstant(m_index, (byte)10);
int class_index = c2.getClassIndex();
index = c2.getNameAndTypeIndex();
name = Class2HTML.referenceClass(class_index);
}
String str = Class2HTML.toHTML(this.constant_pool.constantToString(this.constant_pool.getConstant(index, (byte)12)));
ConstantNameAndType c5 = (ConstantNameAndType)this.constant_pool.getConstant(index, (byte)12);
String signature = this.constant_pool.constantToString(c5.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 k = 0; k < args.length; ++k) {
buf.append(Class2HTML.referenceType(args[k]));
if (k < args.length - 1) {
buf.append(", ");
}
}
buf.append("):").append(Class2HTML.referenceType(type));
break;
}
case 19:
case 20: {
int index = bytes.readShort();
buf.append("").append(Class2HTML.toHTML(this.constant_pool.constantToString(index, this.constant_pool.getConstant(index).getTag()))).append("");
break;
}
case 18: {
int index = bytes.readUnsignedByte();
buf.append("").append(Class2HTML.toHTML(this.constant_pool.constantToString(index, this.constant_pool.getConstant(index).getTag()))).append("");
break;
}
case 189: {
int index = bytes.readShort();
buf.append(this.constant_html.referenceConstant(index));
break;
}
case 197: {
int index = bytes.readShort();
int dimensions = bytes.readByte();
buf.append(this.constant_html.referenceConstant(index)).append(":").append(dimensions).append("-dimensional");
break;
}
case 132: {
int vindex;
int constant;
if (CodeHTML.wide) {
vindex = bytes.readShort();
constant = bytes.readShort();
CodeHTML.wide = false;
}
else {
vindex = bytes.readUnsignedByte();
constant = bytes.readByte();
}
buf.append("%").append(vindex).append(" ").append(constant);
break;
}
default: {
if (Const.getNoOfOperands((int)opcode) > 0) {
for (int l = 0; (long)l < Const.getOperandTypeCount((int)opcode); ++l) {
switch (Const.getOperandType((int)opcode, l)) {
case 8: {
buf.append(bytes.readUnsignedByte());
break;
}
case 9: {
buf.append((int)bytes.readShort());
break;
}
case 10: {
buf.append(bytes.readInt());
break;
}
default: {
throw new IllegalStateException("Unreachable default case reached! " + (int)Const.getOperandType((int)opcode, l));
}
}
buf.append(" ");
}
break;
}
break;
}
}
buf.append(" | ");
return buf.toString();
}
private void findGotos(ByteSequence bytes, Code code) throws IOException {
this.goto_set = new BitSet(bytes.available());
if (code != null) {
CodeException[] ce;
for (CodeException cex : ce = code.getExceptionTable()) {
this.goto_set.set(cex.getStartPC());
this.goto_set.set(cex.getEndPC());
this.goto_set.set(cex.getHandlerPC());
}
Attribute[] attributes = code.getAttributes();
int length2 = attributes.length;
int n = 0;
while (n < length2) {
Attribute attribute = attributes[n];
if (attribute.getTag() == 5) {
LocalVariable[] vars;
for (LocalVariable var : vars = ((LocalVariableTable)attribute).getLocalVariableTable()) {
int start = var.getStartPC();
int end = start + var.getLength();
this.goto_set.set(start);
this.goto_set.set(end);
}
break;
}
++n;
}
}
while (bytes.available() > 0) {
int opcode = bytes.readUnsignedByte();
switch (opcode) {
case 170:
case 171: {
int remainder = bytes.getIndex() % 4;
int no_pad_bytes = (remainder == 0) ? 0 : (4 - remainder);
for (int j = 0; j < no_pad_bytes; ++j) {
bytes.readByte();
}
int default_offset = bytes.readInt();
if (opcode == 170) {
int low = bytes.readInt();
int high = bytes.readInt();
int offset = bytes.getIndex() - 12 - no_pad_bytes - 1;
default_offset += offset;
this.goto_set.set(default_offset);
for (int k = 0; k < high - low + 1; ++k) {
int index = offset + bytes.readInt();
this.goto_set.set(index);
}
continue;
}
int npairs = bytes.readInt();
int offset = bytes.getIndex() - 8 - no_pad_bytes - 1;
default_offset += offset;
this.goto_set.set(default_offset);
for (int i = 0; i < npairs; ++i) {
bytes.readInt();
int index = offset + bytes.readInt();
this.goto_set.set(index);
}
continue;
}
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.goto_set.set(index);
continue;
}
case 200:
case 201: {
int index = bytes.getIndex() + bytes.readInt() - 1;
this.goto_set.set(index);
continue;
}
default: {
bytes.unreadByte();
this.codeToHTML(bytes, 0);
continue;
}
}
}
}
private void writeMethod(Method method, int method_number) throws IOException {
String signature = method.getSignature();
String[] args = Utility.methodSignatureArgumentTypes(signature, false);
String type = Utility.methodSignatureReturnType(signature, false);
String name = method.getName();
String html_name = Class2HTML.toHTML(name);
String access = Utility.accessToString(method.getAccessFlags());
access = Utility.replace(access, " ", " ");
Attribute[] attributes = method.getAttributes();
this.file.print("" + access + " " + Class2HTML.referenceType(type) + " " + html_name + "(");
for (int i = 0; i < args.length; ++i) {
this.file.print(Class2HTML.referenceType(args[i]));
if (i < args.length - 1) {
this.file.print(", ");
}
}
this.file.println(")
");
Code c = null;
byte[] code = null;
if (attributes.length > 0) {
this.file.print("Attributes
\n");
for (int j = 0; j < attributes.length; ++j) {
byte tag = attributes[j].getTag();
if (tag != -1) {
this.file.print("- " + Const.getAttributeName((int)tag) + "
\n");
}
else {
this.file.print("- " + attributes[j] + "
");
}
if (tag == 2) {
c = (Code)attributes[j];
Attribute[] attributes2 = c.getAttributes();
code = c.getCode();
this.file.print("");
}
}
this.file.println("
");
}
if (code != null) {
try (final ByteSequence stream = new ByteSequence(code)) {
stream.mark(stream.available());
this.findGotos(stream, c);
stream.reset();
this.file.println("Byte offset | Instruction | Argument | ");
while (stream.available() > 0) {
int offset = stream.getIndex();
String str = this.codeToHTML(stream, method_number);
String anchor = "";
if (this.goto_set.get(offset)) {
anchor = "";
}
String anchor2;
if (stream.getIndex() == code.length) {
anchor2 = "" + offset + "";
}
else {
anchor2 = "" + offset;
}
this.file.println("
---|
" + anchor2 + " | " + anchor + str + " |
");
}
}
this.file.println(" |
");
this.file.println("
");
}
}
static {
CodeHTML.wide = false;
}
}