package org.apache.bcel.util;
package .tmp;
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.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.LocalVariable;
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++)
writeMethod(methods[i], i);
this.printWriter.println("");
}
}
private String codeToHTML(ByteSequence bytes, int methodNumber) throws IOException {
String name, signature;
int low, high, index, classIndex, vindex, constant, jumpTable[], offset, i, npairs, j, windex;
ConstantFieldref c1;
String fieldName;
int mIndex;
String str;
ConstantNameAndType c2;
String args[], type;
int k, dimensions;
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 (int m = 0; m < noPadBytes; m++)
bytes.readByte();
defaultOffset = bytes.readInt();
}
switch (opcode) {
case 170:
low = bytes.readInt();
high = bytes.readInt();
offset = bytes.getIndex() - 12 - noPadBytes - 1;
defaultOffset += offset;
buf.append("");
jumpTable = new int[high - low + 1];
for (i = 0; i < jumpTable.length; i++) {
jumpTable[i] = offset + bytes.readInt();
buf.append("").append(low + i).append(" | ");
}
buf.append("default | \n");
for (int element : jumpTable)
buf.append("").append(element).append(" | ");
buf.append("").append(defaultOffset)
.append(" | \n \n");
buf.append(" | ");
return buf.toString();
case 171:
npairs = bytes.readInt();
offset = bytes.getIndex() - 8 - noPadBytes - 1;
jumpTable = new int[npairs];
defaultOffset += offset;
buf.append("\n");
buf.append("");
return buf.toString();
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:
index = bytes.getIndex() + bytes.readShort() - 1;
buf.append("").append(index).append("");
buf.append("");
return buf.toString();
case 200:
case 201:
windex = bytes.getIndex() + bytes.readInt() - 1;
buf.append("").append(windex).append("");
buf.append("");
return buf.toString();
case 21:
case 22:
case 23:
case 24:
case 25:
case 54:
case 55:
case 56:
case 57:
case 58:
case 169:
if (wide) {
vindex = bytes.readShort();
wide = false;
} else {
vindex = bytes.readUnsignedByte();
}
buf.append("%").append(vindex);
buf.append("");
return buf.toString();
case 196:
wide = true;
buf.append("(wide)");
buf.append("");
return buf.toString();
case 188:
buf.append("").append(Const.getTypeName(bytes.readByte())).append("");
buf.append("");
return buf.toString();
case 178:
case 179:
case 180:
case 181:
index = bytes.readShort();
c1 = (ConstantFieldref)this.constantPool.getConstant(index, (byte)9, ConstantFieldref.class);
classIndex = c1.getClassIndex();
name = this.constantPool.getConstantString(classIndex, (byte)7);
name = Utility.compactClassName(name, false);
index = c1.getNameAndTypeIndex();
fieldName = this.constantPool.constantToString(index, (byte)12);
if (name.equals(this.className)) {
buf.append("").append(fieldName).append("\n");
} else {
buf.append(this.constantHtml.referenceConstant(classIndex)).append(".").append(fieldName);
}
buf.append("");
return buf.toString();
case 187:
case 192:
case 193:
index = bytes.readShort();
buf.append(this.constantHtml.referenceConstant(index));
buf.append("");
return buf.toString();
case 182:
case 183:
case 184:
case 185:
case 186:
mIndex = bytes.readShort();
if (opcode == 185) {
bytes.readUnsignedByte();
bytes.readUnsignedByte();
ConstantInterfaceMethodref 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();
ConstantInvokeDynamic c = (ConstantInvokeDynamic)this.constantPool.getConstant(mIndex, (byte)18, ConstantInvokeDynamic.class);
index = c.getNameAndTypeIndex();
name = "#" + c.getBootstrapMethodAttrIndex();
} else {
ConstantMethodref c = (ConstantMethodref)this.constantPool.getConstant(mIndex, (byte)10, ConstantMethodref.class);
classIndex = c.getClassIndex();
index = c.getNameAndTypeIndex();
name = Class2HTML.referenceClass(classIndex);
}
str = Class2HTML.toHTML(this.constantPool.constantToString(this.constantPool.getConstant(index, (byte)12)));
c2 = (ConstantNameAndType)this.constantPool.getConstant(index, (byte)12, ConstantNameAndType.class);
signature = this.constantPool.constantToString(c2.getSignatureIndex(), (byte)1);
args = Utility.methodSignatureArgumentTypes(signature, false);
type = Utility.methodSignatureReturnType(signature, false);
buf.append(name).append(".").append(str).append("").append("(");
for (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));
buf.append("");
return buf.toString();
case 19:
case 20:
index = bytes.readShort();
buf.append("").append(Class2HTML.toHTML(this.constantPool.constantToString(index, this.constantPool.getConstant(index).getTag()))).append("");
buf.append("");
return buf.toString();
case 18:
index = bytes.readUnsignedByte();
buf.append("").append(Class2HTML.toHTML(this.constantPool.constantToString(index, this.constantPool.getConstant(index).getTag()))).append("");
buf.append("");
return buf.toString();
case 189:
index = bytes.readShort();
buf.append(this.constantHtml.referenceConstant(index));
buf.append("");
return buf.toString();
case 197:
index = bytes.readShort();
dimensions = bytes.readByte();
buf.append(this.constantHtml.referenceConstant(index)).append(":").append(dimensions).append("-dimensional");
buf.append("");
return buf.toString();
case 132:
if (wide) {
vindex = bytes.readShort();
constant = bytes.readShort();
wide = false;
} else {
vindex = bytes.readUnsignedByte();
constant = bytes.readByte();
}
buf.append("%").append(vindex).append(" ").append(constant);
buf.append("");
return buf.toString();
}
if (Const.getNoOfOperands(opcode) > 0)
for (int m = 0; m < Const.getOperandTypeCount(opcode); m++) {
switch (Const.getOperandType(opcode, m)) {
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, m));
}
buf.append(" ");
}
buf.append("");
return buf.toString();
}
private void findGotos(ByteSequence bytes, Code code) throws IOException {
this.gotoSet = new BitSet(bytes.available());
if (code != null) {
CodeException[] ce = code.getExceptionTable();
for (CodeException cex : ce) {
this.gotoSet.set(cex.getStartPC());
this.gotoSet.set(cex.getEndPC());
this.gotoSet.set(cex.getHandlerPC());
}
Attribute[] attributes = code.getAttributes();
for (Attribute attribute : attributes) {
if (attribute.getTag() == 5) {
((LocalVariableTable)attribute).forEach(var -> {
int start = var.getStartPC();
this.gotoSet.set(start);
this.gotoSet.set(start + var.getLength());
});
break;
}
}
}
while (bytes.available() > 0) {
int index, remainder, noPadBytes, defaultOffset, offset, j, npairs, i, opcode = bytes.readUnsignedByte();
switch (opcode) {
case 170:
case 171:
remainder = bytes.getIndex() % 4;
noPadBytes = (remainder == 0) ? 0 : (4 - remainder);
for (j = 0; j < noPadBytes; j++)
bytes.readByte();
defaultOffset = bytes.readInt();
if (opcode == 170) {
int low = bytes.readInt();
int high = bytes.readInt();
int k = bytes.getIndex() - 12 - noPadBytes - 1;
defaultOffset += k;
this.gotoSet.set(defaultOffset);
for (int m = 0; m < high - low + 1; m++) {
int n = k + bytes.readInt();
this.gotoSet.set(n);
}
continue;
}
npairs = bytes.readInt();
offset = bytes.getIndex() - 8 - noPadBytes - 1;
defaultOffset += offset;
this.gotoSet.set(defaultOffset);
for (i = 0; i < npairs; i++) {
bytes.readInt();
int k = offset + bytes.readInt();
this.gotoSet.set(k);
}
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:
index = bytes.getIndex() + bytes.readShort() - 1;
this.gotoSet.set(index);
continue;
case 200:
case 201:
index = bytes.getIndex() + bytes.readInt() - 1;
this.gotoSet.set(index);
continue;
}
bytes.unreadByte();
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)
this.printWriter.print(", ");
}
this.printWriter.println(")
");
Code c = null;
byte[] code = null;
if (attributes.length > 0) {
this.printWriter.print("Attributes
\n");
for (int j = 0; j < attributes.length; j++) {
byte tag = attributes[j].getTag();
if (tag != -1) {
this.printWriter.print("- " +
Const.getAttributeName(tag) + "
\n");
} else {
this.printWriter.print("- " + attributes[j] + "
");
}
if (tag == 2) {
c = (Code)attributes[j];
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());
findGotos(stream, c);
stream.reset();
this.printWriter.println("Byte offset | Instruction | Argument | ");
while (stream.available() > 0) {
String anchor2;
int offset = stream.getIndex();
String str = codeToHTML(stream, methodNumber);
String anchor = "";
if (this.gotoSet.get(offset))
anchor = "";
if (stream.getIndex() == code.length) {
anchor2 = "" + offset + "";
} else {
anchor2 = "" + offset;
}
this.printWriter.println("
---|
" + anchor2 + " | " + anchor + str + " |
");
}
}
this.printWriter.println(" |
");
this.printWriter.println("
");
}
}
}