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

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