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(""); } buf.append("\n"); for (int element : jump_table) { buf.append(""); } buf.append("\n
").append(low + j).append("default
").append(element).append("").append(default_offset).append("
\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(""); for (int i = 0; i < npairs; ++i) { int match = bytes.readInt(); jump_table[i] = offset + bytes.readInt(); buf.append(""); } buf.append("\n"); for (int i = 0; i < npairs; ++i) { buf.append(""); } buf.append("\n
").append(match).append("default
").append(jump_table[i]).append("").append(default_offset).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

"); } if (code != null) { try (final ByteSequence stream = new ByteSequence(code)) { stream.mark(stream.available()); this.findGotos(stream, c); stream.reset(); this.file.println(""); 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(""); } } this.file.println(""); this.file.println("
Byte
offset
InstructionArgument
" + anchor2 + "" + anchor + str + "
"); } } static { CodeHTML.wide = false; } }