diff --git a/src/main/java/com/jhe/hexed/JHexEditor.java b/src/main/java/com/jhe/hexed/JHexEditor.java index f1552ad8..bec2480b 100644 --- a/src/main/java/com/jhe/hexed/JHexEditor.java +++ b/src/main/java/com/jhe/hexed/JHexEditor.java @@ -1,8 +1,21 @@ package com.jhe.hexed; -import javax.swing.*; -import java.awt.*; -import java.awt.event.*; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.event.AdjustmentEvent; +import java.awt.event.AdjustmentListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.KeyEvent; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import javax.swing.JPanel; +import javax.swing.JScrollBar; /** * Created by IntelliJ IDEA. User: laullon Date: 08-abr-2003 Time: 13:21:09 @@ -15,8 +28,8 @@ public class JHexEditor extends JPanel implements FocusListener, protected static Font font = new Font("Monospaced", 0, 12); protected int border = 2; public boolean DEBUG = false; - private JPanel panel; - private JScrollBar sb; + private final JPanel panel; + private final JScrollBar sb; private int inicio = 0; private int lineas = 10; diff --git a/src/main/java/com/jhe/hexed/JHexEditorASCII.java b/src/main/java/com/jhe/hexed/JHexEditorASCII.java index a2f7ce91..330294a2 100644 --- a/src/main/java/com/jhe/hexed/JHexEditorASCII.java +++ b/src/main/java/com/jhe/hexed/JHexEditorASCII.java @@ -1,8 +1,14 @@ package com.jhe.hexed; -import javax.swing.*; -import java.awt.*; -import java.awt.event.*; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import javax.swing.JComponent; /** * Created by IntelliJ IDEA. User: laullon Date: 09-abr-2003 Time: 12:47:18 @@ -10,7 +16,7 @@ import java.awt.event.*; public class JHexEditorASCII extends JComponent implements MouseListener, KeyListener { private static final long serialVersionUID = 5505374841731053461L; - private JHexEditor he; + private final JHexEditor he; public JHexEditorASCII(JHexEditor he) { this.he = he; diff --git a/src/main/java/com/jhe/hexed/JHexEditorHEX.java b/src/main/java/com/jhe/hexed/JHexEditorHEX.java index b0a1954d..4391dfff 100644 --- a/src/main/java/com/jhe/hexed/JHexEditorHEX.java +++ b/src/main/java/com/jhe/hexed/JHexEditorHEX.java @@ -1,8 +1,14 @@ package com.jhe.hexed; -import javax.swing.*; -import java.awt.*; -import java.awt.event.*; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import javax.swing.JComponent; /** * Created by IntelliJ IDEA. User: laullon Date: 09-abr-2003 Time: 12:47:32 @@ -10,8 +16,8 @@ import java.awt.event.*; public class JHexEditorHEX extends JComponent implements MouseListener, KeyListener { private static final long serialVersionUID = 1481995655372014571L; - private JHexEditor he; - private int cursor = 0; + private final JHexEditor he; + private final int cursor = 0; public JHexEditorHEX(JHexEditor he) { this.he = he; diff --git a/src/main/java/jd/cli/Main.java b/src/main/java/jd/cli/Main.java index 0aec9dee..2c18e632 100644 --- a/src/main/java/jd/cli/Main.java +++ b/src/main/java/jd/cli/Main.java @@ -2,7 +2,6 @@ package jd.cli; import java.io.File; import java.io.PrintStream; - import jd.cli.loader.DirectoryLoader; import jd.cli.preferences.CommonPreferences; import jd.cli.printer.text.PlainTextPrinter; diff --git a/src/main/java/jd/cli/loader/BaseLoader.java b/src/main/java/jd/cli/loader/BaseLoader.java index b8b138eb..3a488fd8 100644 --- a/src/main/java/jd/cli/loader/BaseLoader.java +++ b/src/main/java/jd/cli/loader/BaseLoader.java @@ -1,7 +1,6 @@ package jd.cli.loader; import java.io.File; - import jd.core.loader.Loader; public abstract class BaseLoader implements Loader { diff --git a/src/main/java/jd/cli/loader/DirectoryLoader.java b/src/main/java/jd/cli/loader/DirectoryLoader.java index 7fce9e06..a7d6f847 100644 --- a/src/main/java/jd/cli/loader/DirectoryLoader.java +++ b/src/main/java/jd/cli/loader/DirectoryLoader.java @@ -5,7 +5,6 @@ import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; - import jd.core.loader.LoaderException; diff --git a/src/main/java/jd/cli/loader/JarLoader.java b/src/main/java/jd/cli/loader/JarLoader.java index 3d4483fb..433ac37b 100644 --- a/src/main/java/jd/cli/loader/JarLoader.java +++ b/src/main/java/jd/cli/loader/JarLoader.java @@ -5,12 +5,11 @@ import java.io.File; import java.io.IOException; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; - import jd.core.loader.LoaderException; public class JarLoader extends BaseLoader { - private ZipFile zipFile; + private final ZipFile zipFile; public JarLoader(File file) throws LoaderException { super(file); diff --git a/src/main/java/jd/cli/loader/LoaderManager.java b/src/main/java/jd/cli/loader/LoaderManager.java index 14c4b901..f824db32 100644 --- a/src/main/java/jd/cli/loader/LoaderManager.java +++ b/src/main/java/jd/cli/loader/LoaderManager.java @@ -3,7 +3,6 @@ package jd.cli.loader; import java.io.File; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; - import jd.core.loader.LoaderException; public class LoaderManager { diff --git a/src/main/java/jd/cli/printer/html/HtmlPrinter.java b/src/main/java/jd/cli/printer/html/HtmlPrinter.java index 55d22574..0eea9577 100644 --- a/src/main/java/jd/cli/printer/html/HtmlPrinter.java +++ b/src/main/java/jd/cli/printer/html/HtmlPrinter.java @@ -1,7 +1,6 @@ package jd.cli.printer.html; import java.io.PrintStream; - import jd.cli.util.VersionUtil; import jd.core.CoreConstants; import jd.core.printer.Printer; @@ -32,9 +31,9 @@ import jd.core.printer.Printer; public class HtmlPrinter implements Printer { private final static boolean DEBUG = true; - private PrintStream printStream; - private StringBuffer sbLineNumber; - private StringBuffer sbCode; + private final PrintStream printStream; + private final StringBuffer sbLineNumber; + private final StringBuffer sbCode; private int maxLineNumber; private int majorVersion; private int minorVersion; @@ -57,20 +56,20 @@ public class HtmlPrinter implements Printer { public void print(char c) { switch (c) { - case '<': - this.sbCode.append("<"); - break; - case '>': - this.sbCode.append(">"); - break; - default: - this.sbCode.append(String.valueOf(c)); - break; + case '<': + this.sbCode.append("<"); + break; + case '>': + this.sbCode.append(">"); + break; + default: + this.sbCode.append(c); + break; } } public void print(int i) { - this.sbCode.append(String.valueOf(i)); + this.sbCode.append(i); } public void print(String s) { @@ -228,9 +227,11 @@ public class HtmlPrinter implements Printer { "body,html{font-family:Lucida Grande,Lucida Sans Unicode,Arial,sans-serif;font-size:90%}" + "#demo .out{background-color:#FFFFFF}" + - "#demo .out .content{padding:0px;font-size:12px;font-family:courier new,courier;white-space:pre;border-radius:0 0 10px 10px}" + + "#demo .out .content{padding:0px;font-size:12px;font-family:courier new,courier;" + + "white-space:pre;border-radius:0 0 10px 10px}" + "#demo .out .content .e{color:#FF0000;margin:10px}" + - "#linenumber{float:left;margin:0;padding:1px 8px 5px 1px;border-style:solid;border-color:#888888;border-width:0 1px 0 0;color:#888888}" + + "#linenumber{float:left;margin:0;padding:1px 8px 5px 1px;border-style:solid;" + + "border-color:#888888;border-width:0 1px 0 0;color:#888888}" + "#linenumber s{text-decoration:none}" + "#linenumber span{color:#FF0000;font-style:normal}" + "#javacode{padding:0 0 5px 0;margin:1px 5px 1px 5px;color:black}" + @@ -248,13 +249,19 @@ public class HtmlPrinter implements Printer { "#javacode em{color:#0000c0;font-style:italic;line-height:1}" + "#javacode samp{font-style:italic;line-height:1}" + "#javacode .debuglayoutblock{color:#000000;background-color:#ccffff;border:1px solid #99eeee}" + - "#javacode .debugseparatorlayoutblock{color:#000000;background-color:#ccffcc;border:1px solid #99ee99}" + - "#javacode .debugstatementblocklayoutblock{color:#000000;background-color:#ffcccc;border:1px solid #ee9999}" + - "#javacode .debugenumblocklayoutblock{color:#000000;background-color:#ffffcc;border:1px solid #eeee99}" + - "#javacode .debugcommentdeprecatedlayoutblock{color:#000000;background-color:#fefefe;border:1px solid #e9e9e9}" + + "#javacode .debugseparatorlayoutblock{color:#000000;background-color:#ccffcc;border:1px solid" + + " #99ee99}" + + "#javacode .debugstatementblocklayoutblock{color:#000000;background-color:#ffcccc;border:1px " + + "solid #ee9999}" + + "#javacode .debugenumblocklayoutblock{color:#000000;background-color:#ffffcc;border:1px solid" + + " #eeee99}" + + "#javacode .debugcommentdeprecatedlayoutblock{color:#000000;background-color:#fefefe;" + + "border:1px solid #e9e9e9}" + "#javacode .debugmarker{color:#000000;background-color:#ffd2ff;border:1px solid #cfb2cf}" + - "#javacode .debugcaseblocklayoutblock{color:#000000;background-color:#ffde66;border:1px solid #ff9a11}" + - "#metadata{padding:5px;color:#444444;background-color:#EEEEEE;border-radius:0 0 10px 10px;font-size:11px}" + + "#javacode .debugcaseblocklayoutblock{color:#000000;background-color:#ffde66;border:1px solid" + + " #ff9a11}" + + "#metadata{padding:5px;color:#444444;background-color:#EEEEEE;border-radius:0 0 10px 10px;" + + "font-size:11px}" + "" + "" + @@ -274,7 +281,8 @@ public class HtmlPrinter implements Printer { this.printStream.print(""); this.printStream.print("
"); - this.printStream.print("Java Class Version: " + VersionUtil.getJDKVersion(this.majorVersion, this.minorVersion) + "
"); + this.printStream.print("Java Class Version: " + VersionUtil.getJDKVersion(this.majorVersion, + this.minorVersion) + "
"); this.printStream.print("JD-CL Version: " + "0.1.0" + "
"); this.printStream.print("JD-Core Version: " + CoreConstants.JD_CORE_VERSION); this.printStream.print("
"); diff --git a/src/main/java/jd/cli/printer/text/PlainTextPrinter.java b/src/main/java/jd/cli/printer/text/PlainTextPrinter.java index a2c066b9..070c6221 100644 --- a/src/main/java/jd/cli/printer/text/PlainTextPrinter.java +++ b/src/main/java/jd/cli/printer/text/PlainTextPrinter.java @@ -1,7 +1,6 @@ package jd.cli.printer.text; import java.io.PrintStream; - import jd.cli.preferences.CommonPreferences; import jd.core.model.instruction.bytecode.instruction.Instruction; import jd.core.printer.Printer; @@ -340,7 +339,7 @@ public class PlainTextPrinter implements Printer { char c = s.charAt(i); if (c == '\t') { - this.printStream.append(c); + this.printStream.append('\t'); } else if (c < 32) { // Write octal format this.printStream.append("\\0"); diff --git a/src/main/java/jd/cli/util/ClassFileUtil.java b/src/main/java/jd/cli/util/ClassFileUtil.java index a954b652..77b8f83d 100644 --- a/src/main/java/jd/cli/util/ClassFileUtil.java +++ b/src/main/java/jd/cli/util/ClassFileUtil.java @@ -6,7 +6,6 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; - import jd.core.CoreConstants; import jd.core.model.classfile.constant.Constant; import jd.core.model.classfile.constant.ConstantClass; @@ -104,34 +103,34 @@ public class ClassFileUtil { byte tag = dis.readByte(); switch (tag) { - case ConstantConstant.CONSTANT_Class: - constants[i] = new ConstantClass(tag, dis.readUnsignedShort()); - break; - case ConstantConstant.CONSTANT_Utf8: - constants[i] = new ConstantUtf8(tag, dis.readUTF()); - break; - case ConstantConstant.CONSTANT_Long: - case ConstantConstant.CONSTANT_Double: - dis.read(); - dis.read(); - dis.read(); - dis.read(); - i++; - case ConstantConstant.CONSTANT_Fieldref: - case ConstantConstant.CONSTANT_Methodref: - case ConstantConstant.CONSTANT_InterfaceMethodref: - case ConstantConstant.CONSTANT_NameAndType: - case ConstantConstant.CONSTANT_Integer: - case ConstantConstant.CONSTANT_Float: - dis.read(); - dis.read(); - case ConstantConstant.CONSTANT_String: - dis.read(); - dis.read(); - break; - default: - //throw new ClassFormatException("Invalid constant pool entry"); - return constants; + case ConstantConstant.CONSTANT_Class: + constants[i] = new ConstantClass(tag, dis.readUnsignedShort()); + break; + case ConstantConstant.CONSTANT_Utf8: + constants[i] = new ConstantUtf8(tag, dis.readUTF()); + break; + case ConstantConstant.CONSTANT_Long: + case ConstantConstant.CONSTANT_Double: + dis.read(); + dis.read(); + dis.read(); + dis.read(); + i++; + case ConstantConstant.CONSTANT_Fieldref: + case ConstantConstant.CONSTANT_Methodref: + case ConstantConstant.CONSTANT_InterfaceMethodref: + case ConstantConstant.CONSTANT_NameAndType: + case ConstantConstant.CONSTANT_Integer: + case ConstantConstant.CONSTANT_Float: + dis.read(); + dis.read(); + case ConstantConstant.CONSTANT_String: + dis.read(); + dis.read(); + break; + default: + //throw new ClassFormatException("Invalid constant pool entry"); + return constants; } } diff --git a/src/main/java/me/konloch/kontainer/io/DiskReader.java b/src/main/java/me/konloch/kontainer/io/DiskReader.java index 5581f5e1..27786c96 100644 --- a/src/main/java/me/konloch/kontainer/io/DiskReader.java +++ b/src/main/java/me/konloch/kontainer/io/DiskReader.java @@ -1,13 +1,12 @@ package me.konloch.kontainer.io; -import the.bytecode.club.bytecodeviewer.util.EncodeUtils; - import java.io.BufferedReader; -import java.io.FileReader; import java.io.File; +import java.io.FileReader; import java.util.ArrayList; import java.util.HashMap; import java.util.Random; +import the.bytecode.club.bytecodeviewer.util.EncodeUtils; /** * Used to load from the disk, optional caching diff --git a/src/main/java/me/konloch/kontainer/io/DiskWriter.java b/src/main/java/me/konloch/kontainer/io/DiskWriter.java index 0248fec5..c3717361 100644 --- a/src/main/java/me/konloch/kontainer/io/DiskWriter.java +++ b/src/main/java/me/konloch/kontainer/io/DiskWriter.java @@ -19,7 +19,7 @@ public class DiskWriter { * @param fileName The file name * @param difference Normally an integer * @return The filename with the difference inserted and the file extension - * preserved + * preserved */ public static String insertFileName(String fileName, String difference) { String[] babe = fileName.split("\\."); diff --git a/src/main/java/org/objectweb/asm/ClassReader.java b/src/main/java/org/objectweb/asm/ClassReader.java index a8dc6672..c407c317 100644 --- a/src/main/java/org/objectweb/asm/ClassReader.java +++ b/src/main/java/org/objectweb/asm/ClassReader.java @@ -37,3597 +37,3606 @@ import java.io.InputStream; * appropriate visit methods of a given {@link ClassVisitor} for each field, method and bytecode * instruction encountered. * - * @see JVMS 4 * @author Eric Bruneton * @author Eugene Kuleshov + * @see JVMS 4 */ public class ClassReader { - /** - * A flag to skip the Code attributes. If this flag is set the Code attributes are neither parsed - * nor visited. - */ - public static final int SKIP_CODE = 1; + /** + * A flag to skip the Code attributes. If this flag is set the Code attributes are neither parsed + * nor visited. + */ + public static final int SKIP_CODE = 1; - /** - * A flag to skip the SourceFile, SourceDebugExtension, LocalVariableTable, LocalVariableTypeTable - * and LineNumberTable attributes. If this flag is set these attributes are neither parsed nor - * visited (i.e. {@link ClassVisitor#visitSource}, {@link MethodVisitor#visitLocalVariable} and - * {@link MethodVisitor#visitLineNumber} are not called). - */ - public static final int SKIP_DEBUG = 2; + /** + * A flag to skip the SourceFile, SourceDebugExtension, LocalVariableTable, LocalVariableTypeTable + * and LineNumberTable attributes. If this flag is set these attributes are neither parsed nor + * visited (i.e. {@link ClassVisitor#visitSource}, {@link MethodVisitor#visitLocalVariable} and + * {@link MethodVisitor#visitLineNumber} are not called). + */ + public static final int SKIP_DEBUG = 2; - /** - * A flag to skip the StackMap and StackMapTable attributes. If this flag is set these attributes - * are neither parsed nor visited (i.e. {@link MethodVisitor#visitFrame} is not called). This flag - * is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is used: it avoids visiting frames - * that will be ignored and recomputed from scratch. - */ - public static final int SKIP_FRAMES = 4; + /** + * A flag to skip the StackMap and StackMapTable attributes. If this flag is set these attributes + * are neither parsed nor visited (i.e. {@link MethodVisitor#visitFrame} is not called). This flag + * is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is used: it avoids visiting frames + * that will be ignored and recomputed from scratch. + */ + public static final int SKIP_FRAMES = 4; - /** - * A flag to expand the stack map frames. By default stack map frames are visited in their - * original format (i.e. "expanded" for classes whose version is less than V1_6, and "compressed" - * for the other classes). If this flag is set, stack map frames are always visited in expanded - * format (this option adds a decompression/compression step in ClassReader and ClassWriter which - * degrades performance quite a lot). - */ - public static final int EXPAND_FRAMES = 8; + /** + * A flag to expand the stack map frames. By default stack map frames are visited in their + * original format (i.e. "expanded" for classes whose version is less than V1_6, and "compressed" + * for the other classes). If this flag is set, stack map frames are always visited in expanded + * format (this option adds a decompression/compression step in ClassReader and ClassWriter which + * degrades performance quite a lot). + */ + public static final int EXPAND_FRAMES = 8; - /** - * A flag to expand the ASM specific instructions into an equivalent sequence of standard bytecode - * instructions. When resolving a forward jump it may happen that the signed 2 bytes offset - * reserved for it is not sufficient to store the bytecode offset. In this case the jump - * instruction is replaced with a temporary ASM specific instruction using an unsigned 2 bytes - * offset (see {@link Label#resolve}). This internal flag is used to re-read classes containing - * such instructions, in order to replace them with standard instructions. In addition, when this - * flag is used, goto_w and jsr_w are not converted into goto and jsr, to make sure that - * infinite loops where a goto_w is replaced with a goto in ClassReader and converted back to a - * goto_w in ClassWriter cannot occur. - */ - static final int EXPAND_ASM_INSNS = 256; + /** + * A flag to expand the ASM specific instructions into an equivalent sequence of standard bytecode + * instructions. When resolving a forward jump it may happen that the signed 2 bytes offset + * reserved for it is not sufficient to store the bytecode offset. In this case the jump + * instruction is replaced with a temporary ASM specific instruction using an unsigned 2 bytes + * offset (see {@link Label#resolve}). This internal flag is used to re-read classes containing + * such instructions, in order to replace them with standard instructions. In addition, when this + * flag is used, goto_w and jsr_w are not converted into goto and jsr, to make sure that + * infinite loops where a goto_w is replaced with a goto in ClassReader and converted back to a + * goto_w in ClassWriter cannot occur. + */ + static final int EXPAND_ASM_INSNS = 256; - /** The size of the temporary byte array used to read class input streams chunk by chunk. */ - private static final int INPUT_STREAM_DATA_CHUNK_SIZE = 4096; + /** + * The size of the temporary byte array used to read class input streams chunk by chunk. + */ + private static final int INPUT_STREAM_DATA_CHUNK_SIZE = 4096; - /** - * A byte array containing the JVMS ClassFile structure to be parsed. - * - * @deprecated Use {@link #readByte(int)} and the other read methods instead. This field will - * eventually be deleted. - */ - @Deprecated - // DontCheck(MemberName): can't be renamed (for backward binary compatibility). - public final byte[] b; + /** + * A byte array containing the JVMS ClassFile structure to be parsed. + * + * @deprecated Use {@link #readByte(int)} and the other read methods instead. This field will + * eventually be deleted. + */ + @Deprecated + // DontCheck(MemberName): can't be renamed (for backward binary compatibility). + public final byte[] b; - /** - * A byte array containing the JVMS ClassFile structure to be parsed. The content of this array - * must not be modified. This field is intended for {@link Attribute} sub classes, and is normally - * not needed by class visitors. - * - *

NOTE: the ClassFile structure can start at any offset within this array, i.e. it does not - * necessarily start at offset 0. Use {@link #getItem} and {@link #header} to get correct - * ClassFile element offsets within this byte array. - */ - final byte[] classFileBuffer; + /** + * A byte array containing the JVMS ClassFile structure to be parsed. The content of this array + * must not be modified. This field is intended for {@link Attribute} sub classes, and is normally + * not needed by class visitors. + * + *

NOTE: the ClassFile structure can start at any offset within this array, i.e. it does not + * necessarily start at offset 0. Use {@link #getItem} and {@link #header} to get correct + * ClassFile element offsets within this byte array. + */ + final byte[] classFileBuffer; - /** - * The offset in bytes, in {@link #classFileBuffer}, of each cp_info entry of the ClassFile's - * constant_pool array, plus one. In other words, the offset of constant pool entry i is - * given by cpInfoOffsets[i] - 1, i.e. its cp_info's tag field is given by b[cpInfoOffsets[i] - - * 1]. - */ - private final int[] cpInfoOffsets; + /** + * The offset in bytes, in {@link #classFileBuffer}, of each cp_info entry of the ClassFile's + * constant_pool array, plus one. In other words, the offset of constant pool entry i is + * given by cpInfoOffsets[i] - 1, i.e. its cp_info's tag field is given by b[cpInfoOffsets[i] - + * 1]. + */ + private final int[] cpInfoOffsets; - /** - * The String objects corresponding to the CONSTANT_Utf8 constant pool items. This cache avoids - * multiple parsing of a given CONSTANT_Utf8 constant pool item. - */ - private final String[] constantUtf8Values; + /** + * The String objects corresponding to the CONSTANT_Utf8 constant pool items. This cache avoids + * multiple parsing of a given CONSTANT_Utf8 constant pool item. + */ + private final String[] constantUtf8Values; - /** - * The ConstantDynamic objects corresponding to the CONSTANT_Dynamic constant pool items. This - * cache avoids multiple parsing of a given CONSTANT_Dynamic constant pool item. - */ - private final ConstantDynamic[] constantDynamicValues; + /** + * The ConstantDynamic objects corresponding to the CONSTANT_Dynamic constant pool items. This + * cache avoids multiple parsing of a given CONSTANT_Dynamic constant pool item. + */ + private final ConstantDynamic[] constantDynamicValues; - /** - * The start offsets in {@link #classFileBuffer} of each element of the bootstrap_methods array - * (in the BootstrapMethods attribute). - * - * @see JVMS - * 4.7.23 - */ - private final int[] bootstrapMethodOffsets; + /** + * The start offsets in {@link #classFileBuffer} of each element of the bootstrap_methods array + * (in the BootstrapMethods attribute). + * + * @see JVMS + * 4.7.23 + */ + private final int[] bootstrapMethodOffsets; - /** - * A conservative estimate of the maximum length of the strings contained in the constant pool of - * the class. - */ - private final int maxStringLength; + /** + * A conservative estimate of the maximum length of the strings contained in the constant pool of + * the class. + */ + private final int maxStringLength; - /** The offset in bytes of the ClassFile's access_flags field. */ - public final int header; + /** + * The offset in bytes of the ClassFile's access_flags field. + */ + public final int header; - // ----------------------------------------------------------------------------------------------- - // Constructors - // ----------------------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------------------- + // Constructors + // ----------------------------------------------------------------------------------------------- - /** - * Constructs a new {@link ClassReader} object. - * - * @param classFile the JVMS ClassFile structure to be read. - */ - public ClassReader(final byte[] classFile) { - this(classFile, 0, classFile.length); - } - - /** - * Constructs a new {@link ClassReader} object. - * - * @param classFileBuffer a byte array containing the JVMS ClassFile structure to be read. - * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read. - * @param classFileLength the length in bytes of the ClassFile to be read. - */ - public ClassReader( - final byte[] classFileBuffer, - final int classFileOffset, - final int classFileLength) { // NOPMD(UnusedFormalParameter) used for backward compatibility. - this(classFileBuffer, classFileOffset, /* checkClassVersion = */ true); - } - - /** - * Constructs a new {@link ClassReader} object. This internal constructor must not be exposed - * as a public API. - * - * @param classFileBuffer a byte array containing the JVMS ClassFile structure to be read. - * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read. - * @param checkClassVersion whether to check the class version or not. - */ - ClassReader( - final byte[] classFileBuffer, final int classFileOffset, final boolean checkClassVersion) { - this.classFileBuffer = classFileBuffer; - this.b = classFileBuffer; - // Check the class' major_version. This field is after the magic and minor_version fields, which - // use 4 and 2 bytes respectively. - if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V17) { - throw new IllegalArgumentException( - "Unsupported class file major version " + readShort(classFileOffset + 6)); - } - // Create the constant pool arrays. The constant_pool_count field is after the magic, - // minor_version and major_version fields, which use 4, 2 and 2 bytes respectively. - int constantPoolCount = readUnsignedShort(classFileOffset + 8); - cpInfoOffsets = new int[constantPoolCount]; - constantUtf8Values = new String[constantPoolCount]; - // Compute the offset of each constant pool entry, as well as a conservative estimate of the - // maximum length of the constant pool strings. The first constant pool entry is after the - // magic, minor_version, major_version and constant_pool_count fields, which use 4, 2, 2 and 2 - // bytes respectively. - int currentCpInfoIndex = 1; - int currentCpInfoOffset = classFileOffset + 10; - int currentMaxStringLength = 0; - boolean hasBootstrapMethods = false; - boolean hasConstantDynamic = false; - // The offset of the other entries depend on the total size of all the previous entries. - while (currentCpInfoIndex < constantPoolCount) { - cpInfoOffsets[currentCpInfoIndex++] = currentCpInfoOffset + 1; - int cpInfoSize; - switch (classFileBuffer[currentCpInfoOffset]) { - case Symbol.CONSTANT_FIELDREF_TAG: - case Symbol.CONSTANT_METHODREF_TAG: - case Symbol.CONSTANT_INTERFACE_METHODREF_TAG: - case Symbol.CONSTANT_INTEGER_TAG: - case Symbol.CONSTANT_FLOAT_TAG: - case Symbol.CONSTANT_NAME_AND_TYPE_TAG: - cpInfoSize = 5; - break; - case Symbol.CONSTANT_DYNAMIC_TAG: - cpInfoSize = 5; - hasBootstrapMethods = true; - hasConstantDynamic = true; - break; - case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG: - cpInfoSize = 5; - hasBootstrapMethods = true; - break; - case Symbol.CONSTANT_LONG_TAG: - case Symbol.CONSTANT_DOUBLE_TAG: - cpInfoSize = 9; - currentCpInfoIndex++; - break; - case Symbol.CONSTANT_UTF8_TAG: - cpInfoSize = 3 + readUnsignedShort(currentCpInfoOffset + 1); - if (cpInfoSize > currentMaxStringLength) { - // The size in bytes of this CONSTANT_Utf8 structure provides a conservative estimate - // of the length in characters of the corresponding string, and is much cheaper to - // compute than this exact length. - currentMaxStringLength = cpInfoSize; - } - break; - case Symbol.CONSTANT_METHOD_HANDLE_TAG: - cpInfoSize = 4; - break; - case Symbol.CONSTANT_CLASS_TAG: - case Symbol.CONSTANT_STRING_TAG: - case Symbol.CONSTANT_METHOD_TYPE_TAG: - case Symbol.CONSTANT_PACKAGE_TAG: - case Symbol.CONSTANT_MODULE_TAG: - cpInfoSize = 3; - break; - default: - throw new IllegalArgumentException(); - } - currentCpInfoOffset += cpInfoSize; - } - maxStringLength = currentMaxStringLength; - // The Classfile's access_flags field is just after the last constant pool entry. - header = currentCpInfoOffset; - - // Allocate the cache of ConstantDynamic values, if there is at least one. - constantDynamicValues = hasConstantDynamic ? new ConstantDynamic[constantPoolCount] : null; - - // Read the BootstrapMethods attribute, if any (only get the offset of each method). - bootstrapMethodOffsets = - hasBootstrapMethods ? readBootstrapMethodsAttribute(currentMaxStringLength) : null; - } - - /** - * Constructs a new {@link ClassReader} object. - * - * @param inputStream an input stream of the JVMS ClassFile structure to be read. This input - * stream must contain nothing more than the ClassFile structure itself. It is read from its - * current position to its end. - * @throws IOException if a problem occurs during reading. - */ - public ClassReader(final InputStream inputStream) throws IOException { - this(readStream(inputStream, false)); - } - - /** - * Constructs a new {@link ClassReader} object. - * - * @param className the fully qualified name of the class to be read. The ClassFile structure is - * retrieved with the current class loader's {@link ClassLoader#getSystemResourceAsStream}. - * @throws IOException if an exception occurs during reading. - */ - public ClassReader(final String className) throws IOException { - this( - readStream( - ClassLoader.getSystemResourceAsStream(className.replace('.', '/') + ".class"), true)); - } - - /** - * Reads the given input stream and returns its content as a byte array. - * - * @param inputStream an input stream. - * @param close true to close the input stream after reading. - * @return the content of the given input stream. - * @throws IOException if a problem occurs during reading. - */ - private static byte[] readStream(final InputStream inputStream, final boolean close) - throws IOException { - if (inputStream == null) { - throw new IOException("Class not found"); - } - try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { - byte[] data = new byte[INPUT_STREAM_DATA_CHUNK_SIZE]; - int bytesRead; - while ((bytesRead = inputStream.read(data, 0, data.length)) != -1) { - outputStream.write(data, 0, bytesRead); - } - outputStream.flush(); - return outputStream.toByteArray(); - } finally { - if (close) { - inputStream.close(); - } - } - } - - // ----------------------------------------------------------------------------------------------- - // Accessors - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the class's access flags (see {@link Opcodes}). This value may not reflect Deprecated - * and Synthetic flags when bytecode is before 1.5 and those flags are represented by attributes. - * - * @return the class access flags. - * @see ClassVisitor#visit(int, int, String, String, String, String[]) - */ - public int getAccess() { - return readUnsignedShort(header); - } - - /** - * Returns the internal name of the class (see {@link Type#getInternalName()}). - * - * @return the internal class name. - * @see ClassVisitor#visit(int, int, String, String, String, String[]) - */ - public String getClassName() { - // this_class is just after the access_flags field (using 2 bytes). - return readClass(header + 2, new char[maxStringLength]); - } - - /** - * Returns the internal of name of the super class (see {@link Type#getInternalName()}). For - * interfaces, the super class is {@link Object}. - * - * @return the internal name of the super class, or {@literal null} for {@link Object} class. - * @see ClassVisitor#visit(int, int, String, String, String, String[]) - */ - public String getSuperName() { - // super_class is after the access_flags and this_class fields (2 bytes each). - return readClass(header + 4, new char[maxStringLength]); - } - - /** - * Returns the internal names of the implemented interfaces (see {@link Type#getInternalName()}). - * - * @return the internal names of the directly implemented interfaces. Inherited implemented - * interfaces are not returned. - * @see ClassVisitor#visit(int, int, String, String, String, String[]) - */ - public String[] getInterfaces() { - // interfaces_count is after the access_flags, this_class and super_class fields (2 bytes each). - int currentOffset = header + 6; - int interfacesCount = readUnsignedShort(currentOffset); - String[] interfaces = new String[interfacesCount]; - if (interfacesCount > 0) { - char[] charBuffer = new char[maxStringLength]; - for (int i = 0; i < interfacesCount; ++i) { - currentOffset += 2; - interfaces[i] = readClass(currentOffset, charBuffer); - } - } - return interfaces; - } - - // ----------------------------------------------------------------------------------------------- - // Public methods - // ----------------------------------------------------------------------------------------------- - - /** - * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this - * {@link ClassReader}. - * - * @param classVisitor the visitor that must visit this class. - * @param parsingOptions the options to use to parse this class. One or more of {@link - * #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}. - */ - public void accept(final ClassVisitor classVisitor, final int parsingOptions) { - accept(classVisitor, new Attribute[0], parsingOptions); - } - - /** - * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this - * {@link ClassReader}. - * - * @param classVisitor the visitor that must visit this class. - * @param attributePrototypes prototypes of the attributes that must be parsed during the visit of - * the class. Any attribute whose type is not equal to the type of one the prototypes will not - * be parsed: its byte array value will be passed unchanged to the ClassWriter. This may - * corrupt it if this value contains references to the constant pool, or has syntactic or - * semantic links with a class element that has been transformed by a class adapter between - * the reader and the writer. - * @param parsingOptions the options to use to parse this class. One or more of {@link - * #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}. - */ - public void accept( - final ClassVisitor classVisitor, - final Attribute[] attributePrototypes, - final int parsingOptions) { - Context context = new Context(); - context.attributePrototypes = attributePrototypes; - context.parsingOptions = parsingOptions; - context.charBuffer = new char[maxStringLength]; - - // Read the access_flags, this_class, super_class, interface_count and interfaces fields. - char[] charBuffer = context.charBuffer; - int currentOffset = header; - int accessFlags = readUnsignedShort(currentOffset); - String thisClass = readClass(currentOffset + 2, charBuffer); - String superClass = readClass(currentOffset + 4, charBuffer); - String[] interfaces = new String[readUnsignedShort(currentOffset + 6)]; - currentOffset += 8; - for (int i = 0; i < interfaces.length; ++i) { - interfaces[i] = readClass(currentOffset, charBuffer); - currentOffset += 2; + /** + * Constructs a new {@link ClassReader} object. + * + * @param classFile the JVMS ClassFile structure to be read. + */ + public ClassReader(final byte[] classFile) { + this(classFile, 0, classFile.length); } - // Read the class attributes (the variables are ordered as in Section 4.7 of the JVMS). - // Attribute offsets exclude the attribute_name_index and attribute_length fields. - // - The offset of the InnerClasses attribute, or 0. - int innerClassesOffset = 0; - // - The offset of the EnclosingMethod attribute, or 0. - int enclosingMethodOffset = 0; - // - The string corresponding to the Signature attribute, or null. - String signature = null; - // - The string corresponding to the SourceFile attribute, or null. - String sourceFile = null; - // - The string corresponding to the SourceDebugExtension attribute, or null. - String sourceDebugExtension = null; - // - The offset of the RuntimeVisibleAnnotations attribute, or 0. - int runtimeVisibleAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. - int runtimeInvisibleAnnotationsOffset = 0; - // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. - int runtimeVisibleTypeAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. - int runtimeInvisibleTypeAnnotationsOffset = 0; - // - The offset of the Module attribute, or 0. - int moduleOffset = 0; - // - The offset of the ModulePackages attribute, or 0. - int modulePackagesOffset = 0; - // - The string corresponding to the ModuleMainClass attribute, or null. - String moduleMainClass = null; - // - The string corresponding to the NestHost attribute, or null. - String nestHostClass = null; - // - The offset of the NestMembers attribute, or 0. - int nestMembersOffset = 0; - // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). - // This list in the reverse order or their order in the ClassFile structure. - Attribute attributes = null; - - int currentAttributeOffset = getFirstAttributeOffset(); - for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) { - // Read the attribute_info's attribute_name and attribute_length fields. - String attributeName = readUTF8(currentAttributeOffset, charBuffer); - int attributeLength = readInt(currentAttributeOffset + 2); - currentAttributeOffset += 6; - // The tests are sorted in decreasing frequency order (based on frequencies observed on - // typical classes). - if (Constants.SOURCE_FILE.equals(attributeName)) { - sourceFile = readUTF8(currentAttributeOffset, charBuffer); - } else if (Constants.INNER_CLASSES.equals(attributeName)) { - innerClassesOffset = currentAttributeOffset; - } else if (Constants.ENCLOSING_METHOD.equals(attributeName)) { - enclosingMethodOffset = currentAttributeOffset; - } else if (Constants.NEST_HOST.equals(attributeName)) { - nestHostClass = readClass(currentAttributeOffset, charBuffer); - } else if (Constants.NEST_MEMBERS.equals(attributeName)) { - nestMembersOffset = currentAttributeOffset; - } else if (Constants.SIGNATURE.equals(attributeName)) { - signature = readUTF8(currentAttributeOffset, charBuffer); - } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleAnnotationsOffset = currentAttributeOffset; - } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleTypeAnnotationsOffset = currentAttributeOffset; - } else if (Constants.DEPRECATED.equals(attributeName)) { - accessFlags |= Opcodes.ACC_DEPRECATED; - } else if (Constants.SYNTHETIC.equals(attributeName)) { - accessFlags |= Opcodes.ACC_SYNTHETIC; - } else if (Constants.SOURCE_DEBUG_EXTENSION.equals(attributeName)) { - sourceDebugExtension = - readUtf(currentAttributeOffset, attributeLength, new char[attributeLength]); - } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleAnnotationsOffset = currentAttributeOffset; - } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleTypeAnnotationsOffset = currentAttributeOffset; - } else if (Constants.MODULE.equals(attributeName)) { - moduleOffset = currentAttributeOffset; - } else if (Constants.MODULE_MAIN_CLASS.equals(attributeName)) { - moduleMainClass = readClass(currentAttributeOffset, charBuffer); - } else if (Constants.MODULE_PACKAGES.equals(attributeName)) { - modulePackagesOffset = currentAttributeOffset; - } else if (!Constants.BOOTSTRAP_METHODS.equals(attributeName)) { - // The BootstrapMethods attribute is read in the constructor. - Attribute attribute = - readAttribute( - attributePrototypes, - attributeName, - currentAttributeOffset, - attributeLength, - charBuffer, - -1, - null); - attribute.nextAttribute = attributes; - attributes = attribute; - } - currentAttributeOffset += attributeLength; + /** + * Constructs a new {@link ClassReader} object. + * + * @param classFileBuffer a byte array containing the JVMS ClassFile structure to be read. + * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read. + * @param classFileLength the length in bytes of the ClassFile to be read. + */ + public ClassReader( + final byte[] classFileBuffer, + final int classFileOffset, + final int classFileLength) { // NOPMD(UnusedFormalParameter) used for backward compatibility. + this(classFileBuffer, classFileOffset, /* checkClassVersion = */ true); } - // Visit the class declaration. The minor_version and major_version fields start 6 bytes before - // the first constant pool entry, which itself starts at cpInfoOffsets[1] - 1 (by definition). - classVisitor.visit( - readInt(cpInfoOffsets[1] - 7), accessFlags, thisClass, signature, superClass, interfaces); - - // Visit the SourceFile and SourceDebugExtenstion attributes. - if ((parsingOptions & SKIP_DEBUG) == 0 - && (sourceFile != null || sourceDebugExtension != null)) { - classVisitor.visitSource(sourceFile, sourceDebugExtension); - } - - // Visit the Module, ModulePackages and ModuleMainClass attributes. - if (moduleOffset != 0) { - readModuleAttributes( - classVisitor, context, moduleOffset, modulePackagesOffset, moduleMainClass); - } - - // Visit the NestHost attribute. - if (nestHostClass != null) { - classVisitor.visitNestHost(nestHostClass); - } - - // Visit the EnclosingMethod attribute. - if (enclosingMethodOffset != 0) { - String className = readClass(enclosingMethodOffset, charBuffer); - int methodIndex = readUnsignedShort(enclosingMethodOffset + 2); - String name = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex], charBuffer); - String type = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex] + 2, charBuffer); - classVisitor.visitOuterClass(className, name, type); - } - - // Visit the RuntimeVisibleAnnotations attribute. - if (runtimeVisibleAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); - int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeInvisibleAnnotations attribute. - if (runtimeInvisibleAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset); - int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeVisibleTypeAnnotations attribute. - if (runtimeVisibleTypeAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset); - int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the target_type, target_info and target_path fields. - currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - classVisitor.visitTypeAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeInvisibleTypeAnnotations attribute. - if (runtimeInvisibleTypeAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset); - int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the target_type, target_info and target_path fields. - currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - classVisitor.visitTypeAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the non standard attributes. - while (attributes != null) { - // Copy and reset the nextAttribute field so that it can also be used in ClassWriter. - Attribute nextAttribute = attributes.nextAttribute; - attributes.nextAttribute = null; - classVisitor.visitAttribute(attributes); - attributes = nextAttribute; - } - - // Visit the NestedMembers attribute. - if (nestMembersOffset != 0) { - int numberOfNestMembers = readUnsignedShort(nestMembersOffset); - int currentNestMemberOffset = nestMembersOffset + 2; - while (numberOfNestMembers-- > 0) { - classVisitor.visitNestMember(readClass(currentNestMemberOffset, charBuffer)); - currentNestMemberOffset += 2; - } - } - - // Visit the InnerClasses attribute. - if (innerClassesOffset != 0) { - int numberOfClasses = readUnsignedShort(innerClassesOffset); - int currentClassesOffset = innerClassesOffset + 2; - while (numberOfClasses-- > 0) { - classVisitor.visitInnerClass( - readClass(currentClassesOffset, charBuffer), - readClass(currentClassesOffset + 2, charBuffer), - readUTF8(currentClassesOffset + 4, charBuffer), - readUnsignedShort(currentClassesOffset + 6)); - currentClassesOffset += 8; - } - } - - // Visit the fields and methods. - int fieldsCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (fieldsCount-- > 0) { - currentOffset = readField(classVisitor, context, currentOffset); - } - int methodsCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (methodsCount-- > 0) { - currentOffset = readMethod(classVisitor, context, currentOffset); - } - - // Visit the end of the class. - classVisitor.visitEnd(); - } - - // ---------------------------------------------------------------------------------------------- - // Methods to parse modules, fields and methods - // ---------------------------------------------------------------------------------------------- - - /** - * Reads the Module, ModulePackages and ModuleMainClass attributes and visit them. - * - * @param classVisitor the current class visitor - * @param context information about the class being parsed. - * @param moduleOffset the offset of the Module attribute (excluding the attribute_info's - * attribute_name_index and attribute_length fields). - * @param modulePackagesOffset the offset of the ModulePackages attribute (excluding the - * attribute_info's attribute_name_index and attribute_length fields), or 0. - * @param moduleMainClass the string corresponding to the ModuleMainClass attribute, or null. - */ - private void readModuleAttributes( - final ClassVisitor classVisitor, - final Context context, - final int moduleOffset, - final int modulePackagesOffset, - final String moduleMainClass) { - char[] buffer = context.charBuffer; - - // Read the module_name_index, module_flags and module_version_index fields and visit them. - int currentOffset = moduleOffset; - String moduleName = readModule(currentOffset, buffer); - int moduleFlags = readUnsignedShort(currentOffset + 2); - String moduleVersion = readUTF8(currentOffset + 4, buffer); - currentOffset += 6; - ModuleVisitor moduleVisitor = classVisitor.visitModule(moduleName, moduleFlags, moduleVersion); - if (moduleVisitor == null) { - return; - } - - // Visit the ModuleMainClass attribute. - if (moduleMainClass != null) { - moduleVisitor.visitMainClass(moduleMainClass); - } - - // Visit the ModulePackages attribute. - if (modulePackagesOffset != 0) { - int packageCount = readUnsignedShort(modulePackagesOffset); - int currentPackageOffset = modulePackagesOffset + 2; - while (packageCount-- > 0) { - moduleVisitor.visitPackage(readPackage(currentPackageOffset, buffer)); - currentPackageOffset += 2; - } - } - - // Read the 'requires_count' and 'requires' fields. - int requiresCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (requiresCount-- > 0) { - // Read the requires_index, requires_flags and requires_version fields and visit them. - String requires = readModule(currentOffset, buffer); - int requiresFlags = readUnsignedShort(currentOffset + 2); - String requiresVersion = readUTF8(currentOffset + 4, buffer); - currentOffset += 6; - moduleVisitor.visitRequire(requires, requiresFlags, requiresVersion); - } - - // Read the 'exports_count' and 'exports' fields. - int exportsCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (exportsCount-- > 0) { - // Read the exports_index, exports_flags, exports_to_count and exports_to_index fields - // and visit them. - String exports = readPackage(currentOffset, buffer); - int exportsFlags = readUnsignedShort(currentOffset + 2); - int exportsToCount = readUnsignedShort(currentOffset + 4); - currentOffset += 6; - String[] exportsTo = null; - if (exportsToCount != 0) { - exportsTo = new String[exportsToCount]; - for (int i = 0; i < exportsToCount; ++i) { - exportsTo[i] = readModule(currentOffset, buffer); - currentOffset += 2; + /** + * Constructs a new {@link ClassReader} object. This internal constructor must not be exposed + * as a public API. + * + * @param classFileBuffer a byte array containing the JVMS ClassFile structure to be read. + * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read. + * @param checkClassVersion whether to check the class version or not. + */ + ClassReader( + final byte[] classFileBuffer, final int classFileOffset, final boolean checkClassVersion) { + this.classFileBuffer = classFileBuffer; + this.b = classFileBuffer; + // Check the class' major_version. This field is after the magic and minor_version fields, which + // use 4 and 2 bytes respectively. + if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V17) { + throw new IllegalArgumentException( + "Unsupported class file major version " + readShort(classFileOffset + 6)); } - } - moduleVisitor.visitExport(exports, exportsFlags, exportsTo); - } - - // Reads the 'opens_count' and 'opens' fields. - int opensCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (opensCount-- > 0) { - // Read the opens_index, opens_flags, opens_to_count and opens_to_index fields and visit them. - String opens = readPackage(currentOffset, buffer); - int opensFlags = readUnsignedShort(currentOffset + 2); - int opensToCount = readUnsignedShort(currentOffset + 4); - currentOffset += 6; - String[] opensTo = null; - if (opensToCount != 0) { - opensTo = new String[opensToCount]; - for (int i = 0; i < opensToCount; ++i) { - opensTo[i] = readModule(currentOffset, buffer); - currentOffset += 2; - } - } - moduleVisitor.visitOpen(opens, opensFlags, opensTo); - } - - // Read the 'uses_count' and 'uses' fields. - int usesCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (usesCount-- > 0) { - moduleVisitor.visitUse(readClass(currentOffset, buffer)); - currentOffset += 2; - } - - // Read the 'provides_count' and 'provides' fields. - int providesCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (providesCount-- > 0) { - // Read the provides_index, provides_with_count and provides_with_index fields and visit them. - String provides = readClass(currentOffset, buffer); - int providesWithCount = readUnsignedShort(currentOffset + 2); - currentOffset += 4; - String[] providesWith = new String[providesWithCount]; - for (int i = 0; i < providesWithCount; ++i) { - providesWith[i] = readClass(currentOffset, buffer); - currentOffset += 2; - } - moduleVisitor.visitProvide(provides, providesWith); - } - - // Visit the end of the module attributes. - moduleVisitor.visitEnd(); - } - - /** - * Reads a JVMS field_info structure and makes the given visitor visit it. - * - * @param classVisitor the visitor that must visit the field. - * @param context information about the class being parsed. - * @param fieldInfoOffset the start offset of the field_info structure. - * @return the offset of the first byte following the field_info structure. - */ - private int readField( - final ClassVisitor classVisitor, final Context context, final int fieldInfoOffset) { - char[] charBuffer = context.charBuffer; - - // Read the access_flags, name_index and descriptor_index fields. - int currentOffset = fieldInfoOffset; - int accessFlags = readUnsignedShort(currentOffset); - String name = readUTF8(currentOffset + 2, charBuffer); - String descriptor = readUTF8(currentOffset + 4, charBuffer); - currentOffset += 6; - - // Read the field attributes (the variables are ordered as in Section 4.7 of the JVMS). - // Attribute offsets exclude the attribute_name_index and attribute_length fields. - // - The value corresponding to the ConstantValue attribute, or null. - Object constantValue = null; - // - The string corresponding to the Signature attribute, or null. - String signature = null; - // - The offset of the RuntimeVisibleAnnotations attribute, or 0. - int runtimeVisibleAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. - int runtimeInvisibleAnnotationsOffset = 0; - // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. - int runtimeVisibleTypeAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. - int runtimeInvisibleTypeAnnotationsOffset = 0; - // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). - // This list in the reverse order or their order in the ClassFile structure. - Attribute attributes = null; - - int attributesCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (attributesCount-- > 0) { - // Read the attribute_info's attribute_name and attribute_length fields. - String attributeName = readUTF8(currentOffset, charBuffer); - int attributeLength = readInt(currentOffset + 2); - currentOffset += 6; - // The tests are sorted in decreasing frequency order (based on frequencies observed on - // typical classes). - if (Constants.CONSTANT_VALUE.equals(attributeName)) { - int constantvalueIndex = readUnsignedShort(currentOffset); - constantValue = constantvalueIndex == 0 ? null : readConst(constantvalueIndex, charBuffer); - } else if (Constants.SIGNATURE.equals(attributeName)) { - signature = readUTF8(currentOffset, charBuffer); - } else if (Constants.DEPRECATED.equals(attributeName)) { - accessFlags |= Opcodes.ACC_DEPRECATED; - } else if (Constants.SYNTHETIC.equals(attributeName)) { - accessFlags |= Opcodes.ACC_SYNTHETIC; - } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleTypeAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleTypeAnnotationsOffset = currentOffset; - } else { - Attribute attribute = - readAttribute( - context.attributePrototypes, - attributeName, - currentOffset, - attributeLength, - charBuffer, - -1, - null); - attribute.nextAttribute = attributes; - attributes = attribute; - } - currentOffset += attributeLength; - } - - // Visit the field declaration. - FieldVisitor fieldVisitor = - classVisitor.visitField(accessFlags, name, descriptor, signature, constantValue); - if (fieldVisitor == null) { - return currentOffset; - } - - // Visit the RuntimeVisibleAnnotations attribute. - if (runtimeVisibleAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); - int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeInvisibleAnnotations attribute. - if (runtimeInvisibleAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset); - int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeVisibleTypeAnnotations attribute. - if (runtimeVisibleTypeAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset); - int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the target_type, target_info and target_path fields. - currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - fieldVisitor.visitTypeAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeInvisibleTypeAnnotations attribute. - if (runtimeInvisibleTypeAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset); - int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the target_type, target_info and target_path fields. - currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - fieldVisitor.visitTypeAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the non standard attributes. - while (attributes != null) { - // Copy and reset the nextAttribute field so that it can also be used in FieldWriter. - Attribute nextAttribute = attributes.nextAttribute; - attributes.nextAttribute = null; - fieldVisitor.visitAttribute(attributes); - attributes = nextAttribute; - } - - // Visit the end of the field. - fieldVisitor.visitEnd(); - return currentOffset; - } - - /** - * Reads a JVMS method_info structure and makes the given visitor visit it. - * - * @param classVisitor the visitor that must visit the method. - * @param context information about the class being parsed. - * @param methodInfoOffset the start offset of the method_info structure. - * @return the offset of the first byte following the method_info structure. - */ - private int readMethod( - final ClassVisitor classVisitor, final Context context, final int methodInfoOffset) { - char[] charBuffer = context.charBuffer; - - // Read the access_flags, name_index and descriptor_index fields. - int currentOffset = methodInfoOffset; - context.currentMethodAccessFlags = readUnsignedShort(currentOffset); - context.currentMethodName = readUTF8(currentOffset + 2, charBuffer); - context.currentMethodDescriptor = readUTF8(currentOffset + 4, charBuffer); - currentOffset += 6; - - // Read the method attributes (the variables are ordered as in Section 4.7 of the JVMS). - // Attribute offsets exclude the attribute_name_index and attribute_length fields. - // - The offset of the Code attribute, or 0. - int codeOffset = 0; - // - The offset of the Exceptions attribute, or 0. - int exceptionsOffset = 0; - // - The strings corresponding to the Exceptions attribute, or null. - String[] exceptions = null; - // - Whether the method has a Synthetic attribute. - boolean synthetic = false; - // - The constant pool index contained in the Signature attribute, or 0. - int signatureIndex = 0; - // - The offset of the RuntimeVisibleAnnotations attribute, or 0. - int runtimeVisibleAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. - int runtimeInvisibleAnnotationsOffset = 0; - // - The offset of the RuntimeVisibleParameterAnnotations attribute, or 0. - int runtimeVisibleParameterAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleParameterAnnotations attribute, or 0. - int runtimeInvisibleParameterAnnotationsOffset = 0; - // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. - int runtimeVisibleTypeAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. - int runtimeInvisibleTypeAnnotationsOffset = 0; - // - The offset of the AnnotationDefault attribute, or 0. - int annotationDefaultOffset = 0; - // - The offset of the MethodParameters attribute, or 0. - int methodParametersOffset = 0; - // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). - // This list in the reverse order or their order in the ClassFile structure. - Attribute attributes = null; - - int attributesCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (attributesCount-- > 0) { - // Read the attribute_info's attribute_name and attribute_length fields. - String attributeName = readUTF8(currentOffset, charBuffer); - int attributeLength = readInt(currentOffset + 2); - currentOffset += 6; - // The tests are sorted in decreasing frequency order (based on frequencies observed on - // typical classes). - if (Constants.CODE.equals(attributeName)) { - if ((context.parsingOptions & SKIP_CODE) == 0) { - codeOffset = currentOffset; - } - } else if (Constants.EXCEPTIONS.equals(attributeName)) { - exceptionsOffset = currentOffset; - exceptions = new String[readUnsignedShort(exceptionsOffset)]; - int currentExceptionOffset = exceptionsOffset + 2; - for (int i = 0; i < exceptions.length; ++i) { - exceptions[i] = readClass(currentExceptionOffset, charBuffer); - currentExceptionOffset += 2; - } - } else if (Constants.SIGNATURE.equals(attributeName)) { - signatureIndex = readUnsignedShort(currentOffset); - } else if (Constants.DEPRECATED.equals(attributeName)) { - context.currentMethodAccessFlags |= Opcodes.ACC_DEPRECATED; - } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleTypeAnnotationsOffset = currentOffset; - } else if (Constants.ANNOTATION_DEFAULT.equals(attributeName)) { - annotationDefaultOffset = currentOffset; - } else if (Constants.SYNTHETIC.equals(attributeName)) { - synthetic = true; - context.currentMethodAccessFlags |= Opcodes.ACC_SYNTHETIC; - } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleTypeAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleParameterAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleParameterAnnotationsOffset = currentOffset; - } else if (Constants.METHOD_PARAMETERS.equals(attributeName)) { - methodParametersOffset = currentOffset; - } else { - Attribute attribute = - readAttribute( - context.attributePrototypes, - attributeName, - currentOffset, - attributeLength, - charBuffer, - -1, - null); - attribute.nextAttribute = attributes; - attributes = attribute; - } - currentOffset += attributeLength; - } - - // Visit the method declaration. - MethodVisitor methodVisitor = - classVisitor.visitMethod( - context.currentMethodAccessFlags, - context.currentMethodName, - context.currentMethodDescriptor, - signatureIndex == 0 ? null : readUtf(signatureIndex, charBuffer), - exceptions); - if (methodVisitor == null) { - return currentOffset; - } - - // If the returned MethodVisitor is in fact a MethodWriter, it means there is no method - // adapter between the reader and the writer. In this case, it might be possible to copy - // the method attributes directly into the writer. If so, return early without visiting - // the content of these attributes. - if (methodVisitor instanceof MethodWriter) { - MethodWriter methodWriter = (MethodWriter) methodVisitor; - if (methodWriter.canCopyMethodAttributes( - this, - synthetic, - (context.currentMethodAccessFlags & Opcodes.ACC_DEPRECATED) != 0, - readUnsignedShort(methodInfoOffset + 4), - signatureIndex, - exceptionsOffset)) { - methodWriter.setMethodAttributesSource(methodInfoOffset, currentOffset - methodInfoOffset); - return currentOffset; - } - } - - // Visit the MethodParameters attribute. - if (methodParametersOffset != 0) { - int parametersCount = readByte(methodParametersOffset); - int currentParameterOffset = methodParametersOffset + 1; - while (parametersCount-- > 0) { - // Read the name_index and access_flags fields and visit them. - methodVisitor.visitParameter( - readUTF8(currentParameterOffset, charBuffer), - readUnsignedShort(currentParameterOffset + 2)); - currentParameterOffset += 4; - } - } - - // Visit the AnnotationDefault attribute. - if (annotationDefaultOffset != 0) { - AnnotationVisitor annotationVisitor = methodVisitor.visitAnnotationDefault(); - readElementValue(annotationVisitor, annotationDefaultOffset, null, charBuffer); - if (annotationVisitor != null) { - annotationVisitor.visitEnd(); - } - } - - // Visit the RuntimeVisibleAnnotations attribute. - if (runtimeVisibleAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); - int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeInvisibleAnnotations attribute. - if (runtimeInvisibleAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset); - int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeVisibleTypeAnnotations attribute. - if (runtimeVisibleTypeAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset); - int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the target_type, target_info and target_path fields. - currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - methodVisitor.visitTypeAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeInvisibleTypeAnnotations attribute. - if (runtimeInvisibleTypeAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset); - int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the target_type, target_info and target_path fields. - currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - methodVisitor.visitTypeAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeVisibleParameterAnnotations attribute. - if (runtimeVisibleParameterAnnotationsOffset != 0) { - readParameterAnnotations( - methodVisitor, context, runtimeVisibleParameterAnnotationsOffset, /* visible = */ true); - } - - // Visit the RuntimeInvisibleParameterAnnotations attribute. - if (runtimeInvisibleParameterAnnotationsOffset != 0) { - readParameterAnnotations( - methodVisitor, - context, - runtimeInvisibleParameterAnnotationsOffset, - /* visible = */ false); - } - - // Visit the non standard attributes. - while (attributes != null) { - // Copy and reset the nextAttribute field so that it can also be used in MethodWriter. - Attribute nextAttribute = attributes.nextAttribute; - attributes.nextAttribute = null; - methodVisitor.visitAttribute(attributes); - attributes = nextAttribute; - } - - // Visit the Code attribute. - if (codeOffset != 0) { - methodVisitor.visitCode(); - readCode(methodVisitor, context, codeOffset); - } - - // Visit the end of the method. - methodVisitor.visitEnd(); - return currentOffset; - } - - // ---------------------------------------------------------------------------------------------- - // Methods to parse a Code attribute - // ---------------------------------------------------------------------------------------------- - - /** - * Reads a JVMS 'Code' attribute and makes the given visitor visit it. - * - * @param methodVisitor the visitor that must visit the Code attribute. - * @param context information about the class being parsed. - * @param codeOffset the start offset in {@link #classFileBuffer} of the Code attribute, excluding - * its attribute_name_index and attribute_length fields. - */ - private void readCode( - final MethodVisitor methodVisitor, final Context context, final int codeOffset) { - int currentOffset = codeOffset; - - // Read the max_stack, max_locals and code_length fields. - final byte[] classBuffer = classFileBuffer; - final char[] charBuffer = context.charBuffer; - final int majorVersion = readUnsignedShort(6); - final int minorVersion = readUnsignedShort(4); - - final int maxStack; - final int maxLocals; - final int codeLength; - - if (majorVersion == 45 && minorVersion <= 2) { - maxStack = readByte(currentOffset); - maxLocals = readByte(currentOffset + 1); - codeLength = readUnsignedShort(currentOffset + 2); - currentOffset += 4; - } else { - maxStack = readUnsignedShort(currentOffset); - maxLocals = readUnsignedShort(currentOffset + 2); - codeLength = readInt(currentOffset + 4); - currentOffset += 8; - } - - // Read the bytecode 'code' array to create a label for each referenced instruction. - final int bytecodeStartOffset = currentOffset; - final int bytecodeEndOffset = currentOffset + codeLength; - final Label[] labels = context.currentMethodLabels = new Label[codeLength + 1]; - while (currentOffset < bytecodeEndOffset) { - final int bytecodeOffset = currentOffset - bytecodeStartOffset; - final int opcode = classBuffer[currentOffset] & 0xFF; - switch (opcode) { - case Opcodes.NOP: - case Opcodes.ACONST_NULL: - case Opcodes.ICONST_M1: - case Opcodes.ICONST_0: - case Opcodes.ICONST_1: - case Opcodes.ICONST_2: - case Opcodes.ICONST_3: - case Opcodes.ICONST_4: - case Opcodes.ICONST_5: - case Opcodes.LCONST_0: - case Opcodes.LCONST_1: - case Opcodes.FCONST_0: - case Opcodes.FCONST_1: - case Opcodes.FCONST_2: - case Opcodes.DCONST_0: - case Opcodes.DCONST_1: - case Opcodes.IALOAD: - case Opcodes.LALOAD: - case Opcodes.FALOAD: - case Opcodes.DALOAD: - case Opcodes.AALOAD: - case Opcodes.BALOAD: - case Opcodes.CALOAD: - case Opcodes.SALOAD: - case Opcodes.IASTORE: - case Opcodes.LASTORE: - case Opcodes.FASTORE: - case Opcodes.DASTORE: - case Opcodes.AASTORE: - case Opcodes.BASTORE: - case Opcodes.CASTORE: - case Opcodes.SASTORE: - case Opcodes.POP: - case Opcodes.POP2: - case Opcodes.DUP: - case Opcodes.DUP_X1: - case Opcodes.DUP_X2: - case Opcodes.DUP2: - case Opcodes.DUP2_X1: - case Opcodes.DUP2_X2: - case Opcodes.SWAP: - case Opcodes.IADD: - case Opcodes.LADD: - case Opcodes.FADD: - case Opcodes.DADD: - case Opcodes.ISUB: - case Opcodes.LSUB: - case Opcodes.FSUB: - case Opcodes.DSUB: - case Opcodes.IMUL: - case Opcodes.LMUL: - case Opcodes.FMUL: - case Opcodes.DMUL: - case Opcodes.IDIV: - case Opcodes.LDIV: - case Opcodes.FDIV: - case Opcodes.DDIV: - case Opcodes.IREM: - case Opcodes.LREM: - case Opcodes.FREM: - case Opcodes.DREM: - case Opcodes.INEG: - case Opcodes.LNEG: - case Opcodes.FNEG: - case Opcodes.DNEG: - case Opcodes.ISHL: - case Opcodes.LSHL: - case Opcodes.ISHR: - case Opcodes.LSHR: - case Opcodes.IUSHR: - case Opcodes.LUSHR: - case Opcodes.IAND: - case Opcodes.LAND: - case Opcodes.IOR: - case Opcodes.LOR: - case Opcodes.IXOR: - case Opcodes.LXOR: - case Opcodes.I2L: - case Opcodes.I2F: - case Opcodes.I2D: - case Opcodes.L2I: - case Opcodes.L2F: - case Opcodes.L2D: - case Opcodes.F2I: - case Opcodes.F2L: - case Opcodes.F2D: - case Opcodes.D2I: - case Opcodes.D2L: - case Opcodes.D2F: - case Opcodes.I2B: - case Opcodes.I2C: - case Opcodes.I2S: - case Opcodes.LCMP: - case Opcodes.FCMPL: - case Opcodes.FCMPG: - case Opcodes.DCMPL: - case Opcodes.DCMPG: - case Opcodes.IRETURN: - case Opcodes.LRETURN: - case Opcodes.FRETURN: - case Opcodes.DRETURN: - case Opcodes.ARETURN: - case Opcodes.RETURN: - case Opcodes.ARRAYLENGTH: - case Opcodes.ATHROW: - case Opcodes.MONITORENTER: - case Opcodes.MONITOREXIT: - case Constants.ILOAD_0: - case Constants.ILOAD_1: - case Constants.ILOAD_2: - case Constants.ILOAD_3: - case Constants.LLOAD_0: - case Constants.LLOAD_1: - case Constants.LLOAD_2: - case Constants.LLOAD_3: - case Constants.FLOAD_0: - case Constants.FLOAD_1: - case Constants.FLOAD_2: - case Constants.FLOAD_3: - case Constants.DLOAD_0: - case Constants.DLOAD_1: - case Constants.DLOAD_2: - case Constants.DLOAD_3: - case Constants.ALOAD_0: - case Constants.ALOAD_1: - case Constants.ALOAD_2: - case Constants.ALOAD_3: - case Constants.ISTORE_0: - case Constants.ISTORE_1: - case Constants.ISTORE_2: - case Constants.ISTORE_3: - case Constants.LSTORE_0: - case Constants.LSTORE_1: - case Constants.LSTORE_2: - case Constants.LSTORE_3: - case Constants.FSTORE_0: - case Constants.FSTORE_1: - case Constants.FSTORE_2: - case Constants.FSTORE_3: - case Constants.DSTORE_0: - case Constants.DSTORE_1: - case Constants.DSTORE_2: - case Constants.DSTORE_3: - case Constants.ASTORE_0: - case Constants.ASTORE_1: - case Constants.ASTORE_2: - case Constants.ASTORE_3: - currentOffset += 1; - break; - case Opcodes.IFEQ: - case Opcodes.IFNE: - case Opcodes.IFLT: - case Opcodes.IFGE: - case Opcodes.IFGT: - case Opcodes.IFLE: - case Opcodes.IF_ICMPEQ: - case Opcodes.IF_ICMPNE: - case Opcodes.IF_ICMPLT: - case Opcodes.IF_ICMPGE: - case Opcodes.IF_ICMPGT: - case Opcodes.IF_ICMPLE: - case Opcodes.IF_ACMPEQ: - case Opcodes.IF_ACMPNE: - case Opcodes.GOTO: - case Opcodes.JSR: - case Opcodes.IFNULL: - case Opcodes.IFNONNULL: - createLabel(bytecodeOffset + readShort(currentOffset + 1), labels); - currentOffset += 3; - break; - case Constants.ASM_IFEQ: - case Constants.ASM_IFNE: - case Constants.ASM_IFLT: - case Constants.ASM_IFGE: - case Constants.ASM_IFGT: - case Constants.ASM_IFLE: - case Constants.ASM_IF_ICMPEQ: - case Constants.ASM_IF_ICMPNE: - case Constants.ASM_IF_ICMPLT: - case Constants.ASM_IF_ICMPGE: - case Constants.ASM_IF_ICMPGT: - case Constants.ASM_IF_ICMPLE: - case Constants.ASM_IF_ACMPEQ: - case Constants.ASM_IF_ACMPNE: - case Constants.ASM_GOTO: - case Constants.ASM_JSR: - case Constants.ASM_IFNULL: - case Constants.ASM_IFNONNULL: - createLabel(bytecodeOffset + readUnsignedShort(currentOffset + 1), labels); - currentOffset += 3; - break; - case Constants.GOTO_W: - case Constants.JSR_W: - case Constants.ASM_GOTO_W: - createLabel(bytecodeOffset + readInt(currentOffset + 1), labels); - currentOffset += 5; - break; - case Constants.WIDE: - switch (classBuffer[currentOffset + 1] & 0xFF) { - case Opcodes.ILOAD: - case Opcodes.FLOAD: - case Opcodes.ALOAD: - case Opcodes.LLOAD: - case Opcodes.DLOAD: - case Opcodes.ISTORE: - case Opcodes.FSTORE: - case Opcodes.ASTORE: - case Opcodes.LSTORE: - case Opcodes.DSTORE: - case Opcodes.RET: - currentOffset += 4; - break; - case Opcodes.IINC: - currentOffset += 6; - break; + // Create the constant pool arrays. The constant_pool_count field is after the magic, + // minor_version and major_version fields, which use 4, 2 and 2 bytes respectively. + int constantPoolCount = readUnsignedShort(classFileOffset + 8); + cpInfoOffsets = new int[constantPoolCount]; + constantUtf8Values = new String[constantPoolCount]; + // Compute the offset of each constant pool entry, as well as a conservative estimate of the + // maximum length of the constant pool strings. The first constant pool entry is after the + // magic, minor_version, major_version and constant_pool_count fields, which use 4, 2, 2 and 2 + // bytes respectively. + int currentCpInfoIndex = 1; + int currentCpInfoOffset = classFileOffset + 10; + int currentMaxStringLength = 0; + boolean hasBootstrapMethods = false; + boolean hasConstantDynamic = false; + // The offset of the other entries depend on the total size of all the previous entries. + while (currentCpInfoIndex < constantPoolCount) { + cpInfoOffsets[currentCpInfoIndex++] = currentCpInfoOffset + 1; + int cpInfoSize; + switch (classFileBuffer[currentCpInfoOffset]) { + case Symbol.CONSTANT_FIELDREF_TAG: + case Symbol.CONSTANT_METHODREF_TAG: + case Symbol.CONSTANT_INTERFACE_METHODREF_TAG: + case Symbol.CONSTANT_INTEGER_TAG: + case Symbol.CONSTANT_FLOAT_TAG: + case Symbol.CONSTANT_NAME_AND_TYPE_TAG: + cpInfoSize = 5; + break; + case Symbol.CONSTANT_DYNAMIC_TAG: + cpInfoSize = 5; + hasBootstrapMethods = true; + hasConstantDynamic = true; + break; + case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG: + cpInfoSize = 5; + hasBootstrapMethods = true; + break; + case Symbol.CONSTANT_LONG_TAG: + case Symbol.CONSTANT_DOUBLE_TAG: + cpInfoSize = 9; + currentCpInfoIndex++; + break; + case Symbol.CONSTANT_UTF8_TAG: + cpInfoSize = 3 + readUnsignedShort(currentCpInfoOffset + 1); + if (cpInfoSize > currentMaxStringLength) { + // The size in bytes of this CONSTANT_Utf8 structure provides a conservative estimate + // of the length in characters of the corresponding string, and is much cheaper to + // compute than this exact length. + currentMaxStringLength = cpInfoSize; + } + break; + case Symbol.CONSTANT_METHOD_HANDLE_TAG: + cpInfoSize = 4; + break; + case Symbol.CONSTANT_CLASS_TAG: + case Symbol.CONSTANT_STRING_TAG: + case Symbol.CONSTANT_METHOD_TYPE_TAG: + case Symbol.CONSTANT_PACKAGE_TAG: + case Symbol.CONSTANT_MODULE_TAG: + cpInfoSize = 3; + break; default: - throw new IllegalArgumentException(); - } - break; - case Opcodes.TABLESWITCH: - // Skip 0 to 3 padding bytes. - currentOffset += 4 - (bytecodeOffset & 3); - // Read the default label and the number of table entries. - createLabel(bytecodeOffset + readInt(currentOffset), labels); - int numTableEntries = readInt(currentOffset + 8) - readInt(currentOffset + 4) + 1; - currentOffset += 12; - // Read the table labels. - while (numTableEntries-- > 0) { - createLabel(bytecodeOffset + readInt(currentOffset), labels); - currentOffset += 4; - } - break; - case Opcodes.LOOKUPSWITCH: - // Skip 0 to 3 padding bytes. - currentOffset += 4 - (bytecodeOffset & 3); - // Read the default label and the number of switch cases. - createLabel(bytecodeOffset + readInt(currentOffset), labels); - int numSwitchCases = readInt(currentOffset + 4); - currentOffset += 8; - // Read the switch labels. - while (numSwitchCases-- > 0) { - createLabel(bytecodeOffset + readInt(currentOffset + 4), labels); - currentOffset += 8; - } - break; - case Opcodes.ILOAD: - case Opcodes.LLOAD: - case Opcodes.FLOAD: - case Opcodes.DLOAD: - case Opcodes.ALOAD: - case Opcodes.ISTORE: - case Opcodes.LSTORE: - case Opcodes.FSTORE: - case Opcodes.DSTORE: - case Opcodes.ASTORE: - case Opcodes.RET: - case Opcodes.BIPUSH: - case Opcodes.NEWARRAY: - case Opcodes.LDC: - currentOffset += 2; - break; - case Opcodes.SIPUSH: - case Constants.LDC_W: - case Constants.LDC2_W: - case Opcodes.GETSTATIC: - case Opcodes.PUTSTATIC: - case Opcodes.GETFIELD: - case Opcodes.PUTFIELD: - case Opcodes.INVOKEVIRTUAL: - case Opcodes.INVOKESPECIAL: - case Opcodes.INVOKESTATIC: - case Opcodes.NEW: - case Opcodes.ANEWARRAY: - case Opcodes.CHECKCAST: - case Opcodes.INSTANCEOF: - case Opcodes.IINC: - currentOffset += 3; - break; - case Opcodes.INVOKEINTERFACE: - case Opcodes.INVOKEDYNAMIC: - currentOffset += 5; - break; - case Opcodes.MULTIANEWARRAY: - currentOffset += 4; - break; - default: - throw new IllegalArgumentException(); - } - } - - // Read the 'exception_table_length' and 'exception_table' field to create a label for each - // referenced instruction, and to make methodVisitor visit the corresponding try catch blocks. - int exceptionTableLength = readUnsignedShort(currentOffset); - currentOffset += 2; - while (exceptionTableLength-- > 0) { - Label start = createLabel(readUnsignedShort(currentOffset), labels); - Label end = createLabel(readUnsignedShort(currentOffset + 2), labels); - Label handler = createLabel(readUnsignedShort(currentOffset + 4), labels); - String catchType = readUTF8(cpInfoOffsets[readUnsignedShort(currentOffset + 6)], charBuffer); - currentOffset += 8; - methodVisitor.visitTryCatchBlock(start, end, handler, catchType); - } - - // Read the Code attributes to create a label for each referenced instruction (the variables - // are ordered as in Section 4.7 of the JVMS). Attribute offsets exclude the - // attribute_name_index and attribute_length fields. - // - The offset of the current 'stack_map_frame' in the StackMap[Table] attribute, or 0. - // Initially, this is the offset of the first 'stack_map_frame' entry. Then this offset is - // updated after each stack_map_frame is read. - int stackMapFrameOffset = 0; - // - The end offset of the StackMap[Table] attribute, or 0. - int stackMapTableEndOffset = 0; - // - Whether the stack map frames are compressed (i.e. in a StackMapTable) or not. - boolean compressedFrames = true; - // - The offset of the LocalVariableTable attribute, or 0. - int localVariableTableOffset = 0; - // - The offset of the LocalVariableTypeTable attribute, or 0. - int localVariableTypeTableOffset = 0; - // - The offset of each 'type_annotation' entry in the RuntimeVisibleTypeAnnotations - // attribute, or null. - int[] visibleTypeAnnotationOffsets = null; - // - The offset of each 'type_annotation' entry in the RuntimeInvisibleTypeAnnotations - // attribute, or null. - int[] invisibleTypeAnnotationOffsets = null; - // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). - // This list in the reverse order or their order in the ClassFile structure. - Attribute attributes = null; - - int attributesCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (attributesCount-- > 0) { - // Read the attribute_info's attribute_name and attribute_length fields. - String attributeName = readUTF8(currentOffset, charBuffer); - int attributeLength = readInt(currentOffset + 2); - currentOffset += 6; - if (Constants.LOCAL_VARIABLE_TABLE.equals(attributeName)) { - if ((context.parsingOptions & SKIP_DEBUG) == 0) { - localVariableTableOffset = currentOffset; - // Parse the attribute to find the corresponding (debug only) labels. - int currentLocalVariableTableOffset = currentOffset; - int localVariableTableLength = readUnsignedShort(currentLocalVariableTableOffset); - currentLocalVariableTableOffset += 2; - while (localVariableTableLength-- > 0) { - int startPc = readUnsignedShort(currentLocalVariableTableOffset); - createDebugLabel(startPc, labels); - int length = readUnsignedShort(currentLocalVariableTableOffset + 2); - createDebugLabel(startPc + length, labels); - // Skip the name_index, descriptor_index and index fields (2 bytes each). - currentLocalVariableTableOffset += 10; - } - } - } else if (Constants.LOCAL_VARIABLE_TYPE_TABLE.equals(attributeName)) { - localVariableTypeTableOffset = currentOffset; - // Here we do not extract the labels corresponding to the attribute content. We assume they - // are the same or a subset of those of the LocalVariableTable attribute. - } else if (Constants.LINE_NUMBER_TABLE.equals(attributeName)) { - if ((context.parsingOptions & SKIP_DEBUG) == 0) { - // Parse the attribute to find the corresponding (debug only) labels. - int currentLineNumberTableOffset = currentOffset; - int lineNumberTableLength = readUnsignedShort(currentLineNumberTableOffset); - currentLineNumberTableOffset += 2; - while (lineNumberTableLength-- > 0) { - int startPc = readUnsignedShort(currentLineNumberTableOffset); - int lineNumber = readUnsignedShort(currentLineNumberTableOffset + 2); - currentLineNumberTableOffset += 4; - createDebugLabel(startPc, labels); - labels[startPc].addLineNumber(lineNumber); - } - } - } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - visibleTypeAnnotationOffsets = - readTypeAnnotations(methodVisitor, context, currentOffset, /* visible = */ true); - // Here we do not extract the labels corresponding to the attribute content. This would - // require a full parsing of the attribute, which would need to be repeated when parsing - // the bytecode instructions (see below). Instead, the content of the attribute is read one - // type annotation at a time (i.e. after a type annotation has been visited, the next type - // annotation is read), and the labels it contains are also extracted one annotation at a - // time. This assumes that type annotations are ordered by increasing bytecode offset. - } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - invisibleTypeAnnotationOffsets = - readTypeAnnotations(methodVisitor, context, currentOffset, /* visible = */ false); - // Same comment as above for the RuntimeVisibleTypeAnnotations attribute. - } else if (Constants.STACK_MAP_TABLE.equals(attributeName)) { - if ((context.parsingOptions & SKIP_FRAMES) == 0) { - stackMapFrameOffset = currentOffset + 2; - stackMapTableEndOffset = currentOffset + attributeLength; - } - // Here we do not extract the labels corresponding to the attribute content. This would - // require a full parsing of the attribute, which would need to be repeated when parsing - // the bytecode instructions (see below). Instead, the content of the attribute is read one - // frame at a time (i.e. after a frame has been visited, the next frame is read), and the - // labels it contains are also extracted one frame at a time. Thanks to the ordering of - // frames, having only a "one frame lookahead" is not a problem, i.e. it is not possible to - // see an offset smaller than the offset of the current instruction and for which no Label - // exist. Except for UNINITIALIZED type offsets. We solve this by parsing the stack map - // table without a full decoding (see below). - } else if ("StackMap".equals(attributeName)) { - if ((context.parsingOptions & SKIP_FRAMES) == 0) { - stackMapFrameOffset = currentOffset + 2; - stackMapTableEndOffset = currentOffset + attributeLength; - compressedFrames = false; - } - // IMPORTANT! Here we assume that the frames are ordered, as in the StackMapTable attribute, - // although this is not guaranteed by the attribute format. This allows an incremental - // extraction of the labels corresponding to this attribute (see the comment above for the - // StackMapTable attribute). - } else { - Attribute attribute = - readAttribute( - context.attributePrototypes, - attributeName, - currentOffset, - attributeLength, - charBuffer, - codeOffset, - labels); - attribute.nextAttribute = attributes; - attributes = attribute; - } - currentOffset += attributeLength; - } - - // Initialize the context fields related to stack map frames, and generate the first - // (implicit) stack map frame, if needed. - final boolean expandFrames = (context.parsingOptions & EXPAND_FRAMES) != 0; - if (stackMapFrameOffset != 0) { - // The bytecode offset of the first explicit frame is not offset_delta + 1 but only - // offset_delta. Setting the implicit frame offset to -1 allows us to use of the - // "offset_delta + 1" rule in all cases. - context.currentFrameOffset = -1; - context.currentFrameType = 0; - context.currentFrameLocalCount = 0; - context.currentFrameLocalCountDelta = 0; - context.currentFrameLocalTypes = new Object[maxLocals]; - context.currentFrameStackCount = 0; - context.currentFrameStackTypes = new Object[maxStack]; - if (expandFrames) { - computeImplicitFrame(context); - } - // Find the labels for UNINITIALIZED frame types. Instead of decoding each element of the - // stack map table, we look for 3 consecutive bytes that "look like" an UNINITIALIZED type - // (tag ITEM_Uninitialized, offset within bytecode bounds, NEW instruction at this offset). - // We may find false positives (i.e. not real UNINITIALIZED types), but this should be rare, - // and the only consequence will be the creation of an unneeded label. This is better than - // creating a label for each NEW instruction, and faster than fully decoding the whole stack - // map table. - for (int offset = stackMapFrameOffset; offset < stackMapTableEndOffset - 2; ++offset) { - if (classBuffer[offset] == Frame.ITEM_UNINITIALIZED) { - int potentialBytecodeOffset = readUnsignedShort(offset + 1); - if (potentialBytecodeOffset >= 0 - && potentialBytecodeOffset < codeLength - && (classBuffer[bytecodeStartOffset + potentialBytecodeOffset] & 0xFF) - == Opcodes.NEW) { - createLabel(potentialBytecodeOffset, labels); - } - } - } - } - if (expandFrames && (context.parsingOptions & EXPAND_ASM_INSNS) != 0) { - // Expanding the ASM specific instructions can introduce F_INSERT frames, even if the method - // does not currently have any frame. These inserted frames must be computed by simulating the - // effect of the bytecode instructions, one by one, starting from the implicit first frame. - // For this, MethodWriter needs to know maxLocals before the first instruction is visited. To - // ensure this, we visit the implicit first frame here (passing only maxLocals - the rest is - // computed in MethodWriter). - methodVisitor.visitFrame(Opcodes.F_NEW, maxLocals, null, 0, null); - } - - // Visit the bytecode instructions. First, introduce state variables for the incremental parsing - // of the type annotations. - - // Index of the next runtime visible type annotation to read (in the - // visibleTypeAnnotationOffsets array). - int currentVisibleTypeAnnotationIndex = 0; - // The bytecode offset of the next runtime visible type annotation to read, or -1. - int currentVisibleTypeAnnotationBytecodeOffset = - getTypeAnnotationBytecodeOffset(visibleTypeAnnotationOffsets, 0); - // Index of the next runtime invisible type annotation to read (in the - // invisibleTypeAnnotationOffsets array). - int currentInvisibleTypeAnnotationIndex = 0; - // The bytecode offset of the next runtime invisible type annotation to read, or -1. - int currentInvisibleTypeAnnotationBytecodeOffset = - getTypeAnnotationBytecodeOffset(invisibleTypeAnnotationOffsets, 0); - - // Whether a F_INSERT stack map frame must be inserted before the current instruction. - boolean insertFrame = false; - - // The delta to subtract from a goto_w or jsr_w opcode to get the corresponding goto or jsr - // opcode, or 0 if goto_w and jsr_w must be left unchanged (i.e. when expanding ASM specific - // instructions). - final int wideJumpOpcodeDelta = - (context.parsingOptions & EXPAND_ASM_INSNS) == 0 ? Constants.WIDE_JUMP_OPCODE_DELTA : 0; - - currentOffset = bytecodeStartOffset; - while (currentOffset < bytecodeEndOffset) { - final int currentBytecodeOffset = currentOffset - bytecodeStartOffset; - - // Visit the label and the line number(s) for this bytecode offset, if any. - Label currentLabel = labels[currentBytecodeOffset]; - if (currentLabel != null) { - currentLabel.accept(methodVisitor, (context.parsingOptions & SKIP_DEBUG) == 0); - } - - // Visit the stack map frame for this bytecode offset, if any. - while (stackMapFrameOffset != 0 - && (context.currentFrameOffset == currentBytecodeOffset - || context.currentFrameOffset == -1)) { - // If there is a stack map frame for this offset, make methodVisitor visit it, and read the - // next stack map frame if there is one. - if (context.currentFrameOffset != -1) { - if (!compressedFrames || expandFrames) { - methodVisitor.visitFrame( - Opcodes.F_NEW, - context.currentFrameLocalCount, - context.currentFrameLocalTypes, - context.currentFrameStackCount, - context.currentFrameStackTypes); - } else { - methodVisitor.visitFrame( - context.currentFrameType, - context.currentFrameLocalCountDelta, - context.currentFrameLocalTypes, - context.currentFrameStackCount, - context.currentFrameStackTypes); - } - // Since there is already a stack map frame for this bytecode offset, there is no need to - // insert a new one. - insertFrame = false; - } - if (stackMapFrameOffset < stackMapTableEndOffset) { - stackMapFrameOffset = - readStackMapFrame(stackMapFrameOffset, compressedFrames, expandFrames, context); - } else { - stackMapFrameOffset = 0; - } - } - - // Insert a stack map frame for this bytecode offset, if requested by setting insertFrame to - // true during the previous iteration. The actual frame content is computed in MethodWriter. - if (insertFrame) { - if ((context.parsingOptions & EXPAND_FRAMES) != 0) { - methodVisitor.visitFrame(Constants.F_INSERT, 0, null, 0, null); - } - insertFrame = false; - } - - // Visit the instruction at this bytecode offset. - int opcode = classBuffer[currentOffset] & 0xFF; - switch (opcode) { - case Opcodes.NOP: - case Opcodes.ACONST_NULL: - case Opcodes.ICONST_M1: - case Opcodes.ICONST_0: - case Opcodes.ICONST_1: - case Opcodes.ICONST_2: - case Opcodes.ICONST_3: - case Opcodes.ICONST_4: - case Opcodes.ICONST_5: - case Opcodes.LCONST_0: - case Opcodes.LCONST_1: - case Opcodes.FCONST_0: - case Opcodes.FCONST_1: - case Opcodes.FCONST_2: - case Opcodes.DCONST_0: - case Opcodes.DCONST_1: - case Opcodes.IALOAD: - case Opcodes.LALOAD: - case Opcodes.FALOAD: - case Opcodes.DALOAD: - case Opcodes.AALOAD: - case Opcodes.BALOAD: - case Opcodes.CALOAD: - case Opcodes.SALOAD: - case Opcodes.IASTORE: - case Opcodes.LASTORE: - case Opcodes.FASTORE: - case Opcodes.DASTORE: - case Opcodes.AASTORE: - case Opcodes.BASTORE: - case Opcodes.CASTORE: - case Opcodes.SASTORE: - case Opcodes.POP: - case Opcodes.POP2: - case Opcodes.DUP: - case Opcodes.DUP_X1: - case Opcodes.DUP_X2: - case Opcodes.DUP2: - case Opcodes.DUP2_X1: - case Opcodes.DUP2_X2: - case Opcodes.SWAP: - case Opcodes.IADD: - case Opcodes.LADD: - case Opcodes.FADD: - case Opcodes.DADD: - case Opcodes.ISUB: - case Opcodes.LSUB: - case Opcodes.FSUB: - case Opcodes.DSUB: - case Opcodes.IMUL: - case Opcodes.LMUL: - case Opcodes.FMUL: - case Opcodes.DMUL: - case Opcodes.IDIV: - case Opcodes.LDIV: - case Opcodes.FDIV: - case Opcodes.DDIV: - case Opcodes.IREM: - case Opcodes.LREM: - case Opcodes.FREM: - case Opcodes.DREM: - case Opcodes.INEG: - case Opcodes.LNEG: - case Opcodes.FNEG: - case Opcodes.DNEG: - case Opcodes.ISHL: - case Opcodes.LSHL: - case Opcodes.ISHR: - case Opcodes.LSHR: - case Opcodes.IUSHR: - case Opcodes.LUSHR: - case Opcodes.IAND: - case Opcodes.LAND: - case Opcodes.IOR: - case Opcodes.LOR: - case Opcodes.IXOR: - case Opcodes.LXOR: - case Opcodes.I2L: - case Opcodes.I2F: - case Opcodes.I2D: - case Opcodes.L2I: - case Opcodes.L2F: - case Opcodes.L2D: - case Opcodes.F2I: - case Opcodes.F2L: - case Opcodes.F2D: - case Opcodes.D2I: - case Opcodes.D2L: - case Opcodes.D2F: - case Opcodes.I2B: - case Opcodes.I2C: - case Opcodes.I2S: - case Opcodes.LCMP: - case Opcodes.FCMPL: - case Opcodes.FCMPG: - case Opcodes.DCMPL: - case Opcodes.DCMPG: - case Opcodes.IRETURN: - case Opcodes.LRETURN: - case Opcodes.FRETURN: - case Opcodes.DRETURN: - case Opcodes.ARETURN: - case Opcodes.RETURN: - case Opcodes.ARRAYLENGTH: - case Opcodes.ATHROW: - case Opcodes.MONITORENTER: - case Opcodes.MONITOREXIT: - methodVisitor.visitInsn(opcode); - currentOffset += 1; - break; - case Constants.ILOAD_0: - case Constants.ILOAD_1: - case Constants.ILOAD_2: - case Constants.ILOAD_3: - case Constants.LLOAD_0: - case Constants.LLOAD_1: - case Constants.LLOAD_2: - case Constants.LLOAD_3: - case Constants.FLOAD_0: - case Constants.FLOAD_1: - case Constants.FLOAD_2: - case Constants.FLOAD_3: - case Constants.DLOAD_0: - case Constants.DLOAD_1: - case Constants.DLOAD_2: - case Constants.DLOAD_3: - case Constants.ALOAD_0: - case Constants.ALOAD_1: - case Constants.ALOAD_2: - case Constants.ALOAD_3: - opcode -= Constants.ILOAD_0; - methodVisitor.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3); - currentOffset += 1; - break; - case Constants.ISTORE_0: - case Constants.ISTORE_1: - case Constants.ISTORE_2: - case Constants.ISTORE_3: - case Constants.LSTORE_0: - case Constants.LSTORE_1: - case Constants.LSTORE_2: - case Constants.LSTORE_3: - case Constants.FSTORE_0: - case Constants.FSTORE_1: - case Constants.FSTORE_2: - case Constants.FSTORE_3: - case Constants.DSTORE_0: - case Constants.DSTORE_1: - case Constants.DSTORE_2: - case Constants.DSTORE_3: - case Constants.ASTORE_0: - case Constants.ASTORE_1: - case Constants.ASTORE_2: - case Constants.ASTORE_3: - opcode -= Constants.ISTORE_0; - methodVisitor.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), opcode & 0x3); - currentOffset += 1; - break; - case Opcodes.IFEQ: - case Opcodes.IFNE: - case Opcodes.IFLT: - case Opcodes.IFGE: - case Opcodes.IFGT: - case Opcodes.IFLE: - case Opcodes.IF_ICMPEQ: - case Opcodes.IF_ICMPNE: - case Opcodes.IF_ICMPLT: - case Opcodes.IF_ICMPGE: - case Opcodes.IF_ICMPGT: - case Opcodes.IF_ICMPLE: - case Opcodes.IF_ACMPEQ: - case Opcodes.IF_ACMPNE: - case Opcodes.GOTO: - case Opcodes.JSR: - case Opcodes.IFNULL: - case Opcodes.IFNONNULL: - methodVisitor.visitJumpInsn( - opcode, labels[currentBytecodeOffset + readShort(currentOffset + 1)]); - currentOffset += 3; - break; - case Constants.GOTO_W: - case Constants.JSR_W: - methodVisitor.visitJumpInsn( - opcode - wideJumpOpcodeDelta, - labels[currentBytecodeOffset + readInt(currentOffset + 1)]); - currentOffset += 5; - break; - case Constants.ASM_IFEQ: - case Constants.ASM_IFNE: - case Constants.ASM_IFLT: - case Constants.ASM_IFGE: - case Constants.ASM_IFGT: - case Constants.ASM_IFLE: - case Constants.ASM_IF_ICMPEQ: - case Constants.ASM_IF_ICMPNE: - case Constants.ASM_IF_ICMPLT: - case Constants.ASM_IF_ICMPGE: - case Constants.ASM_IF_ICMPGT: - case Constants.ASM_IF_ICMPLE: - case Constants.ASM_IF_ACMPEQ: - case Constants.ASM_IF_ACMPNE: - case Constants.ASM_GOTO: - case Constants.ASM_JSR: - case Constants.ASM_IFNULL: - case Constants.ASM_IFNONNULL: - { - // A forward jump with an offset > 32767. In this case we automatically replace ASM_GOTO - // with GOTO_W, ASM_JSR with JSR_W and ASM_IFxxx with IFNOTxxx GOTO_W L:..., - // where IFNOTxxx is the "opposite" opcode of ASMS_IFxxx (e.g. IFNE for ASM_IFEQ) and - // where designates the instruction just after the GOTO_W. - // First, change the ASM specific opcodes ASM_IFEQ ... ASM_JSR, ASM_IFNULL and - // ASM_IFNONNULL to IFEQ ... JSR, IFNULL and IFNONNULL. - opcode = - opcode < Constants.ASM_IFNULL - ? opcode - Constants.ASM_OPCODE_DELTA - : opcode - Constants.ASM_IFNULL_OPCODE_DELTA; - Label target = labels[currentBytecodeOffset + readUnsignedShort(currentOffset + 1)]; - if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) { - // Replace GOTO with GOTO_W and JSR with JSR_W. - methodVisitor.visitJumpInsn(opcode + Constants.WIDE_JUMP_OPCODE_DELTA, target); - } else { - // Compute the "opposite" of opcode. This can be done by flipping the least - // significant bit for IFNULL and IFNONNULL, and similarly for IFEQ ... IF_ACMPEQ - // (with a pre and post offset by 1). - opcode = opcode < Opcodes.GOTO ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1; - Label endif = createLabel(currentBytecodeOffset + 3, labels); - methodVisitor.visitJumpInsn(opcode, endif); - methodVisitor.visitJumpInsn(Constants.GOTO_W, target); - // endif designates the instruction just after GOTO_W, and is visited as part of the - // next instruction. Since it is a jump target, we need to insert a frame here. - insertFrame = true; - } - currentOffset += 3; - break; - } - case Constants.ASM_GOTO_W: - // Replace ASM_GOTO_W with GOTO_W. - methodVisitor.visitJumpInsn( - Constants.GOTO_W, labels[currentBytecodeOffset + readInt(currentOffset + 1)]); - // The instruction just after is a jump target (because ASM_GOTO_W is used in patterns - // IFNOTxxx ASM_GOTO_W L:..., see MethodWriter), so we need to insert a frame - // here. - insertFrame = true; - currentOffset += 5; - break; - case Constants.WIDE: - opcode = classBuffer[currentOffset + 1] & 0xFF; - if (opcode == Opcodes.IINC) { - methodVisitor.visitIincInsn( - readUnsignedShort(currentOffset + 2), readShort(currentOffset + 4)); - currentOffset += 6; - } else { - methodVisitor.visitVarInsn(opcode, readUnsignedShort(currentOffset + 2)); - currentOffset += 4; - } - break; - case Opcodes.TABLESWITCH: - { - // Skip 0 to 3 padding bytes. - currentOffset += 4 - (currentBytecodeOffset & 3); - // Read the instruction. - Label defaultLabel = labels[currentBytecodeOffset + readInt(currentOffset)]; - int low = readInt(currentOffset + 4); - int high = readInt(currentOffset + 8); - currentOffset += 12; - Label[] table = new Label[high - low + 1]; - for (int i = 0; i < table.length; ++i) { - table[i] = labels[currentBytecodeOffset + readInt(currentOffset)]; - currentOffset += 4; - } - methodVisitor.visitTableSwitchInsn(low, high, defaultLabel, table); - break; - } - case Opcodes.LOOKUPSWITCH: - { - // Skip 0 to 3 padding bytes. - currentOffset += 4 - (currentBytecodeOffset & 3); - // Read the instruction. - Label defaultLabel = labels[currentBytecodeOffset + readInt(currentOffset)]; - int numPairs = readInt(currentOffset + 4); - currentOffset += 8; - int[] keys = new int[numPairs]; - Label[] values = new Label[numPairs]; - for (int i = 0; i < numPairs; ++i) { - keys[i] = readInt(currentOffset); - values[i] = labels[currentBytecodeOffset + readInt(currentOffset + 4)]; - currentOffset += 8; - } - methodVisitor.visitLookupSwitchInsn(defaultLabel, keys, values); - break; - } - case Opcodes.ILOAD: - case Opcodes.LLOAD: - case Opcodes.FLOAD: - case Opcodes.DLOAD: - case Opcodes.ALOAD: - case Opcodes.ISTORE: - case Opcodes.LSTORE: - case Opcodes.FSTORE: - case Opcodes.DSTORE: - case Opcodes.ASTORE: - case Opcodes.RET: - methodVisitor.visitVarInsn(opcode, classBuffer[currentOffset + 1] & 0xFF); - currentOffset += 2; - break; - case Opcodes.BIPUSH: - case Opcodes.NEWARRAY: - methodVisitor.visitIntInsn(opcode, classBuffer[currentOffset + 1]); - currentOffset += 2; - break; - case Opcodes.SIPUSH: - methodVisitor.visitIntInsn(opcode, readShort(currentOffset + 1)); - currentOffset += 3; - break; - case Opcodes.LDC: - methodVisitor.visitLdcInsn(readConst(classBuffer[currentOffset + 1] & 0xFF, charBuffer)); - currentOffset += 2; - break; - case Constants.LDC_W: - case Constants.LDC2_W: - methodVisitor.visitLdcInsn(readConst(readUnsignedShort(currentOffset + 1), charBuffer)); - currentOffset += 3; - break; - case Opcodes.GETSTATIC: - case Opcodes.PUTSTATIC: - case Opcodes.GETFIELD: - case Opcodes.PUTFIELD: - case Opcodes.INVOKEVIRTUAL: - case Opcodes.INVOKESPECIAL: - case Opcodes.INVOKESTATIC: - case Opcodes.INVOKEINTERFACE: - { - int cpInfoOffset = cpInfoOffsets[readUnsignedShort(currentOffset + 1)]; - int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)]; - String owner = readClass(cpInfoOffset, charBuffer); - String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); - String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); - if (opcode < Opcodes.INVOKEVIRTUAL) { - methodVisitor.visitFieldInsn(opcode, owner, name, descriptor); - } else { - boolean isInterface = - classBuffer[cpInfoOffset - 1] == Symbol.CONSTANT_INTERFACE_METHODREF_TAG; - methodVisitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface); - } - if (opcode == Opcodes.INVOKEINTERFACE) { - currentOffset += 5; - } else { - currentOffset += 3; - } - break; - } - case Opcodes.INVOKEDYNAMIC: - { - int cpInfoOffset = cpInfoOffsets[readUnsignedShort(currentOffset + 1)]; - int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)]; - String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); - String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); - int bootstrapMethodOffset = bootstrapMethodOffsets[readUnsignedShort(cpInfoOffset)]; - Handle handle = - (Handle) readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); - Object[] bootstrapMethodArguments = - new Object[readUnsignedShort(bootstrapMethodOffset + 2)]; - bootstrapMethodOffset += 4; - for (int i = 0; i < bootstrapMethodArguments.length; i++) { - bootstrapMethodArguments[i] = - readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); - bootstrapMethodOffset += 2; - } - methodVisitor.visitInvokeDynamicInsn( - name, descriptor, handle, bootstrapMethodArguments); - currentOffset += 5; - break; - } - case Opcodes.NEW: - case Opcodes.ANEWARRAY: - case Opcodes.CHECKCAST: - case Opcodes.INSTANCEOF: - methodVisitor.visitTypeInsn(opcode, readClass(currentOffset + 1, charBuffer)); - currentOffset += 3; - break; - case Opcodes.IINC: - methodVisitor.visitIincInsn( - classBuffer[currentOffset + 1] & 0xFF, classBuffer[currentOffset + 2]); - currentOffset += 3; - break; - case Opcodes.MULTIANEWARRAY: - methodVisitor.visitMultiANewArrayInsn( - readClass(currentOffset + 1, charBuffer), classBuffer[currentOffset + 3] & 0xFF); - currentOffset += 4; - break; - default: - throw new AssertionError(); - } - - // Visit the runtime visible instruction annotations, if any. - while (visibleTypeAnnotationOffsets != null - && currentVisibleTypeAnnotationIndex < visibleTypeAnnotationOffsets.length - && currentVisibleTypeAnnotationBytecodeOffset <= currentBytecodeOffset) { - if (currentVisibleTypeAnnotationBytecodeOffset == currentBytecodeOffset) { - // Parse the target_type, target_info and target_path fields. - int currentAnnotationOffset = - readTypeAnnotationTarget( - context, visibleTypeAnnotationOffsets[currentVisibleTypeAnnotationIndex]); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - readElementValues( - methodVisitor.visitInsnAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - currentVisibleTypeAnnotationBytecodeOffset = - getTypeAnnotationBytecodeOffset( - visibleTypeAnnotationOffsets, ++currentVisibleTypeAnnotationIndex); - } - - // Visit the runtime invisible instruction annotations, if any. - while (invisibleTypeAnnotationOffsets != null - && currentInvisibleTypeAnnotationIndex < invisibleTypeAnnotationOffsets.length - && currentInvisibleTypeAnnotationBytecodeOffset <= currentBytecodeOffset) { - if (currentInvisibleTypeAnnotationBytecodeOffset == currentBytecodeOffset) { - // Parse the target_type, target_info and target_path fields. - int currentAnnotationOffset = - readTypeAnnotationTarget( - context, invisibleTypeAnnotationOffsets[currentInvisibleTypeAnnotationIndex]); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - readElementValues( - methodVisitor.visitInsnAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - currentInvisibleTypeAnnotationBytecodeOffset = - getTypeAnnotationBytecodeOffset( - invisibleTypeAnnotationOffsets, ++currentInvisibleTypeAnnotationIndex); - } - } - if (labels[codeLength] != null) { - methodVisitor.visitLabel(labels[codeLength]); - } - - // Visit LocalVariableTable and LocalVariableTypeTable attributes. - if (localVariableTableOffset != 0 && (context.parsingOptions & SKIP_DEBUG) == 0) { - // The (start_pc, index, signature_index) fields of each entry of the LocalVariableTypeTable. - int[] typeTable = null; - if (localVariableTypeTableOffset != 0) { - typeTable = new int[readUnsignedShort(localVariableTypeTableOffset) * 3]; - currentOffset = localVariableTypeTableOffset + 2; - int typeTableIndex = typeTable.length; - while (typeTableIndex > 0) { - // Store the offset of 'signature_index', and the value of 'index' and 'start_pc'. - typeTable[--typeTableIndex] = currentOffset + 6; - typeTable[--typeTableIndex] = readUnsignedShort(currentOffset + 8); - typeTable[--typeTableIndex] = readUnsignedShort(currentOffset); - currentOffset += 10; - } - } - int localVariableTableLength = readUnsignedShort(localVariableTableOffset); - currentOffset = localVariableTableOffset + 2; - while (localVariableTableLength-- > 0) { - int startPc = readUnsignedShort(currentOffset); - int length = readUnsignedShort(currentOffset + 2); - String name = readUTF8(currentOffset + 4, charBuffer); - String descriptor = readUTF8(currentOffset + 6, charBuffer); - int index = readUnsignedShort(currentOffset + 8); - currentOffset += 10; - String signature = null; - if (typeTable != null) { - for (int i = 0; i < typeTable.length; i += 3) { - if (typeTable[i] == startPc && typeTable[i + 1] == index) { - signature = readUTF8(typeTable[i + 2], charBuffer); - break; + throw new IllegalArgumentException(); } - } + currentCpInfoOffset += cpInfoSize; } - methodVisitor.visitLocalVariable( - name, descriptor, signature, labels[startPc], labels[startPc + length], index); - } + maxStringLength = currentMaxStringLength; + // The Classfile's access_flags field is just after the last constant pool entry. + header = currentCpInfoOffset; + + // Allocate the cache of ConstantDynamic values, if there is at least one. + constantDynamicValues = hasConstantDynamic ? new ConstantDynamic[constantPoolCount] : null; + + // Read the BootstrapMethods attribute, if any (only get the offset of each method). + bootstrapMethodOffsets = + hasBootstrapMethods ? readBootstrapMethodsAttribute(currentMaxStringLength) : null; } - // Visit the local variable type annotations of the RuntimeVisibleTypeAnnotations attribute. - if (visibleTypeAnnotationOffsets != null) { - for (int typeAnnotationOffset : visibleTypeAnnotationOffsets) { - int targetType = readByte(typeAnnotationOffset); - if (targetType == TypeReference.LOCAL_VARIABLE - || targetType == TypeReference.RESOURCE_VARIABLE) { - // Parse the target_type, target_info and target_path fields. - currentOffset = readTypeAnnotationTarget(context, typeAnnotationOffset); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentOffset, charBuffer); - currentOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - readElementValues( - methodVisitor.visitLocalVariableAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - context.currentLocalVariableAnnotationRangeStarts, - context.currentLocalVariableAnnotationRangeEnds, - context.currentLocalVariableAnnotationRangeIndices, - annotationDescriptor, - /* visible = */ true), - currentOffset, - /* named = */ true, - charBuffer); + /** + * Constructs a new {@link ClassReader} object. + * + * @param inputStream an input stream of the JVMS ClassFile structure to be read. This input + * stream must contain nothing more than the ClassFile structure itself. It is read from its + * current position to its end. + * @throws IOException if a problem occurs during reading. + */ + public ClassReader(final InputStream inputStream) throws IOException { + this(readStream(inputStream, false)); + } + + /** + * Constructs a new {@link ClassReader} object. + * + * @param className the fully qualified name of the class to be read. The ClassFile structure is + * retrieved with the current class loader's {@link ClassLoader#getSystemResourceAsStream}. + * @throws IOException if an exception occurs during reading. + */ + public ClassReader(final String className) throws IOException { + this( + readStream( + ClassLoader.getSystemResourceAsStream(className.replace('.', '/') + ".class"), true)); + } + + /** + * Reads the given input stream and returns its content as a byte array. + * + * @param inputStream an input stream. + * @param close true to close the input stream after reading. + * @return the content of the given input stream. + * @throws IOException if a problem occurs during reading. + */ + private static byte[] readStream(final InputStream inputStream, final boolean close) + throws IOException { + if (inputStream == null) { + throw new IOException("Class not found"); } - } - } - - // Visit the local variable type annotations of the RuntimeInvisibleTypeAnnotations attribute. - if (invisibleTypeAnnotationOffsets != null) { - for (int typeAnnotationOffset : invisibleTypeAnnotationOffsets) { - int targetType = readByte(typeAnnotationOffset); - if (targetType == TypeReference.LOCAL_VARIABLE - || targetType == TypeReference.RESOURCE_VARIABLE) { - // Parse the target_type, target_info and target_path fields. - currentOffset = readTypeAnnotationTarget(context, typeAnnotationOffset); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentOffset, charBuffer); - currentOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - readElementValues( - methodVisitor.visitLocalVariableAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - context.currentLocalVariableAnnotationRangeStarts, - context.currentLocalVariableAnnotationRangeEnds, - context.currentLocalVariableAnnotationRangeIndices, - annotationDescriptor, - /* visible = */ false), - currentOffset, - /* named = */ true, - charBuffer); + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + byte[] data = new byte[INPUT_STREAM_DATA_CHUNK_SIZE]; + int bytesRead; + while ((bytesRead = inputStream.read(data, 0, data.length)) != -1) { + outputStream.write(data, 0, bytesRead); + } + outputStream.flush(); + return outputStream.toByteArray(); + } finally { + if (close) { + inputStream.close(); + } } - } } - // Visit the non standard attributes. - while (attributes != null) { - // Copy and reset the nextAttribute field so that it can also be used in MethodWriter. - Attribute nextAttribute = attributes.nextAttribute; - attributes.nextAttribute = null; - methodVisitor.visitAttribute(attributes); - attributes = nextAttribute; + // ----------------------------------------------------------------------------------------------- + // Accessors + // ----------------------------------------------------------------------------------------------- + + /** + * Returns the class's access flags (see {@link Opcodes}). This value may not reflect Deprecated + * and Synthetic flags when bytecode is before 1.5 and those flags are represented by attributes. + * + * @return the class access flags. + * @see ClassVisitor#visit(int, int, String, String, String, String[]) + */ + public int getAccess() { + return readUnsignedShort(header); } - // Visit the max stack and max locals values. - methodVisitor.visitMaxs(maxStack, maxLocals); - } - - /** - * Returns the label corresponding to the given bytecode offset. The default implementation of - * this method creates a label for the given offset if it has not been already created. - * - * @param bytecodeOffset a bytecode offset in a method. - * @param labels the already created labels, indexed by their offset. If a label already exists - * for bytecodeOffset this method must not create a new one. Otherwise it must store the new - * label in this array. - * @return a non null Label, which must be equal to labels[bytecodeOffset]. - */ - protected Label readLabel(final int bytecodeOffset, final Label[] labels) { - if (labels[bytecodeOffset] == null) { - labels[bytecodeOffset] = new Label(); + /** + * Returns the internal name of the class (see {@link Type#getInternalName()}). + * + * @return the internal class name. + * @see ClassVisitor#visit(int, int, String, String, String, String[]) + */ + public String getClassName() { + // this_class is just after the access_flags field (using 2 bytes). + return readClass(header + 2, new char[maxStringLength]); } - return labels[bytecodeOffset]; - } - /** - * Creates a label without the {@link Label#FLAG_DEBUG_ONLY} flag set, for the given bytecode - * offset. The label is created with a call to {@link #readLabel} and its {@link - * Label#FLAG_DEBUG_ONLY} flag is cleared. - * - * @param bytecodeOffset a bytecode offset in a method. - * @param labels the already created labels, indexed by their offset. - * @return a Label without the {@link Label#FLAG_DEBUG_ONLY} flag set. - */ - private Label createLabel(final int bytecodeOffset, final Label[] labels) { - Label label = readLabel(bytecodeOffset, labels); - label.flags &= ~Label.FLAG_DEBUG_ONLY; - return label; - } - - /** - * Creates a label with the {@link Label#FLAG_DEBUG_ONLY} flag set, if there is no already - * existing label for the given bytecode offset (otherwise does nothing). The label is created - * with a call to {@link #readLabel}. - * - * @param bytecodeOffset a bytecode offset in a method. - * @param labels the already created labels, indexed by their offset. - */ - private void createDebugLabel(final int bytecodeOffset, final Label[] labels) { - if (labels[bytecodeOffset] == null) { - readLabel(bytecodeOffset, labels).flags |= Label.FLAG_DEBUG_ONLY; + /** + * Returns the internal of name of the super class (see {@link Type#getInternalName()}). For + * interfaces, the super class is {@link Object}. + * + * @return the internal name of the super class, or {@literal null} for {@link Object} class. + * @see ClassVisitor#visit(int, int, String, String, String, String[]) + */ + public String getSuperName() { + // super_class is after the access_flags and this_class fields (2 bytes each). + return readClass(header + 4, new char[maxStringLength]); } - } - // ---------------------------------------------------------------------------------------------- - // Methods to parse annotations, type annotations and parameter annotations - // ---------------------------------------------------------------------------------------------- + /** + * Returns the internal names of the implemented interfaces (see {@link Type#getInternalName()}). + * + * @return the internal names of the directly implemented interfaces. Inherited implemented + * interfaces are not returned. + * @see ClassVisitor#visit(int, int, String, String, String, String[]) + */ + public String[] getInterfaces() { + // interfaces_count is after the access_flags, this_class and super_class fields (2 bytes each). + int currentOffset = header + 6; + int interfacesCount = readUnsignedShort(currentOffset); + String[] interfaces = new String[interfacesCount]; + if (interfacesCount > 0) { + char[] charBuffer = new char[maxStringLength]; + for (int i = 0; i < interfacesCount; ++i) { + currentOffset += 2; + interfaces[i] = readClass(currentOffset, charBuffer); + } + } + return interfaces; + } - /** - * Parses a Runtime[In]VisibleTypeAnnotations attribute to find the offset of each type_annotation - * entry it contains, to find the corresponding labels, and to visit the try catch block - * annotations. - * - * @param methodVisitor the method visitor to be used to visit the try catch block annotations. - * @param context information about the class being parsed. - * @param runtimeTypeAnnotationsOffset the start offset of a Runtime[In]VisibleTypeAnnotations - * attribute, excluding the attribute_info's attribute_name_index and attribute_length fields. - * @param visible true if the attribute to parse is a RuntimeVisibleTypeAnnotations attribute, - * false it is a RuntimeInvisibleTypeAnnotations attribute. - * @return the start offset of each entry of the Runtime[In]VisibleTypeAnnotations_attribute's - * 'annotations' array field. - */ - private int[] readTypeAnnotations( - final MethodVisitor methodVisitor, - final Context context, - final int runtimeTypeAnnotationsOffset, - final boolean visible) { - char[] charBuffer = context.charBuffer; - int currentOffset = runtimeTypeAnnotationsOffset; - // Read the num_annotations field and create an array to store the type_annotation offsets. - int[] typeAnnotationsOffsets = new int[readUnsignedShort(currentOffset)]; - currentOffset += 2; - // Parse the 'annotations' array field. - for (int i = 0; i < typeAnnotationsOffsets.length; ++i) { - typeAnnotationsOffsets[i] = currentOffset; - // Parse the type_annotation's target_type and the target_info fields. The size of the - // target_info field depends on the value of target_type. - int targetType = readInt(currentOffset); - switch (targetType >>> 24) { + // ----------------------------------------------------------------------------------------------- + // Public methods + // ----------------------------------------------------------------------------------------------- + + /** + * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this + * {@link ClassReader}. + * + * @param classVisitor the visitor that must visit this class. + * @param parsingOptions the options to use to parse this class. One or more of {@link + * #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}. + */ + public void accept(final ClassVisitor classVisitor, final int parsingOptions) { + accept(classVisitor, new Attribute[0], parsingOptions); + } + + /** + * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this + * {@link ClassReader}. + * + * @param classVisitor the visitor that must visit this class. + * @param attributePrototypes prototypes of the attributes that must be parsed during the visit of + * the class. Any attribute whose type is not equal to the type of one the prototypes + * will not + * be parsed: its byte array value will be passed unchanged to the ClassWriter. + * This may + * corrupt it if this value contains references to the constant pool, or has syntactic or + * semantic links with a class element that has been transformed by a class adapter + * between + * the reader and the writer. + * @param parsingOptions the options to use to parse this class. One or more of {@link + * #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}. + */ + public void accept( + final ClassVisitor classVisitor, + final Attribute[] attributePrototypes, + final int parsingOptions) { + Context context = new Context(); + context.attributePrototypes = attributePrototypes; + context.parsingOptions = parsingOptions; + context.charBuffer = new char[maxStringLength]; + + // Read the access_flags, this_class, super_class, interface_count and interfaces fields. + char[] charBuffer = context.charBuffer; + int currentOffset = header; + int accessFlags = readUnsignedShort(currentOffset); + String thisClass = readClass(currentOffset + 2, charBuffer); + String superClass = readClass(currentOffset + 4, charBuffer); + String[] interfaces = new String[readUnsignedShort(currentOffset + 6)]; + currentOffset += 8; + for (int i = 0; i < interfaces.length; ++i) { + interfaces[i] = readClass(currentOffset, charBuffer); + currentOffset += 2; + } + + // Read the class attributes (the variables are ordered as in Section 4.7 of the JVMS). + // Attribute offsets exclude the attribute_name_index and attribute_length fields. + // - The offset of the InnerClasses attribute, or 0. + int innerClassesOffset = 0; + // - The offset of the EnclosingMethod attribute, or 0. + int enclosingMethodOffset = 0; + // - The string corresponding to the Signature attribute, or null. + String signature = null; + // - The string corresponding to the SourceFile attribute, or null. + String sourceFile = null; + // - The string corresponding to the SourceDebugExtension attribute, or null. + String sourceDebugExtension = null; + // - The offset of the RuntimeVisibleAnnotations attribute, or 0. + int runtimeVisibleAnnotationsOffset = 0; + // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. + int runtimeInvisibleAnnotationsOffset = 0; + // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. + int runtimeVisibleTypeAnnotationsOffset = 0; + // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. + int runtimeInvisibleTypeAnnotationsOffset = 0; + // - The offset of the Module attribute, or 0. + int moduleOffset = 0; + // - The offset of the ModulePackages attribute, or 0. + int modulePackagesOffset = 0; + // - The string corresponding to the ModuleMainClass attribute, or null. + String moduleMainClass = null; + // - The string corresponding to the NestHost attribute, or null. + String nestHostClass = null; + // - The offset of the NestMembers attribute, or 0. + int nestMembersOffset = 0; + // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). + // This list in the reverse order or their order in the ClassFile structure. + Attribute attributes = null; + + int currentAttributeOffset = getFirstAttributeOffset(); + for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) { + // Read the attribute_info's attribute_name and attribute_length fields. + String attributeName = readUTF8(currentAttributeOffset, charBuffer); + int attributeLength = readInt(currentAttributeOffset + 2); + currentAttributeOffset += 6; + // The tests are sorted in decreasing frequency order (based on frequencies observed on + // typical classes). + if (Constants.SOURCE_FILE.equals(attributeName)) { + sourceFile = readUTF8(currentAttributeOffset, charBuffer); + } else if (Constants.INNER_CLASSES.equals(attributeName)) { + innerClassesOffset = currentAttributeOffset; + } else if (Constants.ENCLOSING_METHOD.equals(attributeName)) { + enclosingMethodOffset = currentAttributeOffset; + } else if (Constants.NEST_HOST.equals(attributeName)) { + nestHostClass = readClass(currentAttributeOffset, charBuffer); + } else if (Constants.NEST_MEMBERS.equals(attributeName)) { + nestMembersOffset = currentAttributeOffset; + } else if (Constants.SIGNATURE.equals(attributeName)) { + signature = readUTF8(currentAttributeOffset, charBuffer); + } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { + runtimeVisibleAnnotationsOffset = currentAttributeOffset; + } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { + runtimeVisibleTypeAnnotationsOffset = currentAttributeOffset; + } else if (Constants.DEPRECATED.equals(attributeName)) { + accessFlags |= Opcodes.ACC_DEPRECATED; + } else if (Constants.SYNTHETIC.equals(attributeName)) { + accessFlags |= Opcodes.ACC_SYNTHETIC; + } else if (Constants.SOURCE_DEBUG_EXTENSION.equals(attributeName)) { + sourceDebugExtension = + readUtf(currentAttributeOffset, attributeLength, new char[attributeLength]); + } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { + runtimeInvisibleAnnotationsOffset = currentAttributeOffset; + } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { + runtimeInvisibleTypeAnnotationsOffset = currentAttributeOffset; + } else if (Constants.MODULE.equals(attributeName)) { + moduleOffset = currentAttributeOffset; + } else if (Constants.MODULE_MAIN_CLASS.equals(attributeName)) { + moduleMainClass = readClass(currentAttributeOffset, charBuffer); + } else if (Constants.MODULE_PACKAGES.equals(attributeName)) { + modulePackagesOffset = currentAttributeOffset; + } else if (!Constants.BOOTSTRAP_METHODS.equals(attributeName)) { + // The BootstrapMethods attribute is read in the constructor. + Attribute attribute = + readAttribute( + attributePrototypes, + attributeName, + currentAttributeOffset, + attributeLength, + charBuffer, + -1, + null); + attribute.nextAttribute = attributes; + attributes = attribute; + } + currentAttributeOffset += attributeLength; + } + + // Visit the class declaration. The minor_version and major_version fields start 6 bytes before + // the first constant pool entry, which itself starts at cpInfoOffsets[1] - 1 (by definition). + classVisitor.visit( + readInt(cpInfoOffsets[1] - 7), accessFlags, thisClass, signature, superClass, interfaces); + + // Visit the SourceFile and SourceDebugExtenstion attributes. + if ((parsingOptions & SKIP_DEBUG) == 0 + && (sourceFile != null || sourceDebugExtension != null)) { + classVisitor.visitSource(sourceFile, sourceDebugExtension); + } + + // Visit the Module, ModulePackages and ModuleMainClass attributes. + if (moduleOffset != 0) { + readModuleAttributes( + classVisitor, context, moduleOffset, modulePackagesOffset, moduleMainClass); + } + + // Visit the NestHost attribute. + if (nestHostClass != null) { + classVisitor.visitNestHost(nestHostClass); + } + + // Visit the EnclosingMethod attribute. + if (enclosingMethodOffset != 0) { + String className = readClass(enclosingMethodOffset, charBuffer); + int methodIndex = readUnsignedShort(enclosingMethodOffset + 2); + String name = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex], charBuffer); + String type = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex] + 2, charBuffer); + classVisitor.visitOuterClass(className, name, type); + } + + // Visit the RuntimeVisibleAnnotations attribute. + if (runtimeVisibleAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); + int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeInvisibleAnnotations attribute. + if (runtimeInvisibleAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset); + int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeVisibleTypeAnnotations attribute. + if (runtimeVisibleTypeAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset); + int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the target_type, target_info and target_path fields. + currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + classVisitor.visitTypeAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + annotationDescriptor, + /* visible = */ true), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeInvisibleTypeAnnotations attribute. + if (runtimeInvisibleTypeAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset); + int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the target_type, target_info and target_path fields. + currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + classVisitor.visitTypeAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + annotationDescriptor, + /* visible = */ false), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the non standard attributes. + while (attributes != null) { + // Copy and reset the nextAttribute field so that it can also be used in ClassWriter. + Attribute nextAttribute = attributes.nextAttribute; + attributes.nextAttribute = null; + classVisitor.visitAttribute(attributes); + attributes = nextAttribute; + } + + // Visit the NestedMembers attribute. + if (nestMembersOffset != 0) { + int numberOfNestMembers = readUnsignedShort(nestMembersOffset); + int currentNestMemberOffset = nestMembersOffset + 2; + while (numberOfNestMembers-- > 0) { + classVisitor.visitNestMember(readClass(currentNestMemberOffset, charBuffer)); + currentNestMemberOffset += 2; + } + } + + // Visit the InnerClasses attribute. + if (innerClassesOffset != 0) { + int numberOfClasses = readUnsignedShort(innerClassesOffset); + int currentClassesOffset = innerClassesOffset + 2; + while (numberOfClasses-- > 0) { + classVisitor.visitInnerClass( + readClass(currentClassesOffset, charBuffer), + readClass(currentClassesOffset + 2, charBuffer), + readUTF8(currentClassesOffset + 4, charBuffer), + readUnsignedShort(currentClassesOffset + 6)); + currentClassesOffset += 8; + } + } + + // Visit the fields and methods. + int fieldsCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (fieldsCount-- > 0) { + currentOffset = readField(classVisitor, context, currentOffset); + } + int methodsCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (methodsCount-- > 0) { + currentOffset = readMethod(classVisitor, context, currentOffset); + } + + // Visit the end of the class. + classVisitor.visitEnd(); + } + + // ---------------------------------------------------------------------------------------------- + // Methods to parse modules, fields and methods + // ---------------------------------------------------------------------------------------------- + + /** + * Reads the Module, ModulePackages and ModuleMainClass attributes and visit them. + * + * @param classVisitor the current class visitor + * @param context information about the class being parsed. + * @param moduleOffset the offset of the Module attribute (excluding the attribute_info's + * attribute_name_index and attribute_length fields). + * @param modulePackagesOffset the offset of the ModulePackages attribute (excluding the + * attribute_info's attribute_name_index and attribute_length fields), or 0. + * @param moduleMainClass the string corresponding to the ModuleMainClass attribute, or null. + */ + private void readModuleAttributes( + final ClassVisitor classVisitor, + final Context context, + final int moduleOffset, + final int modulePackagesOffset, + final String moduleMainClass) { + char[] buffer = context.charBuffer; + + // Read the module_name_index, module_flags and module_version_index fields and visit them. + int currentOffset = moduleOffset; + String moduleName = readModule(currentOffset, buffer); + int moduleFlags = readUnsignedShort(currentOffset + 2); + String moduleVersion = readUTF8(currentOffset + 4, buffer); + currentOffset += 6; + ModuleVisitor moduleVisitor = classVisitor.visitModule(moduleName, moduleFlags, moduleVersion); + if (moduleVisitor == null) { + return; + } + + // Visit the ModuleMainClass attribute. + if (moduleMainClass != null) { + moduleVisitor.visitMainClass(moduleMainClass); + } + + // Visit the ModulePackages attribute. + if (modulePackagesOffset != 0) { + int packageCount = readUnsignedShort(modulePackagesOffset); + int currentPackageOffset = modulePackagesOffset + 2; + while (packageCount-- > 0) { + moduleVisitor.visitPackage(readPackage(currentPackageOffset, buffer)); + currentPackageOffset += 2; + } + } + + // Read the 'requires_count' and 'requires' fields. + int requiresCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (requiresCount-- > 0) { + // Read the requires_index, requires_flags and requires_version fields and visit them. + String requires = readModule(currentOffset, buffer); + int requiresFlags = readUnsignedShort(currentOffset + 2); + String requiresVersion = readUTF8(currentOffset + 4, buffer); + currentOffset += 6; + moduleVisitor.visitRequire(requires, requiresFlags, requiresVersion); + } + + // Read the 'exports_count' and 'exports' fields. + int exportsCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (exportsCount-- > 0) { + // Read the exports_index, exports_flags, exports_to_count and exports_to_index fields + // and visit them. + String exports = readPackage(currentOffset, buffer); + int exportsFlags = readUnsignedShort(currentOffset + 2); + int exportsToCount = readUnsignedShort(currentOffset + 4); + currentOffset += 6; + String[] exportsTo = null; + if (exportsToCount != 0) { + exportsTo = new String[exportsToCount]; + for (int i = 0; i < exportsToCount; ++i) { + exportsTo[i] = readModule(currentOffset, buffer); + currentOffset += 2; + } + } + moduleVisitor.visitExport(exports, exportsFlags, exportsTo); + } + + // Reads the 'opens_count' and 'opens' fields. + int opensCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (opensCount-- > 0) { + // Read the opens_index, opens_flags, opens_to_count and opens_to_index fields and visit them. + String opens = readPackage(currentOffset, buffer); + int opensFlags = readUnsignedShort(currentOffset + 2); + int opensToCount = readUnsignedShort(currentOffset + 4); + currentOffset += 6; + String[] opensTo = null; + if (opensToCount != 0) { + opensTo = new String[opensToCount]; + for (int i = 0; i < opensToCount; ++i) { + opensTo[i] = readModule(currentOffset, buffer); + currentOffset += 2; + } + } + moduleVisitor.visitOpen(opens, opensFlags, opensTo); + } + + // Read the 'uses_count' and 'uses' fields. + int usesCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (usesCount-- > 0) { + moduleVisitor.visitUse(readClass(currentOffset, buffer)); + currentOffset += 2; + } + + // Read the 'provides_count' and 'provides' fields. + int providesCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (providesCount-- > 0) { + // Read the provides_index, provides_with_count and provides_with_index fields and visit them. + String provides = readClass(currentOffset, buffer); + int providesWithCount = readUnsignedShort(currentOffset + 2); + currentOffset += 4; + String[] providesWith = new String[providesWithCount]; + for (int i = 0; i < providesWithCount; ++i) { + providesWith[i] = readClass(currentOffset, buffer); + currentOffset += 2; + } + moduleVisitor.visitProvide(provides, providesWith); + } + + // Visit the end of the module attributes. + moduleVisitor.visitEnd(); + } + + /** + * Reads a JVMS field_info structure and makes the given visitor visit it. + * + * @param classVisitor the visitor that must visit the field. + * @param context information about the class being parsed. + * @param fieldInfoOffset the start offset of the field_info structure. + * @return the offset of the first byte following the field_info structure. + */ + private int readField( + final ClassVisitor classVisitor, final Context context, final int fieldInfoOffset) { + char[] charBuffer = context.charBuffer; + + // Read the access_flags, name_index and descriptor_index fields. + int currentOffset = fieldInfoOffset; + int accessFlags = readUnsignedShort(currentOffset); + String name = readUTF8(currentOffset + 2, charBuffer); + String descriptor = readUTF8(currentOffset + 4, charBuffer); + currentOffset += 6; + + // Read the field attributes (the variables are ordered as in Section 4.7 of the JVMS). + // Attribute offsets exclude the attribute_name_index and attribute_length fields. + // - The value corresponding to the ConstantValue attribute, or null. + Object constantValue = null; + // - The string corresponding to the Signature attribute, or null. + String signature = null; + // - The offset of the RuntimeVisibleAnnotations attribute, or 0. + int runtimeVisibleAnnotationsOffset = 0; + // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. + int runtimeInvisibleAnnotationsOffset = 0; + // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. + int runtimeVisibleTypeAnnotationsOffset = 0; + // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. + int runtimeInvisibleTypeAnnotationsOffset = 0; + // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). + // This list in the reverse order or their order in the ClassFile structure. + Attribute attributes = null; + + int attributesCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (attributesCount-- > 0) { + // Read the attribute_info's attribute_name and attribute_length fields. + String attributeName = readUTF8(currentOffset, charBuffer); + int attributeLength = readInt(currentOffset + 2); + currentOffset += 6; + // The tests are sorted in decreasing frequency order (based on frequencies observed on + // typical classes). + if (Constants.CONSTANT_VALUE.equals(attributeName)) { + int constantvalueIndex = readUnsignedShort(currentOffset); + constantValue = constantvalueIndex == 0 ? null : readConst(constantvalueIndex, charBuffer); + } else if (Constants.SIGNATURE.equals(attributeName)) { + signature = readUTF8(currentOffset, charBuffer); + } else if (Constants.DEPRECATED.equals(attributeName)) { + accessFlags |= Opcodes.ACC_DEPRECATED; + } else if (Constants.SYNTHETIC.equals(attributeName)) { + accessFlags |= Opcodes.ACC_SYNTHETIC; + } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { + runtimeVisibleAnnotationsOffset = currentOffset; + } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { + runtimeVisibleTypeAnnotationsOffset = currentOffset; + } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { + runtimeInvisibleAnnotationsOffset = currentOffset; + } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { + runtimeInvisibleTypeAnnotationsOffset = currentOffset; + } else { + Attribute attribute = + readAttribute( + context.attributePrototypes, + attributeName, + currentOffset, + attributeLength, + charBuffer, + -1, + null); + attribute.nextAttribute = attributes; + attributes = attribute; + } + currentOffset += attributeLength; + } + + // Visit the field declaration. + FieldVisitor fieldVisitor = + classVisitor.visitField(accessFlags, name, descriptor, signature, constantValue); + if (fieldVisitor == null) { + return currentOffset; + } + + // Visit the RuntimeVisibleAnnotations attribute. + if (runtimeVisibleAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); + int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeInvisibleAnnotations attribute. + if (runtimeInvisibleAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset); + int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeVisibleTypeAnnotations attribute. + if (runtimeVisibleTypeAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset); + int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the target_type, target_info and target_path fields. + currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + fieldVisitor.visitTypeAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + annotationDescriptor, + /* visible = */ true), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeInvisibleTypeAnnotations attribute. + if (runtimeInvisibleTypeAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset); + int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the target_type, target_info and target_path fields. + currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + fieldVisitor.visitTypeAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + annotationDescriptor, + /* visible = */ false), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the non standard attributes. + while (attributes != null) { + // Copy and reset the nextAttribute field so that it can also be used in FieldWriter. + Attribute nextAttribute = attributes.nextAttribute; + attributes.nextAttribute = null; + fieldVisitor.visitAttribute(attributes); + attributes = nextAttribute; + } + + // Visit the end of the field. + fieldVisitor.visitEnd(); + return currentOffset; + } + + /** + * Reads a JVMS method_info structure and makes the given visitor visit it. + * + * @param classVisitor the visitor that must visit the method. + * @param context information about the class being parsed. + * @param methodInfoOffset the start offset of the method_info structure. + * @return the offset of the first byte following the method_info structure. + */ + private int readMethod( + final ClassVisitor classVisitor, final Context context, final int methodInfoOffset) { + char[] charBuffer = context.charBuffer; + + // Read the access_flags, name_index and descriptor_index fields. + int currentOffset = methodInfoOffset; + context.currentMethodAccessFlags = readUnsignedShort(currentOffset); + context.currentMethodName = readUTF8(currentOffset + 2, charBuffer); + context.currentMethodDescriptor = readUTF8(currentOffset + 4, charBuffer); + currentOffset += 6; + + // Read the method attributes (the variables are ordered as in Section 4.7 of the JVMS). + // Attribute offsets exclude the attribute_name_index and attribute_length fields. + // - The offset of the Code attribute, or 0. + int codeOffset = 0; + // - The offset of the Exceptions attribute, or 0. + int exceptionsOffset = 0; + // - The strings corresponding to the Exceptions attribute, or null. + String[] exceptions = null; + // - Whether the method has a Synthetic attribute. + boolean synthetic = false; + // - The constant pool index contained in the Signature attribute, or 0. + int signatureIndex = 0; + // - The offset of the RuntimeVisibleAnnotations attribute, or 0. + int runtimeVisibleAnnotationsOffset = 0; + // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. + int runtimeInvisibleAnnotationsOffset = 0; + // - The offset of the RuntimeVisibleParameterAnnotations attribute, or 0. + int runtimeVisibleParameterAnnotationsOffset = 0; + // - The offset of the RuntimeInvisibleParameterAnnotations attribute, or 0. + int runtimeInvisibleParameterAnnotationsOffset = 0; + // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. + int runtimeVisibleTypeAnnotationsOffset = 0; + // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. + int runtimeInvisibleTypeAnnotationsOffset = 0; + // - The offset of the AnnotationDefault attribute, or 0. + int annotationDefaultOffset = 0; + // - The offset of the MethodParameters attribute, or 0. + int methodParametersOffset = 0; + // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). + // This list in the reverse order or their order in the ClassFile structure. + Attribute attributes = null; + + int attributesCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (attributesCount-- > 0) { + // Read the attribute_info's attribute_name and attribute_length fields. + String attributeName = readUTF8(currentOffset, charBuffer); + int attributeLength = readInt(currentOffset + 2); + currentOffset += 6; + // The tests are sorted in decreasing frequency order (based on frequencies observed on + // typical classes). + if (Constants.CODE.equals(attributeName)) { + if ((context.parsingOptions & SKIP_CODE) == 0) { + codeOffset = currentOffset; + } + } else if (Constants.EXCEPTIONS.equals(attributeName)) { + exceptionsOffset = currentOffset; + exceptions = new String[readUnsignedShort(exceptionsOffset)]; + int currentExceptionOffset = exceptionsOffset + 2; + for (int i = 0; i < exceptions.length; ++i) { + exceptions[i] = readClass(currentExceptionOffset, charBuffer); + currentExceptionOffset += 2; + } + } else if (Constants.SIGNATURE.equals(attributeName)) { + signatureIndex = readUnsignedShort(currentOffset); + } else if (Constants.DEPRECATED.equals(attributeName)) { + context.currentMethodAccessFlags |= Opcodes.ACC_DEPRECATED; + } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { + runtimeVisibleAnnotationsOffset = currentOffset; + } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { + runtimeVisibleTypeAnnotationsOffset = currentOffset; + } else if (Constants.ANNOTATION_DEFAULT.equals(attributeName)) { + annotationDefaultOffset = currentOffset; + } else if (Constants.SYNTHETIC.equals(attributeName)) { + synthetic = true; + context.currentMethodAccessFlags |= Opcodes.ACC_SYNTHETIC; + } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { + runtimeInvisibleAnnotationsOffset = currentOffset; + } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { + runtimeInvisibleTypeAnnotationsOffset = currentOffset; + } else if (Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(attributeName)) { + runtimeVisibleParameterAnnotationsOffset = currentOffset; + } else if (Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(attributeName)) { + runtimeInvisibleParameterAnnotationsOffset = currentOffset; + } else if (Constants.METHOD_PARAMETERS.equals(attributeName)) { + methodParametersOffset = currentOffset; + } else { + Attribute attribute = + readAttribute( + context.attributePrototypes, + attributeName, + currentOffset, + attributeLength, + charBuffer, + -1, + null); + attribute.nextAttribute = attributes; + attributes = attribute; + } + currentOffset += attributeLength; + } + + // Visit the method declaration. + MethodVisitor methodVisitor = + classVisitor.visitMethod( + context.currentMethodAccessFlags, + context.currentMethodName, + context.currentMethodDescriptor, + signatureIndex == 0 ? null : readUtf(signatureIndex, charBuffer), + exceptions); + if (methodVisitor == null) { + return currentOffset; + } + + // If the returned MethodVisitor is in fact a MethodWriter, it means there is no method + // adapter between the reader and the writer. In this case, it might be possible to copy + // the method attributes directly into the writer. If so, return early without visiting + // the content of these attributes. + if (methodVisitor instanceof MethodWriter) { + MethodWriter methodWriter = (MethodWriter) methodVisitor; + if (methodWriter.canCopyMethodAttributes( + this, + synthetic, + (context.currentMethodAccessFlags & Opcodes.ACC_DEPRECATED) != 0, + readUnsignedShort(methodInfoOffset + 4), + signatureIndex, + exceptionsOffset)) { + methodWriter.setMethodAttributesSource(methodInfoOffset, currentOffset - methodInfoOffset); + return currentOffset; + } + } + + // Visit the MethodParameters attribute. + if (methodParametersOffset != 0) { + int parametersCount = readByte(methodParametersOffset); + int currentParameterOffset = methodParametersOffset + 1; + while (parametersCount-- > 0) { + // Read the name_index and access_flags fields and visit them. + methodVisitor.visitParameter( + readUTF8(currentParameterOffset, charBuffer), + readUnsignedShort(currentParameterOffset + 2)); + currentParameterOffset += 4; + } + } + + // Visit the AnnotationDefault attribute. + if (annotationDefaultOffset != 0) { + AnnotationVisitor annotationVisitor = methodVisitor.visitAnnotationDefault(); + readElementValue(annotationVisitor, annotationDefaultOffset, null, charBuffer); + if (annotationVisitor != null) { + annotationVisitor.visitEnd(); + } + } + + // Visit the RuntimeVisibleAnnotations attribute. + if (runtimeVisibleAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); + int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeInvisibleAnnotations attribute. + if (runtimeInvisibleAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset); + int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeVisibleTypeAnnotations attribute. + if (runtimeVisibleTypeAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset); + int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the target_type, target_info and target_path fields. + currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + methodVisitor.visitTypeAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + annotationDescriptor, + /* visible = */ true), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeInvisibleTypeAnnotations attribute. + if (runtimeInvisibleTypeAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset); + int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the target_type, target_info and target_path fields. + currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + methodVisitor.visitTypeAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + annotationDescriptor, + /* visible = */ false), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeVisibleParameterAnnotations attribute. + if (runtimeVisibleParameterAnnotationsOffset != 0) { + readParameterAnnotations( + methodVisitor, context, runtimeVisibleParameterAnnotationsOffset, /* visible = */ true); + } + + // Visit the RuntimeInvisibleParameterAnnotations attribute. + if (runtimeInvisibleParameterAnnotationsOffset != 0) { + readParameterAnnotations( + methodVisitor, + context, + runtimeInvisibleParameterAnnotationsOffset, + /* visible = */ false); + } + + // Visit the non standard attributes. + while (attributes != null) { + // Copy and reset the nextAttribute field so that it can also be used in MethodWriter. + Attribute nextAttribute = attributes.nextAttribute; + attributes.nextAttribute = null; + methodVisitor.visitAttribute(attributes); + attributes = nextAttribute; + } + + // Visit the Code attribute. + if (codeOffset != 0) { + methodVisitor.visitCode(); + readCode(methodVisitor, context, codeOffset); + } + + // Visit the end of the method. + methodVisitor.visitEnd(); + return currentOffset; + } + + // ---------------------------------------------------------------------------------------------- + // Methods to parse a Code attribute + // ---------------------------------------------------------------------------------------------- + + /** + * Reads a JVMS 'Code' attribute and makes the given visitor visit it. + * + * @param methodVisitor the visitor that must visit the Code attribute. + * @param context information about the class being parsed. + * @param codeOffset the start offset in {@link #classFileBuffer} of the Code attribute, excluding + * its attribute_name_index and attribute_length fields. + */ + private void readCode( + final MethodVisitor methodVisitor, final Context context, final int codeOffset) { + int currentOffset = codeOffset; + + // Read the max_stack, max_locals and code_length fields. + final byte[] classBuffer = classFileBuffer; + final char[] charBuffer = context.charBuffer; + final int majorVersion = readUnsignedShort(6); + final int minorVersion = readUnsignedShort(4); + + final int maxStack; + final int maxLocals; + final int codeLength; + + if (majorVersion == 45 && minorVersion <= 2) { + maxStack = readByte(currentOffset); + maxLocals = readByte(currentOffset + 1); + codeLength = readUnsignedShort(currentOffset + 2); + currentOffset += 4; + } else { + maxStack = readUnsignedShort(currentOffset); + maxLocals = readUnsignedShort(currentOffset + 2); + codeLength = readInt(currentOffset + 4); + currentOffset += 8; + } + + // Read the bytecode 'code' array to create a label for each referenced instruction. + final int bytecodeStartOffset = currentOffset; + final int bytecodeEndOffset = currentOffset + codeLength; + final Label[] labels = context.currentMethodLabels = new Label[codeLength + 1]; + while (currentOffset < bytecodeEndOffset) { + final int bytecodeOffset = currentOffset - bytecodeStartOffset; + final int opcode = classBuffer[currentOffset] & 0xFF; + switch (opcode) { + case Opcodes.NOP: + case Opcodes.ACONST_NULL: + case Opcodes.ICONST_M1: + case Opcodes.ICONST_0: + case Opcodes.ICONST_1: + case Opcodes.ICONST_2: + case Opcodes.ICONST_3: + case Opcodes.ICONST_4: + case Opcodes.ICONST_5: + case Opcodes.LCONST_0: + case Opcodes.LCONST_1: + case Opcodes.FCONST_0: + case Opcodes.FCONST_1: + case Opcodes.FCONST_2: + case Opcodes.DCONST_0: + case Opcodes.DCONST_1: + case Opcodes.IALOAD: + case Opcodes.LALOAD: + case Opcodes.FALOAD: + case Opcodes.DALOAD: + case Opcodes.AALOAD: + case Opcodes.BALOAD: + case Opcodes.CALOAD: + case Opcodes.SALOAD: + case Opcodes.IASTORE: + case Opcodes.LASTORE: + case Opcodes.FASTORE: + case Opcodes.DASTORE: + case Opcodes.AASTORE: + case Opcodes.BASTORE: + case Opcodes.CASTORE: + case Opcodes.SASTORE: + case Opcodes.POP: + case Opcodes.POP2: + case Opcodes.DUP: + case Opcodes.DUP_X1: + case Opcodes.DUP_X2: + case Opcodes.DUP2: + case Opcodes.DUP2_X1: + case Opcodes.DUP2_X2: + case Opcodes.SWAP: + case Opcodes.IADD: + case Opcodes.LADD: + case Opcodes.FADD: + case Opcodes.DADD: + case Opcodes.ISUB: + case Opcodes.LSUB: + case Opcodes.FSUB: + case Opcodes.DSUB: + case Opcodes.IMUL: + case Opcodes.LMUL: + case Opcodes.FMUL: + case Opcodes.DMUL: + case Opcodes.IDIV: + case Opcodes.LDIV: + case Opcodes.FDIV: + case Opcodes.DDIV: + case Opcodes.IREM: + case Opcodes.LREM: + case Opcodes.FREM: + case Opcodes.DREM: + case Opcodes.INEG: + case Opcodes.LNEG: + case Opcodes.FNEG: + case Opcodes.DNEG: + case Opcodes.ISHL: + case Opcodes.LSHL: + case Opcodes.ISHR: + case Opcodes.LSHR: + case Opcodes.IUSHR: + case Opcodes.LUSHR: + case Opcodes.IAND: + case Opcodes.LAND: + case Opcodes.IOR: + case Opcodes.LOR: + case Opcodes.IXOR: + case Opcodes.LXOR: + case Opcodes.I2L: + case Opcodes.I2F: + case Opcodes.I2D: + case Opcodes.L2I: + case Opcodes.L2F: + case Opcodes.L2D: + case Opcodes.F2I: + case Opcodes.F2L: + case Opcodes.F2D: + case Opcodes.D2I: + case Opcodes.D2L: + case Opcodes.D2F: + case Opcodes.I2B: + case Opcodes.I2C: + case Opcodes.I2S: + case Opcodes.LCMP: + case Opcodes.FCMPL: + case Opcodes.FCMPG: + case Opcodes.DCMPL: + case Opcodes.DCMPG: + case Opcodes.IRETURN: + case Opcodes.LRETURN: + case Opcodes.FRETURN: + case Opcodes.DRETURN: + case Opcodes.ARETURN: + case Opcodes.RETURN: + case Opcodes.ARRAYLENGTH: + case Opcodes.ATHROW: + case Opcodes.MONITORENTER: + case Opcodes.MONITOREXIT: + case Constants.ILOAD_0: + case Constants.ILOAD_1: + case Constants.ILOAD_2: + case Constants.ILOAD_3: + case Constants.LLOAD_0: + case Constants.LLOAD_1: + case Constants.LLOAD_2: + case Constants.LLOAD_3: + case Constants.FLOAD_0: + case Constants.FLOAD_1: + case Constants.FLOAD_2: + case Constants.FLOAD_3: + case Constants.DLOAD_0: + case Constants.DLOAD_1: + case Constants.DLOAD_2: + case Constants.DLOAD_3: + case Constants.ALOAD_0: + case Constants.ALOAD_1: + case Constants.ALOAD_2: + case Constants.ALOAD_3: + case Constants.ISTORE_0: + case Constants.ISTORE_1: + case Constants.ISTORE_2: + case Constants.ISTORE_3: + case Constants.LSTORE_0: + case Constants.LSTORE_1: + case Constants.LSTORE_2: + case Constants.LSTORE_3: + case Constants.FSTORE_0: + case Constants.FSTORE_1: + case Constants.FSTORE_2: + case Constants.FSTORE_3: + case Constants.DSTORE_0: + case Constants.DSTORE_1: + case Constants.DSTORE_2: + case Constants.DSTORE_3: + case Constants.ASTORE_0: + case Constants.ASTORE_1: + case Constants.ASTORE_2: + case Constants.ASTORE_3: + currentOffset += 1; + break; + case Opcodes.IFEQ: + case Opcodes.IFNE: + case Opcodes.IFLT: + case Opcodes.IFGE: + case Opcodes.IFGT: + case Opcodes.IFLE: + case Opcodes.IF_ICMPEQ: + case Opcodes.IF_ICMPNE: + case Opcodes.IF_ICMPLT: + case Opcodes.IF_ICMPGE: + case Opcodes.IF_ICMPGT: + case Opcodes.IF_ICMPLE: + case Opcodes.IF_ACMPEQ: + case Opcodes.IF_ACMPNE: + case Opcodes.GOTO: + case Opcodes.JSR: + case Opcodes.IFNULL: + case Opcodes.IFNONNULL: + createLabel(bytecodeOffset + readShort(currentOffset + 1), labels); + currentOffset += 3; + break; + case Constants.ASM_IFEQ: + case Constants.ASM_IFNE: + case Constants.ASM_IFLT: + case Constants.ASM_IFGE: + case Constants.ASM_IFGT: + case Constants.ASM_IFLE: + case Constants.ASM_IF_ICMPEQ: + case Constants.ASM_IF_ICMPNE: + case Constants.ASM_IF_ICMPLT: + case Constants.ASM_IF_ICMPGE: + case Constants.ASM_IF_ICMPGT: + case Constants.ASM_IF_ICMPLE: + case Constants.ASM_IF_ACMPEQ: + case Constants.ASM_IF_ACMPNE: + case Constants.ASM_GOTO: + case Constants.ASM_JSR: + case Constants.ASM_IFNULL: + case Constants.ASM_IFNONNULL: + createLabel(bytecodeOffset + readUnsignedShort(currentOffset + 1), labels); + currentOffset += 3; + break; + case Constants.GOTO_W: + case Constants.JSR_W: + case Constants.ASM_GOTO_W: + createLabel(bytecodeOffset + readInt(currentOffset + 1), labels); + currentOffset += 5; + break; + case Constants.WIDE: + switch (classBuffer[currentOffset + 1] & 0xFF) { + case Opcodes.ILOAD: + case Opcodes.FLOAD: + case Opcodes.ALOAD: + case Opcodes.LLOAD: + case Opcodes.DLOAD: + case Opcodes.ISTORE: + case Opcodes.FSTORE: + case Opcodes.ASTORE: + case Opcodes.LSTORE: + case Opcodes.DSTORE: + case Opcodes.RET: + currentOffset += 4; + break; + case Opcodes.IINC: + currentOffset += 6; + break; + default: + throw new IllegalArgumentException(); + } + break; + case Opcodes.TABLESWITCH: + // Skip 0 to 3 padding bytes. + currentOffset += 4 - (bytecodeOffset & 3); + // Read the default label and the number of table entries. + createLabel(bytecodeOffset + readInt(currentOffset), labels); + int numTableEntries = readInt(currentOffset + 8) - readInt(currentOffset + 4) + 1; + currentOffset += 12; + // Read the table labels. + while (numTableEntries-- > 0) { + createLabel(bytecodeOffset + readInt(currentOffset), labels); + currentOffset += 4; + } + break; + case Opcodes.LOOKUPSWITCH: + // Skip 0 to 3 padding bytes. + currentOffset += 4 - (bytecodeOffset & 3); + // Read the default label and the number of switch cases. + createLabel(bytecodeOffset + readInt(currentOffset), labels); + int numSwitchCases = readInt(currentOffset + 4); + currentOffset += 8; + // Read the switch labels. + while (numSwitchCases-- > 0) { + createLabel(bytecodeOffset + readInt(currentOffset + 4), labels); + currentOffset += 8; + } + break; + case Opcodes.ILOAD: + case Opcodes.LLOAD: + case Opcodes.FLOAD: + case Opcodes.DLOAD: + case Opcodes.ALOAD: + case Opcodes.ISTORE: + case Opcodes.LSTORE: + case Opcodes.FSTORE: + case Opcodes.DSTORE: + case Opcodes.ASTORE: + case Opcodes.RET: + case Opcodes.BIPUSH: + case Opcodes.NEWARRAY: + case Opcodes.LDC: + currentOffset += 2; + break; + case Opcodes.SIPUSH: + case Constants.LDC_W: + case Constants.LDC2_W: + case Opcodes.GETSTATIC: + case Opcodes.PUTSTATIC: + case Opcodes.GETFIELD: + case Opcodes.PUTFIELD: + case Opcodes.INVOKEVIRTUAL: + case Opcodes.INVOKESPECIAL: + case Opcodes.INVOKESTATIC: + case Opcodes.NEW: + case Opcodes.ANEWARRAY: + case Opcodes.CHECKCAST: + case Opcodes.INSTANCEOF: + case Opcodes.IINC: + currentOffset += 3; + break; + case Opcodes.INVOKEINTERFACE: + case Opcodes.INVOKEDYNAMIC: + currentOffset += 5; + break; + case Opcodes.MULTIANEWARRAY: + currentOffset += 4; + break; + default: + throw new IllegalArgumentException(); + } + } + + // Read the 'exception_table_length' and 'exception_table' field to create a label for each + // referenced instruction, and to make methodVisitor visit the corresponding try catch blocks. + int exceptionTableLength = readUnsignedShort(currentOffset); + currentOffset += 2; + while (exceptionTableLength-- > 0) { + Label start = createLabel(readUnsignedShort(currentOffset), labels); + Label end = createLabel(readUnsignedShort(currentOffset + 2), labels); + Label handler = createLabel(readUnsignedShort(currentOffset + 4), labels); + String catchType = readUTF8(cpInfoOffsets[readUnsignedShort(currentOffset + 6)], charBuffer); + currentOffset += 8; + methodVisitor.visitTryCatchBlock(start, end, handler, catchType); + } + + // Read the Code attributes to create a label for each referenced instruction (the variables + // are ordered as in Section 4.7 of the JVMS). Attribute offsets exclude the + // attribute_name_index and attribute_length fields. + // - The offset of the current 'stack_map_frame' in the StackMap[Table] attribute, or 0. + // Initially, this is the offset of the first 'stack_map_frame' entry. Then this offset is + // updated after each stack_map_frame is read. + int stackMapFrameOffset = 0; + // - The end offset of the StackMap[Table] attribute, or 0. + int stackMapTableEndOffset = 0; + // - Whether the stack map frames are compressed (i.e. in a StackMapTable) or not. + boolean compressedFrames = true; + // - The offset of the LocalVariableTable attribute, or 0. + int localVariableTableOffset = 0; + // - The offset of the LocalVariableTypeTable attribute, or 0. + int localVariableTypeTableOffset = 0; + // - The offset of each 'type_annotation' entry in the RuntimeVisibleTypeAnnotations + // attribute, or null. + int[] visibleTypeAnnotationOffsets = null; + // - The offset of each 'type_annotation' entry in the RuntimeInvisibleTypeAnnotations + // attribute, or null. + int[] invisibleTypeAnnotationOffsets = null; + // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). + // This list in the reverse order or their order in the ClassFile structure. + Attribute attributes = null; + + int attributesCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (attributesCount-- > 0) { + // Read the attribute_info's attribute_name and attribute_length fields. + String attributeName = readUTF8(currentOffset, charBuffer); + int attributeLength = readInt(currentOffset + 2); + currentOffset += 6; + if (Constants.LOCAL_VARIABLE_TABLE.equals(attributeName)) { + if ((context.parsingOptions & SKIP_DEBUG) == 0) { + localVariableTableOffset = currentOffset; + // Parse the attribute to find the corresponding (debug only) labels. + int currentLocalVariableTableOffset = currentOffset; + int localVariableTableLength = readUnsignedShort(currentLocalVariableTableOffset); + currentLocalVariableTableOffset += 2; + while (localVariableTableLength-- > 0) { + int startPc = readUnsignedShort(currentLocalVariableTableOffset); + createDebugLabel(startPc, labels); + int length = readUnsignedShort(currentLocalVariableTableOffset + 2); + createDebugLabel(startPc + length, labels); + // Skip the name_index, descriptor_index and index fields (2 bytes each). + currentLocalVariableTableOffset += 10; + } + } + } else if (Constants.LOCAL_VARIABLE_TYPE_TABLE.equals(attributeName)) { + localVariableTypeTableOffset = currentOffset; + // Here we do not extract the labels corresponding to the attribute content. We assume they + // are the same or a subset of those of the LocalVariableTable attribute. + } else if (Constants.LINE_NUMBER_TABLE.equals(attributeName)) { + if ((context.parsingOptions & SKIP_DEBUG) == 0) { + // Parse the attribute to find the corresponding (debug only) labels. + int currentLineNumberTableOffset = currentOffset; + int lineNumberTableLength = readUnsignedShort(currentLineNumberTableOffset); + currentLineNumberTableOffset += 2; + while (lineNumberTableLength-- > 0) { + int startPc = readUnsignedShort(currentLineNumberTableOffset); + int lineNumber = readUnsignedShort(currentLineNumberTableOffset + 2); + currentLineNumberTableOffset += 4; + createDebugLabel(startPc, labels); + labels[startPc].addLineNumber(lineNumber); + } + } + } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { + visibleTypeAnnotationOffsets = + readTypeAnnotations(methodVisitor, context, currentOffset, /* visible = */ true); + // Here we do not extract the labels corresponding to the attribute content. This would + // require a full parsing of the attribute, which would need to be repeated when parsing + // the bytecode instructions (see below). Instead, the content of the attribute is read one + // type annotation at a time (i.e. after a type annotation has been visited, the next type + // annotation is read), and the labels it contains are also extracted one annotation at a + // time. This assumes that type annotations are ordered by increasing bytecode offset. + } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { + invisibleTypeAnnotationOffsets = + readTypeAnnotations(methodVisitor, context, currentOffset, /* visible = */ false); + // Same comment as above for the RuntimeVisibleTypeAnnotations attribute. + } else if (Constants.STACK_MAP_TABLE.equals(attributeName)) { + if ((context.parsingOptions & SKIP_FRAMES) == 0) { + stackMapFrameOffset = currentOffset + 2; + stackMapTableEndOffset = currentOffset + attributeLength; + } + // Here we do not extract the labels corresponding to the attribute content. This would + // require a full parsing of the attribute, which would need to be repeated when parsing + // the bytecode instructions (see below). Instead, the content of the attribute is read one + // frame at a time (i.e. after a frame has been visited, the next frame is read), and the + // labels it contains are also extracted one frame at a time. Thanks to the ordering of + // frames, having only a "one frame lookahead" is not a problem, i.e. it is not possible to + // see an offset smaller than the offset of the current instruction and for which no Label + // exist. Except for UNINITIALIZED type offsets. We solve this by parsing the stack map + // table without a full decoding (see below). + } else if ("StackMap".equals(attributeName)) { + if ((context.parsingOptions & SKIP_FRAMES) == 0) { + stackMapFrameOffset = currentOffset + 2; + stackMapTableEndOffset = currentOffset + attributeLength; + compressedFrames = false; + } + // IMPORTANT! Here we assume that the frames are ordered, as in the StackMapTable attribute, + // although this is not guaranteed by the attribute format. This allows an incremental + // extraction of the labels corresponding to this attribute (see the comment above for the + // StackMapTable attribute). + } else { + Attribute attribute = + readAttribute( + context.attributePrototypes, + attributeName, + currentOffset, + attributeLength, + charBuffer, + codeOffset, + labels); + attribute.nextAttribute = attributes; + attributes = attribute; + } + currentOffset += attributeLength; + } + + // Initialize the context fields related to stack map frames, and generate the first + // (implicit) stack map frame, if needed. + final boolean expandFrames = (context.parsingOptions & EXPAND_FRAMES) != 0; + if (stackMapFrameOffset != 0) { + // The bytecode offset of the first explicit frame is not offset_delta + 1 but only + // offset_delta. Setting the implicit frame offset to -1 allows us to use of the + // "offset_delta + 1" rule in all cases. + context.currentFrameOffset = -1; + context.currentFrameType = 0; + context.currentFrameLocalCount = 0; + context.currentFrameLocalCountDelta = 0; + context.currentFrameLocalTypes = new Object[maxLocals]; + context.currentFrameStackCount = 0; + context.currentFrameStackTypes = new Object[maxStack]; + if (expandFrames) { + computeImplicitFrame(context); + } + // Find the labels for UNINITIALIZED frame types. Instead of decoding each element of the + // stack map table, we look for 3 consecutive bytes that "look like" an UNINITIALIZED type + // (tag ITEM_Uninitialized, offset within bytecode bounds, NEW instruction at this offset). + // We may find false positives (i.e. not real UNINITIALIZED types), but this should be rare, + // and the only consequence will be the creation of an unneeded label. This is better than + // creating a label for each NEW instruction, and faster than fully decoding the whole stack + // map table. + for (int offset = stackMapFrameOffset; offset < stackMapTableEndOffset - 2; ++offset) { + if (classBuffer[offset] == Frame.ITEM_UNINITIALIZED) { + int potentialBytecodeOffset = readUnsignedShort(offset + 1); + if (potentialBytecodeOffset >= 0 + && potentialBytecodeOffset < codeLength + && (classBuffer[bytecodeStartOffset + potentialBytecodeOffset] & 0xFF) + == Opcodes.NEW) { + createLabel(potentialBytecodeOffset, labels); + } + } + } + } + if (expandFrames && (context.parsingOptions & EXPAND_ASM_INSNS) != 0) { + // Expanding the ASM specific instructions can introduce F_INSERT frames, even if the method + // does not currently have any frame. These inserted frames must be computed by simulating the + // effect of the bytecode instructions, one by one, starting from the implicit first frame. + // For this, MethodWriter needs to know maxLocals before the first instruction is visited. To + // ensure this, we visit the implicit first frame here (passing only maxLocals - the rest is + // computed in MethodWriter). + methodVisitor.visitFrame(Opcodes.F_NEW, maxLocals, null, 0, null); + } + + // Visit the bytecode instructions. First, introduce state variables for the incremental parsing + // of the type annotations. + + // Index of the next runtime visible type annotation to read (in the + // visibleTypeAnnotationOffsets array). + int currentVisibleTypeAnnotationIndex = 0; + // The bytecode offset of the next runtime visible type annotation to read, or -1. + int currentVisibleTypeAnnotationBytecodeOffset = + getTypeAnnotationBytecodeOffset(visibleTypeAnnotationOffsets, 0); + // Index of the next runtime invisible type annotation to read (in the + // invisibleTypeAnnotationOffsets array). + int currentInvisibleTypeAnnotationIndex = 0; + // The bytecode offset of the next runtime invisible type annotation to read, or -1. + int currentInvisibleTypeAnnotationBytecodeOffset = + getTypeAnnotationBytecodeOffset(invisibleTypeAnnotationOffsets, 0); + + // Whether a F_INSERT stack map frame must be inserted before the current instruction. + boolean insertFrame = false; + + // The delta to subtract from a goto_w or jsr_w opcode to get the corresponding goto or jsr + // opcode, or 0 if goto_w and jsr_w must be left unchanged (i.e. when expanding ASM specific + // instructions). + final int wideJumpOpcodeDelta = + (context.parsingOptions & EXPAND_ASM_INSNS) == 0 ? Constants.WIDE_JUMP_OPCODE_DELTA : 0; + + currentOffset = bytecodeStartOffset; + while (currentOffset < bytecodeEndOffset) { + final int currentBytecodeOffset = currentOffset - bytecodeStartOffset; + + // Visit the label and the line number(s) for this bytecode offset, if any. + Label currentLabel = labels[currentBytecodeOffset]; + if (currentLabel != null) { + currentLabel.accept(methodVisitor, (context.parsingOptions & SKIP_DEBUG) == 0); + } + + // Visit the stack map frame for this bytecode offset, if any. + while (stackMapFrameOffset != 0 + && (context.currentFrameOffset == currentBytecodeOffset + || context.currentFrameOffset == -1)) { + // If there is a stack map frame for this offset, make methodVisitor visit it, and read the + // next stack map frame if there is one. + if (context.currentFrameOffset != -1) { + if (!compressedFrames || expandFrames) { + methodVisitor.visitFrame( + Opcodes.F_NEW, + context.currentFrameLocalCount, + context.currentFrameLocalTypes, + context.currentFrameStackCount, + context.currentFrameStackTypes); + } else { + methodVisitor.visitFrame( + context.currentFrameType, + context.currentFrameLocalCountDelta, + context.currentFrameLocalTypes, + context.currentFrameStackCount, + context.currentFrameStackTypes); + } + // Since there is already a stack map frame for this bytecode offset, there is no need to + // insert a new one. + insertFrame = false; + } + if (stackMapFrameOffset < stackMapTableEndOffset) { + stackMapFrameOffset = + readStackMapFrame(stackMapFrameOffset, compressedFrames, expandFrames, context); + } else { + stackMapFrameOffset = 0; + } + } + + // Insert a stack map frame for this bytecode offset, if requested by setting insertFrame to + // true during the previous iteration. The actual frame content is computed in MethodWriter. + if (insertFrame) { + if ((context.parsingOptions & EXPAND_FRAMES) != 0) { + methodVisitor.visitFrame(Constants.F_INSERT, 0, null, 0, null); + } + insertFrame = false; + } + + // Visit the instruction at this bytecode offset. + int opcode = classBuffer[currentOffset] & 0xFF; + switch (opcode) { + case Opcodes.NOP: + case Opcodes.ACONST_NULL: + case Opcodes.ICONST_M1: + case Opcodes.ICONST_0: + case Opcodes.ICONST_1: + case Opcodes.ICONST_2: + case Opcodes.ICONST_3: + case Opcodes.ICONST_4: + case Opcodes.ICONST_5: + case Opcodes.LCONST_0: + case Opcodes.LCONST_1: + case Opcodes.FCONST_0: + case Opcodes.FCONST_1: + case Opcodes.FCONST_2: + case Opcodes.DCONST_0: + case Opcodes.DCONST_1: + case Opcodes.IALOAD: + case Opcodes.LALOAD: + case Opcodes.FALOAD: + case Opcodes.DALOAD: + case Opcodes.AALOAD: + case Opcodes.BALOAD: + case Opcodes.CALOAD: + case Opcodes.SALOAD: + case Opcodes.IASTORE: + case Opcodes.LASTORE: + case Opcodes.FASTORE: + case Opcodes.DASTORE: + case Opcodes.AASTORE: + case Opcodes.BASTORE: + case Opcodes.CASTORE: + case Opcodes.SASTORE: + case Opcodes.POP: + case Opcodes.POP2: + case Opcodes.DUP: + case Opcodes.DUP_X1: + case Opcodes.DUP_X2: + case Opcodes.DUP2: + case Opcodes.DUP2_X1: + case Opcodes.DUP2_X2: + case Opcodes.SWAP: + case Opcodes.IADD: + case Opcodes.LADD: + case Opcodes.FADD: + case Opcodes.DADD: + case Opcodes.ISUB: + case Opcodes.LSUB: + case Opcodes.FSUB: + case Opcodes.DSUB: + case Opcodes.IMUL: + case Opcodes.LMUL: + case Opcodes.FMUL: + case Opcodes.DMUL: + case Opcodes.IDIV: + case Opcodes.LDIV: + case Opcodes.FDIV: + case Opcodes.DDIV: + case Opcodes.IREM: + case Opcodes.LREM: + case Opcodes.FREM: + case Opcodes.DREM: + case Opcodes.INEG: + case Opcodes.LNEG: + case Opcodes.FNEG: + case Opcodes.DNEG: + case Opcodes.ISHL: + case Opcodes.LSHL: + case Opcodes.ISHR: + case Opcodes.LSHR: + case Opcodes.IUSHR: + case Opcodes.LUSHR: + case Opcodes.IAND: + case Opcodes.LAND: + case Opcodes.IOR: + case Opcodes.LOR: + case Opcodes.IXOR: + case Opcodes.LXOR: + case Opcodes.I2L: + case Opcodes.I2F: + case Opcodes.I2D: + case Opcodes.L2I: + case Opcodes.L2F: + case Opcodes.L2D: + case Opcodes.F2I: + case Opcodes.F2L: + case Opcodes.F2D: + case Opcodes.D2I: + case Opcodes.D2L: + case Opcodes.D2F: + case Opcodes.I2B: + case Opcodes.I2C: + case Opcodes.I2S: + case Opcodes.LCMP: + case Opcodes.FCMPL: + case Opcodes.FCMPG: + case Opcodes.DCMPL: + case Opcodes.DCMPG: + case Opcodes.IRETURN: + case Opcodes.LRETURN: + case Opcodes.FRETURN: + case Opcodes.DRETURN: + case Opcodes.ARETURN: + case Opcodes.RETURN: + case Opcodes.ARRAYLENGTH: + case Opcodes.ATHROW: + case Opcodes.MONITORENTER: + case Opcodes.MONITOREXIT: + methodVisitor.visitInsn(opcode); + currentOffset += 1; + break; + case Constants.ILOAD_0: + case Constants.ILOAD_1: + case Constants.ILOAD_2: + case Constants.ILOAD_3: + case Constants.LLOAD_0: + case Constants.LLOAD_1: + case Constants.LLOAD_2: + case Constants.LLOAD_3: + case Constants.FLOAD_0: + case Constants.FLOAD_1: + case Constants.FLOAD_2: + case Constants.FLOAD_3: + case Constants.DLOAD_0: + case Constants.DLOAD_1: + case Constants.DLOAD_2: + case Constants.DLOAD_3: + case Constants.ALOAD_0: + case Constants.ALOAD_1: + case Constants.ALOAD_2: + case Constants.ALOAD_3: + opcode -= Constants.ILOAD_0; + methodVisitor.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3); + currentOffset += 1; + break; + case Constants.ISTORE_0: + case Constants.ISTORE_1: + case Constants.ISTORE_2: + case Constants.ISTORE_3: + case Constants.LSTORE_0: + case Constants.LSTORE_1: + case Constants.LSTORE_2: + case Constants.LSTORE_3: + case Constants.FSTORE_0: + case Constants.FSTORE_1: + case Constants.FSTORE_2: + case Constants.FSTORE_3: + case Constants.DSTORE_0: + case Constants.DSTORE_1: + case Constants.DSTORE_2: + case Constants.DSTORE_3: + case Constants.ASTORE_0: + case Constants.ASTORE_1: + case Constants.ASTORE_2: + case Constants.ASTORE_3: + opcode -= Constants.ISTORE_0; + methodVisitor.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), opcode & 0x3); + currentOffset += 1; + break; + case Opcodes.IFEQ: + case Opcodes.IFNE: + case Opcodes.IFLT: + case Opcodes.IFGE: + case Opcodes.IFGT: + case Opcodes.IFLE: + case Opcodes.IF_ICMPEQ: + case Opcodes.IF_ICMPNE: + case Opcodes.IF_ICMPLT: + case Opcodes.IF_ICMPGE: + case Opcodes.IF_ICMPGT: + case Opcodes.IF_ICMPLE: + case Opcodes.IF_ACMPEQ: + case Opcodes.IF_ACMPNE: + case Opcodes.GOTO: + case Opcodes.JSR: + case Opcodes.IFNULL: + case Opcodes.IFNONNULL: + methodVisitor.visitJumpInsn( + opcode, labels[currentBytecodeOffset + readShort(currentOffset + 1)]); + currentOffset += 3; + break; + case Constants.GOTO_W: + case Constants.JSR_W: + methodVisitor.visitJumpInsn( + opcode - wideJumpOpcodeDelta, + labels[currentBytecodeOffset + readInt(currentOffset + 1)]); + currentOffset += 5; + break; + case Constants.ASM_IFEQ: + case Constants.ASM_IFNE: + case Constants.ASM_IFLT: + case Constants.ASM_IFGE: + case Constants.ASM_IFGT: + case Constants.ASM_IFLE: + case Constants.ASM_IF_ICMPEQ: + case Constants.ASM_IF_ICMPNE: + case Constants.ASM_IF_ICMPLT: + case Constants.ASM_IF_ICMPGE: + case Constants.ASM_IF_ICMPGT: + case Constants.ASM_IF_ICMPLE: + case Constants.ASM_IF_ACMPEQ: + case Constants.ASM_IF_ACMPNE: + case Constants.ASM_GOTO: + case Constants.ASM_JSR: + case Constants.ASM_IFNULL: + case Constants.ASM_IFNONNULL: { + // A forward jump with an offset > 32767. In this case we automatically replace ASM_GOTO + // with GOTO_W, ASM_JSR with JSR_W and ASM_IFxxx with IFNOTxxx GOTO_W L:..., + // where IFNOTxxx is the "opposite" opcode of ASMS_IFxxx (e.g. IFNE for ASM_IFEQ) and + // where designates the instruction just after the GOTO_W. + // First, change the ASM specific opcodes ASM_IFEQ ... ASM_JSR, ASM_IFNULL and + // ASM_IFNONNULL to IFEQ ... JSR, IFNULL and IFNONNULL. + opcode = + opcode < Constants.ASM_IFNULL + ? opcode - Constants.ASM_OPCODE_DELTA + : opcode - Constants.ASM_IFNULL_OPCODE_DELTA; + Label target = labels[currentBytecodeOffset + readUnsignedShort(currentOffset + 1)]; + if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) { + // Replace GOTO with GOTO_W and JSR with JSR_W. + methodVisitor.visitJumpInsn(opcode + Constants.WIDE_JUMP_OPCODE_DELTA, target); + } else { + // Compute the "opposite" of opcode. This can be done by flipping the least + // significant bit for IFNULL and IFNONNULL, and similarly for IFEQ ... IF_ACMPEQ + // (with a pre and post offset by 1). + opcode = opcode < Opcodes.GOTO ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1; + Label endif = createLabel(currentBytecodeOffset + 3, labels); + methodVisitor.visitJumpInsn(opcode, endif); + methodVisitor.visitJumpInsn(Constants.GOTO_W, target); + // endif designates the instruction just after GOTO_W, and is visited as part of the + // next instruction. Since it is a jump target, we need to insert a frame here. + insertFrame = true; + } + currentOffset += 3; + break; + } + case Constants.ASM_GOTO_W: + // Replace ASM_GOTO_W with GOTO_W. + methodVisitor.visitJumpInsn( + Constants.GOTO_W, labels[currentBytecodeOffset + readInt(currentOffset + 1)]); + // The instruction just after is a jump target (because ASM_GOTO_W is used in patterns + // IFNOTxxx ASM_GOTO_W L:..., see MethodWriter), so we need to insert a frame + // here. + insertFrame = true; + currentOffset += 5; + break; + case Constants.WIDE: + opcode = classBuffer[currentOffset + 1] & 0xFF; + if (opcode == Opcodes.IINC) { + methodVisitor.visitIincInsn( + readUnsignedShort(currentOffset + 2), readShort(currentOffset + 4)); + currentOffset += 6; + } else { + methodVisitor.visitVarInsn(opcode, readUnsignedShort(currentOffset + 2)); + currentOffset += 4; + } + break; + case Opcodes.TABLESWITCH: { + // Skip 0 to 3 padding bytes. + currentOffset += 4 - (currentBytecodeOffset & 3); + // Read the instruction. + Label defaultLabel = labels[currentBytecodeOffset + readInt(currentOffset)]; + int low = readInt(currentOffset + 4); + int high = readInt(currentOffset + 8); + currentOffset += 12; + Label[] table = new Label[high - low + 1]; + for (int i = 0; i < table.length; ++i) { + table[i] = labels[currentBytecodeOffset + readInt(currentOffset)]; + currentOffset += 4; + } + methodVisitor.visitTableSwitchInsn(low, high, defaultLabel, table); + break; + } + case Opcodes.LOOKUPSWITCH: { + // Skip 0 to 3 padding bytes. + currentOffset += 4 - (currentBytecodeOffset & 3); + // Read the instruction. + Label defaultLabel = labels[currentBytecodeOffset + readInt(currentOffset)]; + int numPairs = readInt(currentOffset + 4); + currentOffset += 8; + int[] keys = new int[numPairs]; + Label[] values = new Label[numPairs]; + for (int i = 0; i < numPairs; ++i) { + keys[i] = readInt(currentOffset); + values[i] = labels[currentBytecodeOffset + readInt(currentOffset + 4)]; + currentOffset += 8; + } + methodVisitor.visitLookupSwitchInsn(defaultLabel, keys, values); + break; + } + case Opcodes.ILOAD: + case Opcodes.LLOAD: + case Opcodes.FLOAD: + case Opcodes.DLOAD: + case Opcodes.ALOAD: + case Opcodes.ISTORE: + case Opcodes.LSTORE: + case Opcodes.FSTORE: + case Opcodes.DSTORE: + case Opcodes.ASTORE: + case Opcodes.RET: + methodVisitor.visitVarInsn(opcode, classBuffer[currentOffset + 1] & 0xFF); + currentOffset += 2; + break; + case Opcodes.BIPUSH: + case Opcodes.NEWARRAY: + methodVisitor.visitIntInsn(opcode, classBuffer[currentOffset + 1]); + currentOffset += 2; + break; + case Opcodes.SIPUSH: + methodVisitor.visitIntInsn(opcode, readShort(currentOffset + 1)); + currentOffset += 3; + break; + case Opcodes.LDC: + methodVisitor.visitLdcInsn(readConst(classBuffer[currentOffset + 1] & 0xFF, charBuffer)); + currentOffset += 2; + break; + case Constants.LDC_W: + case Constants.LDC2_W: + methodVisitor.visitLdcInsn(readConst(readUnsignedShort(currentOffset + 1), charBuffer)); + currentOffset += 3; + break; + case Opcodes.GETSTATIC: + case Opcodes.PUTSTATIC: + case Opcodes.GETFIELD: + case Opcodes.PUTFIELD: + case Opcodes.INVOKEVIRTUAL: + case Opcodes.INVOKESPECIAL: + case Opcodes.INVOKESTATIC: + case Opcodes.INVOKEINTERFACE: { + int cpInfoOffset = cpInfoOffsets[readUnsignedShort(currentOffset + 1)]; + int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)]; + String owner = readClass(cpInfoOffset, charBuffer); + String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); + String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); + if (opcode < Opcodes.INVOKEVIRTUAL) { + methodVisitor.visitFieldInsn(opcode, owner, name, descriptor); + } else { + boolean isInterface = + classBuffer[cpInfoOffset - 1] == Symbol.CONSTANT_INTERFACE_METHODREF_TAG; + methodVisitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface); + } + if (opcode == Opcodes.INVOKEINTERFACE) { + currentOffset += 5; + } else { + currentOffset += 3; + } + break; + } + case Opcodes.INVOKEDYNAMIC: { + int cpInfoOffset = cpInfoOffsets[readUnsignedShort(currentOffset + 1)]; + int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)]; + String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); + String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); + int bootstrapMethodOffset = bootstrapMethodOffsets[readUnsignedShort(cpInfoOffset)]; + Handle handle = + (Handle) readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); + Object[] bootstrapMethodArguments = + new Object[readUnsignedShort(bootstrapMethodOffset + 2)]; + bootstrapMethodOffset += 4; + for (int i = 0; i < bootstrapMethodArguments.length; i++) { + bootstrapMethodArguments[i] = + readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); + bootstrapMethodOffset += 2; + } + methodVisitor.visitInvokeDynamicInsn( + name, descriptor, handle, bootstrapMethodArguments); + currentOffset += 5; + break; + } + case Opcodes.NEW: + case Opcodes.ANEWARRAY: + case Opcodes.CHECKCAST: + case Opcodes.INSTANCEOF: + methodVisitor.visitTypeInsn(opcode, readClass(currentOffset + 1, charBuffer)); + currentOffset += 3; + break; + case Opcodes.IINC: + methodVisitor.visitIincInsn( + classBuffer[currentOffset + 1] & 0xFF, classBuffer[currentOffset + 2]); + currentOffset += 3; + break; + case Opcodes.MULTIANEWARRAY: + methodVisitor.visitMultiANewArrayInsn( + readClass(currentOffset + 1, charBuffer), classBuffer[currentOffset + 3] & 0xFF); + currentOffset += 4; + break; + default: + throw new AssertionError(); + } + + // Visit the runtime visible instruction annotations, if any. + while (visibleTypeAnnotationOffsets != null + && currentVisibleTypeAnnotationIndex < visibleTypeAnnotationOffsets.length + && currentVisibleTypeAnnotationBytecodeOffset <= currentBytecodeOffset) { + if (currentVisibleTypeAnnotationBytecodeOffset == currentBytecodeOffset) { + // Parse the target_type, target_info and target_path fields. + int currentAnnotationOffset = + readTypeAnnotationTarget( + context, visibleTypeAnnotationOffsets[currentVisibleTypeAnnotationIndex]); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + readElementValues( + methodVisitor.visitInsnAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + annotationDescriptor, + /* visible = */ true), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + currentVisibleTypeAnnotationBytecodeOffset = + getTypeAnnotationBytecodeOffset( + visibleTypeAnnotationOffsets, ++currentVisibleTypeAnnotationIndex); + } + + // Visit the runtime invisible instruction annotations, if any. + while (invisibleTypeAnnotationOffsets != null + && currentInvisibleTypeAnnotationIndex < invisibleTypeAnnotationOffsets.length + && currentInvisibleTypeAnnotationBytecodeOffset <= currentBytecodeOffset) { + if (currentInvisibleTypeAnnotationBytecodeOffset == currentBytecodeOffset) { + // Parse the target_type, target_info and target_path fields. + int currentAnnotationOffset = + readTypeAnnotationTarget( + context, invisibleTypeAnnotationOffsets[currentInvisibleTypeAnnotationIndex]); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + readElementValues( + methodVisitor.visitInsnAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + annotationDescriptor, + /* visible = */ false), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + currentInvisibleTypeAnnotationBytecodeOffset = + getTypeAnnotationBytecodeOffset( + invisibleTypeAnnotationOffsets, ++currentInvisibleTypeAnnotationIndex); + } + } + if (labels[codeLength] != null) { + methodVisitor.visitLabel(labels[codeLength]); + } + + // Visit LocalVariableTable and LocalVariableTypeTable attributes. + if (localVariableTableOffset != 0 && (context.parsingOptions & SKIP_DEBUG) == 0) { + // The (start_pc, index, signature_index) fields of each entry of the LocalVariableTypeTable. + int[] typeTable = null; + if (localVariableTypeTableOffset != 0) { + typeTable = new int[readUnsignedShort(localVariableTypeTableOffset) * 3]; + currentOffset = localVariableTypeTableOffset + 2; + int typeTableIndex = typeTable.length; + while (typeTableIndex > 0) { + // Store the offset of 'signature_index', and the value of 'index' and 'start_pc'. + typeTable[--typeTableIndex] = currentOffset + 6; + typeTable[--typeTableIndex] = readUnsignedShort(currentOffset + 8); + typeTable[--typeTableIndex] = readUnsignedShort(currentOffset); + currentOffset += 10; + } + } + int localVariableTableLength = readUnsignedShort(localVariableTableOffset); + currentOffset = localVariableTableOffset + 2; + while (localVariableTableLength-- > 0) { + int startPc = readUnsignedShort(currentOffset); + int length = readUnsignedShort(currentOffset + 2); + String name = readUTF8(currentOffset + 4, charBuffer); + String descriptor = readUTF8(currentOffset + 6, charBuffer); + int index = readUnsignedShort(currentOffset + 8); + currentOffset += 10; + String signature = null; + if (typeTable != null) { + for (int i = 0; i < typeTable.length; i += 3) { + if (typeTable[i] == startPc && typeTable[i + 1] == index) { + signature = readUTF8(typeTable[i + 2], charBuffer); + break; + } + } + } + methodVisitor.visitLocalVariable( + name, descriptor, signature, labels[startPc], labels[startPc + length], index); + } + } + + // Visit the local variable type annotations of the RuntimeVisibleTypeAnnotations attribute. + if (visibleTypeAnnotationOffsets != null) { + for (int typeAnnotationOffset : visibleTypeAnnotationOffsets) { + int targetType = readByte(typeAnnotationOffset); + if (targetType == TypeReference.LOCAL_VARIABLE + || targetType == TypeReference.RESOURCE_VARIABLE) { + // Parse the target_type, target_info and target_path fields. + currentOffset = readTypeAnnotationTarget(context, typeAnnotationOffset); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentOffset, charBuffer); + currentOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + readElementValues( + methodVisitor.visitLocalVariableAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + context.currentLocalVariableAnnotationRangeStarts, + context.currentLocalVariableAnnotationRangeEnds, + context.currentLocalVariableAnnotationRangeIndices, + annotationDescriptor, + /* visible = */ true), + currentOffset, + /* named = */ true, + charBuffer); + } + } + } + + // Visit the local variable type annotations of the RuntimeInvisibleTypeAnnotations attribute. + if (invisibleTypeAnnotationOffsets != null) { + for (int typeAnnotationOffset : invisibleTypeAnnotationOffsets) { + int targetType = readByte(typeAnnotationOffset); + if (targetType == TypeReference.LOCAL_VARIABLE + || targetType == TypeReference.RESOURCE_VARIABLE) { + // Parse the target_type, target_info and target_path fields. + currentOffset = readTypeAnnotationTarget(context, typeAnnotationOffset); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentOffset, charBuffer); + currentOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + readElementValues( + methodVisitor.visitLocalVariableAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + context.currentLocalVariableAnnotationRangeStarts, + context.currentLocalVariableAnnotationRangeEnds, + context.currentLocalVariableAnnotationRangeIndices, + annotationDescriptor, + /* visible = */ false), + currentOffset, + /* named = */ true, + charBuffer); + } + } + } + + // Visit the non standard attributes. + while (attributes != null) { + // Copy and reset the nextAttribute field so that it can also be used in MethodWriter. + Attribute nextAttribute = attributes.nextAttribute; + attributes.nextAttribute = null; + methodVisitor.visitAttribute(attributes); + attributes = nextAttribute; + } + + // Visit the max stack and max locals values. + methodVisitor.visitMaxs(maxStack, maxLocals); + } + + /** + * Returns the label corresponding to the given bytecode offset. The default implementation of + * this method creates a label for the given offset if it has not been already created. + * + * @param bytecodeOffset a bytecode offset in a method. + * @param labels the already created labels, indexed by their offset. If a label already exists + * for bytecodeOffset this method must not create a new one. Otherwise it must store the new + * label in this array. + * @return a non null Label, which must be equal to labels[bytecodeOffset]. + */ + protected Label readLabel(final int bytecodeOffset, final Label[] labels) { + if (labels[bytecodeOffset] == null) { + labels[bytecodeOffset] = new Label(); + } + return labels[bytecodeOffset]; + } + + /** + * Creates a label without the {@link Label#FLAG_DEBUG_ONLY} flag set, for the given bytecode + * offset. The label is created with a call to {@link #readLabel} and its {@link + * Label#FLAG_DEBUG_ONLY} flag is cleared. + * + * @param bytecodeOffset a bytecode offset in a method. + * @param labels the already created labels, indexed by their offset. + * @return a Label without the {@link Label#FLAG_DEBUG_ONLY} flag set. + */ + private Label createLabel(final int bytecodeOffset, final Label[] labels) { + Label label = readLabel(bytecodeOffset, labels); + label.flags &= ~Label.FLAG_DEBUG_ONLY; + return label; + } + + /** + * Creates a label with the {@link Label#FLAG_DEBUG_ONLY} flag set, if there is no already + * existing label for the given bytecode offset (otherwise does nothing). The label is created + * with a call to {@link #readLabel}. + * + * @param bytecodeOffset a bytecode offset in a method. + * @param labels the already created labels, indexed by their offset. + */ + private void createDebugLabel(final int bytecodeOffset, final Label[] labels) { + if (labels[bytecodeOffset] == null) { + readLabel(bytecodeOffset, labels).flags |= Label.FLAG_DEBUG_ONLY; + } + } + + // ---------------------------------------------------------------------------------------------- + // Methods to parse annotations, type annotations and parameter annotations + // ---------------------------------------------------------------------------------------------- + + /** + * Parses a Runtime[In]VisibleTypeAnnotations attribute to find the offset of each type_annotation + * entry it contains, to find the corresponding labels, and to visit the try catch block + * annotations. + * + * @param methodVisitor the method visitor to be used to visit the try catch block annotations. + * @param context information about the class being parsed. + * @param runtimeTypeAnnotationsOffset the start offset of a Runtime[In]VisibleTypeAnnotations + * attribute, excluding the attribute_info's attribute_name_index and + * attribute_length fields. + * @param visible true if the attribute to parse is a RuntimeVisibleTypeAnnotations attribute, + * false it is a RuntimeInvisibleTypeAnnotations attribute. + * @return the start offset of each entry of the Runtime[In]VisibleTypeAnnotations_attribute's + * 'annotations' array field. + */ + private int[] readTypeAnnotations( + final MethodVisitor methodVisitor, + final Context context, + final int runtimeTypeAnnotationsOffset, + final boolean visible) { + char[] charBuffer = context.charBuffer; + int currentOffset = runtimeTypeAnnotationsOffset; + // Read the num_annotations field and create an array to store the type_annotation offsets. + int[] typeAnnotationsOffsets = new int[readUnsignedShort(currentOffset)]; + currentOffset += 2; + // Parse the 'annotations' array field. + for (int i = 0; i < typeAnnotationsOffsets.length; ++i) { + typeAnnotationsOffsets[i] = currentOffset; + // Parse the type_annotation's target_type and the target_info fields. The size of the + // target_info field depends on the value of target_type. + int targetType = readInt(currentOffset); + switch (targetType >>> 24) { + case TypeReference.LOCAL_VARIABLE: + case TypeReference.RESOURCE_VARIABLE: + // A localvar_target has a variable size, which depends on the value of their table_length + // field. It also references bytecode offsets, for which we need labels. + int tableLength = readUnsignedShort(currentOffset + 1); + currentOffset += 3; + while (tableLength-- > 0) { + int startPc = readUnsignedShort(currentOffset); + int length = readUnsignedShort(currentOffset + 2); + // Skip the index field (2 bytes). + currentOffset += 6; + createLabel(startPc, context.currentMethodLabels); + createLabel(startPc + length, context.currentMethodLabels); + } + break; + case TypeReference.CAST: + case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: + case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT: + case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: + case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT: + currentOffset += 4; + break; + case TypeReference.CLASS_EXTENDS: + case TypeReference.CLASS_TYPE_PARAMETER_BOUND: + case TypeReference.METHOD_TYPE_PARAMETER_BOUND: + case TypeReference.THROWS: + case TypeReference.EXCEPTION_PARAMETER: + case TypeReference.INSTANCEOF: + case TypeReference.NEW: + case TypeReference.CONSTRUCTOR_REFERENCE: + case TypeReference.METHOD_REFERENCE: + currentOffset += 3; + break; + case TypeReference.CLASS_TYPE_PARAMETER: + case TypeReference.METHOD_TYPE_PARAMETER: + case TypeReference.METHOD_FORMAL_PARAMETER: + case TypeReference.FIELD: + case TypeReference.METHOD_RETURN: + case TypeReference.METHOD_RECEIVER: + default: + // TypeReference type which can't be used in Code attribute, or which is unknown. + throw new IllegalArgumentException(); + } + // Parse the rest of the type_annotation structure, starting with the target_path structure + // (whose size depends on its path_length field). + int pathLength = readByte(currentOffset); + if ((targetType >>> 24) == TypeReference.EXCEPTION_PARAMETER) { + // Parse the target_path structure and create a corresponding TypePath. + TypePath path = pathLength == 0 ? null : new TypePath(classFileBuffer, currentOffset); + currentOffset += 1 + 2 * pathLength; + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentOffset, charBuffer); + currentOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentOffset = + readElementValues( + methodVisitor.visitTryCatchAnnotation( + targetType & 0xFFFFFF00, path, annotationDescriptor, visible), + currentOffset, + /* named = */ true, + charBuffer); + } else { + // We don't want to visit the other target_type annotations, so we just skip them (which + // requires some parsing because the element_value_pairs array has a variable size). First, + // skip the target_path structure: + currentOffset += 3 + 2 * pathLength; + // Then skip the num_element_value_pairs and element_value_pairs fields (by reading them + // with a null AnnotationVisitor). + currentOffset = + readElementValues( + /* annotationVisitor = */ null, currentOffset, /* named = */ true, charBuffer); + } + } + return typeAnnotationsOffsets; + } + + /** + * Returns the bytecode offset corresponding to the specified JVMS 'type_annotation' structure, or + * -1 if there is no such type_annotation of if it does not have a bytecode offset. + * + * @param typeAnnotationOffsets the offset of each 'type_annotation' entry in a + * Runtime[In]VisibleTypeAnnotations attribute, or null. + * @param typeAnnotationIndex the index a 'type_annotation' entry in typeAnnotationOffsets. + * @return bytecode offset corresponding to the specified JVMS 'type_annotation' structure, or -1 + * if there is no such type_annotation of if it does not have a bytecode offset. + */ + private int getTypeAnnotationBytecodeOffset( + final int[] typeAnnotationOffsets, final int typeAnnotationIndex) { + if (typeAnnotationOffsets == null + || typeAnnotationIndex >= typeAnnotationOffsets.length + || readByte(typeAnnotationOffsets[typeAnnotationIndex]) < TypeReference.INSTANCEOF) { + return -1; + } + return readUnsignedShort(typeAnnotationOffsets[typeAnnotationIndex] + 1); + } + + /** + * Parses the header of a JVMS type_annotation structure to extract its target_type, target_info + * and target_path (the result is stored in the given context), and returns the start offset of + * the rest of the type_annotation structure. + * + * @param context information about the class being parsed. This is where the extracted + * target_type and target_path must be stored. + * @param typeAnnotationOffset the start offset of a type_annotation structure. + * @return the start offset of the rest of the type_annotation structure. + */ + private int readTypeAnnotationTarget(final Context context, final int typeAnnotationOffset) { + int currentOffset = typeAnnotationOffset; + // Parse and store the target_type structure. + int targetType = readInt(typeAnnotationOffset); + switch (targetType >>> 24) { + case TypeReference.CLASS_TYPE_PARAMETER: + case TypeReference.METHOD_TYPE_PARAMETER: + case TypeReference.METHOD_FORMAL_PARAMETER: + targetType &= 0xFFFF0000; + currentOffset += 2; + break; + case TypeReference.FIELD: + case TypeReference.METHOD_RETURN: + case TypeReference.METHOD_RECEIVER: + targetType &= 0xFF000000; + currentOffset += 1; + break; case TypeReference.LOCAL_VARIABLE: case TypeReference.RESOURCE_VARIABLE: - // A localvar_target has a variable size, which depends on the value of their table_length - // field. It also references bytecode offsets, for which we need labels. - int tableLength = readUnsignedShort(currentOffset + 1); - currentOffset += 3; - while (tableLength-- > 0) { - int startPc = readUnsignedShort(currentOffset); - int length = readUnsignedShort(currentOffset + 2); - // Skip the index field (2 bytes). - currentOffset += 6; - createLabel(startPc, context.currentMethodLabels); - createLabel(startPc + length, context.currentMethodLabels); - } - break; + targetType &= 0xFF000000; + int tableLength = readUnsignedShort(currentOffset + 1); + currentOffset += 3; + context.currentLocalVariableAnnotationRangeStarts = new Label[tableLength]; + context.currentLocalVariableAnnotationRangeEnds = new Label[tableLength]; + context.currentLocalVariableAnnotationRangeIndices = new int[tableLength]; + for (int i = 0; i < tableLength; ++i) { + int startPc = readUnsignedShort(currentOffset); + int length = readUnsignedShort(currentOffset + 2); + int index = readUnsignedShort(currentOffset + 4); + currentOffset += 6; + context.currentLocalVariableAnnotationRangeStarts[i] = + createLabel(startPc, context.currentMethodLabels); + context.currentLocalVariableAnnotationRangeEnds[i] = + createLabel(startPc + length, context.currentMethodLabels); + context.currentLocalVariableAnnotationRangeIndices[i] = index; + } + break; case TypeReference.CAST: case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT: case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT: - currentOffset += 4; - break; + targetType &= 0xFF0000FF; + currentOffset += 4; + break; case TypeReference.CLASS_EXTENDS: case TypeReference.CLASS_TYPE_PARAMETER_BOUND: case TypeReference.METHOD_TYPE_PARAMETER_BOUND: case TypeReference.THROWS: case TypeReference.EXCEPTION_PARAMETER: + targetType &= 0xFFFFFF00; + currentOffset += 3; + break; case TypeReference.INSTANCEOF: case TypeReference.NEW: case TypeReference.CONSTRUCTOR_REFERENCE: case TypeReference.METHOD_REFERENCE: - currentOffset += 3; - break; - case TypeReference.CLASS_TYPE_PARAMETER: - case TypeReference.METHOD_TYPE_PARAMETER: - case TypeReference.METHOD_FORMAL_PARAMETER: - case TypeReference.FIELD: - case TypeReference.METHOD_RETURN: - case TypeReference.METHOD_RECEIVER: + targetType &= 0xFF000000; + currentOffset += 3; + break; default: - // TypeReference type which can't be used in Code attribute, or which is unknown. - throw new IllegalArgumentException(); - } - // Parse the rest of the type_annotation structure, starting with the target_path structure - // (whose size depends on its path_length field). - int pathLength = readByte(currentOffset); - if ((targetType >>> 24) == TypeReference.EXCEPTION_PARAMETER) { - // Parse the target_path structure and create a corresponding TypePath. - TypePath path = pathLength == 0 ? null : new TypePath(classFileBuffer, currentOffset); - currentOffset += 1 + 2 * pathLength; - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentOffset, charBuffer); - currentOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentOffset = - readElementValues( - methodVisitor.visitTryCatchAnnotation( - targetType & 0xFFFFFF00, path, annotationDescriptor, visible), - currentOffset, - /* named = */ true, - charBuffer); - } else { - // We don't want to visit the other target_type annotations, so we just skip them (which - // requires some parsing because the element_value_pairs array has a variable size). First, - // skip the target_path structure: - currentOffset += 3 + 2 * pathLength; - // Then skip the num_element_value_pairs and element_value_pairs fields (by reading them - // with a null AnnotationVisitor). - currentOffset = - readElementValues( - /* annotationVisitor = */ null, currentOffset, /* named = */ true, charBuffer); - } - } - return typeAnnotationsOffsets; - } - - /** - * Returns the bytecode offset corresponding to the specified JVMS 'type_annotation' structure, or - * -1 if there is no such type_annotation of if it does not have a bytecode offset. - * - * @param typeAnnotationOffsets the offset of each 'type_annotation' entry in a - * Runtime[In]VisibleTypeAnnotations attribute, or null. - * @param typeAnnotationIndex the index a 'type_annotation' entry in typeAnnotationOffsets. - * @return bytecode offset corresponding to the specified JVMS 'type_annotation' structure, or -1 - * if there is no such type_annotation of if it does not have a bytecode offset. - */ - private int getTypeAnnotationBytecodeOffset( - final int[] typeAnnotationOffsets, final int typeAnnotationIndex) { - if (typeAnnotationOffsets == null - || typeAnnotationIndex >= typeAnnotationOffsets.length - || readByte(typeAnnotationOffsets[typeAnnotationIndex]) < TypeReference.INSTANCEOF) { - return -1; - } - return readUnsignedShort(typeAnnotationOffsets[typeAnnotationIndex] + 1); - } - - /** - * Parses the header of a JVMS type_annotation structure to extract its target_type, target_info - * and target_path (the result is stored in the given context), and returns the start offset of - * the rest of the type_annotation structure. - * - * @param context information about the class being parsed. This is where the extracted - * target_type and target_path must be stored. - * @param typeAnnotationOffset the start offset of a type_annotation structure. - * @return the start offset of the rest of the type_annotation structure. - */ - private int readTypeAnnotationTarget(final Context context, final int typeAnnotationOffset) { - int currentOffset = typeAnnotationOffset; - // Parse and store the target_type structure. - int targetType = readInt(typeAnnotationOffset); - switch (targetType >>> 24) { - case TypeReference.CLASS_TYPE_PARAMETER: - case TypeReference.METHOD_TYPE_PARAMETER: - case TypeReference.METHOD_FORMAL_PARAMETER: - targetType &= 0xFFFF0000; - currentOffset += 2; - break; - case TypeReference.FIELD: - case TypeReference.METHOD_RETURN: - case TypeReference.METHOD_RECEIVER: - targetType &= 0xFF000000; - currentOffset += 1; - break; - case TypeReference.LOCAL_VARIABLE: - case TypeReference.RESOURCE_VARIABLE: - targetType &= 0xFF000000; - int tableLength = readUnsignedShort(currentOffset + 1); - currentOffset += 3; - context.currentLocalVariableAnnotationRangeStarts = new Label[tableLength]; - context.currentLocalVariableAnnotationRangeEnds = new Label[tableLength]; - context.currentLocalVariableAnnotationRangeIndices = new int[tableLength]; - for (int i = 0; i < tableLength; ++i) { - int startPc = readUnsignedShort(currentOffset); - int length = readUnsignedShort(currentOffset + 2); - int index = readUnsignedShort(currentOffset + 4); - currentOffset += 6; - context.currentLocalVariableAnnotationRangeStarts[i] = - createLabel(startPc, context.currentMethodLabels); - context.currentLocalVariableAnnotationRangeEnds[i] = - createLabel(startPc + length, context.currentMethodLabels); - context.currentLocalVariableAnnotationRangeIndices[i] = index; + throw new IllegalArgumentException(); } - break; - case TypeReference.CAST: - case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: - case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT: - case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: - case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT: - targetType &= 0xFF0000FF; - currentOffset += 4; - break; - case TypeReference.CLASS_EXTENDS: - case TypeReference.CLASS_TYPE_PARAMETER_BOUND: - case TypeReference.METHOD_TYPE_PARAMETER_BOUND: - case TypeReference.THROWS: - case TypeReference.EXCEPTION_PARAMETER: - targetType &= 0xFFFFFF00; - currentOffset += 3; - break; - case TypeReference.INSTANCEOF: - case TypeReference.NEW: - case TypeReference.CONSTRUCTOR_REFERENCE: - case TypeReference.METHOD_REFERENCE: - targetType &= 0xFF000000; - currentOffset += 3; - break; - default: - throw new IllegalArgumentException(); + context.currentTypeAnnotationTarget = targetType; + // Parse and store the target_path structure. + int pathLength = readByte(currentOffset); + context.currentTypeAnnotationTargetPath = + pathLength == 0 ? null : new TypePath(classFileBuffer, currentOffset); + // Return the start offset of the rest of the type_annotation structure. + return currentOffset + 1 + 2 * pathLength; } - context.currentTypeAnnotationTarget = targetType; - // Parse and store the target_path structure. - int pathLength = readByte(currentOffset); - context.currentTypeAnnotationTargetPath = - pathLength == 0 ? null : new TypePath(classFileBuffer, currentOffset); - // Return the start offset of the rest of the type_annotation structure. - return currentOffset + 1 + 2 * pathLength; - } - /** - * Reads a Runtime[In]VisibleParameterAnnotations attribute and makes the given visitor visit it. - * - * @param methodVisitor the visitor that must visit the parameter annotations. - * @param context information about the class being parsed. - * @param runtimeParameterAnnotationsOffset the start offset of a - * Runtime[In]VisibleParameterAnnotations attribute, excluding the attribute_info's - * attribute_name_index and attribute_length fields. - * @param visible true if the attribute to parse is a RuntimeVisibleParameterAnnotations - * attribute, false it is a RuntimeInvisibleParameterAnnotations attribute. - */ - private void readParameterAnnotations( - final MethodVisitor methodVisitor, - final Context context, - final int runtimeParameterAnnotationsOffset, - final boolean visible) { - int currentOffset = runtimeParameterAnnotationsOffset; - int numParameters = classFileBuffer[currentOffset++] & 0xFF; - methodVisitor.visitAnnotableParameterCount(numParameters, visible); - char[] charBuffer = context.charBuffer; - for (int i = 0; i < numParameters; ++i) { - int numAnnotations = readUnsignedShort(currentOffset); - currentOffset += 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentOffset, charBuffer); + /** + * Reads a Runtime[In]VisibleParameterAnnotations attribute and makes the given visitor visit it. + * + * @param methodVisitor the visitor that must visit the parameter annotations. + * @param context information about the class being parsed. + * @param runtimeParameterAnnotationsOffset the start offset of a + * Runtime[In]VisibleParameterAnnotations attribute, excluding the + * attribute_info's + * attribute_name_index and attribute_length fields. + * @param visible true if the attribute to parse is a RuntimeVisibleParameterAnnotations + * attribute, false it is a RuntimeInvisibleParameterAnnotations attribute. + */ + private void readParameterAnnotations( + final MethodVisitor methodVisitor, + final Context context, + final int runtimeParameterAnnotationsOffset, + final boolean visible) { + int currentOffset = runtimeParameterAnnotationsOffset; + int numParameters = classFileBuffer[currentOffset++] & 0xFF; + methodVisitor.visitAnnotableParameterCount(numParameters, visible); + char[] charBuffer = context.charBuffer; + for (int i = 0; i < numParameters; ++i) { + int numAnnotations = readUnsignedShort(currentOffset); + currentOffset += 2; + while (numAnnotations-- > 0) { + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentOffset, charBuffer); + currentOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentOffset = + readElementValues( + methodVisitor.visitParameterAnnotation(i, annotationDescriptor, visible), + currentOffset, + /* named = */ true, + charBuffer); + } + } + } + + /** + * Reads the element values of a JVMS 'annotation' structure and makes the given visitor visit + * them. This method can also be used to read the values of the JVMS 'array_value' field of an + * annotation's 'element_value'. + * + * @param annotationVisitor the visitor that must visit the values. + * @param annotationOffset the start offset of an 'annotation' structure (excluding its type_index + * field) or of an 'array_value' structure. + * @param named if the annotation values are named or not. This should be true to parse the values + * of a JVMS 'annotation' structure, and false to parse the JVMS 'array_value' of an + * annotation's element_value. + * @param charBuffer the buffer used to read strings in the constant pool. + * @return the end offset of the JVMS 'annotation' or 'array_value' structure. + */ + private int readElementValues( + final AnnotationVisitor annotationVisitor, + final int annotationOffset, + final boolean named, + final char[] charBuffer) { + int currentOffset = annotationOffset; + // Read the num_element_value_pairs field (or num_values field for an array_value). + int numElementValuePairs = readUnsignedShort(currentOffset); currentOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentOffset = - readElementValues( - methodVisitor.visitParameterAnnotation(i, annotationDescriptor, visible), - currentOffset, - /* named = */ true, - charBuffer); - } + if (named) { + // Parse the element_value_pairs array. + while (numElementValuePairs-- > 0) { + String elementName = readUTF8(currentOffset, charBuffer); + currentOffset = + readElementValue(annotationVisitor, currentOffset + 2, elementName, charBuffer); + } + } else { + // Parse the array_value array. + while (numElementValuePairs-- > 0) { + currentOffset = + readElementValue(annotationVisitor, currentOffset, /* named = */ null, charBuffer); + } + } + if (annotationVisitor != null) { + annotationVisitor.visitEnd(); + } + return currentOffset; } - } - /** - * Reads the element values of a JVMS 'annotation' structure and makes the given visitor visit - * them. This method can also be used to read the values of the JVMS 'array_value' field of an - * annotation's 'element_value'. - * - * @param annotationVisitor the visitor that must visit the values. - * @param annotationOffset the start offset of an 'annotation' structure (excluding its type_index - * field) or of an 'array_value' structure. - * @param named if the annotation values are named or not. This should be true to parse the values - * of a JVMS 'annotation' structure, and false to parse the JVMS 'array_value' of an - * annotation's element_value. - * @param charBuffer the buffer used to read strings in the constant pool. - * @return the end offset of the JVMS 'annotation' or 'array_value' structure. - */ - private int readElementValues( - final AnnotationVisitor annotationVisitor, - final int annotationOffset, - final boolean named, - final char[] charBuffer) { - int currentOffset = annotationOffset; - // Read the num_element_value_pairs field (or num_values field for an array_value). - int numElementValuePairs = readUnsignedShort(currentOffset); - currentOffset += 2; - if (named) { - // Parse the element_value_pairs array. - while (numElementValuePairs-- > 0) { - String elementName = readUTF8(currentOffset, charBuffer); - currentOffset = - readElementValue(annotationVisitor, currentOffset + 2, elementName, charBuffer); - } - } else { - // Parse the array_value array. - while (numElementValuePairs-- > 0) { - currentOffset = - readElementValue(annotationVisitor, currentOffset, /* named = */ null, charBuffer); - } - } - if (annotationVisitor != null) { - annotationVisitor.visitEnd(); - } - return currentOffset; - } + /** + * Reads a JVMS 'element_value' structure and makes the given visitor visit it. + * + * @param annotationVisitor the visitor that must visit the element_value structure. + * @param elementValueOffset the start offset in {@link #classFileBuffer} of the element_value + * structure to be read. + * @param elementName the name of the element_value structure to be read, or {@literal null}. + * @param charBuffer the buffer used to read strings in the constant pool. + * @return the end offset of the JVMS 'element_value' structure. + */ + private int readElementValue( + final AnnotationVisitor annotationVisitor, + final int elementValueOffset, + final String elementName, + final char[] charBuffer) { + int currentOffset = elementValueOffset; + if (annotationVisitor == null) { + switch (classFileBuffer[currentOffset] & 0xFF) { + case 'e': // enum_const_value + return currentOffset + 5; + case '@': // annotation_value + return readElementValues(null, currentOffset + 3, /* named = */ true, charBuffer); + case '[': // array_value + return readElementValues(null, currentOffset + 1, /* named = */ false, charBuffer); + default: + return currentOffset + 3; + } + } + switch (classFileBuffer[currentOffset++] & 0xFF) { + case 'B': // const_value_index, CONSTANT_Integer + annotationVisitor.visit( + elementName, (byte) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); + currentOffset += 2; + break; + case 'C': // const_value_index, CONSTANT_Integer + annotationVisitor.visit( + elementName, (char) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); + currentOffset += 2; + break; + case 'D': // const_value_index, CONSTANT_Double + case 'F': // const_value_index, CONSTANT_Float + case 'I': // const_value_index, CONSTANT_Integer + case 'J': // const_value_index, CONSTANT_Long + annotationVisitor.visit( + elementName, readConst(readUnsignedShort(currentOffset), charBuffer)); + currentOffset += 2; + break; + case 'S': // const_value_index, CONSTANT_Integer + annotationVisitor.visit( + elementName, (short) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); + currentOffset += 2; + break; - /** - * Reads a JVMS 'element_value' structure and makes the given visitor visit it. - * - * @param annotationVisitor the visitor that must visit the element_value structure. - * @param elementValueOffset the start offset in {@link #classFileBuffer} of the element_value - * structure to be read. - * @param elementName the name of the element_value structure to be read, or {@literal null}. - * @param charBuffer the buffer used to read strings in the constant pool. - * @return the end offset of the JVMS 'element_value' structure. - */ - private int readElementValue( - final AnnotationVisitor annotationVisitor, - final int elementValueOffset, - final String elementName, - final char[] charBuffer) { - int currentOffset = elementValueOffset; - if (annotationVisitor == null) { - switch (classFileBuffer[currentOffset] & 0xFF) { + case 'Z': // const_value_index, CONSTANT_Integer + annotationVisitor.visit( + elementName, + readInt(cpInfoOffsets[readUnsignedShort(currentOffset)]) == 0 + ? Boolean.FALSE + : Boolean.TRUE); + currentOffset += 2; + break; + case 's': // const_value_index, CONSTANT_Utf8 + annotationVisitor.visit(elementName, readUTF8(currentOffset, charBuffer)); + currentOffset += 2; + break; case 'e': // enum_const_value - return currentOffset + 5; + annotationVisitor.visitEnum( + elementName, + readUTF8(currentOffset, charBuffer), + readUTF8(currentOffset + 2, charBuffer)); + currentOffset += 4; + break; + case 'c': // class_info + annotationVisitor.visit(elementName, Type.getType(readUTF8(currentOffset, charBuffer))); + currentOffset += 2; + break; case '@': // annotation_value - return readElementValues(null, currentOffset + 3, /* named = */ true, charBuffer); - case '[': // array_value - return readElementValues(null, currentOffset + 1, /* named = */ false, charBuffer); - default: - return currentOffset + 3; - } - } - switch (classFileBuffer[currentOffset++] & 0xFF) { - case 'B': // const_value_index, CONSTANT_Integer - annotationVisitor.visit( - elementName, (byte) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); - currentOffset += 2; - break; - case 'C': // const_value_index, CONSTANT_Integer - annotationVisitor.visit( - elementName, (char) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); - currentOffset += 2; - break; - case 'D': // const_value_index, CONSTANT_Double - case 'F': // const_value_index, CONSTANT_Float - case 'I': // const_value_index, CONSTANT_Integer - case 'J': // const_value_index, CONSTANT_Long - annotationVisitor.visit( - elementName, readConst(readUnsignedShort(currentOffset), charBuffer)); - currentOffset += 2; - break; - case 'S': // const_value_index, CONSTANT_Integer - annotationVisitor.visit( - elementName, (short) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); - currentOffset += 2; - break; - - case 'Z': // const_value_index, CONSTANT_Integer - annotationVisitor.visit( - elementName, - readInt(cpInfoOffsets[readUnsignedShort(currentOffset)]) == 0 - ? Boolean.FALSE - : Boolean.TRUE); - currentOffset += 2; - break; - case 's': // const_value_index, CONSTANT_Utf8 - annotationVisitor.visit(elementName, readUTF8(currentOffset, charBuffer)); - currentOffset += 2; - break; - case 'e': // enum_const_value - annotationVisitor.visitEnum( - elementName, - readUTF8(currentOffset, charBuffer), - readUTF8(currentOffset + 2, charBuffer)); - currentOffset += 4; - break; - case 'c': // class_info - annotationVisitor.visit(elementName, Type.getType(readUTF8(currentOffset, charBuffer))); - currentOffset += 2; - break; - case '@': // annotation_value - currentOffset = - readElementValues( - annotationVisitor.visitAnnotation(elementName, readUTF8(currentOffset, charBuffer)), - currentOffset + 2, - true, - charBuffer); - break; - case '[': // array_value - int numValues = readUnsignedShort(currentOffset); - currentOffset += 2; - if (numValues == 0) { - return readElementValues( - annotationVisitor.visitArray(elementName), - currentOffset - 2, - /* named = */ false, - charBuffer); - } - switch (classFileBuffer[currentOffset] & 0xFF) { - case 'B': - byte[] byteValues = new byte[numValues]; - for (int i = 0; i < numValues; i++) { - byteValues[i] = (byte) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); - currentOffset += 3; - } - annotationVisitor.visit(elementName, byteValues); - break; - case 'Z': - boolean[] booleanValues = new boolean[numValues]; - for (int i = 0; i < numValues; i++) { - booleanValues[i] = readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]) != 0; - currentOffset += 3; - } - annotationVisitor.visit(elementName, booleanValues); - break; - case 'S': - short[] shortValues = new short[numValues]; - for (int i = 0; i < numValues; i++) { - shortValues[i] = (short) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); - currentOffset += 3; - } - annotationVisitor.visit(elementName, shortValues); - break; - case 'C': - char[] charValues = new char[numValues]; - for (int i = 0; i < numValues; i++) { - charValues[i] = (char) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); - currentOffset += 3; - } - annotationVisitor.visit(elementName, charValues); - break; - case 'I': - int[] intValues = new int[numValues]; - for (int i = 0; i < numValues; i++) { - intValues[i] = readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); - currentOffset += 3; - } - annotationVisitor.visit(elementName, intValues); - break; - case 'J': - long[] longValues = new long[numValues]; - for (int i = 0; i < numValues; i++) { - longValues[i] = readLong(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); - currentOffset += 3; - } - annotationVisitor.visit(elementName, longValues); - break; - case 'F': - float[] floatValues = new float[numValues]; - for (int i = 0; i < numValues; i++) { - floatValues[i] = - Float.intBitsToFloat( - readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)])); - currentOffset += 3; - } - annotationVisitor.visit(elementName, floatValues); - break; - case 'D': - double[] doubleValues = new double[numValues]; - for (int i = 0; i < numValues; i++) { - doubleValues[i] = - Double.longBitsToDouble( - readLong(cpInfoOffsets[readUnsignedShort(currentOffset + 1)])); - currentOffset += 3; - } - annotationVisitor.visit(elementName, doubleValues); - break; - default: currentOffset = readElementValues( - annotationVisitor.visitArray(elementName), - currentOffset - 2, - /* named = */ false, + annotationVisitor.visitAnnotation(elementName, readUTF8(currentOffset, charBuffer)), + currentOffset + 2, + true, charBuffer); break; - } - break; - default: - throw new IllegalArgumentException(); - } - return currentOffset; - } - - // ---------------------------------------------------------------------------------------------- - // Methods to parse stack map frames - // ---------------------------------------------------------------------------------------------- - - /** - * Computes the implicit frame of the method currently being parsed (as defined in the given - * {@link Context}) and stores it in the given context. - * - * @param context information about the class being parsed. - */ - private void computeImplicitFrame(final Context context) { - String methodDescriptor = context.currentMethodDescriptor; - Object[] locals = context.currentFrameLocalTypes; - int numLocal = 0; - if ((context.currentMethodAccessFlags & Opcodes.ACC_STATIC) == 0) { - if ("".equals(context.currentMethodName)) { - locals[numLocal++] = Opcodes.UNINITIALIZED_THIS; - } else { - locals[numLocal++] = readClass(header + 2, context.charBuffer); - } - } - // Parse the method descriptor, one argument type descriptor at each iteration. Start by - // skipping the first method descriptor character, which is always '('. - int currentMethodDescritorOffset = 1; - while (true) { - int currentArgumentDescriptorStartOffset = currentMethodDescritorOffset; - switch (methodDescriptor.charAt(currentMethodDescritorOffset++)) { - case 'Z': - case 'C': - case 'B': - case 'S': - case 'I': - locals[numLocal++] = Opcodes.INTEGER; - break; - case 'F': - locals[numLocal++] = Opcodes.FLOAT; - break; - case 'J': - locals[numLocal++] = Opcodes.LONG; - break; - case 'D': - locals[numLocal++] = Opcodes.DOUBLE; - break; - case '[': - while (methodDescriptor.charAt(currentMethodDescritorOffset) == '[') { - ++currentMethodDescritorOffset; - } - if (methodDescriptor.charAt(currentMethodDescritorOffset) == 'L') { - ++currentMethodDescritorOffset; - while (methodDescriptor.charAt(currentMethodDescritorOffset) != ';') { - ++currentMethodDescritorOffset; + case '[': // array_value + int numValues = readUnsignedShort(currentOffset); + currentOffset += 2; + if (numValues == 0) { + return readElementValues( + annotationVisitor.visitArray(elementName), + currentOffset - 2, + /* named = */ false, + charBuffer); } - } - locals[numLocal++] = - methodDescriptor.substring( - currentArgumentDescriptorStartOffset, ++currentMethodDescritorOffset); - break; - case 'L': - while (methodDescriptor.charAt(currentMethodDescritorOffset) != ';') { - ++currentMethodDescritorOffset; - } - locals[numLocal++] = - methodDescriptor.substring( - currentArgumentDescriptorStartOffset + 1, currentMethodDescritorOffset++); - break; + switch (classFileBuffer[currentOffset] & 0xFF) { + case 'B': + byte[] byteValues = new byte[numValues]; + for (int i = 0; i < numValues; i++) { + byteValues[i] = (byte) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); + currentOffset += 3; + } + annotationVisitor.visit(elementName, byteValues); + break; + case 'Z': + boolean[] booleanValues = new boolean[numValues]; + for (int i = 0; i < numValues; i++) { + booleanValues[i] = readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]) != 0; + currentOffset += 3; + } + annotationVisitor.visit(elementName, booleanValues); + break; + case 'S': + short[] shortValues = new short[numValues]; + for (int i = 0; i < numValues; i++) { + shortValues[i] = (short) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); + currentOffset += 3; + } + annotationVisitor.visit(elementName, shortValues); + break; + case 'C': + char[] charValues = new char[numValues]; + for (int i = 0; i < numValues; i++) { + charValues[i] = (char) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); + currentOffset += 3; + } + annotationVisitor.visit(elementName, charValues); + break; + case 'I': + int[] intValues = new int[numValues]; + for (int i = 0; i < numValues; i++) { + intValues[i] = readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); + currentOffset += 3; + } + annotationVisitor.visit(elementName, intValues); + break; + case 'J': + long[] longValues = new long[numValues]; + for (int i = 0; i < numValues; i++) { + longValues[i] = readLong(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); + currentOffset += 3; + } + annotationVisitor.visit(elementName, longValues); + break; + case 'F': + float[] floatValues = new float[numValues]; + for (int i = 0; i < numValues; i++) { + floatValues[i] = + Float.intBitsToFloat( + readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)])); + currentOffset += 3; + } + annotationVisitor.visit(elementName, floatValues); + break; + case 'D': + double[] doubleValues = new double[numValues]; + for (int i = 0; i < numValues; i++) { + doubleValues[i] = + Double.longBitsToDouble( + readLong(cpInfoOffsets[readUnsignedShort(currentOffset + 1)])); + currentOffset += 3; + } + annotationVisitor.visit(elementName, doubleValues); + break; + default: + currentOffset = + readElementValues( + annotationVisitor.visitArray(elementName), + currentOffset - 2, + /* named = */ false, + charBuffer); + break; + } + break; default: - context.currentFrameLocalCount = numLocal; - return; - } + throw new IllegalArgumentException(); + } + return currentOffset; } - } - /** - * Reads a JVMS 'stack_map_frame' structure and stores the result in the given {@link Context} - * object. This method can also be used to read a full_frame structure, excluding its frame_type - * field (this is used to parse the legacy StackMap attributes). - * - * @param stackMapFrameOffset the start offset in {@link #classFileBuffer} of the - * stack_map_frame_value structure to be read, or the start offset of a full_frame structure - * (excluding its frame_type field). - * @param compressed true to read a 'stack_map_frame' structure, false to read a 'full_frame' - * structure without its frame_type field. - * @param expand if the stack map frame must be expanded. See {@link #EXPAND_FRAMES}. - * @param context where the parsed stack map frame must be stored. - * @return the end offset of the JVMS 'stack_map_frame' or 'full_frame' structure. - */ - private int readStackMapFrame( - final int stackMapFrameOffset, - final boolean compressed, - final boolean expand, - final Context context) { - int currentOffset = stackMapFrameOffset; - final char[] charBuffer = context.charBuffer; - final Label[] labels = context.currentMethodLabels; - int frameType; - if (compressed) { - // Read the frame_type field. - frameType = classFileBuffer[currentOffset++] & 0xFF; - } else { - frameType = Frame.FULL_FRAME; - context.currentFrameOffset = -1; - } - int offsetDelta; - context.currentFrameLocalCountDelta = 0; - if (frameType < Frame.SAME_LOCALS_1_STACK_ITEM_FRAME) { - offsetDelta = frameType; - context.currentFrameType = Opcodes.F_SAME; - context.currentFrameStackCount = 0; - } else if (frameType < Frame.RESERVED) { - offsetDelta = frameType - Frame.SAME_LOCALS_1_STACK_ITEM_FRAME; - currentOffset = - readVerificationTypeInfo( - currentOffset, context.currentFrameStackTypes, 0, charBuffer, labels); - context.currentFrameType = Opcodes.F_SAME1; - context.currentFrameStackCount = 1; - } else if (frameType >= Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { - offsetDelta = readUnsignedShort(currentOffset); - currentOffset += 2; - if (frameType == Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { - currentOffset = - readVerificationTypeInfo( - currentOffset, context.currentFrameStackTypes, 0, charBuffer, labels); - context.currentFrameType = Opcodes.F_SAME1; - context.currentFrameStackCount = 1; - } else if (frameType >= Frame.CHOP_FRAME && frameType < Frame.SAME_FRAME_EXTENDED) { - context.currentFrameType = Opcodes.F_CHOP; - context.currentFrameLocalCountDelta = Frame.SAME_FRAME_EXTENDED - frameType; - context.currentFrameLocalCount -= context.currentFrameLocalCountDelta; - context.currentFrameStackCount = 0; - } else if (frameType == Frame.SAME_FRAME_EXTENDED) { - context.currentFrameType = Opcodes.F_SAME; - context.currentFrameStackCount = 0; - } else if (frameType < Frame.FULL_FRAME) { - int local = expand ? context.currentFrameLocalCount : 0; - for (int k = frameType - Frame.SAME_FRAME_EXTENDED; k > 0; k--) { - currentOffset = - readVerificationTypeInfo( - currentOffset, context.currentFrameLocalTypes, local++, charBuffer, labels); - } - context.currentFrameType = Opcodes.F_APPEND; - context.currentFrameLocalCountDelta = frameType - Frame.SAME_FRAME_EXTENDED; - context.currentFrameLocalCount += context.currentFrameLocalCountDelta; - context.currentFrameStackCount = 0; - } else { - final int numberOfLocals = readUnsignedShort(currentOffset); - currentOffset += 2; - context.currentFrameType = Opcodes.F_FULL; - context.currentFrameLocalCountDelta = numberOfLocals; - context.currentFrameLocalCount = numberOfLocals; - for (int local = 0; local < numberOfLocals; ++local) { - currentOffset = - readVerificationTypeInfo( - currentOffset, context.currentFrameLocalTypes, local, charBuffer, labels); - } - final int numberOfStackItems = readUnsignedShort(currentOffset); - currentOffset += 2; - context.currentFrameStackCount = numberOfStackItems; - for (int stack = 0; stack < numberOfStackItems; ++stack) { - currentOffset = - readVerificationTypeInfo( - currentOffset, context.currentFrameStackTypes, stack, charBuffer, labels); - } - } - } else { - throw new IllegalArgumentException(); - } - context.currentFrameOffset += offsetDelta + 1; - createLabel(context.currentFrameOffset, labels); - return currentOffset; - } + // ---------------------------------------------------------------------------------------------- + // Methods to parse stack map frames + // ---------------------------------------------------------------------------------------------- - /** - * Reads a JVMS 'verification_type_info' structure and stores it at the given index in the given - * array. - * - * @param verificationTypeInfoOffset the start offset of the 'verification_type_info' structure to - * read. - * @param frame the array where the parsed type must be stored. - * @param index the index in 'frame' where the parsed type must be stored. - * @param charBuffer the buffer used to read strings in the constant pool. - * @param labels the labels of the method currently being parsed, indexed by their offset. If the - * parsed type is an ITEM_Uninitialized, a new label for the corresponding NEW instruction is - * stored in this array if it does not already exist. - * @return the end offset of the JVMS 'verification_type_info' structure. - */ - private int readVerificationTypeInfo( - final int verificationTypeInfoOffset, - final Object[] frame, - final int index, - final char[] charBuffer, - final Label[] labels) { - int currentOffset = verificationTypeInfoOffset; - int tag = classFileBuffer[currentOffset++] & 0xFF; - switch (tag) { - case Frame.ITEM_TOP: - frame[index] = Opcodes.TOP; - break; - case Frame.ITEM_INTEGER: - frame[index] = Opcodes.INTEGER; - break; - case Frame.ITEM_FLOAT: - frame[index] = Opcodes.FLOAT; - break; - case Frame.ITEM_DOUBLE: - frame[index] = Opcodes.DOUBLE; - break; - case Frame.ITEM_LONG: - frame[index] = Opcodes.LONG; - break; - case Frame.ITEM_NULL: - frame[index] = Opcodes.NULL; - break; - case Frame.ITEM_UNINITIALIZED_THIS: - frame[index] = Opcodes.UNINITIALIZED_THIS; - break; - case Frame.ITEM_OBJECT: - frame[index] = readClass(currentOffset, charBuffer); + /** + * Computes the implicit frame of the method currently being parsed (as defined in the given + * {@link Context}) and stores it in the given context. + * + * @param context information about the class being parsed. + */ + private void computeImplicitFrame(final Context context) { + String methodDescriptor = context.currentMethodDescriptor; + Object[] locals = context.currentFrameLocalTypes; + int numLocal = 0; + if ((context.currentMethodAccessFlags & OpcodesC_STATIC) == 0) { + if ("".equals(context.currentMethodName)) { + locals[numLocal++] = Opcodes.UNINITIALIZED_THIS; + } else { + locals[numLocal++] = readClass(header + 2, context.charBuffer); + } + } + // Parse the method descriptor, one argument type descriptor at each iteration. Start by + // skipping the first method descriptor character, which is always '('. + int currentMethodDescritorOffset = 1; + while (true) { + int currentArgumentDescriptorStartOffset = currentMethodDescritorOffset; + switch (methodDescriptor.charAt(currentMethodDescritorOffset++)) { + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + locals[numLocal++] = Opcodes.INTEGER; + break; + case 'F': + locals[numLocal++] = Opcodes.FLOAT; + break; + case 'J': + locals[numLocal++] = Opcodes.LONG; + break; + case 'D': + locals[numLocal++] = Opcodes.DOUBLE; + break; + case '[': + while (methodDescriptor.charAt(currentMethodDescritorOffset) == '[') { + ++currentMethodDescritorOffset; + } + if (methodDescriptor.charAt(currentMethodDescritorOffset) == 'L') { + ++currentMethodDescritorOffset; + while (methodDescriptor.charAt(currentMethodDescritorOffset) != ';') { + ++currentMethodDescritorOffset; + } + } + locals[numLocal++] = + methodDescriptor.substring( + currentArgumentDescriptorStartOffset, ++currentMethodDescritorOffset); + break; + case 'L': + while (methodDescriptor.charAt(currentMethodDescritorOffset) != ';') { + ++currentMethodDescritorOffset; + } + locals[numLocal++] = + methodDescriptor.substring( + currentArgumentDescriptorStartOffset + 1, currentMethodDescritorOffset++); + break; + default: + context.currentFrameLocalCount = numLocal; + return; + } + } + } + + /** + * Reads a JVMS 'stack_map_frame' structure and stores the result in the given {@link Context} + * object. This method can also be used to read a full_frame structure, excluding its frame_type + * field (this is used to parse the legacy StackMap attributes). + * + * @param stackMapFrameOffset the start offset in {@link #classFileBuffer} of the + * stack_map_frame_value structure to be read, or the start offset of a full_frame + * structure + * (excluding its frame_type field). + * @param compressed true to read a 'stack_map_frame' structure, false to read a 'full_frame' + * structure without its frame_type field. + * @param expand if the stack map frame must be expanded. See {@link #EXPAND_FRAMES}. + * @param context where the parsed stack map frame must be stored. + * @return the end offset of the JVMS 'stack_map_frame' or 'full_frame' structure. + */ + private int readStackMapFrame( + final int stackMapFrameOffset, + final boolean compressed, + final boolean expand, + final Context context) { + int currentOffset = stackMapFrameOffset; + final char[] charBuffer = context.charBuffer; + final Label[] labels = context.currentMethodLabels; + int frameType; + if (compressed) { + // Read the frame_type field. + frameType = classFileBuffer[currentOffset++] & 0xFF; + } else { + frameType = Frame.FULL_FRAME; + context.currentFrameOffset = -1; + } + int offsetDelta; + context.currentFrameLocalCountDelta = 0; + if (frameType < Frame.SAME_LOCALS_1_STACK_ITEM_FRAME) { + offsetDelta = frameType; + context.currentFrameType = Opcodes.F_SAME; + context.currentFrameStackCount = 0; + } else if (frameType < Frame.RESERVED) { + offsetDelta = frameType - Frame.SAME_LOCALS_1_STACK_ITEM_FRAME; + currentOffset = + readVerificationTypeInfo( + currentOffset, context.currentFrameStackTypes, 0, charBuffer, labels); + context.currentFrameType = Opcodes.F_SAME1; + context.currentFrameStackCount = 1; + } else if (frameType >= Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { + offsetDelta = readUnsignedShort(currentOffset); + currentOffset += 2; + if (frameType == Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { + currentOffset = + readVerificationTypeInfo( + currentOffset, context.currentFrameStackTypes, 0, charBuffer, labels); + context.currentFrameType = Opcodes.F_SAME1; + context.currentFrameStackCount = 1; + } else if (frameType >= Frame.CHOP_FRAME && frameType < Frame.SAME_FRAME_EXTENDED) { + context.currentFrameType = Opcodes.F_CHOP; + context.currentFrameLocalCountDelta = Frame.SAME_FRAME_EXTENDED - frameType; + context.currentFrameLocalCount -= context.currentFrameLocalCountDelta; + context.currentFrameStackCount = 0; + } else if (frameType == Frame.SAME_FRAME_EXTENDED) { + context.currentFrameType = Opcodes.F_SAME; + context.currentFrameStackCount = 0; + } else if (frameType < Frame.FULL_FRAME) { + int local = expand ? context.currentFrameLocalCount : 0; + for (int k = frameType - Frame.SAME_FRAME_EXTENDED; k > 0; k--) { + currentOffset = + readVerificationTypeInfo( + currentOffset, context.currentFrameLocalTypes, local++, charBuffer, labels); + } + context.currentFrameType = Opcodes.F_APPEND; + context.currentFrameLocalCountDelta = frameType - Frame.SAME_FRAME_EXTENDED; + context.currentFrameLocalCount += context.currentFrameLocalCountDelta; + context.currentFrameStackCount = 0; + } else { + final int numberOfLocals = readUnsignedShort(currentOffset); + currentOffset += 2; + context.currentFrameType = Opcodes.F_FULL; + context.currentFrameLocalCountDelta = numberOfLocals; + context.currentFrameLocalCount = numberOfLocals; + for (int local = 0; local < numberOfLocals; ++local) { + currentOffset = + readVerificationTypeInfo( + currentOffset, context.currentFrameLocalTypes, local, charBuffer, labels); + } + final int numberOfStackItems = readUnsignedShort(currentOffset); + currentOffset += 2; + context.currentFrameStackCount = numberOfStackItems; + for (int stack = 0; stack < numberOfStackItems; ++stack) { + currentOffset = + readVerificationTypeInfo( + currentOffset, context.currentFrameStackTypes, stack, charBuffer, labels); + } + } + } else { + throw new IllegalArgumentException(); + } + context.currentFrameOffset += offsetDelta + 1; + createLabel(context.currentFrameOffset, labels); + return currentOffset; + } + + /** + * Reads a JVMS 'verification_type_info' structure and stores it at the given index in the given + * array. + * + * @param verificationTypeInfoOffset the start offset of the 'verification_type_info' structure to + * read. + * @param frame the array where the parsed type must be stored. + * @param index the index in 'frame' where the parsed type must be stored. + * @param charBuffer the buffer used to read strings in the constant pool. + * @param labels the labels of the method currently being parsed, indexed by their offset. If + * the + * parsed type is an ITEM_Uninitialized, a new label for the corresponding NEW + * instruction is + * stored in this array if it does not already exist. + * @return the end offset of the JVMS 'verification_type_info' structure. + */ + private int readVerificationTypeInfo( + final int verificationTypeInfoOffset, + final Object[] frame, + final int index, + final char[] charBuffer, + final Label[] labels) { + int currentOffset = verificationTypeInfoOffset; + int tag = classFileBuffer[currentOffset++] & 0xFF; + switch (tag) { + case Frame.ITEM_TOP: + frame[index] = Opcodes.TOP; + break; + case Frame.ITEM_INTEGER: + frame[index] = Opcodes.INTEGER; + break; + case Frame.ITEM_FLOAT: + frame[index] = Opcodes.FLOAT; + break; + case Frame.ITEM_DOUBLE: + frame[index] = Opcodes.DOUBLE; + break; + case Frame.ITEM_LONG: + frame[index] = Opcodes.LONG; + break; + case Frame.ITEM_NULL: + frame[index] = Opcodes.NULL; + break; + case Frame.ITEM_UNINITIALIZED_THIS: + frame[index] = Opcodes.UNINITIALIZED_THIS; + break; + case Frame.ITEM_OBJECT: + frame[index] = readClass(currentOffset, charBuffer); + currentOffset += 2; + break; + case Frame.ITEM_UNINITIALIZED: + frame[index] = createLabel(readUnsignedShort(currentOffset), labels); + currentOffset += 2; + break; + default: + throw new IllegalArgumentException(); + } + return currentOffset; + } + + // ---------------------------------------------------------------------------------------------- + // Methods to parse attributes + // ---------------------------------------------------------------------------------------------- + + /** + * Returns the offset in {@link #classFileBuffer} of the first ClassFile's 'attributes' array + * field entry. + * + * @return the offset in {@link #classFileBuffer} of the first ClassFile's 'attributes' array + * field entry. + */ + final int getFirstAttributeOffset() { + // Skip the access_flags, this_class, super_class, and interfaces_count fields (using 2 bytes + // each), as well as the interfaces array field (2 bytes per interface). + int currentOffset = header + 8 + readUnsignedShort(header + 6) * 2; + + // Read the fields_count field. + int fieldsCount = readUnsignedShort(currentOffset); currentOffset += 2; - break; - case Frame.ITEM_UNINITIALIZED: - frame[index] = createLabel(readUnsignedShort(currentOffset), labels); + // Skip the 'fields' array field. + while (fieldsCount-- > 0) { + // Invariant: currentOffset is the offset of a field_info structure. + // Skip the access_flags, name_index and descriptor_index fields (2 bytes each), and read the + // attributes_count field. + int attributesCount = readUnsignedShort(currentOffset + 6); + currentOffset += 8; + // Skip the 'attributes' array field. + while (attributesCount-- > 0) { + // Invariant: currentOffset is the offset of an attribute_info structure. + // Read the attribute_length field (2 bytes after the start of the attribute_info) and skip + // this many bytes, plus 6 for the attribute_name_index and attribute_length fields + // (yielding the total size of the attribute_info structure). + currentOffset += 6 + readInt(currentOffset + 2); + } + } + + // Skip the methods_count and 'methods' fields, using the same method as above. + int methodsCount = readUnsignedShort(currentOffset); currentOffset += 2; - break; - default: + while (methodsCount-- > 0) { + int attributesCount = readUnsignedShort(currentOffset + 6); + currentOffset += 8; + while (attributesCount-- > 0) { + currentOffset += 6 + readInt(currentOffset + 2); + } + } + + // Skip the ClassFile's attributes_count field. + return currentOffset + 2; + } + + /** + * Reads the BootstrapMethods attribute to compute the offset of each bootstrap method. + * + * @param maxStringLength a conservative estimate of the maximum length of the strings contained + * in the constant pool of the class. + * @return the offsets of the bootstrap methods. + */ + private int[] readBootstrapMethodsAttribute(final int maxStringLength) { + char[] charBuffer = new char[maxStringLength]; + int currentAttributeOffset = getFirstAttributeOffset(); + int[] currentBootstrapMethodOffsets = null; + for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) { + // Read the attribute_info's attribute_name and attribute_length fields. + String attributeName = readUTF8(currentAttributeOffset, charBuffer); + int attributeLength = readInt(currentAttributeOffset + 2); + currentAttributeOffset += 6; + if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) { + // Read the num_bootstrap_methods field and create an array of this size. + currentBootstrapMethodOffsets = new int[readUnsignedShort(currentAttributeOffset)]; + // Compute and store the offset of each 'bootstrap_methods' array field entry. + int currentBootstrapMethodOffset = currentAttributeOffset + 2; + for (int j = 0; j < currentBootstrapMethodOffsets.length; ++j) { + currentBootstrapMethodOffsets[j] = currentBootstrapMethodOffset; + // Skip the bootstrap_method_ref and num_bootstrap_arguments fields (2 bytes each), + // as well as the bootstrap_arguments array field (of size num_bootstrap_arguments * 2). + currentBootstrapMethodOffset += + 4 + readUnsignedShort(currentBootstrapMethodOffset + 2) * 2; + } + return currentBootstrapMethodOffsets; + } + currentAttributeOffset += attributeLength; + } throw new IllegalArgumentException(); } - return currentOffset; - } - // ---------------------------------------------------------------------------------------------- - // Methods to parse attributes - // ---------------------------------------------------------------------------------------------- - - /** - * Returns the offset in {@link #classFileBuffer} of the first ClassFile's 'attributes' array - * field entry. - * - * @return the offset in {@link #classFileBuffer} of the first ClassFile's 'attributes' array - * field entry. - */ - final int getFirstAttributeOffset() { - // Skip the access_flags, this_class, super_class, and interfaces_count fields (using 2 bytes - // each), as well as the interfaces array field (2 bytes per interface). - int currentOffset = header + 8 + readUnsignedShort(header + 6) * 2; - - // Read the fields_count field. - int fieldsCount = readUnsignedShort(currentOffset); - currentOffset += 2; - // Skip the 'fields' array field. - while (fieldsCount-- > 0) { - // Invariant: currentOffset is the offset of a field_info structure. - // Skip the access_flags, name_index and descriptor_index fields (2 bytes each), and read the - // attributes_count field. - int attributesCount = readUnsignedShort(currentOffset + 6); - currentOffset += 8; - // Skip the 'attributes' array field. - while (attributesCount-- > 0) { - // Invariant: currentOffset is the offset of an attribute_info structure. - // Read the attribute_length field (2 bytes after the start of the attribute_info) and skip - // this many bytes, plus 6 for the attribute_name_index and attribute_length fields - // (yielding the total size of the attribute_info structure). - currentOffset += 6 + readInt(currentOffset + 2); - } - } - - // Skip the methods_count and 'methods' fields, using the same method as above. - int methodsCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (methodsCount-- > 0) { - int attributesCount = readUnsignedShort(currentOffset + 6); - currentOffset += 8; - while (attributesCount-- > 0) { - currentOffset += 6 + readInt(currentOffset + 2); - } - } - - // Skip the ClassFile's attributes_count field. - return currentOffset + 2; - } - - /** - * Reads the BootstrapMethods attribute to compute the offset of each bootstrap method. - * - * @param maxStringLength a conservative estimate of the maximum length of the strings contained - * in the constant pool of the class. - * @return the offsets of the bootstrap methods. - */ - private int[] readBootstrapMethodsAttribute(final int maxStringLength) { - char[] charBuffer = new char[maxStringLength]; - int currentAttributeOffset = getFirstAttributeOffset(); - int[] currentBootstrapMethodOffsets = null; - for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) { - // Read the attribute_info's attribute_name and attribute_length fields. - String attributeName = readUTF8(currentAttributeOffset, charBuffer); - int attributeLength = readInt(currentAttributeOffset + 2); - currentAttributeOffset += 6; - if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) { - // Read the num_bootstrap_methods field and create an array of this size. - currentBootstrapMethodOffsets = new int[readUnsignedShort(currentAttributeOffset)]; - // Compute and store the offset of each 'bootstrap_methods' array field entry. - int currentBootstrapMethodOffset = currentAttributeOffset + 2; - for (int j = 0; j < currentBootstrapMethodOffsets.length; ++j) { - currentBootstrapMethodOffsets[j] = currentBootstrapMethodOffset; - // Skip the bootstrap_method_ref and num_bootstrap_arguments fields (2 bytes each), - // as well as the bootstrap_arguments array field (of size num_bootstrap_arguments * 2). - currentBootstrapMethodOffset += - 4 + readUnsignedShort(currentBootstrapMethodOffset + 2) * 2; + /** + * Reads a non standard JVMS 'attribute' structure in {@link #classFileBuffer}. + * + * @param attributePrototypes prototypes of the attributes that must be parsed during the visit of + * the class. Any attribute whose type is not equal to the type of one the prototypes + * will not + * be parsed: its byte array value will be passed unchanged to the ClassWriter. + * @param type the type of the attribute. + * @param offset the start offset of the JVMS 'attribute' structure in {@link #classFileBuffer}. + * The 6 attribute header bytes (attribute_name_index and attribute_length) are not + * taken into + * account here. + * @param length the length of the attribute's content (excluding the 6 attribute header bytes). + * @param charBuffer the buffer to be used to read strings in the constant pool. + * @param codeAttributeOffset the start offset of the enclosing Code attribute in {@link + * #classFileBuffer}, or -1 if the attribute to be read is not a code attribute. The 6 + * attribute header bytes (attribute_name_index and attribute_length) are not taken into + * account here. + * @param labels the labels of the method's code, or {@literal null} if the attribute to be read + * is not a code attribute. + * @return the attribute that has been read. + */ + private Attribute readAttribute( + final Attribute[] attributePrototypes, + final String type, + final int offset, + final int length, + final char[] charBuffer, + final int codeAttributeOffset, + final Label[] labels) { + for (Attribute attributePrototype : attributePrototypes) { + if (attributePrototype.type.equals(type)) { + return attributePrototype.read( + this, offset, length, charBuffer, codeAttributeOffset, labels); + } } - return currentBootstrapMethodOffsets; - } - currentAttributeOffset += attributeLength; + return new Attribute(type).read(this, offset, length, null, -1, null); } - throw new IllegalArgumentException(); - } - /** - * Reads a non standard JVMS 'attribute' structure in {@link #classFileBuffer}. - * - * @param attributePrototypes prototypes of the attributes that must be parsed during the visit of - * the class. Any attribute whose type is not equal to the type of one the prototypes will not - * be parsed: its byte array value will be passed unchanged to the ClassWriter. - * @param type the type of the attribute. - * @param offset the start offset of the JVMS 'attribute' structure in {@link #classFileBuffer}. - * The 6 attribute header bytes (attribute_name_index and attribute_length) are not taken into - * account here. - * @param length the length of the attribute's content (excluding the 6 attribute header bytes). - * @param charBuffer the buffer to be used to read strings in the constant pool. - * @param codeAttributeOffset the start offset of the enclosing Code attribute in {@link - * #classFileBuffer}, or -1 if the attribute to be read is not a code attribute. The 6 - * attribute header bytes (attribute_name_index and attribute_length) are not taken into - * account here. - * @param labels the labels of the method's code, or {@literal null} if the attribute to be read - * is not a code attribute. - * @return the attribute that has been read. - */ - private Attribute readAttribute( - final Attribute[] attributePrototypes, - final String type, - final int offset, - final int length, - final char[] charBuffer, - final int codeAttributeOffset, - final Label[] labels) { - for (Attribute attributePrototype : attributePrototypes) { - if (attributePrototype.type.equals(type)) { - return attributePrototype.read( - this, offset, length, charBuffer, codeAttributeOffset, labels); - } + // ----------------------------------------------------------------------------------------------- + // Utility methods: low level parsing + // ----------------------------------------------------------------------------------------------- + + /** + * Returns the number of entries in the class's constant pool table. + * + * @return the number of entries in the class's constant pool table. + */ + public int getItemCount() { + return cpInfoOffsets.length; } - return new Attribute(type).read(this, offset, length, null, -1, null); - } - // ----------------------------------------------------------------------------------------------- - // Utility methods: low level parsing - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the number of entries in the class's constant pool table. - * - * @return the number of entries in the class's constant pool table. - */ - public int getItemCount() { - return cpInfoOffsets.length; - } - - /** - * Returns the start offset in this {@link ClassReader} of a JVMS 'cp_info' structure (i.e. a - * constant pool entry), plus one. This method is intended for {@link Attribute} sub classes, - * and is normally not needed by class generators or adapters. - * - * @param constantPoolEntryIndex the index a constant pool entry in the class's constant pool - * table. - * @return the start offset in this {@link ClassReader} of the corresponding JVMS 'cp_info' - * structure, plus one. - */ - public int getItem(final int constantPoolEntryIndex) { - return cpInfoOffsets[constantPoolEntryIndex]; - } - - /** - * Returns a conservative estimate of the maximum length of the strings contained in the class's - * constant pool table. - * - * @return a conservative estimate of the maximum length of the strings contained in the class's - * constant pool table. - */ - public int getMaxStringLength() { - return maxStringLength; - } - - /** - * Reads a byte value in this {@link ClassReader}. This method is intended for {@link - * Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param offset the start offset of the value to be read in this {@link ClassReader}. - * @return the read value. - */ - public int readByte(final int offset) { - return classFileBuffer[offset] & 0xFF; - } - - /** - * Reads an unsigned short value in this {@link ClassReader}. This method is intended for - * {@link Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param offset the start index of the value to be read in this {@link ClassReader}. - * @return the read value. - */ - public int readUnsignedShort(final int offset) { - byte[] classBuffer = classFileBuffer; - return ((classBuffer[offset] & 0xFF) << 8) | (classBuffer[offset + 1] & 0xFF); - } - - /** - * Reads a signed short value in this {@link ClassReader}. This method is intended for {@link - * Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param offset the start offset of the value to be read in this {@link ClassReader}. - * @return the read value. - */ - public short readShort(final int offset) { - byte[] classBuffer = classFileBuffer; - return (short) (((classBuffer[offset] & 0xFF) << 8) | (classBuffer[offset + 1] & 0xFF)); - } - - /** - * Reads a signed int value in this {@link ClassReader}. This method is intended for {@link - * Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param offset the start offset of the value to be read in this {@link ClassReader}. - * @return the read value. - */ - public int readInt(final int offset) { - byte[] classBuffer = classFileBuffer; - return ((classBuffer[offset] & 0xFF) << 24) - | ((classBuffer[offset + 1] & 0xFF) << 16) - | ((classBuffer[offset + 2] & 0xFF) << 8) - | (classBuffer[offset + 3] & 0xFF); - } - - /** - * Reads a signed long value in this {@link ClassReader}. This method is intended for {@link - * Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param offset the start offset of the value to be read in this {@link ClassReader}. - * @return the read value. - */ - public long readLong(final int offset) { - long l1 = readInt(offset); - long l0 = readInt(offset + 4) & 0xFFFFFFFFL; - return (l1 << 32) | l0; - } - - /** - * Reads a CONSTANT_Utf8 constant pool entry in this {@link ClassReader}. This method is - * intended for {@link Attribute} sub classes, and is normally not needed by class generators or - * adapters. - * - * @param offset the start offset of an unsigned short value in this {@link ClassReader}, whose - * value is the index of a CONSTANT_Utf8 entry in the class's constant pool table. - * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified CONSTANT_Utf8 entry. - */ - // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility). - public String readUTF8(final int offset, final char[] charBuffer) { - int constantPoolEntryIndex = readUnsignedShort(offset); - if (offset == 0 || constantPoolEntryIndex == 0) { - return null; + /** + * Returns the start offset in this {@link ClassReader} of a JVMS 'cp_info' structure (i.e. a + * constant pool entry), plus one. This method is intended for {@link Attribute} sub classes, + * and is normally not needed by class generators or adapters. + * + * @param constantPoolEntryIndex the index a constant pool entry in the class's constant pool + * table. + * @return the start offset in this {@link ClassReader} of the corresponding JVMS 'cp_info' + * structure, plus one. + */ + public int getItem(final int constantPoolEntryIndex) { + return cpInfoOffsets[constantPoolEntryIndex]; } - return readUtf(constantPoolEntryIndex, charBuffer); - } - /** - * Reads a CONSTANT_Utf8 constant pool entry in {@link #classFileBuffer}. - * - * @param constantPoolEntryIndex the index of a CONSTANT_Utf8 entry in the class's constant pool - * table. - * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified CONSTANT_Utf8 entry. - */ - final String readUtf(final int constantPoolEntryIndex, final char[] charBuffer) { - String value = constantUtf8Values[constantPoolEntryIndex]; - if (value != null) { - return value; + /** + * Returns a conservative estimate of the maximum length of the strings contained in the class's + * constant pool table. + * + * @return a conservative estimate of the maximum length of the strings contained in the class's + * constant pool table. + */ + public int getMaxStringLength() { + return maxStringLength; } - int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; - return constantUtf8Values[constantPoolEntryIndex] = - readUtf(cpInfoOffset + 2, readUnsignedShort(cpInfoOffset), charBuffer); - } - /** - * Reads an UTF8 string in {@link #classFileBuffer}. - * - * @param utfOffset the start offset of the UTF8 string to be read. - * @param utfLength the length of the UTF8 string to be read. - * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified UTF8 string. - */ - private String readUtf(final int utfOffset, final int utfLength, final char[] charBuffer) { - int currentOffset = utfOffset; - int endOffset = currentOffset + utfLength; - int strLength = 0; - byte[] classBuffer = classFileBuffer; - while (currentOffset < endOffset) { - int currentByte = classBuffer[currentOffset++]; - if ((currentByte & 0x80) == 0) { - charBuffer[strLength++] = (char) (currentByte & 0x7F); - } else if ((currentByte & 0xE0) == 0xC0) { - charBuffer[strLength++] = - (char) (((currentByte & 0x1F) << 6) + (classBuffer[currentOffset++] & 0x3F)); - } else { - charBuffer[strLength++] = - (char) - (((currentByte & 0xF) << 12) - + ((classBuffer[currentOffset++] & 0x3F) << 6) - + (classBuffer[currentOffset++] & 0x3F)); - } + /** + * Reads a byte value in this {@link ClassReader}. This method is intended for {@link + * Attribute} sub classes, and is normally not needed by class generators or adapters. + * + * @param offset the start offset of the value to be read in this {@link ClassReader}. + * @return the read value. + */ + public int readByte(final int offset) { + return classFileBuffer[offset] & 0xFF; } - return new String(charBuffer, 0, strLength); - } - /** - * Reads a CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, CONSTANT_Module or - * CONSTANT_Package constant pool entry in {@link #classFileBuffer}. This method is intended - * for {@link Attribute} sub classes, and is normally not needed by class generators or - * adapters. - * - * @param offset the start offset of an unsigned short value in {@link #classFileBuffer}, whose - * value is the index of a CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, - * CONSTANT_Module or CONSTANT_Package entry in class's constant pool table. - * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified constant pool entry. - */ - private String readStringish(final int offset, final char[] charBuffer) { - // Get the start offset of the cp_info structure (plus one), and read the CONSTANT_Utf8 entry - // designated by the first two bytes of this cp_info. - return readUTF8(cpInfoOffsets[readUnsignedShort(offset)], charBuffer); - } - - /** - * Reads a CONSTANT_Class constant pool entry in this {@link ClassReader}. This method is - * intended for {@link Attribute} sub classes, and is normally not needed by class generators or - * adapters. - * - * @param offset the start offset of an unsigned short value in this {@link ClassReader}, whose - * value is the index of a CONSTANT_Class entry in class's constant pool table. - * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified CONSTANT_Class entry. - */ - public String readClass(final int offset, final char[] charBuffer) { - return readStringish(offset, charBuffer); - } - - /** - * Reads a CONSTANT_Module constant pool entry in this {@link ClassReader}. This method is - * intended for {@link Attribute} sub classes, and is normally not needed by class generators or - * adapters. - * - * @param offset the start offset of an unsigned short value in this {@link ClassReader}, whose - * value is the index of a CONSTANT_Module entry in class's constant pool table. - * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified CONSTANT_Module entry. - */ - public String readModule(final int offset, final char[] charBuffer) { - return readStringish(offset, charBuffer); - } - - /** - * Reads a CONSTANT_Package constant pool entry in this {@link ClassReader}. This method is - * intended for {@link Attribute} sub classes, and is normally not needed by class generators or - * adapters. - * - * @param offset the start offset of an unsigned short value in this {@link ClassReader}, whose - * value is the index of a CONSTANT_Package entry in class's constant pool table. - * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified CONSTANT_Package entry. - */ - public String readPackage(final int offset, final char[] charBuffer) { - return readStringish(offset, charBuffer); - } - - /** - * Reads a CONSTANT_Dynamic constant pool entry in {@link #classFileBuffer}. - * - * @param constantPoolEntryIndex the index of a CONSTANT_Dynamic entry in the class's constant - * pool table. - * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the ConstantDynamic corresponding to the specified CONSTANT_Dynamic entry. - */ - private ConstantDynamic readConstantDynamic( - final int constantPoolEntryIndex, final char[] charBuffer) { - ConstantDynamic constantDynamic = constantDynamicValues[constantPoolEntryIndex]; - if (constantDynamic != null) { - return constantDynamic; + /** + * Reads an unsigned short value in this {@link ClassReader}. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class generators or adapters. + * + * @param offset the start index of the value to be read in this {@link ClassReader}. + * @return the read value. + */ + public int readUnsignedShort(final int offset) { + byte[] classBuffer = classFileBuffer; + return ((classBuffer[offset] & 0xFF) << 8) | (classBuffer[offset + 1] & 0xFF); } - int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; - int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)]; - String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); - String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); - int bootstrapMethodOffset = bootstrapMethodOffsets[readUnsignedShort(cpInfoOffset)]; - Handle handle = (Handle) readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); - Object[] bootstrapMethodArguments = new Object[readUnsignedShort(bootstrapMethodOffset + 2)]; - bootstrapMethodOffset += 4; - for (int i = 0; i < bootstrapMethodArguments.length; i++) { - bootstrapMethodArguments[i] = readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); - bootstrapMethodOffset += 2; - } - return constantDynamicValues[constantPoolEntryIndex] = - new ConstantDynamic(name, descriptor, handle, bootstrapMethodArguments); - } - /** - * Reads a numeric or string constant pool entry in this {@link ClassReader}. This method is - * intended for {@link Attribute} sub classes, and is normally not needed by class generators or - * adapters. - * - * @param constantPoolEntryIndex the index of a CONSTANT_Integer, CONSTANT_Float, CONSTANT_Long, - * CONSTANT_Double, CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, - * CONSTANT_MethodHandle or CONSTANT_Dynamic entry in the class's constant pool. - * @param charBuffer the buffer to be used to read strings. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, - * {@link Type}, {@link Handle} or {@link ConstantDynamic} corresponding to the specified - * constant pool entry. - */ - public Object readConst(final int constantPoolEntryIndex, final char[] charBuffer) { - int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; - switch (classFileBuffer[cpInfoOffset - 1]) { - case Symbol.CONSTANT_INTEGER_TAG: - return readInt(cpInfoOffset); - case Symbol.CONSTANT_FLOAT_TAG: - return Float.intBitsToFloat(readInt(cpInfoOffset)); - case Symbol.CONSTANT_LONG_TAG: - return readLong(cpInfoOffset); - case Symbol.CONSTANT_DOUBLE_TAG: - return Double.longBitsToDouble(readLong(cpInfoOffset)); - case Symbol.CONSTANT_CLASS_TAG: - return Type.getObjectType(readUTF8(cpInfoOffset, charBuffer)); - case Symbol.CONSTANT_STRING_TAG: - return readUTF8(cpInfoOffset, charBuffer); - case Symbol.CONSTANT_METHOD_TYPE_TAG: - return Type.getMethodType(readUTF8(cpInfoOffset, charBuffer)); - case Symbol.CONSTANT_METHOD_HANDLE_TAG: - int referenceKind = readByte(cpInfoOffset); - int referenceCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 1)]; - int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(referenceCpInfoOffset + 2)]; - String owner = readClass(referenceCpInfoOffset, charBuffer); + /** + * Reads a signed short value in this {@link ClassReader}. This method is intended for {@link + * Attribute} sub classes, and is normally not needed by class generators or adapters. + * + * @param offset the start offset of the value to be read in this {@link ClassReader}. + * @return the read value. + */ + public short readShort(final int offset) { + byte[] classBuffer = classFileBuffer; + return (short) (((classBuffer[offset] & 0xFF) << 8) | (classBuffer[offset + 1] & 0xFF)); + } + + /** + * Reads a signed int value in this {@link ClassReader}. This method is intended for {@link + * Attribute} sub classes, and is normally not needed by class generators or adapters. + * + * @param offset the start offset of the value to be read in this {@link ClassReader}. + * @return the read value. + */ + public int readInt(final int offset) { + byte[] classBuffer = classFileBuffer; + return ((classBuffer[offset] & 0xFF) << 24) + | ((classBuffer[offset + 1] & 0xFF) << 16) + | ((classBuffer[offset + 2] & 0xFF) << 8) + | (classBuffer[offset + 3] & 0xFF); + } + + /** + * Reads a signed long value in this {@link ClassReader}. This method is intended for {@link + * Attribute} sub classes, and is normally not needed by class generators or adapters. + * + * @param offset the start offset of the value to be read in this {@link ClassReader}. + * @return the read value. + */ + public long readLong(final int offset) { + long l1 = readInt(offset); + long l0 = readInt(offset + 4) & 0xFFFFFFFFL; + return (l1 << 32) | l0; + } + + /** + * Reads a CONSTANT_Utf8 constant pool entry in this {@link ClassReader}. This method is + * intended for {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. + * + * @param offset the start offset of an unsigned short value in this {@link ClassReader}, whose + * value is the index of a CONSTANT_Utf8 entry in the class's constant pool table. + * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently + * large. It is not automatically resized. + * @return the String corresponding to the specified CONSTANT_Utf8 entry. + */ + // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility). + public String readUTF8(final int offset, final char[] charBuffer) { + int constantPoolEntryIndex = readUnsignedShort(offset); + if (offset == 0 || constantPoolEntryIndex == 0) { + return null; + } + return readUtf(constantPoolEntryIndex, charBuffer); + } + + /** + * Reads a CONSTANT_Utf8 constant pool entry in {@link #classFileBuffer}. + * + * @param constantPoolEntryIndex the index of a CONSTANT_Utf8 entry in the class's constant pool + * table. + * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently + * large. It is not automatically resized. + * @return the String corresponding to the specified CONSTANT_Utf8 entry. + */ + final String readUtf(final int constantPoolEntryIndex, final char[] charBuffer) { + String value = constantUtf8Values[constantPoolEntryIndex]; + if (value != null) { + return value; + } + int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; + return constantUtf8Values[constantPoolEntryIndex] = + readUtf(cpInfoOffset + 2, readUnsignedShort(cpInfoOffset), charBuffer); + } + + /** + * Reads an UTF8 string in {@link #classFileBuffer}. + * + * @param utfOffset the start offset of the UTF8 string to be read. + * @param utfLength the length of the UTF8 string to be read. + * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently + * large. It is not automatically resized. + * @return the String corresponding to the specified UTF8 string. + */ + private String readUtf(final int utfOffset, final int utfLength, final char[] charBuffer) { + int currentOffset = utfOffset; + int endOffset = currentOffset + utfLength; + int strLength = 0; + byte[] classBuffer = classFileBuffer; + while (currentOffset < endOffset) { + int currentByte = classBuffer[currentOffset++]; + if ((currentByte & 0x80) == 0) { + charBuffer[strLength++] = (char) (currentByte & 0x7F); + } else if ((currentByte & 0xE0) == 0xC0) { + charBuffer[strLength++] = + (char) (((currentByte & 0x1F) << 6) + (classBuffer[currentOffset++] & 0x3F)); + } else { + charBuffer[strLength++] = + (char) + (((currentByte & 0xF) << 12) + + ((classBuffer[currentOffset++] & 0x3F) << 6) + + (classBuffer[currentOffset++] & 0x3F)); + } + } + return new String(charBuffer, 0, strLength); + } + + /** + * Reads a CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, CONSTANT_Module or + * CONSTANT_Package constant pool entry in {@link #classFileBuffer}. This method is intended + * for {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. + * + * @param offset the start offset of an unsigned short value in {@link #classFileBuffer}, whose + * value is the index of a CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, + * CONSTANT_Module or CONSTANT_Package entry in class's constant pool table. + * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently + * large. It is not automatically resized. + * @return the String corresponding to the specified constant pool entry. + */ + private String readStringish(final int offset, final char[] charBuffer) { + // Get the start offset of the cp_info structure (plus one), and read the CONSTANT_Utf8 entry + // designated by the first two bytes of this cp_info. + return readUTF8(cpInfoOffsets[readUnsignedShort(offset)], charBuffer); + } + + /** + * Reads a CONSTANT_Class constant pool entry in this {@link ClassReader}. This method is + * intended for {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. + * + * @param offset the start offset of an unsigned short value in this {@link ClassReader}, whose + * value is the index of a CONSTANT_Class entry in class's constant pool table. + * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently + * large. It is not automatically resized. + * @return the String corresponding to the specified CONSTANT_Class entry. + */ + public String readClass(final int offset, final char[] charBuffer) { + return readStringish(offset, charBuffer); + } + + /** + * Reads a CONSTANT_Module constant pool entry in this {@link ClassReader}. This method is + * intended for {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. + * + * @param offset the start offset of an unsigned short value in this {@link ClassReader}, whose + * value is the index of a CONSTANT_Module entry in class's constant pool table. + * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently + * large. It is not automatically resized. + * @return the String corresponding to the specified CONSTANT_Module entry. + */ + public String readModule(final int offset, final char[] charBuffer) { + return readStringish(offset, charBuffer); + } + + /** + * Reads a CONSTANT_Package constant pool entry in this {@link ClassReader}. This method is + * intended for {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. + * + * @param offset the start offset of an unsigned short value in this {@link ClassReader}, whose + * value is the index of a CONSTANT_Package entry in class's constant pool table. + * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently + * large. It is not automatically resized. + * @return the String corresponding to the specified CONSTANT_Package entry. + */ + public String readPackage(final int offset, final char[] charBuffer) { + return readStringish(offset, charBuffer); + } + + /** + * Reads a CONSTANT_Dynamic constant pool entry in {@link #classFileBuffer}. + * + * @param constantPoolEntryIndex the index of a CONSTANT_Dynamic entry in the class's constant + * pool table. + * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently + * large. It is not automatically resized. + * @return the ConstantDynamic corresponding to the specified CONSTANT_Dynamic entry. + */ + private ConstantDynamic readConstantDynamic( + final int constantPoolEntryIndex, final char[] charBuffer) { + ConstantDynamic constantDynamic = constantDynamicValues[constantPoolEntryIndex]; + if (constantDynamic != null) { + return constantDynamic; + } + int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; + int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)]; String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); - boolean isInterface = - classFileBuffer[referenceCpInfoOffset - 1] == Symbol.CONSTANT_INTERFACE_METHODREF_TAG; - return new Handle(referenceKind, owner, name, descriptor, isInterface); - case Symbol.CONSTANT_DYNAMIC_TAG: - return readConstantDynamic(constantPoolEntryIndex, charBuffer); - default: - throw new IllegalArgumentException(); + int bootstrapMethodOffset = bootstrapMethodOffsets[readUnsignedShort(cpInfoOffset)]; + Handle handle = (Handle) readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); + Object[] bootstrapMethodArguments = new Object[readUnsignedShort(bootstrapMethodOffset + 2)]; + bootstrapMethodOffset += 4; + for (int i = 0; i < bootstrapMethodArguments.length; i++) { + bootstrapMethodArguments[i] = readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); + bootstrapMethodOffset += 2; + } + return constantDynamicValues[constantPoolEntryIndex] = + new ConstantDynamic(name, descriptor, handle, bootstrapMethodArguments); + } + + /** + * Reads a numeric or string constant pool entry in this {@link ClassReader}. This method is + * intended for {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. + * + * @param constantPoolEntryIndex the index of a CONSTANT_Integer, CONSTANT_Float, CONSTANT_Long, + * CONSTANT_Double, CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, + * CONSTANT_MethodHandle or CONSTANT_Dynamic entry in the class's constant pool. + * @param charBuffer the buffer to be used to read strings. This buffer must be sufficiently + * large. It is not automatically resized. + * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, + * {@link Type}, {@link Handle} or {@link ConstantDynamic} corresponding to the specified + * constant pool entry. + */ + public Object readConst(final int constantPoolEntryIndex, final char[] charBuffer) { + int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; + switch (classFileBuffer[cpInfoOffset - 1]) { + case Symbol.CONSTANT_INTEGER_TAG: + return readInt(cpInfoOffset); + case Symbol.CONSTANT_FLOAT_TAG: + return Float.intBitsToFloat(readInt(cpInfoOffset)); + case Symbol.CONSTANT_LONG_TAG: + return readLong(cpInfoOffset); + case Symbol.CONSTANT_DOUBLE_TAG: + return Double.longBitsToDouble(readLong(cpInfoOffset)); + case Symbol.CONSTANT_CLASS_TAG: + return Type.getObjectType(readUTF8(cpInfoOffset, charBuffer)); + case Symbol.CONSTANT_STRING_TAG: + return readUTF8(cpInfoOffset, charBuffer); + case Symbol.CONSTANT_METHOD_TYPE_TAG: + return Type.getMethodType(readUTF8(cpInfoOffset, charBuffer)); + case Symbol.CONSTANT_METHOD_HANDLE_TAG: + int referenceKind = readByte(cpInfoOffset); + int referenceCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 1)]; + int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(referenceCpInfoOffset + 2)]; + String owner = readClass(referenceCpInfoOffset, charBuffer); + String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); + String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); + boolean isInterface = + classFileBuffer[referenceCpInfoOffset - 1] == Symbol.CONSTANT_INTERFACE_METHODREF_TAG; + return new Handle(referenceKind, owner, name, descriptor, isInterface); + case Symbol.CONSTANT_DYNAMIC_TAG: + return readConstantDynamic(constantPoolEntryIndex, charBuffer); + default: + throw new IllegalArgumentException(); + } } - } } diff --git a/src/main/java/org/objectweb/asm/ClassWriter.java b/src/main/java/org/objectweb/asm/ClassWriter.java index 7bd6355c..e119babd 100644 --- a/src/main/java/org/objectweb/asm/ClassWriter.java +++ b/src/main/java/org/objectweb/asm/ClassWriter.java @@ -33,940 +33,970 @@ package org.objectweb.asm; * scratch", or with one or more {@link ClassReader} and adapter {@link ClassVisitor} to generate a * modified class from one or more existing Java classes. * - * @see JVMS 4 * @author Eric Bruneton + * @see JVMS 4 */ public class ClassWriter extends ClassVisitor { - /** - * A flag to automatically compute the maximum stack size and the maximum number of local - * variables of methods. If this flag is set, then the arguments of the {@link - * MethodVisitor#visitMaxs} method of the {@link MethodVisitor} returned by the {@link - * #visitMethod} method will be ignored, and computed automatically from the signature and the - * bytecode of each method. - * - *

Note: for classes whose version is {@link Opcodes#V1_7} of more, this option requires - * valid stack map frames. The maximum stack size is then computed from these frames, and from the - * bytecode instructions in between. If stack map frames are not present or must be recomputed, - * used {@link #COMPUTE_FRAMES} instead. - * - * @see #ClassWriter(int) - */ - public static final int COMPUTE_MAXS = 1; - - /** - * A flag to automatically compute the stack map frames of methods from scratch. If this flag is - * set, then the calls to the {@link MethodVisitor#visitFrame} method are ignored, and the stack - * map frames are recomputed from the methods bytecode. The arguments of the {@link - * MethodVisitor#visitMaxs} method are also ignored and recomputed from the bytecode. In other - * words, {@link #COMPUTE_FRAMES} implies {@link #COMPUTE_MAXS}. - * - * @see #ClassWriter(int) - */ - public static final int COMPUTE_FRAMES = 2; - - // Note: fields are ordered as in the ClassFile structure, and those related to attributes are - // ordered as in Section 4.7 of the JVMS. - - /** - * The minor_version and major_version fields of the JVMS ClassFile structure. minor_version is - * stored in the 16 most significant bits, and major_version in the 16 least significant bits. - */ - private int version; - - /** The symbol table for this class (contains the constant_pool and the BootstrapMethods). */ - private final SymbolTable symbolTable; - - /** - * The access_flags field of the JVMS ClassFile structure. This field can contain ASM specific - * access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the - * ClassFile structure. - */ - private int accessFlags; - - /** The this_class field of the JVMS ClassFile structure. */ - private int thisClass; - - /** The super_class field of the JVMS ClassFile structure. */ - private int superClass; - - /** The interface_count field of the JVMS ClassFile structure. */ - private int interfaceCount; - - /** The 'interfaces' array of the JVMS ClassFile structure. */ - private int[] interfaces; - - /** - * The fields of this class, stored in a linked list of {@link FieldWriter} linked via their - * {@link FieldWriter#fv} field. This field stores the first element of this list. - */ - private FieldWriter firstField; - - /** - * The fields of this class, stored in a linked list of {@link FieldWriter} linked via their - * {@link FieldWriter#fv} field. This field stores the last element of this list. - */ - private FieldWriter lastField; - - /** - * The methods of this class, stored in a linked list of {@link MethodWriter} linked via their - * {@link MethodWriter#mv} field. This field stores the first element of this list. - */ - private MethodWriter firstMethod; - - /** - * The methods of this class, stored in a linked list of {@link MethodWriter} linked via their - * {@link MethodWriter#mv} field. This field stores the last element of this list. - */ - private MethodWriter lastMethod; - - /** The number_of_classes field of the InnerClasses attribute, or 0. */ - private int numberOfInnerClasses; - - /** The 'classes' array of the InnerClasses attribute, or {@literal null}. */ - private ByteVector innerClasses; - - /** The class_index field of the EnclosingMethod attribute, or 0. */ - private int enclosingClassIndex; - - /** The method_index field of the EnclosingMethod attribute. */ - private int enclosingMethodIndex; - - /** The signature_index field of the Signature attribute, or 0. */ - private int signatureIndex; - - /** The source_file_index field of the SourceFile attribute, or 0. */ - private int sourceFileIndex; - - /** The debug_extension field of the SourceDebugExtension attribute, or {@literal null}. */ - private ByteVector debugExtension; - - /** - * The last runtime visible annotation of this class. The previous ones can be accessed with the - * {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. - */ - private AnnotationWriter lastRuntimeVisibleAnnotation; - - /** - * The last runtime invisible annotation of this class. The previous ones can be accessed with the - * {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. - */ - private AnnotationWriter lastRuntimeInvisibleAnnotation; - - /** - * The last runtime visible type annotation of this class. The previous ones can be accessed with - * the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. - */ - private AnnotationWriter lastRuntimeVisibleTypeAnnotation; - - /** - * The last runtime invisible type annotation of this class. The previous ones can be accessed - * with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. - */ - private AnnotationWriter lastRuntimeInvisibleTypeAnnotation; - - /** The Module attribute of this class, or {@literal null}. */ - private ModuleWriter moduleWriter; - - /** The host_class_index field of the NestHost attribute, or 0. */ - private int nestHostClassIndex; - - /** The number_of_classes field of the NestMembers attribute, or 0. */ - private int numberOfNestMemberClasses; - - /** The 'classes' array of the NestMembers attribute, or {@literal null}. */ - private ByteVector nestMemberClasses; - - /** - * The first non standard attribute of this class. The next ones can be accessed with the {@link - * Attribute#nextAttribute} field. May be {@literal null}. - * - *

WARNING: this list stores the attributes in the reverse order of their visit. - * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link - * #toByteArray} method writes the attributes in the order defined by this list, i.e. in the - * reverse order specified by the user. - */ - private Attribute firstAttribute; - - /** - * Indicates what must be automatically computed in {@link MethodWriter}. Must be one of {@link - * MethodWriter#COMPUTE_NOTHING}, {@link MethodWriter#COMPUTE_MAX_STACK_AND_LOCAL}, {@link - * MethodWriter#COMPUTE_INSERTED_FRAMES}, or {@link MethodWriter#COMPUTE_ALL_FRAMES}. - */ - private int compute; - - // ----------------------------------------------------------------------------------------------- - // Constructor - // ----------------------------------------------------------------------------------------------- - - /** - * Constructs a new {@link ClassWriter} object. - * - * @param flags option flags that can be used to modify the default behavior of this class. Must - * be zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}. - */ - public ClassWriter(final int flags) { - this(null, flags); - } - - /** - * Constructs a new {@link ClassWriter} object and enables optimizations for "mostly add" bytecode - * transformations. These optimizations are the following: - * - *

- * - * @param classReader the {@link ClassReader} used to read the original class. It will be used to - * copy the entire constant pool and bootstrap methods from the original class and also to - * copy other fragments of original bytecode where applicable. - * @param flags option flags that can be used to modify the default behavior of this class.Must be - * zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}. These option flags do - * not affect methods that are copied as is in the new class. This means that neither the - * maximum stack size nor the stack frames will be computed for these methods. - */ - public ClassWriter(final ClassReader classReader, final int flags) { - super(Opcodes.ASM7); - symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader); - if ((flags & COMPUTE_FRAMES) != 0) { - this.compute = MethodWriter.COMPUTE_ALL_FRAMES; - } else if ((flags & COMPUTE_MAXS) != 0) { - this.compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL; - } else { - this.compute = MethodWriter.COMPUTE_NOTHING; - } - } - - // ----------------------------------------------------------------------------------------------- - // Implementation of the ClassVisitor abstract class - // ----------------------------------------------------------------------------------------------- - - @Override - public final void visit( - final int version, - final int access, - final String name, - final String signature, - final String superName, - final String[] interfaces) - { - this.version = version; - - //replace all pre jre minor versions to one that's outside of the old format - if((version & 0xFFFF) == 45 && (version >>> 16) <= 2) - { - this.version = (3 << 16) | 45; - } - this.accessFlags = access; - this.thisClass = symbolTable.setMajorVersionAndClassName(this.version & 0xFFFF, name); - if (signature != null) { - this.signatureIndex = symbolTable.addConstantUtf8(signature); - } - this.superClass = superName == null ? 0 : symbolTable.addConstantClass(superName).index; - if (interfaces != null && interfaces.length > 0) { - interfaceCount = interfaces.length; - this.interfaces = new int[interfaceCount]; - for (int i = 0; i < interfaceCount; ++i) { - this.interfaces[i] = symbolTable.addConstantClass(interfaces[i]).index; - } - } - if (compute == MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL && (this.version & 0xFFFF) >= Opcodes.V1_7) { - compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES; - } - } - - @Override - public final void visitSource(final String file, final String debug) { - if (file != null) { - sourceFileIndex = symbolTable.addConstantUtf8(file); - } - if (debug != null) { - debugExtension = new ByteVector().encodeUtf8(debug, 0, Integer.MAX_VALUE); - } - } - - @Override - public final ModuleVisitor visitModule( - final String name, final int access, final String version) { - return moduleWriter = - new ModuleWriter( - symbolTable, - symbolTable.addConstantModule(name).index, - access, - version == null ? 0 : symbolTable.addConstantUtf8(version)); - } - - @Override - public void visitNestHost(final String nestHost) { - nestHostClassIndex = symbolTable.addConstantClass(nestHost).index; - } - - @Override - public final void visitOuterClass( - final String owner, final String name, final String descriptor) { - enclosingClassIndex = symbolTable.addConstantClass(owner).index; - if (name != null && descriptor != null) { - enclosingMethodIndex = symbolTable.addConstantNameAndType(name, descriptor); - } - } - - @Override - public final AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { - if (visible) { - return lastRuntimeVisibleAnnotation = - AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation); - } else { - return lastRuntimeInvisibleAnnotation = - AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation); - } - } - - @Override - public final AnnotationVisitor visitTypeAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - if (visible) { - return lastRuntimeVisibleTypeAnnotation = - AnnotationWriter.create( - symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation); - } else { - return lastRuntimeInvisibleTypeAnnotation = - AnnotationWriter.create( - symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation); - } - } - - @Override - public final void visitAttribute(final Attribute attribute) { - // Store the attributes in the reverse order of their visit by this method. - attribute.nextAttribute = firstAttribute; - firstAttribute = attribute; - } - - @Override - public void visitNestMember(final String nestMember) { - if (nestMemberClasses == null) { - nestMemberClasses = new ByteVector(); - } - ++numberOfNestMemberClasses; - nestMemberClasses.putShort(symbolTable.addConstantClass(nestMember).index); - } - - @Override - public final void visitInnerClass( - final String name, final String outerName, final String innerName, final int access) { - if (innerClasses == null) { - innerClasses = new ByteVector(); - } - // Section 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the constant_pool table - // which represents a class or interface C that is not a package member must have exactly one - // corresponding entry in the classes array". To avoid duplicates we keep track in the info - // field of the Symbol of each CONSTANT_Class_info entry C whether an inner class entry has - // already been added for C. If so, we store the index of this inner class entry (plus one) in - // the info field. This trick allows duplicate detection in O(1) time. - Symbol nameSymbol = symbolTable.addConstantClass(name); - if (nameSymbol.info == 0) { - ++numberOfInnerClasses; - innerClasses.putShort(nameSymbol.index); - innerClasses.putShort(outerName == null ? 0 : symbolTable.addConstantClass(outerName).index); - innerClasses.putShort(innerName == null ? 0 : symbolTable.addConstantUtf8(innerName)); - innerClasses.putShort(access); - nameSymbol.info = numberOfInnerClasses; - } - // Else, compare the inner classes entry nameSymbol.info - 1 with the arguments of this method - // and throw an exception if there is a difference? - } - - @Override - public final FieldVisitor visitField( - final int access, - final String name, - final String descriptor, - final String signature, - final Object value) { - FieldWriter fieldWriter = - new FieldWriter(symbolTable, access, name, descriptor, signature, value); - if (firstField == null) { - firstField = fieldWriter; - } else { - lastField.fv = fieldWriter; - } - return lastField = fieldWriter; - } - - @Override - public final MethodVisitor visitMethod( - final int access, - final String name, - final String descriptor, - final String signature, - final String[] exceptions) { - MethodWriter methodWriter = - new MethodWriter(symbolTable, access, name, descriptor, signature, exceptions, compute); - if (firstMethod == null) { - firstMethod = methodWriter; - } else { - lastMethod.mv = methodWriter; - } - return lastMethod = methodWriter; - } - - @Override - public final void visitEnd() { - // Nothing to do. - } - - // ----------------------------------------------------------------------------------------------- - // Other public methods - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the content of the class file that was built by this ClassWriter. - * - * @return the binary content of the JVMS ClassFile structure that was built by this ClassWriter. - * @throws ClassTooLargeException if the constant pool of the class is too large. - * @throws MethodTooLargeException if the Code attribute of a method is too large. - */ - public byte[] toByteArray() { - // First step: compute the size in bytes of the ClassFile structure. - // The magic field uses 4 bytes, 10 mandatory fields (minor_version, major_version, - // constant_pool_count, access_flags, this_class, super_class, interfaces_count, fields_count, - // methods_count and attributes_count) use 2 bytes each, and each interface uses 2 bytes too. - int size = 24 + 2 * interfaceCount; - int fieldsCount = 0; - FieldWriter fieldWriter = firstField; - while (fieldWriter != null) { - ++fieldsCount; - size += fieldWriter.computeFieldInfoSize(); - fieldWriter = (FieldWriter) fieldWriter.fv; - } - int methodsCount = 0; - MethodWriter methodWriter = firstMethod; - while (methodWriter != null) { - ++methodsCount; - size += methodWriter.computeMethodInfoSize(); - methodWriter = (MethodWriter) methodWriter.mv; - } - // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. - int attributesCount = 0; - if (innerClasses != null) { - ++attributesCount; - size += 8 + innerClasses.length; - symbolTable.addConstantUtf8(Constants.INNER_CLASSES); - } - if (enclosingClassIndex != 0) { - ++attributesCount; - size += 10; - symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD); - } - if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) { - ++attributesCount; - size += 6; - symbolTable.addConstantUtf8(Constants.SYNTHETIC); - } - if (signatureIndex != 0) { - ++attributesCount; - size += 8; - symbolTable.addConstantUtf8(Constants.SIGNATURE); - } - if (sourceFileIndex != 0) { - ++attributesCount; - size += 8; - symbolTable.addConstantUtf8(Constants.SOURCE_FILE); - } - if (debugExtension != null) { - ++attributesCount; - size += 6 + debugExtension.length; - symbolTable.addConstantUtf8(Constants.SOURCE_DEBUG_EXTENSION); - } - if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { - ++attributesCount; - size += 6; - symbolTable.addConstantUtf8(Constants.DEPRECATED); - } - if (lastRuntimeVisibleAnnotation != null) { - ++attributesCount; - size += - lastRuntimeVisibleAnnotation.computeAnnotationsSize( - Constants.RUNTIME_VISIBLE_ANNOTATIONS); - } - if (lastRuntimeInvisibleAnnotation != null) { - ++attributesCount; - size += - lastRuntimeInvisibleAnnotation.computeAnnotationsSize( - Constants.RUNTIME_INVISIBLE_ANNOTATIONS); - } - if (lastRuntimeVisibleTypeAnnotation != null) { - ++attributesCount; - size += - lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - } - if (lastRuntimeInvisibleTypeAnnotation != null) { - ++attributesCount; - size += - lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); - } - if (symbolTable.computeBootstrapMethodsSize() > 0) { - ++attributesCount; - size += symbolTable.computeBootstrapMethodsSize(); - } - if (moduleWriter != null) { - attributesCount += moduleWriter.getAttributeCount(); - size += moduleWriter.computeAttributesSize(); - } - if (nestHostClassIndex != 0) { - ++attributesCount; - size += 8; - symbolTable.addConstantUtf8(Constants.NEST_HOST); - } - if (nestMemberClasses != null) { - ++attributesCount; - size += 8 + nestMemberClasses.length; - symbolTable.addConstantUtf8(Constants.NEST_MEMBERS); - } - if (firstAttribute != null) { - attributesCount += firstAttribute.getAttributeCount(); - size += firstAttribute.computeAttributesSize(symbolTable); - } - // IMPORTANT: this must be the last part of the ClassFile size computation, because the previous - // statements can add attribute names to the constant pool, thereby changing its size! - size += symbolTable.getConstantPoolLength(); - int constantPoolCount = symbolTable.getConstantPoolCount(); - if (constantPoolCount > 0xFFFF) { - throw new ClassTooLargeException(symbolTable.getClassName(), constantPoolCount); - } - - // Second step: allocate a ByteVector of the correct size (in order to avoid any array copy in - // dynamic resizes) and fill it with the ClassFile content. - ByteVector result = new ByteVector(size); - result.putInt(0xCAFEBABE).putInt(version); - symbolTable.putConstantPool(result); - int mask = (version & 0xFFFF) < Opcodes.V1_5 ? Opcodes.ACC_SYNTHETIC : 0; - result.putShort(accessFlags & ~mask).putShort(thisClass).putShort(superClass); - result.putShort(interfaceCount); - for (int i = 0; i < interfaceCount; ++i) { - result.putShort(interfaces[i]); - } - result.putShort(fieldsCount); - fieldWriter = firstField; - while (fieldWriter != null) { - fieldWriter.putFieldInfo(result); - fieldWriter = (FieldWriter) fieldWriter.fv; - } - result.putShort(methodsCount); - boolean hasFrames = false; - boolean hasAsmInstructions = false; - methodWriter = firstMethod; - while (methodWriter != null) { - hasFrames |= methodWriter.hasFrames(); - hasAsmInstructions |= methodWriter.hasAsmInstructions(); - methodWriter.putMethodInfo(result); - methodWriter = (MethodWriter) methodWriter.mv; - } - // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. - result.putShort(attributesCount); - if (innerClasses != null) { - result - .putShort(symbolTable.addConstantUtf8(Constants.INNER_CLASSES)) - .putInt(innerClasses.length + 2) - .putShort(numberOfInnerClasses) - .putByteArray(innerClasses.data, 0, innerClasses.length); - } - if (enclosingClassIndex != 0) { - result - .putShort(symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD)) - .putInt(4) - .putShort(enclosingClassIndex) - .putShort(enclosingMethodIndex); - } - if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) { - result.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0); - } - if (signatureIndex != 0) { - result - .putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE)) - .putInt(2) - .putShort(signatureIndex); - } - if (sourceFileIndex != 0) { - result - .putShort(symbolTable.addConstantUtf8(Constants.SOURCE_FILE)) - .putInt(2) - .putShort(sourceFileIndex); - } - if (debugExtension != null) { - int length = debugExtension.length; - result - .putShort(symbolTable.addConstantUtf8(Constants.SOURCE_DEBUG_EXTENSION)) - .putInt(length) - .putByteArray(debugExtension.data, 0, length); - } - if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { - result.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0); - } - AnnotationWriter.putAnnotations( - symbolTable, - lastRuntimeVisibleAnnotation, - lastRuntimeInvisibleAnnotation, - lastRuntimeVisibleTypeAnnotation, - lastRuntimeInvisibleTypeAnnotation, - result); - symbolTable.putBootstrapMethods(result); - if (moduleWriter != null) { - moduleWriter.putAttributes(result); - } - if (nestHostClassIndex != 0) { - result - .putShort(symbolTable.addConstantUtf8(Constants.NEST_HOST)) - .putInt(2) - .putShort(nestHostClassIndex); - } - if (nestMemberClasses != null) { - result - .putShort(symbolTable.addConstantUtf8(Constants.NEST_MEMBERS)) - .putInt(nestMemberClasses.length + 2) - .putShort(numberOfNestMemberClasses) - .putByteArray(nestMemberClasses.data, 0, nestMemberClasses.length); - } - if (firstAttribute != null) { - firstAttribute.putAttributes(symbolTable, result); - } - - // Third step: replace the ASM specific instructions, if any. - if (hasAsmInstructions) { - return replaceAsmInstructions(result.data, hasFrames); - } else { - return result.data; - } - } - - /** - * Returns the equivalent of the given class file, with the ASM specific instructions replaced - * with standard ones. This is done with a ClassReader -> ClassWriter round trip. - * - * @param classFile a class file containing ASM specific instructions, generated by this - * ClassWriter. - * @param hasFrames whether there is at least one stack map frames in 'classFile'. - * @return an equivalent of 'classFile', with the ASM specific instructions replaced with standard - * ones. - */ - private byte[] replaceAsmInstructions(final byte[] classFile, final boolean hasFrames) { - final Attribute[] attributes = getAttributePrototypes(); - firstField = null; - lastField = null; - firstMethod = null; - lastMethod = null; - lastRuntimeVisibleAnnotation = null; - lastRuntimeInvisibleAnnotation = null; - lastRuntimeVisibleTypeAnnotation = null; - lastRuntimeInvisibleTypeAnnotation = null; - moduleWriter = null; - nestHostClassIndex = 0; - numberOfNestMemberClasses = 0; - nestMemberClasses = null; - firstAttribute = null; - compute = hasFrames ? MethodWriter.COMPUTE_INSERTED_FRAMES : MethodWriter.COMPUTE_NOTHING; - new ClassReader(classFile, 0, /* checkClassVersion = */ false) - .accept( - this, - attributes, - (hasFrames ? ClassReader.EXPAND_FRAMES : 0) | ClassReader.EXPAND_ASM_INSNS); - return toByteArray(); - } - - /** - * Returns the prototypes of the attributes used by this class, its fields and its methods. - * - * @return the prototypes of the attributes used by this class, its fields and its methods. - */ - private Attribute[] getAttributePrototypes() { - Attribute.Set attributePrototypes = new Attribute.Set(); - attributePrototypes.addAttributes(firstAttribute); - FieldWriter fieldWriter = firstField; - while (fieldWriter != null) { - fieldWriter.collectAttributePrototypes(attributePrototypes); - fieldWriter = (FieldWriter) fieldWriter.fv; - } - MethodWriter methodWriter = firstMethod; - while (methodWriter != null) { - methodWriter.collectAttributePrototypes(attributePrototypes); - methodWriter = (MethodWriter) methodWriter.mv; - } - return attributePrototypes.toArray(); - } - - // ----------------------------------------------------------------------------------------------- - // Utility methods: constant pool management for Attribute sub classes - // ----------------------------------------------------------------------------------------------- - - /** - * Adds a number or string constant to the constant pool of the class being build. Does nothing if - * the constant pool already contains a similar item. This method is intended for {@link - * Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param value the value of the constant to be added to the constant pool. This parameter must be - * an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double} or a {@link String}. - * @return the index of a new or already existing constant item with the given value. - */ - public int newConst(final Object value) { - return symbolTable.addConstant(value).index; - } - - /** - * Adds an UTF8 string to the constant pool of the class being build. Does nothing if the constant - * pool already contains a similar item. This method is intended for {@link Attribute} sub - * classes, and is normally not needed by class generators or adapters. - * - * @param value the String value. - * @return the index of a new or already existing UTF8 item. - */ - // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility). - public int newUTF8(final String value) { - return symbolTable.addConstantUtf8(value); - } - - /** - * Adds a class reference to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param value the internal name of the class. - * @return the index of a new or already existing class reference item. - */ - public int newClass(final String value) { - return symbolTable.addConstantClass(value).index; - } - - /** - * Adds a method type reference to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param methodDescriptor method descriptor of the method type. - * @return the index of a new or already existing method type reference item. - */ - public int newMethodType(final String methodDescriptor) { - return symbolTable.addConstantMethodType(methodDescriptor).index; - } - - /** - * Adds a module reference to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param moduleName name of the module. - * @return the index of a new or already existing module reference item. - */ - public int newModule(final String moduleName) { - return symbolTable.addConstantModule(moduleName).index; - } - - /** - * Adds a package reference to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param packageName name of the package in its internal form. - * @return the index of a new or already existing module reference item. - */ - public int newPackage(final String packageName) { - return symbolTable.addConstantPackage(packageName).index; - } - - /** - * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool - * already contains a similar item. This method is intended for {@link Attribute} sub classes, - * and is normally not needed by class generators or adapters. - * - * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link - * Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link - * Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, - * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. - * @param owner the internal name of the field or method owner class. - * @param name the name of the field or method. - * @param descriptor the descriptor of the field or method. - * @return the index of a new or already existing method type reference item. - * @deprecated this method is superseded by {@link #newHandle(int, String, String, String, - * boolean)}. - */ - @Deprecated - public int newHandle( - final int tag, final String owner, final String name, final String descriptor) { - return newHandle(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE); - } - - /** - * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool - * already contains a similar item. This method is intended for {@link Attribute} sub classes, - * and is normally not needed by class generators or adapters. - * - * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link - * Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link - * Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, - * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. - * @param owner the internal name of the field or method owner class. - * @param name the name of the field or method. - * @param descriptor the descriptor of the field or method. - * @param isInterface true if the owner is an interface. - * @return the index of a new or already existing method type reference item. - */ - public int newHandle( - final int tag, - final String owner, - final String name, - final String descriptor, - final boolean isInterface) { - return symbolTable.addConstantMethodHandle(tag, owner, name, descriptor, isInterface).index; - } - - /** - * Adds a dynamic constant reference to the constant pool of the class being build. Does nothing - * if the constant pool already contains a similar item. This method is intended for {@link - * Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param name name of the invoked method. - * @param descriptor field descriptor of the constant type. - * @param bootstrapMethodHandle the bootstrap method. - * @param bootstrapMethodArguments the bootstrap method constant arguments. - * @return the index of a new or already existing dynamic constant reference item. - */ - public int newConstantDynamic( - final String name, - final String descriptor, - final Handle bootstrapMethodHandle, - final Object... bootstrapMethodArguments) { - return symbolTable.addConstantDynamic( - name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments) - .index; - } - - /** - * Adds an invokedynamic reference to the constant pool of the class being build. Does nothing if - * the constant pool already contains a similar item. This method is intended for {@link - * Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param name name of the invoked method. - * @param descriptor descriptor of the invoke method. - * @param bootstrapMethodHandle the bootstrap method. - * @param bootstrapMethodArguments the bootstrap method constant arguments. - * @return the index of a new or already existing invokedynamic reference item. - */ - public int newInvokeDynamic( - final String name, - final String descriptor, - final Handle bootstrapMethodHandle, - final Object... bootstrapMethodArguments) { - return symbolTable.addConstantInvokeDynamic( - name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments) - .index; - } - - /** - * Adds a field reference to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param owner the internal name of the field's owner class. - * @param name the field's name. - * @param descriptor the field's descriptor. - * @return the index of a new or already existing field reference item. - */ - public int newField(final String owner, final String name, final String descriptor) { - return symbolTable.addConstantFieldref(owner, name, descriptor).index; - } - - /** - * Adds a method reference to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param owner the internal name of the method's owner class. - * @param name the method's name. - * @param descriptor the method's descriptor. - * @param isInterface {@literal true} if {@code owner} is an interface. - * @return the index of a new or already existing method reference item. - */ - public int newMethod( - final String owner, final String name, final String descriptor, final boolean isInterface) { - return symbolTable.addConstantMethodref(owner, name, descriptor, isInterface).index; - } - - /** - * Adds a name and type to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param name a name. - * @param descriptor a type descriptor. - * @return the index of a new or already existing name and type item. - */ - public int newNameType(final String name, final String descriptor) { - return symbolTable.addConstantNameAndType(name, descriptor); - } - - // ----------------------------------------------------------------------------------------------- - // Default method to compute common super classes when computing stack map frames - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the common super type of the two given types. The default implementation of this method - * loads the two given classes and uses the java.lang.Class methods to find the common - * super class. It can be overridden to compute this common super type in other ways, in - * particular without actually loading any class, or to take into account the class that is - * currently being generated by this ClassWriter, which can of course not be loaded since it is - * under construction. - * - * @param type1 the internal name of a class. - * @param type2 the internal name of another class. - * @return the internal name of the common super class of the two given classes. - */ - protected String getCommonSuperClass(final String type1, final String type2) { - ClassLoader classLoader = getClassLoader(); - Class class1; - try { - class1 = Class.forName(type1.replace('/', '.'), false, classLoader); - } catch (ClassNotFoundException e) { - throw new TypeNotPresentException(type1, e); - } - Class class2; - try { - class2 = Class.forName(type2.replace('/', '.'), false, classLoader); - } catch (ClassNotFoundException e) { - throw new TypeNotPresentException(type2, e); - } - if (class1.isAssignableFrom(class2)) { - return type1; - } - if (class2.isAssignableFrom(class1)) { - return type2; - } - if (class1.isInterface() || class2.isInterface()) { - return "java/lang/Object"; - } else { - do { - class1 = class1.getSuperclass(); - } while (!class1.isAssignableFrom(class2)); - return class1.getName().replace('.', '/'); - } - } - - /** - * Returns the {@link ClassLoader} to be used by the default implementation of {@link - * #getCommonSuperClass(String, String)}, that of this {@link ClassWriter}'s runtime type by - * default. - * - * @return ClassLoader - */ - protected ClassLoader getClassLoader() { - return getClass().getClassLoader(); - } + /** + * A flag to automatically compute the maximum stack size and the maximum number of local + * variables of methods. If this flag is set, then the arguments of the {@link + * MethodVisitor#visitMaxs} method of the {@link MethodVisitor} returned by the {@link + * #visitMethod} method will be ignored, and computed automatically from the signature and the + * bytecode of each method. + * + *

Note: for classes whose version is {@link Opcodes#V1_7} of more, this option requires + * valid stack map frames. The maximum stack size is then computed from these frames, and from the + * bytecode instructions in between. If stack map frames are not present or must be recomputed, + * used {@link #COMPUTE_FRAMES} instead. + * + * @see #ClassWriter(int) + */ + public static final int COMPUTE_MAXS = 1; + + /** + * A flag to automatically compute the stack map frames of methods from scratch. If this flag is + * set, then the calls to the {@link MethodVisitor#visitFrame} method are ignored, and the stack + * map frames are recomputed from the methods bytecode. The arguments of the {@link + * MethodVisitor#visitMaxs} method are also ignored and recomputed from the bytecode. In other + * words, {@link #COMPUTE_FRAMES} implies {@link #COMPUTE_MAXS}. + * + * @see #ClassWriter(int) + */ + public static final int COMPUTE_FRAMES = 2; + + // Note: fields are ordered as in the ClassFile structure, and those related to attributes are + // ordered as in Section 4.7 of the JVMS. + + /** + * The minor_version and major_version fields of the JVMS ClassFile structure. minor_version is + * stored in the 16 most significant bits, and major_version in the 16 least significant bits. + */ + private int version; + + /** + * The symbol table for this class (contains the constant_pool and the BootstrapMethods). + */ + private final SymbolTable symbolTable; + + /** + * The access_flags field of the JVMS ClassFile structure. This field can contain ASM specific + * access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the + * ClassFile structure. + */ + private int accessFlags; + + /** + * The this_class field of the JVMS ClassFile structure. + */ + private int thisClass; + + /** + * The super_class field of the JVMS ClassFile structure. + */ + private int superClass; + + /** + * The interface_count field of the JVMS ClassFile structure. + */ + private int interfaceCount; + + /** + * The 'interfaces' array of the JVMS ClassFile structure. + */ + private int[] interfaces; + + /** + * The fields of this class, stored in a linked list of {@link FieldWriter} linked via their + * {@link FieldWriter#fv} field. This field stores the first element of this list. + */ + private FieldWriter firstField; + + /** + * The fields of this class, stored in a linked list of {@link FieldWriter} linked via their + * {@link FieldWriter#fv} field. This field stores the last element of this list. + */ + private FieldWriter lastField; + + /** + * The methods of this class, stored in a linked list of {@link MethodWriter} linked via their + * {@link MethodWriter#mv} field. This field stores the first element of this list. + */ + private MethodWriter firstMethod; + + /** + * The methods of this class, stored in a linked list of {@link MethodWriter} linked via their + * {@link MethodWriter#mv} field. This field stores the last element of this list. + */ + private MethodWriter lastMethod; + + /** + * The number_of_classes field of the InnerClasses attribute, or 0. + */ + private int numberOfInnerClasses; + + /** + * The 'classes' array of the InnerClasses attribute, or {@literal null}. + */ + private ByteVector innerClasses; + + /** + * The class_index field of the EnclosingMethod attribute, or 0. + */ + private int enclosingClassIndex; + + /** + * The method_index field of the EnclosingMethod attribute. + */ + private int enclosingMethodIndex; + + /** + * The signature_index field of the Signature attribute, or 0. + */ + private int signatureIndex; + + /** + * The source_file_index field of the SourceFile attribute, or 0. + */ + private int sourceFileIndex; + + /** + * The debug_extension field of the SourceDebugExtension attribute, or {@literal null}. + */ + private ByteVector debugExtension; + + /** + * The last runtime visible annotation of this class. The previous ones can be accessed with the + * {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastRuntimeVisibleAnnotation; + + /** + * The last runtime invisible annotation of this class. The previous ones can be accessed with the + * {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastRuntimeInvisibleAnnotation; + + /** + * The last runtime visible type annotation of this class. The previous ones can be accessed with + * the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastRuntimeVisibleTypeAnnotation; + + /** + * The last runtime invisible type annotation of this class. The previous ones can be accessed + * with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastRuntimeInvisibleTypeAnnotation; + + /** + * The Module attribute of this class, or {@literal null}. + */ + private ModuleWriter moduleWriter; + + /** + * The host_class_index field of the NestHost attribute, or 0. + */ + private int nestHostClassIndex; + + /** + * The number_of_classes field of the NestMembers attribute, or 0. + */ + private int numberOfNestMemberClasses; + + /** + * The 'classes' array of the NestMembers attribute, or {@literal null}. + */ + private ByteVector nestMemberClasses; + + /** + * The first non standard attribute of this class. The next ones can be accessed with the {@link + * Attribute#nextAttribute} field. May be {@literal null}. + * + *

WARNING: this list stores the attributes in the reverse order of their visit. + * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link + * #toByteArray} method writes the attributes in the order defined by this list, i.e. in the + * reverse order specified by the user. + */ + private Attribute firstAttribute; + + /** + * Indicates what must be automatically computed in {@link MethodWriter}. Must be one of {@link + * MethodWriter#COMPUTE_NOTHING}, {@link MethodWriter#COMPUTE_MAX_STACK_AND_LOCAL}, {@link + * MethodWriter#COMPUTE_INSERTED_FRAMES}, or {@link MethodWriter#COMPUTE_ALL_FRAMES}. + */ + private int compute; + + // ----------------------------------------------------------------------------------------------- + // Constructor + // ----------------------------------------------------------------------------------------------- + + /** + * Constructs a new {@link ClassWriter} object. + * + * @param flags option flags that can be used to modify the default behavior of this class. Must + * be zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}. + */ + public ClassWriter(final int flags) { + this(null, flags); + } + + /** + * Constructs a new {@link ClassWriter} object and enables optimizations for "mostly add" bytecode + * transformations. These optimizations are the following: + * + *

+ * + * @param classReader the {@link ClassReader} used to read the original class. It will be used to + * copy the entire constant pool and bootstrap methods from the original class and also to + * copy other fragments of original bytecode where applicable. + * @param flags option flags that can be used to modify the default behavior of this class.Must be + * zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}. These option flags do + * not affect methods that are copied as is in the new class. This means that neither the + * maximum stack size nor the stack frames will be computed for these methods. + */ + public ClassWriter(final ClassReader classReader, final int flags) { + super(Opcodes.ASM7); + symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader); + if ((flags & COMPUTE_FRAMES) != 0) { + this.compute = MethodWriter.COMPUTE_ALL_FRAMES; + } else if ((flags & COMPUTE_MAXS) != 0) { + this.compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL; + } else { + this.compute = MethodWriter.COMPUTE_NOTHING; + } + } + + // ----------------------------------------------------------------------------------------------- + // Implementation of the ClassVisitor abstract class + // ----------------------------------------------------------------------------------------------- + + @Override + public final void visit( + final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) { + this.version = version; + + //replace all pre jre minor versions to one that's outside of the old format + if ((version & 0xFFFF) == 45 && (version >>> 16) <= 2) { + this.version = (3 << 16) | 45; + } + this.accessFlags = access; + this.thisClass = symbolTable.setMajorVersionAndClassName(this.version & 0xFFFF, name); + if (signature != null) { + this.signatureIndex = symbolTable.addConstantUtf8(signature); + } + this.superClass = superName == null ? 0 : symbolTable.addConstantClass(superName).index; + if (interfaces != null && interfaces.length > 0) { + interfaceCount = interfaces.length; + this.interfaces = new int[interfaceCount]; + for (int i = 0; i < interfaceCount; ++i) { + this.interfaces[i] = symbolTable.addConstantClass(interfaces[i]).index; + } + } + if (compute == MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL && (this.version & 0xFFFF) >= Opcodes.V1_7) { + compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES; + } + } + + @Override + public final void visitSource(final String file, final String debug) { + if (file != null) { + sourceFileIndex = symbolTable.addConstantUtf8(file); + } + if (debug != null) { + debugExtension = new ByteVector().encodeUtf8(debug, 0, Integer.MAX_VALUE); + } + } + + @Override + public final ModuleVisitor visitModule( + final String name, final int access, final String version) { + return moduleWriter = + new ModuleWriter( + symbolTable, + symbolTable.addConstantModule(name).index, + access, + version == null ? 0 : symbolTable.addConstantUtf8(version)); + } + + @Override + public void visitNestHost(final String nestHost) { + nestHostClassIndex = symbolTable.addConstantClass(nestHost).index; + } + + @Override + public final void visitOuterClass( + final String owner, final String name, final String descriptor) { + enclosingClassIndex = symbolTable.addConstantClass(owner).index; + if (name != null && descriptor != null) { + enclosingMethodIndex = symbolTable.addConstantNameAndType(name, descriptor); + } + } + + @Override + public final AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { + if (visible) { + return lastRuntimeVisibleAnnotation = + AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation); + } else { + return lastRuntimeInvisibleAnnotation = + AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation); + } + } + + @Override + public final AnnotationVisitor visitTypeAnnotation( + final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { + if (visible) { + return lastRuntimeVisibleTypeAnnotation = + AnnotationWriter.create( + symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation); + } else { + return lastRuntimeInvisibleTypeAnnotation = + AnnotationWriter.create( + symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation); + } + } + + @Override + public final void visitAttribute(final Attribute attribute) { + // Store the attributes in the reverse order of their visit by this method. + attribute.nextAttribute = firstAttribute; + firstAttribute = attribute; + } + + @Override + public void visitNestMember(final String nestMember) { + if (nestMemberClasses == null) { + nestMemberClasses = new ByteVector(); + } + ++numberOfNestMemberClasses; + nestMemberClasses.putShort(symbolTable.addConstantClass(nestMember).index); + } + + @Override + public final void visitInnerClass( + final String name, final String outerName, final String innerName, final int access) { + if (innerClasses == null) { + innerClasses = new ByteVector(); + } + // Section 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the constant_pool table + // which represents a class or interface C that is not a package member must have exactly one + // corresponding entry in the classes array". To avoid duplicates we keep track in the info + // field of the Symbol of each CONSTANT_Class_info entry C whether an inner class entry has + // already been added for C. If so, we store the index of this inner class entry (plus one) in + // the info field. This trick allows duplicate detection in O(1) time. + Symbol nameSymbol = symbolTable.addConstantClass(name); + if (nameSymbol.info == 0) { + ++numberOfInnerClasses; + innerClasses.putShort(nameSymbol.index); + innerClasses.putShort(outerName == null ? 0 : symbolTable.addConstantClass(outerName).index); + innerClasses.putShort(innerName == null ? 0 : symbolTable.addConstantUtf8(innerName)); + innerClasses.putShort(access); + nameSymbol.info = numberOfInnerClasses; + } + // Else, compare the inner classes entry nameSymbol.info - 1 with the arguments of this method + // and throw an exception if there is a difference? + } + + @Override + public final FieldVisitor visitField( + final int access, + final String name, + final String descriptor, + final String signature, + final Object value) { + FieldWriter fieldWriter = + new FieldWriter(symbolTable, access, name, descriptor, signature, value); + if (firstField == null) { + firstField = fieldWriter; + } else { + lastField.fv = fieldWriter; + } + return lastField = fieldWriter; + } + + @Override + public final MethodVisitor visitMethod( + final int access, + final String name, + final String descriptor, + final String signature, + final String[] exceptions) { + MethodWriter methodWriter = + new MethodWriter(symbolTable, access, name, descriptor, signature, exceptions, compute); + if (firstMethod == null) { + firstMethod = methodWriter; + } else { + lastMethod.mv = methodWriter; + } + return lastMethod = methodWriter; + } + + @Override + public final void visitEnd() { + // Nothing to do. + } + + // ----------------------------------------------------------------------------------------------- + // Other public methods + // ----------------------------------------------------------------------------------------------- + + /** + * Returns the content of the class file that was built by this ClassWriter. + * + * @return the binary content of the JVMS ClassFile structure that was built by this ClassWriter. + * @throws ClassTooLargeException if the constant pool of the class is too large. + * @throws MethodTooLargeException if the Code attribute of a method is too large. + */ + public byte[] toByteArray() { + // First step: compute the size in bytes of the ClassFile structure. + // The magic field uses 4 bytes, 10 mandatory fields (minor_version, major_version, + // constant_pool_count, access_flags, this_class, super_class, interfaces_count, fields_count, + // methods_count and attributes_count) use 2 bytes each, and each interface uses 2 bytes too. + int size = 24 + 2 * interfaceCount; + int fieldsCount = 0; + FieldWriter fieldWriter = firstField; + while (fieldWriter != null) { + ++fieldsCount; + size += fieldWriter.computeFieldInfoSize(); + fieldWriter = (FieldWriter) fieldWriter.fv; + } + int methodsCount = 0; + MethodWriter methodWriter = firstMethod; + while (methodWriter != null) { + ++methodsCount; + size += methodWriter.computeMethodInfoSize(); + methodWriter = (MethodWriter) methodWriter.mv; + } + // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. + int attributesCount = 0; + if (innerClasses != null) { + ++attributesCount; + size += 8 + innerClasses.length; + symbolTable.addConstantUtf8(Constants.INNER_CLASSES); + } + if (enclosingClassIndex != 0) { + ++attributesCount; + size += 10; + symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD); + } + if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) { + ++attributesCount; + size += 6; + symbolTable.addConstantUtf8(Constants.SYNTHETIC); + } + if (signatureIndex != 0) { + ++attributesCount; + size += 8; + symbolTable.addConstantUtf8(Constants.SIGNATURE); + } + if (sourceFileIndex != 0) { + ++attributesCount; + size += 8; + symbolTable.addConstantUtf8(Constants.SOURCE_FILE); + } + if (debugExtension != null) { + ++attributesCount; + size += 6 + debugExtension.length; + symbolTable.addConstantUtf8(Constants.SOURCE_DEBUG_EXTENSION); + } + if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { + ++attributesCount; + size += 6; + symbolTable.addConstantUtf8(Constants.DEPRECATED); + } + if (lastRuntimeVisibleAnnotation != null) { + ++attributesCount; + size += + lastRuntimeVisibleAnnotation.computeAnnotationsSize( + Constants.RUNTIME_VISIBLE_ANNOTATIONS); + } + if (lastRuntimeInvisibleAnnotation != null) { + ++attributesCount; + size += + lastRuntimeInvisibleAnnotation.computeAnnotationsSize( + Constants.RUNTIME_INVISIBLE_ANNOTATIONS); + } + if (lastRuntimeVisibleTypeAnnotation != null) { + ++attributesCount; + size += + lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize( + Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); + } + if (lastRuntimeInvisibleTypeAnnotation != null) { + ++attributesCount; + size += + lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize( + Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + } + if (symbolTable.computeBootstrapMethodsSize() > 0) { + ++attributesCount; + size += symbolTable.computeBootstrapMethodsSize(); + } + if (moduleWriter != null) { + attributesCount += moduleWriter.getAttributeCount(); + size += moduleWriter.computeAttributesSize(); + } + if (nestHostClassIndex != 0) { + ++attributesCount; + size += 8; + symbolTable.addConstantUtf8(Constants.NEST_HOST); + } + if (nestMemberClasses != null) { + ++attributesCount; + size += 8 + nestMemberClasses.length; + symbolTable.addConstantUtf8(Constants.NEST_MEMBERS); + } + if (firstAttribute != null) { + attributesCount += firstAttribute.getAttributeCount(); + size += firstAttribute.computeAttributesSize(symbolTable); + } + // IMPORTANT: this must be the last part of the ClassFile size computation, because the previous + // statements can add attribute names to the constant pool, thereby changing its size! + size += symbolTable.getConstantPoolLength(); + int constantPoolCount = symbolTable.getConstantPoolCount(); + if (constantPoolCount > 0xFFFF) { + throw new ClassTooLargeException(symbolTable.getClassName(), constantPoolCount); + } + + // Second step: allocate a ByteVector of the correct size (in order to avoid any array copy in + // dynamic resizes) and fill it with the ClassFile content. + ByteVector result = new ByteVector(size); + result.putInt(0xCAFEBABE).putInt(version); + symbolTable.putConstantPool(result); + int mask = (version & 0xFFFF) < Opcodes.V1_5 ? Opcodes.ACC_SYNTHETIC : 0; + result.putShort(accessFlags & ~mask).putShort(thisClass).putShort(superClass); + result.putShort(interfaceCount); + for (int i = 0; i < interfaceCount; ++i) { + result.putShort(interfaces[i]); + } + result.putShort(fieldsCount); + fieldWriter = firstField; + while (fieldWriter != null) { + fieldWriter.putFieldInfo(result); + fieldWriter = (FieldWriter) fieldWriter.fv; + } + result.putShort(methodsCount); + boolean hasFrames = false; + boolean hasAsmInstructions = false; + methodWriter = firstMethod; + while (methodWriter != null) { + hasFrames |= methodWriter.hasFrames(); + hasAsmInstructions |= methodWriter.hasAsmInstructions(); + methodWriter.putMethodInfo(result); + methodWriter = (MethodWriter) methodWriter.mv; + } + // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. + result.putShort(attributesCount); + if (innerClasses != null) { + result + .putShort(symbolTable.addConstantUtf8(Constants.INNER_CLASSES)) + .putInt(innerClasses.length + 2) + .putShort(numberOfInnerClasses) + .putByteArray(innerClasses.data, 0, innerClasses.length); + } + if (enclosingClassIndex != 0) { + result + .putShort(symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD)) + .putInt(4) + .putShort(enclosingClassIndex) + .putShort(enclosingMethodIndex); + } + if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) { + result.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0); + } + if (signatureIndex != 0) { + result + .putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE)) + .putInt(2) + .putShort(signatureIndex); + } + if (sourceFileIndex != 0) { + result + .putShort(symbolTable.addConstantUtf8(Constants.SOURCE_FILE)) + .putInt(2) + .putShort(sourceFileIndex); + } + if (debugExtension != null) { + int length = debugExtension.length; + result + .putShort(symbolTable.addConstantUtf8(Constants.SOURCE_DEBUG_EXTENSION)) + .putInt(length) + .putByteArray(debugExtension.data, 0, length); + } + if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { + result.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0); + } + AnnotationWriter.putAnnotations( + symbolTable, + lastRuntimeVisibleAnnotation, + lastRuntimeInvisibleAnnotation, + lastRuntimeVisibleTypeAnnotation, + lastRuntimeInvisibleTypeAnnotation, + result); + symbolTable.putBootstrapMethods(result); + if (moduleWriter != null) { + moduleWriter.putAttributes(result); + } + if (nestHostClassIndex != 0) { + result + .putShort(symbolTable.addConstantUtf8(Constants.NEST_HOST)) + .putInt(2) + .putShort(nestHostClassIndex); + } + if (nestMemberClasses != null) { + result + .putShort(symbolTable.addConstantUtf8(Constants.NEST_MEMBERS)) + .putInt(nestMemberClasses.length + 2) + .putShort(numberOfNestMemberClasses) + .putByteArray(nestMemberClasses.data, 0, nestMemberClasses.length); + } + if (firstAttribute != null) { + firstAttribute.putAttributes(symbolTable, result); + } + + // Third step: replace the ASM specific instructions, if any. + if (hasAsmInstructions) { + return replaceAsmInstructions(result.data, hasFrames); + } else { + return result.data; + } + } + + /** + * Returns the equivalent of the given class file, with the ASM specific instructions replaced + * with standard ones. This is done with a ClassReader -> ClassWriter round trip. + * + * @param classFile a class file containing ASM specific instructions, generated by this + * ClassWriter. + * @param hasFrames whether there is at least one stack map frames in 'classFile'. + * @return an equivalent of 'classFile', with the ASM specific instructions replaced with standard + * ones. + */ + private byte[] replaceAsmInstructions(final byte[] classFile, final boolean hasFrames) { + final Attribute[] attributes = getAttributePrototypes(); + firstField = null; + lastField = null; + firstMethod = null; + lastMethod = null; + lastRuntimeVisibleAnnotation = null; + lastRuntimeInvisibleAnnotation = null; + lastRuntimeVisibleTypeAnnotation = null; + lastRuntimeInvisibleTypeAnnotation = null; + moduleWriter = null; + nestHostClassIndex = 0; + numberOfNestMemberClasses = 0; + nestMemberClasses = null; + firstAttribute = null; + compute = hasFrames ? MethodWriter.COMPUTE_INSERTED_FRAMES : MethodWriter.COMPUTE_NOTHING; + new ClassReader(classFile, 0, /* checkClassVersion = */ false) + .accept( + this, + attributes, + (hasFrames ? ClassReader.EXPAND_FRAMES : 0) | ClassReader.EXPAND_ASM_INSNS); + return toByteArray(); + } + + /** + * Returns the prototypes of the attributes used by this class, its fields and its methods. + * + * @return the prototypes of the attributes used by this class, its fields and its methods. + */ + private Attribute[] getAttributePrototypes() { + Attribute.Set attributePrototypes = new Attribute.Set(); + attributePrototypes.addAttributes(firstAttribute); + FieldWriter fieldWriter = firstField; + while (fieldWriter != null) { + fieldWriter.collectAttributePrototypes(attributePrototypes); + fieldWriter = (FieldWriter) fieldWriter.fv; + } + MethodWriter methodWriter = firstMethod; + while (methodWriter != null) { + methodWriter.collectAttributePrototypes(attributePrototypes); + methodWriter = (MethodWriter) methodWriter.mv; + } + return attributePrototypes.toArray(); + } + + // ----------------------------------------------------------------------------------------------- + // Utility methods: constant pool management for Attribute sub classes + // ----------------------------------------------------------------------------------------------- + + /** + * Adds a number or string constant to the constant pool of the class being build. Does nothing if + * the constant pool already contains a similar item. This method is intended for {@link + * Attribute} sub classes, and is normally not needed by class generators or adapters. + * + * @param value the value of the constant to be added to the constant pool. This parameter must be + * an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double} or a {@link String}. + * @return the index of a new or already existing constant item with the given value. + */ + public int newConst(final Object value) { + return symbolTable.addConstant(value).index; + } + + /** + * Adds an UTF8 string to the constant pool of the class being build. Does nothing if the constant + * pool already contains a similar item. This method is intended for {@link Attribute} sub + * classes, and is normally not needed by class generators or adapters. + * + * @param value the String value. + * @return the index of a new or already existing UTF8 item. + */ + // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility). + public int newUTF8(final String value) { + return symbolTable.addConstantUtf8(value); + } + + /** + * Adds a class reference to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. This method is intended for {@link Attribute} + * sub classes, and is normally not needed by class generators or adapters. + * + * @param value the internal name of the class. + * @return the index of a new or already existing class reference item. + */ + public int newClass(final String value) { + return symbolTable.addConstantClass(value).index; + } + + /** + * Adds a method type reference to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. This method is intended for {@link Attribute} + * sub classes, and is normally not needed by class generators or adapters. + * + * @param methodDescriptor method descriptor of the method type. + * @return the index of a new or already existing method type reference item. + */ + public int newMethodType(final String methodDescriptor) { + return symbolTable.addConstantMethodType(methodDescriptor).index; + } + + /** + * Adds a module reference to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. This method is intended for {@link Attribute} + * sub classes, and is normally not needed by class generators or adapters. + * + * @param moduleName name of the module. + * @return the index of a new or already existing module reference item. + */ + public int newModule(final String moduleName) { + return symbolTable.addConstantModule(moduleName).index; + } + + /** + * Adds a package reference to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. This method is intended for {@link Attribute} + * sub classes, and is normally not needed by class generators or adapters. + * + * @param packageName name of the package in its internal form. + * @return the index of a new or already existing module reference item. + */ + public int newPackage(final String packageName) { + return symbolTable.addConstantPackage(packageName).index; + } + + /** + * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool + * already contains a similar item. This method is intended for {@link Attribute} sub classes, + * and is normally not needed by class generators or adapters. + * + * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link + * Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link + * Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner the internal name of the field or method owner class. + * @param name the name of the field or method. + * @param descriptor the descriptor of the field or method. + * @return the index of a new or already existing method type reference item. + * @deprecated this method is superseded by {@link #newHandle(int, String, String, String, + * boolean)}. + */ + @Deprecated + public int newHandle( + final int tag, final String owner, final String name, final String descriptor) { + return newHandle(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE); + } + + /** + * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool + * already contains a similar item. This method is intended for {@link Attribute} sub classes, + * and is normally not needed by class generators or adapters. + * + * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link + * Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link + * Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner the internal name of the field or method owner class. + * @param name the name of the field or method. + * @param descriptor the descriptor of the field or method. + * @param isInterface true if the owner is an interface. + * @return the index of a new or already existing method type reference item. + */ + public int newHandle( + final int tag, + final String owner, + final String name, + final String descriptor, + final boolean isInterface) { + return symbolTable.addConstantMethodHandle(tag, owner, name, descriptor, isInterface).index; + } + + /** + * Adds a dynamic constant reference to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. This method is intended for {@link + * Attribute} sub classes, and is normally not needed by class generators or adapters. + * + * @param name name of the invoked method. + * @param descriptor field descriptor of the constant type. + * @param bootstrapMethodHandle the bootstrap method. + * @param bootstrapMethodArguments the bootstrap method constant arguments. + * @return the index of a new or already existing dynamic constant reference item. + */ + public int newConstantDynamic( + final String name, + final String descriptor, + final Handle bootstrapMethodHandle, + final Object... bootstrapMethodArguments) { + return symbolTable.addConstantDynamic( + name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments) + .index; + } + + /** + * Adds an invokedynamic reference to the constant pool of the class being build. Does nothing if + * the constant pool already contains a similar item. This method is intended for {@link + * Attribute} sub classes, and is normally not needed by class generators or adapters. + * + * @param name name of the invoked method. + * @param descriptor descriptor of the invoke method. + * @param bootstrapMethodHandle the bootstrap method. + * @param bootstrapMethodArguments the bootstrap method constant arguments. + * @return the index of a new or already existing invokedynamic reference item. + */ + public int newInvokeDynamic( + final String name, + final String descriptor, + final Handle bootstrapMethodHandle, + final Object... bootstrapMethodArguments) { + return symbolTable.addConstantInvokeDynamic( + name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments) + .index; + } + + /** + * Adds a field reference to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. This method is intended for {@link Attribute} + * sub classes, and is normally not needed by class generators or adapters. + * + * @param owner the internal name of the field's owner class. + * @param name the field's name. + * @param descriptor the field's descriptor. + * @return the index of a new or already existing field reference item. + */ + public int newField(final String owner, final String name, final String descriptor) { + return symbolTable.addConstantFieldref(owner, name, descriptor).index; + } + + /** + * Adds a method reference to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. This method is intended for {@link Attribute} + * sub classes, and is normally not needed by class generators or adapters. + * + * @param owner the internal name of the method's owner class. + * @param name the method's name. + * @param descriptor the method's descriptor. + * @param isInterface {@literal true} if {@code owner} is an interface. + * @return the index of a new or already existing method reference item. + */ + public int newMethod( + final String owner, final String name, final String descriptor, final boolean isInterface) { + return symbolTable.addConstantMethodref(owner, name, descriptor, isInterface).index; + } + + /** + * Adds a name and type to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. This method is intended for {@link Attribute} + * sub classes, and is normally not needed by class generators or adapters. + * + * @param name a name. + * @param descriptor a type descriptor. + * @return the index of a new or already existing name and type item. + */ + public int newNameType(final String name, final String descriptor) { + return symbolTable.addConstantNameAndType(name, descriptor); + } + + // ----------------------------------------------------------------------------------------------- + // Default method to compute common super classes when computing stack map frames + // ----------------------------------------------------------------------------------------------- + + /** + * Returns the common super type of the two given types. The default implementation of this method + * loads the two given classes and uses the java.lang.Class methods to find the common + * super class. It can be overridden to compute this common super type in other ways, in + * particular without actually loading any class, or to take into account the class that is + * currently being generated by this ClassWriter, which can of course not be loaded since it is + * under construction. + * + * @param type1 the internal name of a class. + * @param type2 the internal name of another class. + * @return the internal name of the common super class of the two given classes. + */ + protected String getCommonSuperClass(final String type1, final String type2) { + ClassLoader classLoader = getClassLoader(); + Class class1; + try { + class1 = Class.forName(type1.replace('/', '.'), false, classLoader); + } catch (ClassNotFoundException e) { + throw new TypeNotPresentException(type1, e); + } + Class class2; + try { + class2 = Class.forName(type2.replace('/', '.'), false, classLoader); + } catch (ClassNotFoundException e) { + throw new TypeNotPresentException(type2, e); + } + if (class1.isAssignableFrom(class2)) { + return type1; + } + if (class2.isAssignableFrom(class1)) { + return type2; + } + if (class1.isInterface() || class2.isInterface()) { + return "java/lang/Object"; + } else { + do { + class1 = class1.getSuperclass(); + } while (!class1.isAssignableFrom(class2)); + return class1.getName().replace('.', '/'); + } + } + + /** + * Returns the {@link ClassLoader} to be used by the default implementation of {@link + * #getCommonSuperClass(String, String)}, that of this {@link ClassWriter}'s runtime type by + * default. + * + * @return ClassLoader + */ + protected ClassLoader getClassLoader() { + return getClass().getClassLoader(); + } } \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bootloader/AbstractLoaderFactory.java b/src/main/java/the/bytecode/club/bootloader/AbstractLoaderFactory.java index 9a3e47ca..c8f1ae99 100644 --- a/src/main/java/the/bytecode/club/bootloader/AbstractLoaderFactory.java +++ b/src/main/java/the/bytecode/club/bootloader/AbstractLoaderFactory.java @@ -2,7 +2,6 @@ package the.bytecode.club.bootloader; import java.util.HashMap; import java.util.Map; - import the.bytecode.club.bootloader.resource.ExternalResource; /*************************************************************************** diff --git a/src/main/java/the/bytecode/club/bootloader/Boot.java b/src/main/java/the/bytecode/club/bootloader/Boot.java index 48709bba..450fab22 100644 --- a/src/main/java/the/bytecode/club/bootloader/Boot.java +++ b/src/main/java/the/bytecode/club/bootloader/Boot.java @@ -6,18 +6,15 @@ import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.List; - import javax.swing.JOptionPane; import javax.swing.SwingUtilities; - -import org.apache.commons.io.FileUtils; - import me.konloch.kontainer.io.HTTPRequest; +import org.apache.commons.io.FileUtils; import the.bytecode.club.bootloader.resource.EmptyExternalResource; import the.bytecode.club.bootloader.resource.ExternalResource; import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.util.ZipUtils; import the.bytecode.club.bytecodeviewer.api.ExceptionUI; +import the.bytecode.club.bytecodeviewer.util.ZipUtils; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -50,9 +47,9 @@ public class Boot { public static boolean downloading = false; private static InitialBootScreen screen; - private static List libsList = new ArrayList(); - private static List libsFileList = new ArrayList(); - private static List urlList = new ArrayList(); + private static final List libsList = new ArrayList(); + private static final List libsFileList = new ArrayList(); + private static final List urlList = new ArrayList(); static { try { @@ -62,8 +59,7 @@ public class Boot { } } - public static void boot(String[] args, boolean CLI) throws Exception - { + public static void boot(String[] args, boolean CLI) throws Exception { bootstrap(); ILoader loader = findLoader(); @@ -108,7 +104,9 @@ public class Boot { } if (urlList.isEmpty()) { - JOptionPane.showMessageDialog(null, "Bytecode Viewer ran into an issue, for some reason github is not returning what we're expecting. Please try rebooting, if this issue persists please contact @Konloch.", "Error", JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(null, "Bytecode Viewer ran into an issue, for some reason github is not " + + "returning what we're expecting. Please try rebooting, if this issue persists please contact " + + "@Konloch.", "Error", JOptionPane.ERROR_MESSAGE); return; } @@ -125,7 +123,8 @@ public class Boot { int completedCheck = 0; for (String s : urlList) { - String fileName = s.substring("https://github.com/Konloch/bytecode-viewer/blob/master/libs/".length(), s.length()); + String fileName = s.substring("https://github.com/Konloch/bytecode-viewer/blob/master/libs/".length() + ); File file = new File(libsDirectory, fileName); boolean passed = false; @@ -177,9 +176,8 @@ public class Boot { System.out.println("Verifying " + fileName + "..."); File f = new File(BytecodeViewer.tempDirectory, "temp"); - if(!f.exists()) - { - f.getParentFile().mkdirs(); + if (!f.exists()) { + f.getParentFile().mkdirs(); } ZipUtils.zipFile(file, f); f.delete(); @@ -223,7 +221,9 @@ public class Boot { File f = new File(s); boolean delete = true; for (String urlS : urlList) { - String fileName = urlS.substring("https://github.com/Konloch/bytecode-viewer/blob/master/libs/".length(), urlS.length()); + String fileName = + urlS.substring("https://github.com/Konloch/bytecode-viewer/blob/master/libs/".length() + ); if (fileName.equals(f.getName())) delete = false; } @@ -250,7 +250,8 @@ public class Boot { } catch (Exception e) { e.printStackTrace(); f.delete(); - JOptionPane.showMessageDialog(null, "Error, Library " + f.getName() + " is corrupt, please restart to redownload it.", + JOptionPane.showMessageDialog(null, "Error, Library " + f.getName() + " is corrupt, please " + + "restart to redownload it.", "Error", JOptionPane.ERROR_MESSAGE); } } @@ -318,31 +319,30 @@ public class Boot { } } - public static void dropKrakatau() - { - File temp = new File(BytecodeViewer.getBCVDirectory() + BytecodeViewer.fs + "krakatau_" + BytecodeViewer.krakatauVersion + ".zip"); + public static void dropKrakatau() { + File temp = + new File(BytecodeViewer.getBCVDirectory() + BytecodeViewer.fs + "krakatau_" + BytecodeViewer.krakatauVersion + ".zip"); File krakatauDirectory = new File(BytecodeViewer.krakatauWorkingDirectory); - BytecodeViewer.krakatauWorkingDirectory = BytecodeViewer.krakatauWorkingDirectory + BytecodeViewer.fs + "Krakatau-master"; - if (!krakatauDirectory.exists() || temp.exists()) - { - if(temp.exists()) + BytecodeViewer.krakatauWorkingDirectory = BytecodeViewer.krakatauWorkingDirectory + BytecodeViewer.fs + + "Krakatau-master"; + if (!krakatauDirectory.exists() || temp.exists()) { + if (temp.exists()) temp.delete(); setState("Bytecode Viewer Boot Screen - Extracting Krakatau"); System.out.println("Extracting Krakatau"); - try - { + try { while (temp.exists()) temp.delete(); - InputStream is = BytecodeViewer.class.getClassLoader().getResourceAsStream("Krakatau-" + BytecodeViewer.krakatauVersion + ".zip"); + InputStream is = + BytecodeViewer.class.getClassLoader().getResourceAsStream("Krakatau-" + BytecodeViewer.krakatauVersion + ".zip"); FileOutputStream baos = new FileOutputStream(temp); int r = 0; byte[] buffer = new byte[8192]; - while ((r = is.read(buffer)) >= 0) - { + while ((r = is.read(buffer)) >= 0) { baos.write(buffer, 0, r); } @@ -350,39 +350,36 @@ public class Boot { ZipUtils.unzipFilesToPath(temp.getAbsolutePath(), krakatauDirectory.getAbsolutePath()); temp.delete(); System.out.println("Succesfully extracted Krakatau"); - } - catch (Exception e) - { + } catch (Exception e) { setState("Bytecode Viewer Boot Screen - ERROR, please contact @Konloch with your stacktrace."); new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); } } } - public static void dropEnjarify() - { - File temp = new File(BytecodeViewer.getBCVDirectory() + BytecodeViewer.fs + "enjarify" + BytecodeViewer.enjarifyVersion + ".zip"); + public static void dropEnjarify() { + File temp = + new File(BytecodeViewer.getBCVDirectory() + BytecodeViewer.fs + "enjarify" + BytecodeViewer.enjarifyVersion + ".zip"); File enjarifyDirectory = new File(BytecodeViewer.enjarifyWorkingDirectory); - BytecodeViewer.enjarifyWorkingDirectory = BytecodeViewer.enjarifyWorkingDirectory + BytecodeViewer.fs + "enjarify-master"; - if (!enjarifyDirectory.exists() || temp.exists()) - { - if(temp.exists()) + BytecodeViewer.enjarifyWorkingDirectory = BytecodeViewer.enjarifyWorkingDirectory + BytecodeViewer.fs + + "enjarify-master"; + if (!enjarifyDirectory.exists() || temp.exists()) { + if (temp.exists()) temp.delete(); setState("Bytecode Viewer Boot Screen - Extracting Enjarify"); System.out.println("Extracting Enjarify"); - try - { + try { while (temp.exists()) temp.delete(); - InputStream is = BytecodeViewer.class.getClassLoader().getResourceAsStream("enjarify-" + BytecodeViewer.enjarifyVersion + ".zip"); + InputStream is = + BytecodeViewer.class.getClassLoader().getResourceAsStream("enjarify-" + BytecodeViewer.enjarifyVersion + ".zip"); FileOutputStream baos = new FileOutputStream(temp); int r = 0; byte[] buffer = new byte[8192]; - while ((r = is.read(buffer)) >= 0) - { + while ((r = is.read(buffer)) >= 0) { baos.write(buffer, 0, r); } @@ -390,9 +387,7 @@ public class Boot { ZipUtils.unzipFilesToPath(temp.getAbsolutePath(), enjarifyDirectory.getAbsolutePath()); temp.delete(); System.out.println("Succesfully extracted Enjarify"); - } - catch (Exception e) - { + } catch (Exception e) { setState("Bytecode Viewer Boot Screen - ERROR, please contact @Konloch with your stacktrace."); new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); } @@ -401,7 +396,8 @@ public class Boot { public static void downloadZipsOnly() throws Exception { for (String s : urlList) { - String fileName = s.substring("https://github.com/Konloch/bytecode-viewer/blob/master/libs/".length(), s.length()); + String fileName = s.substring("https://github.com/Konloch/bytecode-viewer/blob/master/libs/".length() + ); File file = new File(libsDir(), fileName); boolean passed = false; @@ -495,15 +491,18 @@ public class Boot { } } - BytecodeViewer.enjarifyWorkingDirectory = BytecodeViewer.getBCVDirectory() + BytecodeViewer.fs + "enjarify_" + BytecodeViewer.enjarifyVersion + BytecodeViewer.fs + "enjarify-master"; - File enjarifyDirectory = new File(BytecodeViewer.getBCVDirectory() + BytecodeViewer.fs + "enjarify_" + BytecodeViewer.enjarifyVersion); + BytecodeViewer.enjarifyWorkingDirectory = + BytecodeViewer.getBCVDirectory() + BytecodeViewer.fs + "enjarify_" + BytecodeViewer.enjarifyVersion + BytecodeViewer.fs + "enjarify-master"; + File enjarifyDirectory = + new File(BytecodeViewer.getBCVDirectory() + BytecodeViewer.fs + "enjarify_" + BytecodeViewer.enjarifyVersion); if (!enjarifyDirectory.exists()) { try { setState("Bytecode Viewer Boot Screen - Updating to " + enjarifyDirectory.getName() + "..."); ZipUtils.unzipFilesToPath(enjarifyZip.getAbsolutePath(), enjarifyDirectory.getAbsolutePath()); System.out.println("Updated to enjarify v" + BytecodeViewer.enjarifyVersion); } catch (Exception e) { - BytecodeViewer.showMessage("ERROR: There was an issue unzipping enjarify (possibly corrupt). Restart BCV." + BytecodeViewer.nl + + BytecodeViewer.showMessage("ERROR: There was an issue unzipping enjarify (possibly corrupt). Restart " + + "BCV." + BytecodeViewer.nl + "If the error persists contact @Konloch."); new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); enjarifyZip.delete(); @@ -540,14 +539,16 @@ public class Boot { BytecodeViewer.krakatauWorkingDirectory = BytecodeViewer.getBCVDirectory() + BytecodeViewer.fs + "krakatau_" + BytecodeViewer.krakatauVersion + BytecodeViewer.fs + "Krakatau-master"; - File krakatauDirectory = new File(BytecodeViewer.getBCVDirectory() + BytecodeViewer.fs + "krakatau_" + BytecodeViewer.krakatauVersion); + File krakatauDirectory = + new File(BytecodeViewer.getBCVDirectory() + BytecodeViewer.fs + "krakatau_" + BytecodeViewer.krakatauVersion); if (!krakatauDirectory.exists()) { try { setState("Bytecode Viewer Boot Screen - Updating to " + krakatauDirectory.getName() + "..."); ZipUtils.unzipFilesToPath(krakatauZip.getAbsolutePath(), krakatauDirectory.getAbsolutePath()); System.out.println("Updated to krakatau v" + BytecodeViewer.krakatauVersion); } catch (Exception e) { - BytecodeViewer.showMessage("ERROR: There was an issue unzipping Krakatau decompiler (possibly corrupt). Restart BCV." + BytecodeViewer.nl + + BytecodeViewer.showMessage("ERROR: There was an issue unzipping Krakatau decompiler (possibly " + + "corrupt). Restart BCV." + BytecodeViewer.nl + "If the error persists contact @Konloch."); new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); krakatauZip.delete(); diff --git a/src/main/java/the/bytecode/club/bootloader/ClassPathLoader.java b/src/main/java/the/bytecode/club/bootloader/ClassPathLoader.java index 4db7a9fc..1e0606e1 100644 --- a/src/main/java/the/bytecode/club/bootloader/ClassPathLoader.java +++ b/src/main/java/the/bytecode/club/bootloader/ClassPathLoader.java @@ -4,7 +4,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; - import the.bytecode.club.bootloader.resource.ExternalResource; /*************************************************************************** @@ -31,13 +30,14 @@ import the.bytecode.club.bootloader.resource.ExternalResource; */ public class ClassPathLoader implements ILoader { - void extendClassPath(URL url) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, + void extendClassPath(URL url) throws NoSuchMethodException, SecurityException, IllegalAccessException, + IllegalArgumentException, InvocationTargetException { URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); Class urlClass = URLClassLoader.class; - Method method = urlClass.getDeclaredMethod("addURL", new Class[]{URL.class}); + Method method = urlClass.getDeclaredMethod("addURL", URL.class); method.setAccessible(true); - method.invoke(urlClassLoader, new Object[]{url}); + method.invoke(urlClassLoader, url); } /* diff --git a/src/main/java/the/bytecode/club/bootloader/ILoader.java b/src/main/java/the/bytecode/club/bootloader/ILoader.java index 479d7152..a75ea98a 100644 --- a/src/main/java/the/bytecode/club/bootloader/ILoader.java +++ b/src/main/java/the/bytecode/club/bootloader/ILoader.java @@ -24,11 +24,11 @@ import the.bytecode.club.bootloader.resource.ExternalResource; * @author Bibl (don't ban me pls) * @created 19 Jul 2015 02:29:43 */ -public abstract interface ILoader { +public interface ILoader { - public abstract void bind(ExternalResource resource); + void bind(ExternalResource resource); - abstract Class findClass(String name) throws ClassNotFoundException, NoClassDefFoundError; + Class findClass(String name) throws ClassNotFoundException, NoClassDefFoundError; - public abstract Class loadClass(String name) throws ClassNotFoundException, NoClassDefFoundError; + Class loadClass(String name) throws ClassNotFoundException, NoClassDefFoundError; } \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bootloader/InitialBootScreen.java b/src/main/java/the/bytecode/club/bootloader/InitialBootScreen.java index abf5d75d..b10584ac 100644 --- a/src/main/java/the/bytecode/club/bootloader/InitialBootScreen.java +++ b/src/main/java/the/bytecode/club/bootloader/InitialBootScreen.java @@ -7,15 +7,12 @@ import java.awt.Insets; import java.awt.Toolkit; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; -import java.awt.event.WindowStateListener; import java.io.IOException; - import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JProgressBar; import javax.swing.JScrollPane; import javax.swing.text.html.HTMLEditorKit; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.Resources; @@ -45,7 +42,7 @@ import the.bytecode.club.bytecodeviewer.Resources; public class InitialBootScreen extends JFrame { private static final long serialVersionUID = -1098467609722393444L; - private JProgressBar progressBar = new JProgressBar(); + private final JProgressBar progressBar = new JProgressBar(); public InitialBootScreen() throws IOException { setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); @@ -71,9 +68,11 @@ public class InitialBootScreen extends JFrame { setTitle("Bytecode Viewer Boot Screen - Starting Up"); GridBagLayout gridBagLayout = new GridBagLayout(); gridBagLayout.columnWidths = new int[]{0, 0}; - gridBagLayout.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + gridBagLayout.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0}; gridBagLayout.columnWeights = new double[]{1.0, Double.MIN_VALUE}; - gridBagLayout.rowWeights = new double[]{1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + gridBagLayout.rowWeights = new double[]{1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; getContentPane().setLayout(gridBagLayout); JScrollPane scrollPane = new JScrollPane(); @@ -88,7 +87,8 @@ public class InitialBootScreen extends JFrame { JEditorPane editorPane = new JEditorPane(); editorPane.setEditorKit(new HTMLEditorKit()); - editorPane.setText(convertStreamToString(InitialBootScreen.class.getClassLoader().getResourceAsStream("intro.html"))); + editorPane.setText(convertStreamToString(InitialBootScreen.class.getClassLoader().getResourceAsStream("intro" + + ".html"))); scrollPane.setViewportView(editorPane); diff --git a/src/main/java/the/bytecode/club/bootloader/LibraryClassLoader.java b/src/main/java/the/bytecode/club/bootloader/LibraryClassLoader.java index 7538aa63..0561c088 100644 --- a/src/main/java/the/bytecode/club/bootloader/LibraryClassLoader.java +++ b/src/main/java/the/bytecode/club/bootloader/LibraryClassLoader.java @@ -6,11 +6,9 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; - import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.tree.ClassNode; - import the.bytecode.club.bootloader.resource.ExternalResource; import the.bytecode.club.bootloader.resource.JarContents; import the.bytecode.club.bootloader.util.ClassTree; @@ -36,8 +34,8 @@ import the.bytecode.club.bootloader.util.ClassTree; /** * @author Bibl (don't ban me pls) * @created 19 Jul 2015 02:48:41 - *

- * TODO: Resource loading + *

+ * TODO: Resource loading */ @Deprecated public class LibraryClassLoader extends ClassLoader implements ILoader> { @@ -53,7 +51,8 @@ public class LibraryClassLoader extends ClassLoader implements ILoader> resource) { diff --git a/src/main/java/the/bytecode/club/bootloader/LoaderFactory.java b/src/main/java/the/bytecode/club/bootloader/LoaderFactory.java index f72b40ec..32bece81 100644 --- a/src/main/java/the/bytecode/club/bootloader/LoaderFactory.java +++ b/src/main/java/the/bytecode/club/bootloader/LoaderFactory.java @@ -22,7 +22,7 @@ package the.bytecode.club.bootloader; * @author Bibl (don't ban me pls) * @created 21 Jul 2015 00:14:53 */ -public abstract interface LoaderFactory { +public interface LoaderFactory { - public abstract ILoader spawnLoader(); + ILoader spawnLoader(); } \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bootloader/resource/ExternalLibrary.java b/src/main/java/the/bytecode/club/bootloader/resource/ExternalLibrary.java index 40e54242..e1fb2f2a 100644 --- a/src/main/java/the/bytecode/club/bootloader/resource/ExternalLibrary.java +++ b/src/main/java/the/bytecode/club/bootloader/resource/ExternalLibrary.java @@ -9,7 +9,6 @@ import java.net.URL; import java.util.Enumeration; import java.util.jar.JarEntry; import java.util.jar.JarFile; - import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; diff --git a/src/main/java/the/bytecode/club/bootloader/resource/ExternalResource.java b/src/main/java/the/bytecode/club/bootloader/resource/ExternalResource.java index 3bd4d301..f0623430 100644 --- a/src/main/java/the/bytecode/club/bootloader/resource/ExternalResource.java +++ b/src/main/java/the/bytecode/club/bootloader/resource/ExternalResource.java @@ -59,11 +59,8 @@ public abstract class ExternalResource { return false; ExternalResource other = (ExternalResource) obj; if (location == null) { - if (other.location != null) - return false; - } else if (!location.equals(other.location)) - return false; - return true; + return other.location == null; + } else return location.equals(other.location); } @Override diff --git a/src/main/java/the/bytecode/club/bootloader/resource/JarContents.java b/src/main/java/the/bytecode/club/bootloader/resource/JarContents.java index 696e3028..4fa89765 100644 --- a/src/main/java/the/bytecode/club/bootloader/resource/JarContents.java +++ b/src/main/java/the/bytecode/club/bootloader/resource/JarContents.java @@ -6,7 +6,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; - import org.objectweb.asm.tree.ClassNode; /*************************************************************************** diff --git a/src/main/java/the/bytecode/club/bootloader/resource/JarInfo.java b/src/main/java/the/bytecode/club/bootloader/resource/JarInfo.java index dd412a1e..f89d42e6 100644 --- a/src/main/java/the/bytecode/club/bootloader/resource/JarInfo.java +++ b/src/main/java/the/bytecode/club/bootloader/resource/JarInfo.java @@ -114,8 +114,6 @@ public class JarInfo { return false; } else if (!path.equals(other.path)) return false; - if (type != other.type) - return false; - return true; + return type == other.type; } } \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bootloader/resource/JarResource.java b/src/main/java/the/bytecode/club/bootloader/resource/JarResource.java index e87c5a07..18519dd8 100644 --- a/src/main/java/the/bytecode/club/bootloader/resource/JarResource.java +++ b/src/main/java/the/bytecode/club/bootloader/resource/JarResource.java @@ -63,10 +63,7 @@ public class JarResource { if (!Arrays.equals(data, other.data)) return false; if (name == null) { - if (other.name != null) - return false; - } else if (!name.equals(other.name)) - return false; - return true; + return other.name == null; + } else return name.equals(other.name); } } \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bootloader/resource/JarType.java b/src/main/java/the/bytecode/club/bootloader/resource/JarType.java index af6bb115..350ede3d 100644 --- a/src/main/java/the/bytecode/club/bootloader/resource/JarType.java +++ b/src/main/java/the/bytecode/club/bootloader/resource/JarType.java @@ -37,7 +37,7 @@ public enum JarType { private final String prefix; - private JarType(String prefix) { + JarType(String prefix) { this.prefix = prefix; } diff --git a/src/main/java/the/bytecode/club/bootloader/resource/LocateableJarContents.java b/src/main/java/the/bytecode/club/bootloader/resource/LocateableJarContents.java index e05d2de3..b7cc5da5 100644 --- a/src/main/java/the/bytecode/club/bootloader/resource/LocateableJarContents.java +++ b/src/main/java/the/bytecode/club/bootloader/resource/LocateableJarContents.java @@ -1,7 +1,6 @@ package the.bytecode.club.bootloader.resource; import java.net.URL; - import org.objectweb.asm.tree.ClassNode; /*************************************************************************** @@ -35,7 +34,8 @@ public class LocateableJarContents extends JarContents { this.jarUrls = jarUrls; } - public LocateableJarContents(DataContainer classContents, DataContainer resourceContents, URL... jarUrls) { + public LocateableJarContents(DataContainer classContents, DataContainer resourceContents, + URL... jarUrls) { super(classContents, resourceContents); this.jarUrls = jarUrls; } diff --git a/src/main/java/the/bytecode/club/bootloader/util/Base64.java b/src/main/java/the/bytecode/club/bootloader/util/Base64.java index 23704c50..69ba4f01 100644 --- a/src/main/java/the/bytecode/club/bootloader/util/Base64.java +++ b/src/main/java/the/bytecode/club/bootloader/util/Base64.java @@ -1,25 +1,27 @@ package the.bytecode.club.bootloader.util; import java.io.FilterOutputStream; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import java.util.*; +import java.util.Arrays; +import java.util.Objects; public class Base64 { - private Base64() {} + private Base64() { + } /** * Returns a {@link Encoder} that encodes using the * Basic type base64 encoding scheme. * - * @return A Base64 encoder. + * @return A Base64 encoder. */ public static Encoder getEncoder() { - return Encoder.RFC4648; + return Encoder.RFC4648; } /** @@ -27,17 +29,17 @@ public class Base64 { * URL and Filename safe type base64 * encoding scheme. * - * @return A Base64 encoder. + * @return A Base64 encoder. */ public static Encoder getUrlEncoder() { - return Encoder.RFC4648_URLSAFE; + return Encoder.RFC4648_URLSAFE; } /** * Returns a {@link Encoder} that encodes using the * MIME type base64 encoding scheme. * - * @return A Base64 encoder. + * @return A Base64 encoder. */ public static Encoder getMimeEncoder() { return Encoder.RFC2045; @@ -48,41 +50,37 @@ public class Base64 { * MIME type base64 encoding scheme * with specified line length and line separators. * - * @param lineLength - * the length of each output line (rounded down to nearest multiple - * of 4). If {@code lineLength <= 0} the output will not be separated - * in lines - * @param lineSeparator - * the line separator for each output line - * - * @return A Base64 encoder. - * - * @throws IllegalArgumentException if {@code lineSeparator} includes any - * character of "The Base64 Alphabet" as specified in Table 1 of - * RFC 2045. + * @param lineLength the length of each output line (rounded down to nearest multiple + * of 4). If {@code lineLength <= 0} the output will not be separated + * in lines + * @param lineSeparator the line separator for each output line + * @return A Base64 encoder. + * @throws IllegalArgumentException if {@code lineSeparator} includes any + * character of "The Base64 Alphabet" as specified in Table 1 of + * RFC 2045. */ public static Encoder getMimeEncoder(int lineLength, byte[] lineSeparator) { - Objects.requireNonNull(lineSeparator); - int[] base64 = Decoder.fromBase64; - for (byte b : lineSeparator) { - if (base64[b & 0xff] != -1) - throw new IllegalArgumentException( - "Illegal base64 line separator character 0x" + Integer.toString(b, 16)); - } - if (lineLength <= 0) { - return Encoder.RFC4648; - } - return new Encoder(false, lineSeparator, lineLength >> 2 << 2, true); + Objects.requireNonNull(lineSeparator); + int[] base64 = Decoder.fromBase64; + for (byte b : lineSeparator) { + if (base64[b & 0xff] != -1) + throw new IllegalArgumentException( + "Illegal base64 line separator character 0x" + Integer.toString(b, 16)); + } + if (lineLength <= 0) { + return Encoder.RFC4648; + } + return new Encoder(false, lineSeparator, lineLength >> 2 << 2, true); } /** * Returns a {@link Decoder} that decodes using the * Basic type base64 encoding scheme. * - * @return A Base64 decoder. + * @return A Base64 decoder. */ public static Decoder getDecoder() { - return Decoder.RFC4648; + return Decoder.RFC4648; } /** @@ -90,20 +88,20 @@ public class Base64 { * URL and Filename safe type base64 * encoding scheme. * - * @return A Base64 decoder. + * @return A Base64 decoder. */ public static Decoder getUrlDecoder() { - return Decoder.RFC4648_URLSAFE; + return Decoder.RFC4648_URLSAFE; } /** * Returns a {@link Decoder} that decodes using the * MIME type base64 decoding scheme. * - * @return A Base64 decoder. + * @return A Base64 decoder. */ public static Decoder getMimeDecoder() { - return Decoder.RFC2045; + return Decoder.RFC2045; } /** @@ -118,8 +116,8 @@ public class Base64 { * {@link java.lang.NullPointerException NullPointerException} to * be thrown. * - * @see Decoder - * @since 1.8 + * @see Decoder + * @since 1.8 */ public static class Encoder { @@ -141,11 +139,11 @@ public class Base64 { * in "Table 1: The Base64 Alphabet" of RFC 2045 (and RFC 4648). */ private static final char[] toBase64 = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; /** @@ -154,15 +152,15 @@ public class Base64 { * '_'. This table is used when BASE64_URL is specified. */ private static final char[] toBase64URL = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' }; private static final int MIMELINEMAX = 76; - private static final byte[] CRLF = new byte[] {'\r', '\n'}; + private static final byte[] CRLF = new byte[]{'\r', '\n'}; static final Encoder RFC4648 = new Encoder(false, null, -1, true); static final Encoder RFC4648_URLSAFE = new Encoder(true, null, -1, true); @@ -186,17 +184,16 @@ public class Base64 { * byte array using the {@link Base64} encoding scheme. The returned byte * array is of the length of the resulting bytes. * - * @param src - * the byte array to encode - * @return A newly-allocated byte array containing the resulting - * encoded bytes. + * @param src the byte array to encode + * @return A newly-allocated byte array containing the resulting + * encoded bytes. */ public byte[] encode(byte[] src) { int len = outLength(src.length); // dst array size byte[] dst = new byte[len]; int ret = encode0(src, 0, src.length, dst); if (ret != dst.length) - return Arrays.copyOf(dst, ret); + return Arrays.copyOf(dst, ret); return dst; } @@ -210,20 +207,17 @@ public class Base64 { * all bytes from the input byte array. No bytes will be written to the * output byte array if the output byte array is not big enough. * - * @param src - * the byte array to encode - * @param dst - * the output byte array - * @return The number of bytes written to the output byte array - * - * @throws IllegalArgumentException if {@code dst} does not have enough - * space for encoding all input bytes. + * @param src the byte array to encode + * @param dst the output byte array + * @return The number of bytes written to the output byte array + * @throws IllegalArgumentException if {@code dst} does not have enough + * space for encoding all input bytes. */ public int encode(byte[] src, byte[] dst) { int len = outLength(src.length); // dst array size if (dst.length < len) throw new IllegalArgumentException( - "Output byte array is too small for encoding all input bytes"); + "Output byte array is too small for encoding all input bytes"); return encode0(src, 0, src.length, dst); } @@ -240,9 +234,8 @@ public class Base64 { * effect as invoking * {@code new String(encode(src), StandardCharsets.ISO_8859_1)}. * - * @param src - * the byte array to encode - * @return A String containing the resulting Base64 encoded characters + * @param src the byte array to encode + * @return A String containing the resulting Base64 encoded characters */ @SuppressWarnings("deprecation") public String encodeToString(byte[] src) { @@ -254,15 +247,14 @@ public class Base64 { * Encodes all remaining bytes from the specified byte buffer into * a newly-allocated ByteBuffer using the {@link Base64} encoding * scheme. - * + *

* Upon return, the source buffer's position will be updated to * its limit; its limit will not have been changed. The returned * output buffer's position will be zero and its limit will be the * number of resulting encoded bytes. * - * @param buffer - * the source ByteBuffer to encode - * @return A newly-allocated byte buffer containing the encoded bytes. + * @param buffer the source ByteBuffer to encode + * @return A newly-allocated byte buffer containing the encoded bytes. */ public ByteBuffer encode(ByteBuffer buffer) { int len = outLength(buffer.remaining()); @@ -270,9 +262,9 @@ public class Base64 { int ret = 0; if (buffer.hasArray()) { ret = encode0(buffer.array(), - buffer.arrayOffset() + buffer.position(), - buffer.arrayOffset() + buffer.limit(), - dst); + buffer.arrayOffset() + buffer.position(), + buffer.arrayOffset() + buffer.limit(), + dst); buffer.position(buffer.limit()); } else { byte[] src = new byte[buffer.remaining()]; @@ -280,7 +272,7 @@ public class Base64 { ret = encode0(src, 0, src.length, dst); } if (ret != dst.length) - dst = Arrays.copyOf(dst, ret); + dst = Arrays.copyOf(dst, ret); return ByteBuffer.wrap(dst); } @@ -293,15 +285,14 @@ public class Base64 { * output stream. Closing the returned output stream will close the underlying * output stream. * - * @param os - * the output stream. - * @return the output stream for encoding the byte data into the - * specified Base64 encoded format + * @param os the output stream. + * @return the output stream for encoding the byte data into the + * specified Base64 encoded format */ public OutputStream wrap(OutputStream os) { Objects.requireNonNull(os); return new EncOutputStream(os, isURL ? toBase64URL : toBase64, - newline, linemax, doPadding); + newline, linemax, doPadding); } /** @@ -327,42 +318,42 @@ public class Base64 { int sp = off; int slen = (end - off) / 3 * 3; int sl = off + slen; - if (linemax > 0 && slen > linemax / 4 * 3) + if (linemax > 0 && slen > linemax / 4 * 3) slen = linemax / 4 * 3; int dp = 0; while (sp < sl) { int sl0 = Math.min(sp + slen, sl); - for (int sp0 = sp, dp0 = dp ; sp0 < sl0; ) { + for (int sp0 = sp, dp0 = dp; sp0 < sl0; ) { int bits = (src[sp0++] & 0xff) << 16 | - (src[sp0++] & 0xff) << 8 | - (src[sp0++] & 0xff); - dst[dp0++] = (byte)base64[(bits >>> 18) & 0x3f]; - dst[dp0++] = (byte)base64[(bits >>> 12) & 0x3f]; - dst[dp0++] = (byte)base64[(bits >>> 6) & 0x3f]; - dst[dp0++] = (byte)base64[bits & 0x3f]; + (src[sp0++] & 0xff) << 8 | + (src[sp0++] & 0xff); + dst[dp0++] = (byte) base64[(bits >>> 18) & 0x3f]; + dst[dp0++] = (byte) base64[(bits >>> 12) & 0x3f]; + dst[dp0++] = (byte) base64[(bits >>> 6) & 0x3f]; + dst[dp0++] = (byte) base64[bits & 0x3f]; } int dlen = (sl0 - sp) / 3 * 4; dp += dlen; sp = sl0; if (dlen == linemax && sp < end) { - for (byte b : newline){ + for (byte b : newline) { dst[dp++] = b; } } } if (sp < end) { // 1 or 2 leftover bytes int b0 = src[sp++] & 0xff; - dst[dp++] = (byte)base64[b0 >> 2]; + dst[dp++] = (byte) base64[b0 >> 2]; if (sp == end) { - dst[dp++] = (byte)base64[(b0 << 4) & 0x3f]; + dst[dp++] = (byte) base64[(b0 << 4) & 0x3f]; if (doPadding) { dst[dp++] = '='; dst[dp++] = '='; } } else { int b1 = src[sp++] & 0xff; - dst[dp++] = (byte)base64[(b0 << 4) & 0x3f | (b1 >> 4)]; - dst[dp++] = (byte)base64[(b1 << 2) & 0x3f]; + dst[dp++] = (byte) base64[(b0 << 4) & 0x3f | (b1 >> 4)]; + dst[dp++] = (byte) base64[(b1 << 2) & 0x3f]; if (doPadding) { dst[dp++] = '='; } @@ -395,8 +386,8 @@ public class Base64 { * {@link java.lang.NullPointerException NullPointerException} to * be thrown. * - * @see Encoder - * @since 1.8 + * @see Encoder + * @since 1.8 */ public static class Decoder { @@ -414,9 +405,9 @@ public class Base64 { * their 6-bit positive integer equivalents. Characters that * are not in the Base64 alphabet but fall within the bounds of * the array are encoded to -1. - * */ private static final int[] fromBase64 = new int[256]; + static { Arrays.fill(fromBase64, -1); for (int i = 0; i < Encoder.toBase64.length; i++) @@ -437,9 +428,9 @@ public class Base64 { fromBase64URL['='] = -2; } - static final Decoder RFC4648 = new Decoder(false, false); + static final Decoder RFC4648 = new Decoder(false, false); static final Decoder RFC4648_URLSAFE = new Decoder(true, false); - static final Decoder RFC2045 = new Decoder(false, true); + static final Decoder RFC2045 = new Decoder(false, true); /** * Decodes all bytes from the input byte array using the {@link Base64} @@ -447,13 +438,9 @@ public class Base64 { * byte array. The returned byte array is of the length of the resulting * bytes. * - * @param src - * the byte array to decode - * - * @return A newly-allocated byte array containing the decoded bytes. - * - * @throws IllegalArgumentException - * if {@code src} is not in valid Base64 scheme + * @param src the byte array to decode + * @return A newly-allocated byte array containing the decoded bytes. + * @throws IllegalArgumentException if {@code src} is not in valid Base64 scheme */ public byte[] decode(byte[] src) { byte[] dst = new byte[outLength(src, 0, src.length)]; @@ -471,13 +458,9 @@ public class Base64 { *

An invocation of this method has exactly the same effect as invoking * {@code decode(src.getBytes(StandardCharsets.ISO_8859_1))} * - * @param src - * the string to decode - * - * @return A newly-allocated byte array containing the decoded bytes. - * - * @throws IllegalArgumentException - * if {@code src} is not in valid Base64 scheme + * @param src the string to decode + * @return A newly-allocated byte array containing the decoded bytes. + * @throws IllegalArgumentException if {@code src} is not in valid Base64 scheme */ public byte[] decode(String src) { return decode(src.getBytes(StandardCharsets.ISO_8859_1)); @@ -497,22 +480,17 @@ public class Base64 { * then some bytes may have been written to the output byte array before * IllegalargumentException is thrown. * - * @param src - * the byte array to decode - * @param dst - * the output byte array - * - * @return The number of bytes written to the output byte array - * - * @throws IllegalArgumentException - * if {@code src} is not in valid Base64 scheme, or {@code dst} - * does not have enough space for decoding all input bytes. + * @param src the byte array to decode + * @param dst the output byte array + * @return The number of bytes written to the output byte array + * @throws IllegalArgumentException if {@code src} is not in valid Base64 scheme, or {@code dst} + * does not have enough space for decoding all input bytes. */ public int decode(byte[] src, byte[] dst) { int len = outLength(src, 0, src.length); if (dst.length < len) throw new IllegalArgumentException( - "Output byte array is too small for decoding all input bytes"); + "Output byte array is too small for decoding all input bytes"); return decode0(src, 0, src.length, dst); } @@ -529,13 +507,9 @@ public class Base64 { * is not in valid Base64 encoding scheme. The position of the input * buffer will not be advanced in this case. * - * @param buffer - * the ByteBuffer to decode - * - * @return A newly-allocated byte buffer containing the decoded bytes - * - * @throws IllegalArgumentException - * if {@code src} is not in valid Base64 scheme. + * @param buffer the ByteBuffer to decode + * @return A newly-allocated byte buffer containing the decoded bytes + * @throws IllegalArgumentException if {@code src} is not in valid Base64 scheme. */ public ByteBuffer decode(ByteBuffer buffer) { int pos0 = buffer.position(); @@ -570,11 +544,9 @@ public class Base64 { *

Closing the returned input stream will close the underlying * input stream. * - * @param is - * the input stream - * - * @return the input stream for decoding the specified Base64 encoded - * byte stream + * @param is the input stream + * @return the input stream for decoding the specified Base64 encoded + * byte stream */ public InputStream wrap(InputStream is) { Objects.requireNonNull(is); @@ -591,7 +563,7 @@ public class Base64 { if (isMIME && base64[0] == -1) return 0; throw new IllegalArgumentException( - "Input byte[] should at least have 2 bytes for base64 bytes"); + "Input byte[] should at least have 2 bytes for base64 bytes"); } if (isMIME) { // scan all bytes to fill out all non-alphabet. a performance @@ -614,7 +586,7 @@ public class Base64 { paddings++; } } - if (paddings == 0 && (len & 0x3) != 0) + if (paddings == 0 && (len & 0x3) != 0) paddings = 4 - (len & 0x3); return 3 * ((len + 3) / 4) - paddings; } @@ -634,9 +606,9 @@ public class Base64 { // xx= shiftto==6&&sp==sl missing last = // xx=y shiftto==6 last is not = if (shiftto == 6 && (sp == sl || src[sp++] != '=') || - shiftto == 18) { + shiftto == 18) { throw new IllegalArgumentException( - "Input byte array has wrong 4-byte ending unit"); + "Input byte array has wrong 4-byte ending unit"); } break; } @@ -644,29 +616,29 @@ public class Base64 { continue; else throw new IllegalArgumentException( - "Illegal base64 character " + - Integer.toString(src[sp - 1], 16)); + "Illegal base64 character " + + Integer.toString(src[sp - 1], 16)); } bits |= (b << shiftto); shiftto -= 6; if (shiftto < 0) { - dst[dp++] = (byte)(bits >> 16); - dst[dp++] = (byte)(bits >> 8); - dst[dp++] = (byte)(bits); + dst[dp++] = (byte) (bits >> 16); + dst[dp++] = (byte) (bits >> 8); + dst[dp++] = (byte) (bits); shiftto = 18; bits = 0; } } // reached end of byte array or hit padding '=' characters. if (shiftto == 6) { - dst[dp++] = (byte)(bits >> 16); + dst[dp++] = (byte) (bits >> 16); } else if (shiftto == 0) { - dst[dp++] = (byte)(bits >> 16); - dst[dp++] = (byte)(bits >> 8); + dst[dp++] = (byte) (bits >> 16); + dst[dp++] = (byte) (bits >> 8); } else if (shiftto == 12) { // dangling single "x", incorrectly encoded. throw new IllegalArgumentException( - "Last unit does not have enough valid bits"); + "Last unit does not have enough valid bits"); } // anything left is invalid, if is not MIME. // if MIME, ignore all non-base64 character @@ -674,7 +646,7 @@ public class Base64 { if (isMIME && base64[src[sp++]] < 0) continue; throw new IllegalArgumentException( - "Input byte array has incorrect ending byte at " + sp); + "Input byte array has incorrect ending byte at " + sp); } return dp; } @@ -707,7 +679,7 @@ public class Base64 { @Override public void write(int b) throws IOException { byte[] buf = new byte[1]; - buf[0] = (byte)(b & 0xff); + buf[0] = (byte) (b & 0xff); write(buf, 0, 1); } @@ -749,14 +721,14 @@ public class Base64 { while (nBits24-- > 0) { checkNewline(); int bits = (b[off++] & 0xff) << 16 | - (b[off++] & 0xff) << 8 | - (b[off++] & 0xff); + (b[off++] & 0xff) << 8 | + (b[off++] & 0xff); out.write(base64[(bits >>> 18) & 0x3f]); out.write(base64[(bits >>> 12) & 0x3f]); - out.write(base64[(bits >>> 6) & 0x3f]); + out.write(base64[(bits >>> 6) & 0x3f]); out.write(base64[bits & 0x3f]); linepos += 4; - } + } if (leftover == 1) { b0 = b[off++] & 0xff; } else if (leftover == 2) { @@ -783,7 +755,7 @@ public class Base64 { out.write(base64[(b0 << 4) & 0x3f | (b1 >> 4)]); out.write(base64[(b1 << 2) & 0x3f]); if (doPadding) { - out.write('='); + out.write('='); } } leftover = 0; @@ -802,9 +774,9 @@ public class Base64 { private final int[] base64; // base64 -> byte mapping private int bits = 0; // 24-bit buffer for decoding private int nextin = 18; // next available "off" in "bits" for input; - // -> 18, 12, 6, 0 + // -> 18, 12, 6, 0 private int nextout = -8; // next available "off" in "bits" for output; - // -> 8, 0, -8 (no byte for output) + // -> 8, 0, -8 (no byte for output) private boolean eof = false; private boolean closed = false; @@ -814,7 +786,7 @@ public class Base64 { this.isMIME = isMIME; } - private byte[] sbBuf = new byte[1]; + private final byte[] sbBuf = new byte[1]; @Override public int read() throws IOException { @@ -834,7 +806,7 @@ public class Base64 { do { if (len == 0) return off - oldOff; - b[off++] = (byte)(bits >> nextout); + b[off++] = (byte) (bits >> nextout); len--; nextout -= 8; } while (nextout >= 0); @@ -849,14 +821,14 @@ public class Base64 { throw new IOException("Base64 stream has one un-decoded dangling byte."); // treat ending xx/xxx without padding character legal. // same logic as v == '=' below - b[off++] = (byte)(bits >> (16)); + b[off++] = (byte) (bits >> (16)); len--; if (nextin == 0) { // only one padding byte if (len == 0) { // no enough output space bits >>= 8; // shift to lowest byte nextout = 0; } else { - b[off++] = (byte) (bits >> 8); + b[off++] = (byte) (bits >> 8); } } } @@ -871,17 +843,17 @@ public class Base64 { // xx= shiftto==6 && missing last '=' // xx=y or last is not '=' if (nextin == 18 || nextin == 12 || - nextin == 6 && is.read() != '=') { + nextin == 6 && is.read() != '=') { throw new IOException("Illegal base64 ending sequence:" + nextin); } - b[off++] = (byte)(bits >> (16)); + b[off++] = (byte) (bits >> (16)); len--; if (nextin == 0) { // only one padding byte if (len == 0) { // no enough output space bits >>= 8; // shift to lowest byte nextout = 0; } else { - b[off++] = (byte) (bits >> 8); + b[off++] = (byte) (bits >> 8); } } eof = true; @@ -892,14 +864,14 @@ public class Base64 { continue; else throw new IOException("Illegal base64 character " + - Integer.toString(v, 16)); + Integer.toString(v, 16)); } bits |= (v << nextin); if (nextin == 0) { nextin = 18; // clear for next nextout = 16; while (nextout >= 0) { - b[off++] = (byte)(bits >> nextout); + b[off++] = (byte) (bits >> nextout); len--; nextout -= 8; if (len == 0 && nextout >= 0) { // don't clean "bits" diff --git a/src/main/java/the/bytecode/club/bootloader/util/ClassHelper.java b/src/main/java/the/bytecode/club/bootloader/util/ClassHelper.java index 85ed1be9..cd9c4121 100644 --- a/src/main/java/the/bytecode/club/bootloader/util/ClassHelper.java +++ b/src/main/java/the/bytecode/club/bootloader/util/ClassHelper.java @@ -4,7 +4,6 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; - import org.objectweb.asm.tree.ClassNode; /*************************************************************************** diff --git a/src/main/java/the/bytecode/club/bootloader/util/ClassTree.java b/src/main/java/the/bytecode/club/bootloader/util/ClassTree.java index c34330ce..b086a268 100644 --- a/src/main/java/the/bytecode/club/bootloader/util/ClassTree.java +++ b/src/main/java/the/bytecode/club/bootloader/util/ClassTree.java @@ -1,18 +1,17 @@ package the.bytecode.club.bootloader.util; -import static the.bytecode.club.bootloader.util.ClassHelper.convertToMap; -import static the.bytecode.club.bootloader.util.ClassHelper.copyOf; - import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; - import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; +import static the.bytecode.club.bootloader.util.ClassHelper.convertToMap; +import static the.bytecode.club.bootloader.util.ClassHelper.copyOf; + /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * @@ -133,7 +132,8 @@ public class ClassTree { classes.put(node.name, node); } - private void buildSubTree(Map classes, Collection superinterfaces, ClassNode current) { + private void buildSubTree(Map classes, Collection superinterfaces, + ClassNode current) { superinterfaces.add(current); for (String iface : current.interfaces) { ClassNode cs = classes.get(iface); diff --git a/src/main/java/the/bytecode/club/bootloader/util/ValueCreator.java b/src/main/java/the/bytecode/club/bootloader/util/ValueCreator.java index 64b5c796..97501bad 100644 --- a/src/main/java/the/bytecode/club/bootloader/util/ValueCreator.java +++ b/src/main/java/the/bytecode/club/bootloader/util/ValueCreator.java @@ -22,7 +22,7 @@ package the.bytecode.club.bootloader.util; * @author Bibl (don't ban me pls) * @created ages ago */ -public abstract interface ValueCreator { +public interface ValueCreator { - public abstract V create(); + V create(); } \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/BytecodeViewer.java b/src/main/java/the/bytecode/club/bytecodeviewer/BytecodeViewer.java index 61b82fe9..d9d2184c 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/BytecodeViewer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/BytecodeViewer.java @@ -1,6 +1,9 @@ package the.bytecode.club.bytecodeviewer; -import java.awt.*; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import java.awt.Desktop; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; @@ -18,23 +21,17 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.List; - import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.UIManager; import javax.swing.filechooser.FileFilter; - -import com.google.gson.reflect.TypeToken; import me.konloch.kontainer.io.DiskReader; import me.konloch.kontainer.io.DiskWriter; import me.konloch.kontainer.io.HTTPRequest; - import org.apache.commons.io.FileUtils; import org.objectweb.asm.tree.ClassNode; -import com.google.gson.*; - import the.bytecode.club.bootloader.Boot; import the.bytecode.club.bootloader.ILoader; import the.bytecode.club.bootloader.resource.EmptyExternalResource; @@ -49,7 +46,14 @@ import the.bytecode.club.bytecodeviewer.gui.SystemErrConsole; import the.bytecode.club.bytecodeviewer.gui.WorkPane; import the.bytecode.club.bytecodeviewer.obfuscators.mapping.Refactorer; import the.bytecode.club.bytecodeviewer.plugin.PluginManager; -import the.bytecode.club.bytecodeviewer.util.*; +import the.bytecode.club.bytecodeviewer.util.APKTool; +import the.bytecode.club.bytecodeviewer.util.Dex2Jar; +import the.bytecode.club.bytecodeviewer.util.Enjarify; +import the.bytecode.club.bytecodeviewer.util.FileContainer; +import the.bytecode.club.bytecodeviewer.util.JRTExtractor; +import the.bytecode.club.bytecodeviewer.util.JarUtils; +import the.bytecode.club.bytecodeviewer.util.LazyNameUtil; +import the.bytecode.club.bytecodeviewer.util.MiscUtils; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -71,63 +75,65 @@ import the.bytecode.club.bytecodeviewer.util.*; /** * TODO: - * open as folder doesn't actually work - * smali compile - * + * open as folder doesn't actually work + * smali compile + *

* A lightweight Java Reverse Engineering suite, developed by Konloch - http://konloch.me - * + *

* All you have to do is add a jar or class file into the workspace, * select the file you want then it will start decompiling the class in the background. * When it's done it will show the Source code, Bytecode and Hexcode of the class file you chose. - * + *

* There is also a plugin system that will allow you to interact with the loaded classfiles. * For example you can write a String deobfuscator, a malicious code searcher, * or anything else you can think of. - * + *

* You can either use one of the pre-written plugins, or write your own. It supports java scripting. * Once a plugin is activated, it will send a ClassNode ArrayList of every single class loaded in the * file system to the execute function, this allows the user to handle it completely using ASM. - * + *

* Are you a Java Reverse Engineer? Or maybe you want to learn Java Reverse Engineering? - * Join The Bytecode Club, we're noob friendly, and censorship free. - * http://the.bytecode.club - * - * TODO: - * Finish dragging code - * Finish right-click tab menu detection - * make it use that global last used inside of export as jar - * Add https://github.com/ptnkjke/Java-Bytecode-Editor visualize as a plugin - * make zipfile not include the decode shit - * add stackmapframes to bytecode decompiler - * make ez-injection plugin console show all sys.out calls - * add JEB decompiler optionally, requires them to add jeb library jar externally and disable update check ? - * add decompile as zip for krakatau-bytecode, jd-gui and smali for CLI - * add decompile all as zip for CLI - * fix hook inject for EZ-Injection - * fix classfile searcher - * make the decompilers launch in a separate process + * Join The Bytecode Club, we're noob friendly, and censorship free. + * http://the.bytecode.club + *

+ * TODO: + * Finish dragging code + * Finish right-click tab menu detection + * make it use that global last used inside of export as jar + * Add https://github.com/ptnkjke/Java-Bytecode-Editor visualize as a plugin + * make zipfile not include the decode shit + * add stackmapframes to bytecode decompiler + * make ez-injection plugin console show all sys.out calls + * add JEB decompiler optionally, requires them to add jeb library jar externally and disable update check ? + * add decompile as zip for krakatau-bytecode, jd-gui and smali for CLI + * add decompile all as zip for CLI + * fix hook inject for EZ-Injection + * fix classfile searcher + * make the decompilers launch in a separate process * * @author Konloch * @author The entire BCV community */ -public class BytecodeViewer -{ +public class BytecodeViewer { /*per version*/ public static final String VERSION = "2.9.23"; public static String krakatauVersion = "12"; public static String enjarifyVersion = "4"; public static final boolean BLOCK_TAB_MENU = true; public static final boolean PREVIEW_COPY = false; - public static final boolean FAT_JAR = true; //could be automatic by checking if it's loaded a class named whatever for a library + public static final boolean FAT_JAR = true; //could be automatic by checking if it's loaded a class named + // whatever for a library public static final boolean OFFLINE_MODE = true; //disables the automatic updater /*the rest*/ public static boolean verify = false; //eventually may be a setting public static String[] args; public static MainViewerGUI viewer = null; - public static ClassNodeLoader loader = new ClassNodeLoader(); //might be insecure due to assholes targeting BCV, however that's highly unlikely. - public static SecurityMan sm = new SecurityMan(); //might be insecure due to assholes targeting BCV, however that's highly unlikely. + public static ClassNodeLoader loader = new ClassNodeLoader(); //might be insecure due to assholes targeting BCV, + // however that's highly unlikely. + public static SecurityMan sm = new SecurityMan(); //might be insecure due to assholes targeting BCV, however + // that's highly unlikely. public static String python = ""; public static String python3 = ""; public static String rt = ""; @@ -142,21 +148,21 @@ public class BytecodeViewer public static boolean needsReDump = true; public static boolean warnForEditing = false; public static List files = new ArrayList(); //all of BCV's loaded files/classes/etc - private static int maxRecentFiles = 25; + private static final int maxRecentFiles = 25; public static String fs = System.getProperty("file.separator"); public static String nl = System.getProperty("line.separator"); - private static File BCVDir = new File(System.getProperty("user.home") + fs + ".Bytecode-Viewer"); + private static final File BCVDir = new File(System.getProperty("user.home") + fs + ".Bytecode-Viewer"); public static File RT_JAR = new File(System.getProperty("java.home") + fs + "lib" + fs + "rt.jar"); - public static File RT_JAR_DUMPED = new File(getBCVDirectory() + fs + "rt.jar"); - private static String filesName = getBCVDirectory() + fs + "recentfiles.json"; - private static String pluginsName = getBCVDirectory() + fs + "recentplugins.json"; + public static File RT_JAR_DUMPED = new File(getBCVDirectory() + fs + "rt.jar"); + private static final String filesName = getBCVDirectory() + fs + "recentfiles.json"; + private static final String pluginsName = getBCVDirectory() + fs + "recentplugins.json"; public static String settingsName = getBCVDirectory() + fs + "settings.bcv"; public static String tempDirectory = getBCVDirectory() + fs + "bcv_temp" + fs; public static String libsDirectory = getBCVDirectory() + fs + "libs" + fs; public static String krakatauWorkingDirectory = getBCVDirectory() + fs + "krakatau_" + krakatauVersion; public static String enjarifyWorkingDirectory = getBCVDirectory() + fs + "enjarify_" + enjarifyVersion; public static boolean runningObfuscation = false; - private static long start = System.currentTimeMillis(); + private static final long start = System.currentTimeMillis(); public static String lastDirectory = "."; public static List createdProcesses = new ArrayList(); public static Refactorer refactorer = new Refactorer(); @@ -168,23 +174,21 @@ public class BytecodeViewer private static List recentPlugins; private static List recentFiles; - static - { - try - { + static { + try { gson = new GsonBuilder().setPrettyPrinting().create(); - if(new File(filesName).exists()) - recentFiles = gson.fromJson(DiskReader.loadAsString(filesName), new TypeToken>() {}.getType()); + if (new File(filesName).exists()) + recentFiles = gson.fromJson(DiskReader.loadAsString(filesName), new TypeToken>() { + }.getType()); else recentFiles = DiskReader.loadArrayList(getBCVDirectory() + fs + "recentfiles.bcv", false); - if(new File(pluginsName).exists()) - recentPlugins = gson.fromJson(DiskReader.loadAsString(pluginsName), new TypeToken>() {}.getType()); + if (new File(pluginsName).exists()) + recentPlugins = gson.fromJson(DiskReader.loadAsString(pluginsName), new TypeToken>() { + }.getType()); else recentPlugins = DiskReader.loadArrayList(getBCVDirectory() + fs + "recentplugins.bcv", false); - } - catch (Exception e) - { + } catch (Exception e) { e.printStackTrace(); } } @@ -192,11 +196,12 @@ public class BytecodeViewer /** * The version checker thread */ - private static Thread versionChecker = new Thread() { + private static final Thread versionChecker = new Thread() { @Override public void run() { try { - HTTPRequest r = new HTTPRequest(new URL("https://raw.githubusercontent.com/Konloch/bytecode-viewer/master/VERSION")); + HTTPRequest r = new HTTPRequest(new URL("https://raw.githubusercontent" + + ".com/Konloch/bytecode-viewer/master/VERSION")); final String version = r.readSingle(); try { int simplemaths = Integer.parseInt(version.replace(".", "")); @@ -207,8 +212,7 @@ public class BytecodeViewer } - if (!BytecodeViewer.VERSION.equals(version)) - { + if (!BytecodeViewer.VERSION.equals(version)) { JOptionPane pane = new JOptionPane("Your version: " + BytecodeViewer.VERSION + ", latest version: " @@ -230,7 +234,8 @@ public class BytecodeViewer if (Desktop.isDesktopSupported()) { Desktop.getDesktop().browse(new URI("https://github.com/Konloch/bytecode-viewer/releases")); } else { - showMessage("Cannot open the page, please manually type it." + nl + "https://github.com/Konloch/bytecode-viewer/releases"); + showMessage("Cannot open the page, please manually type it." + nl + "https://github" + + ".com/Konloch/bytecode-viewer/releases"); } } if (result == 1) { @@ -283,15 +288,20 @@ public class BytecodeViewer @Override public void run() { try { - InputStream is = new URL("https://github.com/Konloch/bytecode-viewer/releases/download/v" + version + "/BytecodeViewer." + version + ".zip").openConnection().getInputStream(); + InputStream is = new URL("https://github.com/Konloch/bytecode-viewer/releases" + + "/download/v" + version + "/BytecodeViewer." + version + ".zip").openConnection().getInputStream(); FileOutputStream fos = new FileOutputStream(finalFile); try { - System.out.println("Downloading from https://github.com/Konloch/bytecode-viewer/releases/download/v" + version + "/BytecodeViewer." + version + ".zip"); + System.out.println("Downloading from https://github" + + ".com/Konloch/bytecode-viewer/releases/download/v" + version + + "/BytecodeViewer." + version + ".zip"); byte[] buffer = new byte[8192]; int len; int downloaded = 0; boolean flag = false; - showMessage("Downloading the jar in the background, when it's finished you will be alerted with another message box." + nl + nl + "Expect this to take several minutes."); + showMessage("Downloading the jar in the background, when it's finished " + + "you will be alerted with another message box." + nl + nl + + "Expect this to take several minutes."); while ((len = is.read(buffer)) > 0) { fos.write(buffer, 0, len); fos.flush(); @@ -319,17 +329,19 @@ public class BytecodeViewer System.out.println("Download finished!"); showMessage("Download successful! You can find the updated program at " + finalFile.getAbsolutePath()); } catch (FileNotFoundException e) { - try - { - InputStream is = new URL("https://github.com/Konloch/bytecode-viewer/releases/download/v" + version + "/BytecodeViewer." + version + ".jar").openConnection().getInputStream(); + try { + InputStream is = new URL("https://github.com/Konloch/bytecode-viewer" + + "/releases/download/v" + version + "/BytecodeViewer." + version + ".jar").openConnection().getInputStream(); FileOutputStream fos = new FileOutputStream(finalFile); try { - System.out.println("Downloading from https://github.com/Konloch/bytecode-viewer/releases/download/v" + version + "/BytecodeViewer." + version + ".jar"); + System.out.println("Downloading from https://github" + + ".com/Konloch/bytecode-viewer/releases/download/v" + version + "/BytecodeViewer." + version + ".jar"); byte[] buffer = new byte[8192]; int len; int downloaded = 0; boolean flag = false; - showMessage("Downloading the jar in the background, when it's finished you will be alerted with another message box." + nl + nl + "Expect this to take several minutes."); + showMessage("Downloading the jar in the background, when it's " + + "finished you will be alerted with another message box." + nl + nl + "Expect this to take several minutes."); while ((len = is.read(buffer)) > 0) { fos.write(buffer, 0, len); fos.flush(); @@ -356,12 +368,13 @@ public class BytecodeViewer } System.out.println("Download finished!"); showMessage("Download successful! You can find the updated program at " + finalFile.getAbsolutePath()); - } catch (FileNotFoundException ex) { - showMessage("Unable to download, the zip file has not been uploaded yet, please try again in about 10 minutes."); - } catch (Exception ex) { + } catch (FileNotFoundException ex) { + showMessage("Unable to download, the zip file has not been uploaded yet, " + + "please try again in about 10 minutes."); + } catch (Exception ex) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(ex); } - + } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); } @@ -381,7 +394,7 @@ public class BytecodeViewer /** * Pings back to bytecodeviewer.com to be added into the total running statistics */ - private static Thread PingBack = new Thread() { + private static final Thread PingBack = new Thread() { @Override public void run() { try { @@ -395,17 +408,14 @@ public class BytecodeViewer /** * Downloads & installs the krakatau & enjarify zips */ - private static Thread InstallFatJar = new Thread() { + private static final Thread InstallFatJar = new Thread() { @Override public void run() { try { - if(BytecodeViewer.OFFLINE_MODE) - { + if (BytecodeViewer.OFFLINE_MODE) { Boot.dropKrakatau(); Boot.dropEnjarify(); - } - else - { + } else { Boot.populateUrlList(); Boot.populateLibsDirectory(); Boot.downloadZipsOnly(); @@ -421,7 +431,7 @@ public class BytecodeViewer /** * Used to check incase booting failed for some reason, this kicks in as a fail safe */ - private static Thread bootCheck = new Thread() { + private static final Thread bootCheck = new Thread() { boolean finished = false; @SuppressWarnings({"rawtypes", "unchecked"}) @@ -433,14 +443,17 @@ public class BytecodeViewer if (!Boot.completedboot && !Boot.downloading) { if (Boot.libsDir() == null || Boot.libsDir().listFiles() == null || Boot.libsDir().listFiles().length <= 0) { BytecodeViewer.showMessage( - "Github is loading extremely slow, BCV needs to download libraries from github in order" + nl + - "to work, please try ajusting your network settings or manually downloading these libraries" + nl + + "Github is loading extremely slow, BCV needs to download libraries from github in" + + " order" + nl + + "to work, please try ajusting your network settings or manually " + + "downloading these libraries" + nl + "if this error persists."); finished = true; return; } - Boot.setState("Bytecode Viewer Boot Screen (OFFLINE MODE) - Unable to connect to github, force booting..."); + Boot.setState("Bytecode Viewer Boot Screen (OFFLINE MODE) - Unable to connect to github, " + + "force booting..."); System.out.println("Unable to connect to github, force booting..."); List libsList = new ArrayList(); List libsFileList = new ArrayList(); @@ -456,7 +469,8 @@ public class BytecodeViewer if (s.endsWith(".jar")) { File f = new File(s); if (f.exists()) { - Boot.setState("Bytecode Viewer Boot Screen (OFFLINE MODE) - Force Loading Library " + f.getName()); + Boot.setState("Bytecode Viewer Boot Screen (OFFLINE MODE) - Force Loading Library" + + " " + f.getName()); System.out.println("Force loading library " + f.getName()); try { @@ -466,7 +480,8 @@ public class BytecodeViewer } catch (Exception e) { e.printStackTrace(); f.delete(); - JOptionPane.showMessageDialog(null, "Error, Library " + f.getName() + " is corrupt, please restart to redownload it.", + JOptionPane.showMessageDialog(null, "Error, Library " + f.getName() + " is " + + "corrupt, please restart to redownload it.", "Error", JOptionPane.ERROR_MESSAGE); } } @@ -521,14 +536,17 @@ public class BytecodeViewer */ public static void main(String[] args) { BytecodeViewer.args = args; - System.out.println("https://the.bytecode.club - Created by @Konloch - Bytecode Viewer " + VERSION +", Fat-Jar: " + FAT_JAR); + System.out.println("https://the.bytecode.club - Created by @Konloch - Bytecode Viewer " + VERSION + ", " + + "Fat-Jar: " + FAT_JAR); System.setSecurityManager(sm); try { UIManager.put("MenuItem.disabledAreNavigable", Boolean.FALSE); UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); if (PREVIEW_COPY && !CommandLineInput.containsCommand(args)) - showMessage("WARNING: This is a preview/dev copy, you WON'T be alerted when " + VERSION + " is actually out if you use this." + nl + - "Make sure to watch the repo: https://github.com/Konloch/bytecode-viewer for " + VERSION + "'s release"); + showMessage("WARNING: This is a preview/dev copy, you WON'T be alerted when " + VERSION + " is " + + "actually out if you use this." + nl + + "Make sure to watch the repo: https://github.com/Konloch/bytecode-viewer for " + VERSION + + "'s release"); viewer = new MainViewerGUI(); Settings.loadSettings(); @@ -541,10 +559,7 @@ public class BytecodeViewer if (!FAT_JAR) { bootCheck.start(); - if (CLI == CommandLineInput.OPEN_FILE) - Boot.boot(args, false); - else - Boot.boot(args, true); + Boot.boot(args, CLI != CommandLineInput.OPEN_FILE); } else InstallFatJar.start(); @@ -740,23 +755,23 @@ public class BytecodeViewer cv.smali2 != null && cv.smali2.isEditable() || cv.smali3 != null && cv.smali3.isEditable()) { actuallyTried = true; - Object smali[] = cv.getSmali(); + Object[] smali = cv.getSmali(); if (smali != null) { ClassNode origNode = (ClassNode) smali[0]; String smaliText = (String) smali[1]; - byte[] smaliCompiled = the.bytecode.club.bytecodeviewer.compilers.Compiler.smali.compile(smaliText, origNode.name); + byte[] smaliCompiled = + the.bytecode.club.bytecodeviewer.compilers.Compiler.smali.compile(smaliText, + origNode.name); if (smaliCompiled != null) { - try - { + try { ClassNode newNode = JarUtils.getNode(smaliCompiled); BytecodeViewer.updateNode(origNode, newNode); - } - catch(Exception e) - { + } catch (Exception e) { e.printStackTrace(); } } else { - BytecodeViewer.showMessage("There has been an error with assembling your Smali code, please check this. Class: " + origNode.name); + BytecodeViewer.showMessage("There has been an error with assembling your Smali code, " + + "please check this. Class: " + origNode.name); BytecodeViewer.viewer.setIcon(false); return false; } @@ -768,23 +783,23 @@ public class BytecodeViewer cv.krakatau2 != null && cv.krakatau2.isEditable() || cv.krakatau3 != null && cv.krakatau3.isEditable()) { actuallyTried = true; - Object krakatau[] = cv.getKrakatau(); + Object[] krakatau = cv.getKrakatau(); if (krakatau != null) { ClassNode origNode = (ClassNode) krakatau[0]; String krakatauText = (String) krakatau[1]; - byte[] krakatauCompiled = the.bytecode.club.bytecodeviewer.compilers.Compiler.krakatau.compile(krakatauText, origNode.name); + byte[] krakatauCompiled = + the.bytecode.club.bytecodeviewer.compilers.Compiler.krakatau.compile(krakatauText, + origNode.name); if (krakatauCompiled != null) { - try - { + try { ClassNode newNode = JarUtils.getNode(krakatauCompiled); BytecodeViewer.updateNode(origNode, newNode); - } - catch(Exception e) - { + } catch (Exception e) { e.printStackTrace(); } } else { - BytecodeViewer.showMessage("There has been an error with assembling your Krakatau Bytecode, please check this. Class: " + origNode.name); + BytecodeViewer.showMessage("There has been an error with assembling your Krakatau " + + "Bytecode, please check this. Class: " + origNode.name); BytecodeViewer.viewer.setIcon(false); return false; } @@ -795,23 +810,23 @@ public class BytecodeViewer cv.java2 != null && cv.java2.isEditable() || cv.java3 != null && cv.java3.isEditable()) { actuallyTried = true; - Object java[] = cv.getJava(); + Object[] java = cv.getJava(); if (java != null) { ClassNode origNode = (ClassNode) java[0]; String javaText = (String) java[1]; SystemErrConsole errConsole = new SystemErrConsole("Java Compile Issues"); - errConsole.setText("Error compiling class: " + origNode.name + nl + "Keep in mind most decompilers cannot produce compilable classes" + nl + nl); + errConsole.setText("Error compiling class: " + origNode.name + nl + "Keep in mind most " + + "decompilers cannot produce compilable classes" + nl + nl); - byte[] javaCompiled = the.bytecode.club.bytecodeviewer.compilers.Compiler.java.compile(javaText, origNode.name); + byte[] javaCompiled = + the.bytecode.club.bytecodeviewer.compilers.Compiler.java.compile(javaText, + origNode.name); if (javaCompiled != null) { - try - { + try { ClassNode newNode = JarUtils.getNode(javaCompiled); BytecodeViewer.updateNode(origNode, newNode); - } - catch(Exception e) - { + } catch (Exception e) { e.printStackTrace(); } errConsole.finished(); @@ -871,7 +886,8 @@ public class BytecodeViewer boolean finished = false; ArrayList totalFiles = new ArrayList(); totalFiles.add(f); - String dir = f.getAbsolutePath();//f.getAbsolutePath().substring(0, f.getAbsolutePath().length()-f.getName().length()); + String dir = f.getAbsolutePath();//f.getAbsolutePath().substring(0, f.getAbsolutePath + // ().length()-f.getName().length()); while (!finished) { boolean added = false; @@ -888,10 +904,12 @@ public class BytecodeViewer if (!added) { for (File child : totalFiles) if (child.isFile()) { - String fileName = child.getAbsolutePath().substring(dir.length() + 1, child.getAbsolutePath().length()).replaceAll("\\\\", "\\/"); + String fileName = child.getAbsolutePath().substring(dir.length() + 1 + ).replaceAll("\\\\", "\\/"); - files.put(fileName, Files.readAllBytes(Paths.get(child.getAbsolutePath()))); + files.put(fileName, + Files.readAllBytes(Paths.get(child.getAbsolutePath()))); } finished = true; } @@ -917,8 +935,10 @@ public class BytecodeViewer } else if (fn.endsWith(".class")) { try { byte[] bytes = JarUtils.getBytes(new FileInputStream(f)); - String cafebabe = String.format("%02X", bytes[0]) + String.format("%02X", bytes[1]) + String.format("%02X", bytes[2]) + String.format("%02X", bytes[3]); - if (cafebabe.toLowerCase().equals("cafebabe")) { + String cafebabe = String.format("%02X", bytes[0]) + String.format("%02X", + bytes[1]) + String.format("%02X", bytes[2]) + String.format("%02X", + bytes[3]); + if (cafebabe.equalsIgnoreCase("cafebabe")) { final ClassNode cn = JarUtils.getNode(bytes); FileContainer container = new FileContainer(f); @@ -936,19 +956,22 @@ public class BytecodeViewer try { BytecodeViewer.viewer.setIcon(true); - File tempCopy = new File(tempDirectory+fs+MiscUtils.randomString(32)+".apk"); + File tempCopy = new File(tempDirectory + fs + MiscUtils.randomString(32) + + ".apk"); FileUtils.copyFile(f, tempCopy); FileContainer container = new FileContainer(tempCopy, f.getName()); if (viewer.decodeAPKResources.isSelected()) { - File decodedResources = new File(tempDirectory + fs + MiscUtils.randomString(32) + ".apk"); + File decodedResources = + new File(tempDirectory + fs + MiscUtils.randomString(32) + ".apk"); APKTool.decodeResources(tempCopy, decodedResources, container); container.files = JarUtils.loadResources(decodedResources); } - container.files.putAll(JarUtils.loadResources(tempCopy)); //copy and rename to prevent unicode filenames + container.files.putAll(JarUtils.loadResources(tempCopy)); //copy and rename + // to prevent unicode filenames String name = getRandomizedName() + ".jar"; File output = new File(tempDirectory + fs + name); @@ -970,7 +993,8 @@ public class BytecodeViewer try { BytecodeViewer.viewer.setIcon(true); - File tempCopy = new File(tempDirectory+fs+MiscUtils.randomString(32)+".dex"); + File tempCopy = new File(tempDirectory + fs + MiscUtils.randomString(32) + + ".dex"); FileUtils.copyFile(f, tempCopy); //copy and rename to prevent unicode filenames @@ -1052,12 +1076,11 @@ public class BytecodeViewer * * @param ask if should require user input or not */ - public static void resetWorkSpace(boolean ask) - { - if(ask) - { + public static void resetWorkSpace(boolean ask) { + if (ask) { JOptionPane pane = new JOptionPane( - "Are you sure you want to reset the workspace?\n\rIt will also reset your file navigator and search."); + "Are you sure you want to reset the workspace?\n\rIt will also reset your file navigator and " + + "search."); Object[] options = new String[]{"Yes", "No"}; pane.setOptions(options); JDialog dialog = pane.createDialog(viewer, @@ -1081,7 +1104,7 @@ public class BytecodeViewer the.bytecode.club.bytecodeviewer.api.BytecodeViewer.getClassNodeLoader().clear(); } - private static List killList = new ArrayList(); + private static final List killList = new ArrayList(); /** * Add the recent file @@ -1100,8 +1123,8 @@ public class BytecodeViewer killList.clear(); } - if (recentFiles.contains(f.getAbsolutePath())) // already added on the list - recentFiles.remove(f.getAbsolutePath()); + // already added on the list + recentFiles.remove(f.getAbsolutePath()); if (recentFiles.size() >= maxRecentFiles) recentFiles.remove(maxRecentFiles - 1); // zero indexing @@ -1110,7 +1133,7 @@ public class BytecodeViewer resetRecentFilesMenu(); } - private static List killList2 = new ArrayList(); + private static final List killList2 = new ArrayList(); /** * Add to the recent plugin list @@ -1129,8 +1152,8 @@ public class BytecodeViewer killList2.clear(); } - if (recentPlugins.contains(f.getAbsolutePath())) // already added on the list - recentPlugins.remove(f.getAbsolutePath()); + // already added on the list + recentPlugins.remove(f.getAbsolutePath()); if (recentPlugins.size() >= maxRecentFiles) recentPlugins.remove(maxRecentFiles - 1); // zero indexing @@ -1286,10 +1309,9 @@ public class BytecodeViewer String extension = MiscUtils.extension(f.getAbsolutePath()); if (extension != null) - if (extension.equals("jar") || extension.equals("zip") + return extension.equals("jar") || extension.equals("zip") || extension.equals("class") || extension.equals("apk") - || extension.equals("dex")) - return true; + || extension.equals("dex"); return false; } @@ -1407,19 +1429,15 @@ public class BytecodeViewer } } - public static File[] dumpTempFile(FileContainer container) - { + public static File[] dumpTempFile(FileContainer container) { File[] files = new File[2]; //currently won't optimize if you've got two containers with the same name, will need to add this later - if(!LazyNameUtil.SAME_NAME_JAR_WORKSPACE) - { - if (krakatauTempJar != null && !krakatauTempJar.exists()) - { + if (!LazyNameUtil.SAME_NAME_JAR_WORKSPACE) { + if (krakatauTempJar != null && !krakatauTempJar.exists()) { needsReDump = true; } - if (needsReDump && krakatauTempJar != null) - { + if (needsReDump && krakatauTempJar != null) { krakatauTempDir = null; krakatauTempJar = null; } @@ -1439,8 +1457,7 @@ public class BytecodeViewer else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.panel3KrakatauBytecode.getModel())) passes = true; - if (krakatauTempJar != null || !passes) - { + if (krakatauTempJar != null || !passes) { files[0] = krakatauTempJar; files[1] = krakatauTempDir; return files; @@ -1448,21 +1465,25 @@ public class BytecodeViewer currentlyDumping = true; needsReDump = false; - krakatauTempDir = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32) + BytecodeViewer.fs); + krakatauTempDir = + new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32) + BytecodeViewer.fs); krakatauTempDir.mkdir(); - krakatauTempJar = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(32) + ".jar"); - //krakatauTempJar = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(32) + ".jar."+container.name); + krakatauTempJar = + new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(32) + ".jar"); + //krakatauTempJar = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils + // .randomString(32) + ".jar."+container.name); JarUtils.saveAsJarClassesOnly(container.classes, krakatauTempJar.getAbsolutePath()); currentlyDumping = false; - } - else - { + } else { currentlyDumping = true; needsReDump = false; - krakatauTempDir = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32) + BytecodeViewer.fs); + krakatauTempDir = + new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32) + BytecodeViewer.fs); krakatauTempDir.mkdir(); - krakatauTempJar = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(32) + ".jar"); - //krakatauTempJar = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(32) + ".jar."+container.name); + krakatauTempJar = + new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(32) + ".jar"); + //krakatauTempJar = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils + // .randomString(32) + ".jar."+container.name); JarUtils.saveAsJarClassesOnly(container.classes, krakatauTempJar.getAbsolutePath()); currentlyDumping = false; } @@ -1472,41 +1493,28 @@ public class BytecodeViewer return files; } - public synchronized static void rtCheck() - { - if(rt.equals("")) - { - if(RT_JAR.exists()) - { + public synchronized static void rtCheck() { + if (rt.equals("")) { + if (RT_JAR.exists()) { rt = RT_JAR.getAbsolutePath(); - } - else if(RT_JAR_DUMPED.exists()) - { + } else if (RT_JAR_DUMPED.exists()) { rt = RT_JAR_DUMPED.getAbsolutePath(); - } - else - { - try - { + } else { + try { JRTExtractor.extractRT(RT_JAR_DUMPED.getAbsolutePath()); rt = RT_JAR_DUMPED.getAbsolutePath(); - } - catch (Throwable t) - { + } catch (Throwable t) { t.printStackTrace(); } } } } - public static int fileContainersHash(ArrayList fileContainers) - { + public static int fileContainersHash(ArrayList fileContainers) { StringBuilder block = new StringBuilder(); - for(FileContainer container : fileContainers) - { + for (FileContainer container : fileContainers) { block.append(container.name); - for(ClassNode node : container.classes) - { + for (ClassNode node : container.classes) { block.append(node.name); } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/CommandLineInput.java b/src/main/java/the/bytecode/club/bytecodeviewer/CommandLineInput.java index 459996e6..19d4f5a1 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/CommandLineInput.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/CommandLineInput.java @@ -1,16 +1,13 @@ package the.bytecode.club.bytecodeviewer; import java.io.File; - import me.konloch.kontainer.io.DiskWriter; - import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.Options; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.tree.ClassNode; - import the.bytecode.club.bytecodeviewer.decompilers.Decompiler; import the.bytecode.club.bytecodeviewer.util.JarUtils; @@ -72,7 +69,7 @@ public class CommandLineInput { cmd.hasOption("o") || cmd.hasOption("t") || cmd.hasOption("nowait") - ) { + ) { return true; } } catch (Exception e) { @@ -103,7 +100,8 @@ public class CommandLineInput { "-decompiler Selects the decompiler, procyon by default", "-i Selects the input file", "-o Selects the output file", - "-t Must either be the fully qualified classname or \"all\" to decompile all as zip", + "-t Must either be the fully qualified classname or \"all\" to " + + "decompile all as zip", "-nowait Doesn't wait for the user to read the CLI messages" }) System.out.println(s); @@ -149,8 +147,9 @@ public class CommandLineInput { !decompiler.equalsIgnoreCase("krakatau-bytecode") && !decompiler.equalsIgnoreCase("jd-gui") && !decompiler.equalsIgnoreCase("smali") - ) { - System.out.println("Error, no decompiler called '" + decompiler + "' found. Type -decompiler-list for the list"); + ) { + System.out.println("Error, no decompiler called '" + decompiler + "' found. Type -decompiler-list" + + " for the list"); } @@ -175,7 +174,8 @@ public class CommandLineInput { String target = cmd.getOptionValue("t"); if (cmd.getOptionValue("decompiler") == null) { - System.out.println("You can define another decompiler by appending -decompiler \"name\", by default procyon has been set."); + System.out.println("You can define another decompiler by appending -decompiler \"name\", by default " + + "procyon has been set."); decompiler = "procyon"; } @@ -183,7 +183,8 @@ public class CommandLineInput { //if its zip/jar/apk/dex attempt unzip as whole zip //if its just class allow any - File tempZip = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp_"+BytecodeViewer.getRandomizedName()+".jar"); + File tempZip = + new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp_" + BytecodeViewer.getRandomizedName() + ".jar"); if (tempZip.exists()) tempZip.delete(); @@ -321,7 +322,8 @@ public class CommandLineInput { } System.out.println("Finished."); - System.out.println("Bytecode Viewer CLI v" + BytecodeViewer.VERSION + " by @Konloch - http://bytecodeviewer.com"); + System.out.println("Bytecode Viewer CLI v" + BytecodeViewer.VERSION + " by @Konloch - " + + "http://bytecodeviewer.com"); BytecodeViewer.canExit = true; System.exit(0); } catch (Exception e) { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/Resources.java b/src/main/java/the/bytecode/club/bytecodeviewer/Resources.java index 7ae0baa9..3d7530e0 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/Resources.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/Resources.java @@ -5,10 +5,8 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.util.ArrayList; import java.util.List; - import javax.imageio.ImageIO; import javax.swing.ImageIcon; - import org.apache.commons.codec.binary.Base64; import org.imgscalr.Scalr; @@ -63,11 +61,20 @@ public class Resources { static { - icon = b642IMG("iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAUd0lEQVR42pWaWXRbVZaGq5iHqgaSeJZsy7YkD7KtwZItebblQfI8x/HseIodO3bixE5iZw4ZSBwyACkCXQ003dD0oigq1UBqFVQ1HSB0wkyvXt1VPNSiavHCC288/b3/I11ZSszQDzuRfO89Z39n/3uffST9BMBP17Dbgna72B1hdmfQ7hK7W+yeoN0btPvE7v8Rdl+Y3Rsc4+7guHcF5wif9/ag3fYd/v70J/zHWlGFcLPRKqth99Yoc1TVKssTc1b74Krxw1Vbh3yxAl+9Mre/QZmnrvFHG+/Xnud4alwxzpEXnJOm+UGfbEH/wv2NAHkwMQ4P6GLk/1hlDyXFKVuXFI/1yQnKolJ0yqLTEhFjTEKsKRlxZgPi01OQkJ6qTJeRBn2mEYlZpjWN13gP7+VzfJ7G8WjRqXo1xwZDQmhe+kBfHhR7QHz7O300fq6LUhYBQkJ1UxDkFggZdEMQIJoTCkCsAhDn6TgdpKMWE5KyzcqSc9JDZsjNCL3WridZAmA3Q3F8zhMVBFpHELGHxJcHk2KVPZAYE4K5BYSkD+hjQuR8kAMQYENKgkwgUTBJFMzJgQhkpIrzRnHKJA6axdl0pFgzkGrNRJotS5nRbokw7e8pco8GRygugk4ixYXhAnGhOF90ml7Nvd5AX7SoRMKsGRElK7mJD9E4SFSqTg1KgLh0wy0AdF5z2uTIRrozV1lmvg2ZBQHLyLfK33KQnifX8nJgFuO9fC5VQaWr8RhRXWaaWijO92NgbAGQ2whyG5NIu0FJag0IDs5JOBkBtJXXnKfjWW47LG4HcgqdyC1yKePrDAFItaSjrrkZlf5aZBXYA4AuawgqHIgLxQXjvFTB98GEg9zOivCglhffAcHBExkFmSyVEZDJzQQQhyyePOSI07aSAjjKPMgrL4SroliZvbgAxpwsxCcnYmFxCecvXESO3J9bnK8gCa8BMaoE4kJpMFRBOMw6gXkoOT6Q0wSRIJCBIHcQRCW43EDqDWEQISkpGUkUZLJwADpkF+ed4nS+twTu6jJ4aspR5KtU5iwrRGqmGdHxsThw6GH8540PYfU4FSShrQIfDqRJjtHRpHYzDP3UYOh7BIjKizCImLBIECItGIV0mYzyCQeg83S6xF+FsvoaVDT6UNHkQ2WzH56qMqRlmRGTEIdXXn0Nn/3XfyOvxKPu98hzrspiNQ6BuDAZIlGTRIdRZ/T1QZjwnFkfBhMEuUOBcPNR0dCqk0psyYkwCA6uRYGTEqCgqlQ5pJwXx6ta61HT1ghfRzPqulrh72xBcXUFjJnikCEZX/71b3j5lcvweMvU/XyOz3MhOJ6t1I1siQ7nYdTDYeLCCgAXW4PhhqmB3EkQXogS2mgJoQbBnOBg5iAEJ+FkXEXKp7SuWjlU3dqgnG7obkdzTyda+zYq87U2wlnkRoopDTc++Bh/+cuXKCorRXldDfwCW9VSr57nOIW1FaHoMN/CYbiY9Id+xQRh1gfzJS8AcidB7mJLsCEsGvGSF1piU043Q2hR8LbUqdVv3NShHO8c6kX35gFsHO5H48Y2FFaUIiM7C+9eu64glvYdQk6eHcXectS3NaO5u0M9z0iWN9SqcZln4TBUAnOT/hAmVvKFix0VlFgECPsbai9cUoSgpJiAlJOCqAhAcFJGgfJp6e1SAD2jg+gbG1IgzRs7UFpVia6Nm1Qk/ud//4yz5x6HMcOM6lofnrz0Dzh3/hfo6utF86ZO1As0x2NucXwtMlw85gwXU5MYFzk8KvSdDAS5mw2bqlJCy8RiLWcZ5P7AxGZZVRASfkaiRiZtkMkZhY2b+9E/sRlDk2MKpLGjFUXlpZjfvgs3PvwEH3/yOfbvPwxjuhm/fOYf8e9vvysgzwhQLfwivc7BXrT1dytZMr+4SJrMuHicfy2JMSrMlXCQe9jFxgabP1Yplj5TUFLc1LgvsMIQolpkUC+RaBMIrv7g5CjGtk1hZOsWtG/qQrFAbN+xC1ffuaZs8/AI0rMy8MaVN/H21fewY24n7K481DT40SPPD2wZQffIINoHNikYRobzMAdZAMIlZpAughILj0oQ5G4FwjY60H6kqd4nPBr2Ug8KRLclPi+8Uk7rJKnDIcbntmJqfhaD4yPw+mrQ2NiE16/8Hr9784/o6elDVrZFVao3//Af6O7ugaekGM0dbRjdOqGem9g+jeGpcSVNRoZyZe6xlLMqUmL0g2U/PCparlBNZCDIfTwXaF0smzmjndGwSzTy4SwvEklVKv3WtjUpTXcN94mcRjA+uxXTu3Zgascs2ro7kV/oxpGDD+OV37yGixefRq7VionxSbz2xu/x9N8/B19DHQZGhrF99y4sHlzGrn17sG1xXsEMTY2pxWmVnGNF43zFzBeJSq4WFVGJIawcMyr54SA85Kg9wxLIDbP0RtluSfASt0SjFKX+alUqlaT6N6F3bBgj01uwded2zC/txuT2GdSKkzaHHXsXlvDiS7/C0p59sOU51PuXX/ktnnn2BYxOTuDQsaM4fuYUDj9yHEtHDwrMXswszKtFYa6xcDQyX0RiLMtuRiWYK1QJ/WMOa70Y1cRTJkHuJ4g+2Ayy32GlYtuQJ+1FoWi1vKEGvvYmVaG6JbmZ2JM7tmHH3gXsObQf2xd3oqG1GQ6XE16vV5L6n3Di2CNwFeSju6sbz7/wr3j+n1/C/gNH8MjZM3j0icdw8uyKgtl75IBajKn5OWyWPNsk+dLau1Gi0qKiwvmZo/SHjSkrqdaLMR0iQArrm0K9VGAHt6vdmzW92FelcoPRYEL2jQ9jdNukksTCgSUcOH4Eew/vx/D4KMq9FXA4nVjYuRtPXHwK3qpquPLzsXLqLC6JtC499QwOHDyIxy5dFJgLOPHoaRw88TB2H9yH2d07g1EZQYdUMs5HFZTI/JSXVZpP+mVy5Cj5Mw14fmFaUFUE+VkAJF2BsNRlMcklyZhsJRJeVhKGm2Fngm9hNJYW1WoePX0Cx8WhveJM56aNKJRkZiQO7T+Co4eOocDjRkVlJc6dewLnH38SS4t7ce7i4wrm1PlHceTUcSwzKsu7VfIPSeIzB5tkk2U5LpUKRj8oc/pF2ROERYkgVJMG8nOCJNsyVGebLocgljx2pu6aMpQ2VKO2owlNvZ1SJgcwPD2BrbvmsFO0ve/oIRw6eQwPnzqJA0cPY3JmGg3NTSguLYGnqBB75hcxsnkMnsJC7J5fwKmV85id3YaVC+fEzmLPgWVMz2/Hlu3bML1zToFsnqa8BpSMKWfKmvKiP9myMbN6pQWrF8twEOT+EIjBlgmjyCpDwpcjna2zskhqeYXqhfydzWiV0tgzOoSRmUlMyaTbJEFp01KxRqcmML5nAVv2L2Fibhua21pRXlmhgFrkdUlpKZb278P8rnlMTm9V0DM75tAiZXho2zTmDu7H7IF9GJb9aLOU5V6Rb5vIuK6rRXXQ3CBVnhQ51WnT6LCoPOHmHQFS1NCMFLu06XIczZBzQW6pdLfeYhT6pew2+VVDyIF7mB+zUypHugf7pBVpx+Dhneh/dDtGji6iV2S3eWwU/UMD8NXXobS8DCXSJBaJ3Ljj1/p96B4dwYgk9qaJUSVBp0jPXVGOscO7MHZ8D/okR/rGN0s+9oRAWP6dFUVKKQGQ1ZblVhChNLnkwORxKBBXVUkARAbyy4BtgwIyIWVXIHqkspRJL0X9dqxsRd2ZLvScmsPwyUUMHV/ExCMSmZNLGDy2gMkTSxgVB2ljx/Zg4uG9GDu0G91Sasu90sIXiWSsufANSJtydExanj6BEZDBntDmWOT3KoXkFAtIgYDkfS+InDmENrMwEqSSHW4YyGbJkY1DfSiuKBMHcpQTnqoK+Po60TEzis7FKWxankPv8nZ0755F5/wU2qZG0CiFoqqlUUXHH9wYB8dGUFvvh1U64s6js2jcJ/f2daNXgYi0NkaC5JbkC4hNpQDbFX12JIiqWioi+bkKxFrmhrN6NSI+GbBFVmzT+BCGZyYwtHUMrbKTl1fLzuspkI1PHNklSbo8g3x3AdyFHpXshcVFyviaVlpThVZpRYYlp3bI7j4kJbuithrt+6ZRd3pMnK5Hx0BgwbhwfpmX89MPSj1HgdgVSHIkyGr5NUhEjAKSoSIiIIxInRcVLX7UdjULiPRXY4MKZGJ+BpPz2zAoeq6u96kmsPPELPLP1sK70o+qlSHUr4yj9/wONJ+eRN3KKGrPDKPqXDfKzrZh+MRuDEk0muQQ1rl3Kxr2TaBICkt9e7N0DUNqwVpl4agEzu8REEdFoQJJl4ikUVpSZfU5kSBqQzTkWWAU/WUUOZBTVgCHt0g2G2nbm+UE2Cnlt1/OHSP9GJBojAvI3NKCql6N7a0qKlaHDcWSM22LW1C9bwydJ+fQviI92LFtqFwaQc3iKHxjvaiRHbu5pwteiYQqrdKMukuL1EGrR1qf/qlRdI32o0mkWiNlv1yqpluqFkGyJUfS3QEQgz0TOqlcESB8Y8iTiBTkIt1jR3ZpPmyVhXDWlMLtkzJaL7t7Wx3quqXXosSCkWGj1yqnvKKyEqXzmr52lLf4VM/FPkszQlrtNtidDlRUV6G5vQ1V0inz2Ov1VauKxkgMz2xB36Ts7Jt7UbepTfLTL3tZOezlHpF7AbKk/JoFJJURsUtEcs3azr7aayULSJpIyywgFgGxlrtV0rNZe/rZX+K996/h2vX38f6N67j+wQ1lNz78ANdv3MB7167htddfx9DFnYifM+PUSxfxzqfX8f5nHyp757PruPr5+3j783dx7fMPcOPjj/DBRx8qY9fM/z/65GM8/9KL2CiLxHz0yrnHKXtHdVMdrr73jti72LZnF8yy2KmiHoLoRFrBXmu1jU/Ky0SKKxsmt1SuYicsYmbpa5IzTHjrj3/At99++4PGHT7N6/pR92rmcLtw6syKev31119jZHZSJXmBHORMVgt+9eqv1bU//flPqv8zyhaRIiCJtnToJCLhIPfyTaIjEwanBWmUl+QJJWaQ/ishLQmv/+4KvvnmG7wh/8clJkBnTkFcmZzWii3QS7/Da7TlfcvYEB0Ver+0zPfRyqJiohEdGwN9UqKcGDORK3LLkvKdYjYiK9+BL//2V/XMv115XQ5VXlhcUgl7u0NjDU+Oq+6DqmEaJNrFt1xTxHnkngBIBpKdWQrEVGhTkUmSDjPOkIhf/+ZVfPXVV3jzrbfglx27fcsAyqe8qJvtQNNEj7pGm5EdOz4lMfR+z/ISdGkGJKYbZXXZWUt5L3HBXOVBqt+DzMZiGCWC8bKyW+dmQs8NSDXkZ8U3RL58z/nV5wguWeh8UYmoR28VEJFW8IQYOLPzjU5CRZBUudEoECzF/FIm1qCXg9K/4IsvvvhBe/vaVaTU2ULvdz55GMZdXmQv+8XqkLfcCveODngmO+EZaUGWvwyJIhWdOKgvtOClV15Wz1195yoW9uwOjZNfXoxUh0VFI8WZjSRRj17Kb7xEJPJTFHlDkPCopIjMdNJdRicn4JnnnsWnn36KK1euYEqavsmtk9gytWpHjh5R12l1XW2h1wvHDqGorxFlo51wDrXAvaUTjplOlC0OoGR5ALZjnXDtakdavQdRqUnSrhSGntVsVhpN7uKEoF/0Ty+JnmA1Iy7XGAGiPteKt5mgE90lOSXp87PVBhlvNiAqMR6/uPQkrkllevKpS4hN0iFaH4/ohFisj4nCA+seUs0hr9N8sqlpr2ePLiOztxbZIw2wjNYjc7wettk2uKc7YOmqgbGhHGZpy3UpyYhL0quxF/buDj1PSWW4pNy6AipJEbUwl3XBaMTmpEV8QKc+Mo2zEkQSOE+i4pJ+X17HyZl4Q2Iczsr54S3Jj8u/vYwLjz8WsvOPXcDZ8+fw1NNPqes0drva6xdefAHn5Pq58+eD/59bfX/hvBojU/Imxy0V0p4NvSkFaZIbly9fVs+zDVJduUBQ8owGVUP1xIu/casgqx9iM0zxNnMQJpBM/HJynS5WDkSn8brsEz9kzz33HAymNJxeWflR99PUuaeuElbZswwWM2KT9eiSanX60TOBz55FHZQUKyohwmUVm50a8SH2HXzDMDEqCazP6maT+gBsnT4WD8VHY11CDNbr4pTUopMSVBFgRYsXbSeI6YwpSDKnKtMbDdCn3Wq61OSQ8R5GwSXdg6fBC7u3ULXn8cZkxBh0MNosSt6MhEGKAfc5vSMSIsaSEvG1gvrGihcYKoaModPxgcwUxPAbVhk4OkWH2NRENVGCSRyTQpAkVS1ZSnRKdjpM/CyM3xvy2yd5bRJHzLbskJlsgb8ZZZMz5sp+YM1SZ3BHVTHyastgqypCZlGe6mrVV3z8ZoxVSiKSREkJCBc4zmoUkDRZeClEqyC3h0BiLKkBGEqMkREQwuhpUueTRGps1FSXLMmXLg0mD2FZMjmbOVuFR/QqTkm77RC55NHktbMqYHzNv7H5s8n5O1daIBtfC4BVopFdXiB7jFPywaYqJsssO41wCEqfqqF6YrIJkhrx1Zv6MpQgNEZFg2FkqEmGleGlVpl43DA5qaUsHznigLXSA5s4Y68WZ0UqTllhl68M+f7ykPE9/87rvM8uAHyGz3McjmcutMPksQXKv0CoUuvQImG6BSJKIhIEuS309TTDFAETJrNwGE6gdn+ZkBNnFOchq9QVgsqtcIfAFJw4rDlN4zXel122CsCWiIujVSctJ1hqVXLbAnlBnwK5ETD6HP6tbghEg9HyRYPhQIENMzMExAk1IDqhQdExDWwt4zXNeS0C4QCMgkps+2qZ1UrtzRBRWQYNZPW3KPxjOEwE0BpS44RahDQoJbswsLVM9XFB5/nMzQCBDS9dLZ4CCEaCdjME7ZYf1WzINIQufh/MzUA3Q4WDrWW8pjmvSehmGYWi8B1y0vxcEyTiJ05r/Mwp7wd+5vRdP2XiMTrc1vqZE8dZ62dOed/zMyfbWj9z+n/+8OyuNX54ds/3/OjsZzfZzT8+uzdsjO/68dkP/vDs/wBUXNeRym9KEQAAAABJRU5ErkJggg=="); - nextIcon = new ImageIcon(b642IMG("iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAABnRSTlMANzlYqPBJSG/ZAAAASUlEQVR42mNgwAbS0oAEE4yHyWBmYAzjYDC694OJ4f9+BoY3H0BSbz6A2MxA6VciFyDqGAWQTWVkYEkCUrcOsDD8OwtkvMViMwAb8xEUHlHcFAAAAABJRU5ErkJggg==")); - prevIcon = new ImageIcon(b642IMG("iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAABnRSTlMANzlYgKhxpRi1AAAATElEQVR42mNgwAZYHIAEExA7qUAYLApMDmCGEwODCojByM/A8FEAyPi/moFh9QewYjCAM1iA+D2KqYwMrIlA6tUGFoa/Z4GMt1hsBgCe1wuKber+SwAAAABJRU5ErkJggg==")); + icon = b642IMG( + "iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAUd0lEQVR42pWaWXRbVZaGq5iHqgaSeJZsy7YkD7KtwZItebblQfI8x/HseIodO3bixE5iZw4ZSBwyACkCXQ003dD0oigq1UBqFVQ1HSB0wkyvXt1VPNSiavHCC288/b3/I11ZSszQDzuRfO89Z39n/3uffST9BMBP17Dbgna72B1hdmfQ7hK7W+yeoN0btPvE7v8Rdl+Y3Rsc4+7guHcF5wif9/ag3fYd/v70J/zHWlGFcLPRKqth99Yoc1TVKssTc1b74Krxw1Vbh3yxAl+9Mre/QZmnrvFHG+/Xnud4alwxzpEXnJOm+UGfbEH/wv2NAHkwMQ4P6GLk/1hlDyXFKVuXFI/1yQnKolJ0yqLTEhFjTEKsKRlxZgPi01OQkJ6qTJeRBn2mEYlZpjWN13gP7+VzfJ7G8WjRqXo1xwZDQmhe+kBfHhR7QHz7O300fq6LUhYBQkJ1UxDkFggZdEMQIJoTCkCsAhDn6TgdpKMWE5KyzcqSc9JDZsjNCL3WridZAmA3Q3F8zhMVBFpHELGHxJcHk2KVPZAYE4K5BYSkD+hjQuR8kAMQYENKgkwgUTBJFMzJgQhkpIrzRnHKJA6axdl0pFgzkGrNRJotS5nRbokw7e8pco8GRygugk4ixYXhAnGhOF90ml7Nvd5AX7SoRMKsGRElK7mJD9E4SFSqTg1KgLh0wy0AdF5z2uTIRrozV1lmvg2ZBQHLyLfK33KQnifX8nJgFuO9fC5VQaWr8RhRXWaaWijO92NgbAGQ2whyG5NIu0FJag0IDs5JOBkBtJXXnKfjWW47LG4HcgqdyC1yKePrDAFItaSjrrkZlf5aZBXYA4AuawgqHIgLxQXjvFTB98GEg9zOivCglhffAcHBExkFmSyVEZDJzQQQhyyePOSI07aSAjjKPMgrL4SroliZvbgAxpwsxCcnYmFxCecvXESO3J9bnK8gCa8BMaoE4kJpMFRBOMw6gXkoOT6Q0wSRIJCBIHcQRCW43EDqDWEQISkpGUkUZLJwADpkF+ed4nS+twTu6jJ4aspR5KtU5iwrRGqmGdHxsThw6GH8540PYfU4FSShrQIfDqRJjtHRpHYzDP3UYOh7BIjKizCImLBIECItGIV0mYzyCQeg83S6xF+FsvoaVDT6UNHkQ2WzH56qMqRlmRGTEIdXXn0Nn/3XfyOvxKPu98hzrspiNQ6BuDAZIlGTRIdRZ/T1QZjwnFkfBhMEuUOBcPNR0dCqk0psyYkwCA6uRYGTEqCgqlQ5pJwXx6ta61HT1ghfRzPqulrh72xBcXUFjJnikCEZX/71b3j5lcvweMvU/XyOz3MhOJ6t1I1siQ7nYdTDYeLCCgAXW4PhhqmB3EkQXogS2mgJoQbBnOBg5iAEJ+FkXEXKp7SuWjlU3dqgnG7obkdzTyda+zYq87U2wlnkRoopDTc++Bh/+cuXKCorRXldDfwCW9VSr57nOIW1FaHoMN/CYbiY9Id+xQRh1gfzJS8AcidB7mJLsCEsGvGSF1piU043Q2hR8LbUqdVv3NShHO8c6kX35gFsHO5H48Y2FFaUIiM7C+9eu64glvYdQk6eHcXectS3NaO5u0M9z0iWN9SqcZln4TBUAnOT/hAmVvKFix0VlFgECPsbai9cUoSgpJiAlJOCqAhAcFJGgfJp6e1SAD2jg+gbG1IgzRs7UFpVia6Nm1Qk/ud//4yz5x6HMcOM6lofnrz0Dzh3/hfo6utF86ZO1As0x2NucXwtMlw85gwXU5MYFzk8KvSdDAS5mw2bqlJCy8RiLWcZ5P7AxGZZVRASfkaiRiZtkMkZhY2b+9E/sRlDk2MKpLGjFUXlpZjfvgs3PvwEH3/yOfbvPwxjuhm/fOYf8e9vvysgzwhQLfwivc7BXrT1dytZMr+4SJrMuHicfy2JMSrMlXCQe9jFxgabP1Yplj5TUFLc1LgvsMIQolpkUC+RaBMIrv7g5CjGtk1hZOsWtG/qQrFAbN+xC1ffuaZs8/AI0rMy8MaVN/H21fewY24n7K481DT40SPPD2wZQffIINoHNikYRobzMAdZAMIlZpAughILj0oQ5G4FwjY60H6kqd4nPBr2Ug8KRLclPi+8Uk7rJKnDIcbntmJqfhaD4yPw+mrQ2NiE16/8Hr9784/o6elDVrZFVao3//Af6O7ugaekGM0dbRjdOqGem9g+jeGpcSVNRoZyZe6xlLMqUmL0g2U/PCparlBNZCDIfTwXaF0smzmjndGwSzTy4SwvEklVKv3WtjUpTXcN94mcRjA+uxXTu3Zgascs2ro7kV/oxpGDD+OV37yGixefRq7VionxSbz2xu/x9N8/B19DHQZGhrF99y4sHlzGrn17sG1xXsEMTY2pxWmVnGNF43zFzBeJSq4WFVGJIawcMyr54SA85Kg9wxLIDbP0RtluSfASt0SjFKX+alUqlaT6N6F3bBgj01uwded2zC/txuT2GdSKkzaHHXsXlvDiS7/C0p59sOU51PuXX/ktnnn2BYxOTuDQsaM4fuYUDj9yHEtHDwrMXswszKtFYa6xcDQyX0RiLMtuRiWYK1QJ/WMOa70Y1cRTJkHuJ4g+2Ayy32GlYtuQJ+1FoWi1vKEGvvYmVaG6JbmZ2JM7tmHH3gXsObQf2xd3oqG1GQ6XE16vV5L6n3Di2CNwFeSju6sbz7/wr3j+n1/C/gNH8MjZM3j0icdw8uyKgtl75IBajKn5OWyWPNsk+dLau1Gi0qKiwvmZo/SHjSkrqdaLMR0iQArrm0K9VGAHt6vdmzW92FelcoPRYEL2jQ9jdNukksTCgSUcOH4Eew/vx/D4KMq9FXA4nVjYuRtPXHwK3qpquPLzsXLqLC6JtC499QwOHDyIxy5dFJgLOPHoaRw88TB2H9yH2d07g1EZQYdUMs5HFZTI/JSXVZpP+mVy5Cj5Mw14fmFaUFUE+VkAJF2BsNRlMcklyZhsJRJeVhKGm2Fngm9hNJYW1WoePX0Cx8WhveJM56aNKJRkZiQO7T+Co4eOocDjRkVlJc6dewLnH38SS4t7ce7i4wrm1PlHceTUcSwzKsu7VfIPSeIzB5tkk2U5LpUKRj8oc/pF2ROERYkgVJMG8nOCJNsyVGebLocgljx2pu6aMpQ2VKO2owlNvZ1SJgcwPD2BrbvmsFO0ve/oIRw6eQwPnzqJA0cPY3JmGg3NTSguLYGnqBB75hcxsnkMnsJC7J5fwKmV85id3YaVC+fEzmLPgWVMz2/Hlu3bML1zToFsnqa8BpSMKWfKmvKiP9myMbN6pQWrF8twEOT+EIjBlgmjyCpDwpcjna2zskhqeYXqhfydzWiV0tgzOoSRmUlMyaTbJEFp01KxRqcmML5nAVv2L2Fibhua21pRXlmhgFrkdUlpKZb278P8rnlMTm9V0DM75tAiZXho2zTmDu7H7IF9GJb9aLOU5V6Rb5vIuK6rRXXQ3CBVnhQ51WnT6LCoPOHmHQFS1NCMFLu06XIczZBzQW6pdLfeYhT6pew2+VVDyIF7mB+zUypHugf7pBVpx+Dhneh/dDtGji6iV2S3eWwU/UMD8NXXobS8DCXSJBaJ3Ljj1/p96B4dwYgk9qaJUSVBp0jPXVGOscO7MHZ8D/okR/rGN0s+9oRAWP6dFUVKKQGQ1ZblVhChNLnkwORxKBBXVUkARAbyy4BtgwIyIWVXIHqkspRJL0X9dqxsRd2ZLvScmsPwyUUMHV/ExCMSmZNLGDy2gMkTSxgVB2ljx/Zg4uG9GDu0G91Sasu90sIXiWSsufANSJtydExanj6BEZDBntDmWOT3KoXkFAtIgYDkfS+InDmENrMwEqSSHW4YyGbJkY1DfSiuKBMHcpQTnqoK+Po60TEzis7FKWxankPv8nZ0755F5/wU2qZG0CiFoqqlUUXHH9wYB8dGUFvvh1U64s6js2jcJ/f2daNXgYi0NkaC5JbkC4hNpQDbFX12JIiqWioi+bkKxFrmhrN6NSI+GbBFVmzT+BCGZyYwtHUMrbKTl1fLzuspkI1PHNklSbo8g3x3AdyFHpXshcVFyviaVlpThVZpRYYlp3bI7j4kJbuithrt+6ZRd3pMnK5Hx0BgwbhwfpmX89MPSj1HgdgVSHIkyGr5NUhEjAKSoSIiIIxInRcVLX7UdjULiPRXY4MKZGJ+BpPz2zAoeq6u96kmsPPELPLP1sK70o+qlSHUr4yj9/wONJ+eRN3KKGrPDKPqXDfKzrZh+MRuDEk0muQQ1rl3Kxr2TaBICkt9e7N0DUNqwVpl4agEzu8REEdFoQJJl4ikUVpSZfU5kSBqQzTkWWAU/WUUOZBTVgCHt0g2G2nbm+UE2Cnlt1/OHSP9GJBojAvI3NKCql6N7a0qKlaHDcWSM22LW1C9bwydJ+fQviI92LFtqFwaQc3iKHxjvaiRHbu5pwteiYQqrdKMukuL1EGrR1qf/qlRdI32o0mkWiNlv1yqpluqFkGyJUfS3QEQgz0TOqlcESB8Y8iTiBTkIt1jR3ZpPmyVhXDWlMLtkzJaL7t7Wx3quqXXosSCkWGj1yqnvKKyEqXzmr52lLf4VM/FPkszQlrtNtidDlRUV6G5vQ1V0inz2Ov1VauKxkgMz2xB36Ts7Jt7UbepTfLTL3tZOezlHpF7AbKk/JoFJJURsUtEcs3azr7aayULSJpIyywgFgGxlrtV0rNZe/rZX+K996/h2vX38f6N67j+wQ1lNz78ANdv3MB7167htddfx9DFnYifM+PUSxfxzqfX8f5nHyp757PruPr5+3j783dx7fMPcOPjj/DBRx8qY9fM/z/65GM8/9KL2CiLxHz0yrnHKXtHdVMdrr73jti72LZnF8yy2KmiHoLoRFrBXmu1jU/Ky0SKKxsmt1SuYicsYmbpa5IzTHjrj3/At99++4PGHT7N6/pR92rmcLtw6syKev31119jZHZSJXmBHORMVgt+9eqv1bU//flPqv8zyhaRIiCJtnToJCLhIPfyTaIjEwanBWmUl+QJJWaQ/ishLQmv/+4KvvnmG7wh/8clJkBnTkFcmZzWii3QS7/Da7TlfcvYEB0Ver+0zPfRyqJiohEdGwN9UqKcGDORK3LLkvKdYjYiK9+BL//2V/XMv115XQ5VXlhcUgl7u0NjDU+Oq+6DqmEaJNrFt1xTxHnkngBIBpKdWQrEVGhTkUmSDjPOkIhf/+ZVfPXVV3jzrbfglx27fcsAyqe8qJvtQNNEj7pGm5EdOz4lMfR+z/ISdGkGJKYbZXXZWUt5L3HBXOVBqt+DzMZiGCWC8bKyW+dmQs8NSDXkZ8U3RL58z/nV5wguWeh8UYmoR28VEJFW8IQYOLPzjU5CRZBUudEoECzF/FIm1qCXg9K/4IsvvvhBe/vaVaTU2ULvdz55GMZdXmQv+8XqkLfcCveODngmO+EZaUGWvwyJIhWdOKgvtOClV15Wz1195yoW9uwOjZNfXoxUh0VFI8WZjSRRj17Kb7xEJPJTFHlDkPCopIjMdNJdRicn4JnnnsWnn36KK1euYEqavsmtk9gytWpHjh5R12l1XW2h1wvHDqGorxFlo51wDrXAvaUTjplOlC0OoGR5ALZjnXDtakdavQdRqUnSrhSGntVsVhpN7uKEoF/0Ty+JnmA1Iy7XGAGiPteKt5mgE90lOSXp87PVBhlvNiAqMR6/uPQkrkllevKpS4hN0iFaH4/ohFisj4nCA+seUs0hr9N8sqlpr2ePLiOztxbZIw2wjNYjc7wettk2uKc7YOmqgbGhHGZpy3UpyYhL0quxF/buDj1PSWW4pNy6AipJEbUwl3XBaMTmpEV8QKc+Mo2zEkQSOE+i4pJ+X17HyZl4Q2Iczsr54S3Jj8u/vYwLjz8WsvOPXcDZ8+fw1NNPqes0drva6xdefAHn5Pq58+eD/59bfX/hvBojU/Imxy0V0p4NvSkFaZIbly9fVs+zDVJduUBQ8owGVUP1xIu/casgqx9iM0zxNnMQJpBM/HJynS5WDkSn8brsEz9kzz33HAymNJxeWflR99PUuaeuElbZswwWM2KT9eiSanX60TOBz55FHZQUKyohwmUVm50a8SH2HXzDMDEqCazP6maT+gBsnT4WD8VHY11CDNbr4pTUopMSVBFgRYsXbSeI6YwpSDKnKtMbDdCn3Wq61OSQ8R5GwSXdg6fBC7u3ULXn8cZkxBh0MNosSt6MhEGKAfc5vSMSIsaSEvG1gvrGihcYKoaModPxgcwUxPAbVhk4OkWH2NRENVGCSRyTQpAkVS1ZSnRKdjpM/CyM3xvy2yd5bRJHzLbskJlsgb8ZZZMz5sp+YM1SZ3BHVTHyastgqypCZlGe6mrVV3z8ZoxVSiKSREkJCBc4zmoUkDRZeClEqyC3h0BiLKkBGEqMkREQwuhpUueTRGps1FSXLMmXLg0mD2FZMjmbOVuFR/QqTkm77RC55NHktbMqYHzNv7H5s8n5O1daIBtfC4BVopFdXiB7jFPywaYqJsssO41wCEqfqqF6YrIJkhrx1Zv6MpQgNEZFg2FkqEmGleGlVpl43DA5qaUsHznigLXSA5s4Y68WZ0UqTllhl68M+f7ykPE9/87rvM8uAHyGz3McjmcutMPksQXKv0CoUuvQImG6BSJKIhIEuS309TTDFAETJrNwGE6gdn+ZkBNnFOchq9QVgsqtcIfAFJw4rDlN4zXel122CsCWiIujVSctJ1hqVXLbAnlBnwK5ETD6HP6tbghEg9HyRYPhQIENMzMExAk1IDqhQdExDWwt4zXNeS0C4QCMgkps+2qZ1UrtzRBRWQYNZPW3KPxjOEwE0BpS44RahDQoJbswsLVM9XFB5/nMzQCBDS9dLZ4CCEaCdjME7ZYf1WzINIQufh/MzUA3Q4WDrWW8pjmvSehmGYWi8B1y0vxcEyTiJ05r/Mwp7wd+5vRdP2XiMTrc1vqZE8dZ62dOed/zMyfbWj9z+n/+8OyuNX54ds/3/OjsZzfZzT8+uzdsjO/68dkP/vDs/wBUXNeRym9KEQAAAABJRU5ErkJggg=="); + nextIcon = new ImageIcon(b642IMG("iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAMFBMVEX" + + "///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAABnRSTlMANzlYqPBJSG" + + "/ZAAAASUlEQVR42mNgwAbS0oAEE4yHyWBmYAzjYDC694OJ4f9" + + "+BoY3H0BSbz6A2MxA6VciFyDqGAWQTWVkYEkCUrcOsDD8OwtkvMViMwAb8xEUHlHcFAAAAABJRU5ErkJggg==")); + prevIcon = new ImageIcon(b642IMG("iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAMFBMVEX" + + + "///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAABnRSTlMANzlYgKhxpRi1AAAATElEQVR42mNgwAZYHIAEExA7qUAYLApMDmCGEwODCojByM/A8FEAyPi/moFh9QewYjCAM1iA+D2KqYwMrIlA6tUGFoa/Z4GMt1hsBgCe1wuKber+SwAAAABJRU5ErkJggg==")); busyIcon = new ImageIcon(Resources.class.getResource("/1.gif")); - busyB64Icon = new ImageIcon(b642IMG("R0lGODlhEAALAPQAAP///wAAANra2tDQ0Orq6gcHBwAAAC8vL4KCgmFhYbq6uiMjI0tLS4qKimVlZb6+vicnJwUFBU9PT+bm5tjY2PT09Dk5Odzc3PLy8ra2tqCgoMrKyu7u7gAAAAAAAAAAACH5BAkLAAAAIf4aQ3JlYXRlZCB3aXRoIGFqYXhsb2FkLmluZm8AIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAEAALAAAFLSAgjmRpnqSgCuLKAq5AEIM4zDVw03ve27ifDgfkEYe04kDIDC5zrtYKRa2WQgAh+QQJCwAAACwAAAAAEAALAAAFJGBhGAVgnqhpHIeRvsDawqns0qeN5+y967tYLyicBYE7EYkYAgAh+QQJCwAAACwAAAAAEAALAAAFNiAgjothLOOIJAkiGgxjpGKiKMkbz7SN6zIawJcDwIK9W/HISxGBzdHTuBNOmcJVCyoUlk7CEAAh+QQJCwAAACwAAAAAEAALAAAFNSAgjqQIRRFUAo3jNGIkSdHqPI8Tz3V55zuaDacDyIQ+YrBH+hWPzJFzOQQaeavWi7oqnVIhACH5BAkLAAAALAAAAAAQAAsAAAUyICCOZGme1rJY5kRRk7hI0mJSVUXJtF3iOl7tltsBZsNfUegjAY3I5sgFY55KqdX1GgIAIfkECQsAAAAsAAAAABAACwAABTcgII5kaZ4kcV2EqLJipmnZhWGXaOOitm2aXQ4g7P2Ct2ER4AMul00kj5g0Al8tADY2y6C+4FIIACH5BAkLAAAALAAAAAAQAAsAAAUvICCOZGme5ERRk6iy7qpyHCVStA3gNa/7txxwlwv2isSacYUc+l4tADQGQ1mvpBAAIfkECQsAAAAsAAAAABAACwAABS8gII5kaZ7kRFGTqLLuqnIcJVK0DeA1r/u3HHCXC/aKxJpxhRz6Xi0ANAZDWa+kEAA7")); + busyB64Icon = new ImageIcon(b642IMG("R0lGODlhEAALAPQAAP" + + "///wAAANra2tDQ0Orq6gcHBwAAAC8vL4KCgmFhYbq6uiMjI0tLS4qKimVlZb6+vicnJwUFBU9PT" + + + "+bm5tjY2PT09Dk5Odzc3PLy8ra2tqCgoMrKyu7u7gAAAAAAAAAAACH5BAkLAAAAIf4aQ3JlYXRlZCB3aXRoIGFqYXhsb2FkLmluZm8AIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAEAALAAAFLSAgjmRpnqSgCuLKAq5AEIM4zDVw03ve27ifDgfkEYe04kDIDC5zrtYKRa2WQgAh+QQJCwAAACwAAAAAEAALAAAFJGBhGAVgnqhpHIeRvsDawqns0qeN5+y967tYLyicBYE7EYkYAgAh+QQJCwAAACwAAAAAEAALAAAFNiAgjothLOOIJAkiGgxjpGKiKMkbz7SN6zIawJcDwIK9W/HISxGBzdHTuBNOmcJVCyoUlk7CEAAh+QQJCwAAACwAAAAAEAALAAAFNSAgjqQIRRFUAo3jNGIkSdHqPI8Tz3V55zuaDacDyIQ+YrBH+hWPzJFzOQQaeavWi7oqnVIhACH5BAkLAAAALAAAAAAQAAsAAAUyICCOZGme1rJY5kRRk7hI0mJSVUXJtF3iOl7tltsBZsNfUegjAY3I5sgFY55KqdX1GgIAIfkECQsAAAAsAAAAABAACwAABTcgII5kaZ4kcV2EqLJipmnZhWGXaOOitm2aXQ4g7P2Ct2ER4AMul00kj5g0Al8tADY2y6C+4FIIACH5BAkLAAAALAAAAAAQAAsAAAUvICCOZGme5ERRk6iy7qpyHCVStA3gNa/7txxwlwv2isSacYUc+l4tADQGQ1mvpBAAIfkECQsAAAAsAAAAABAACwAABS8gII5kaZ7kRFGTqLLuqnIcJVK0DeA1r/u3HHCXC/aKxJpxhRz6Xi0ANAZDWa+kEAA7")); batIcon = new ImageIcon(Resources.class.getResource("/bat.png")); shIcon = new ImageIcon(Resources.class.getResource("/sh.png")); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/SecurityMan.java b/src/main/java/the/bytecode/club/bytecodeviewer/SecurityMan.java index 3c60bfae..8035e739 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/SecurityMan.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/SecurityMan.java @@ -73,7 +73,7 @@ public class SecurityMan extends SecurityManager { if (allow && !blocking) { System.out.println("Allowing exec:" + cmd); - } else throw new SecurityException("BCV is awesome, blocking("+blocking+") exec " + cmd); + } else throw new SecurityException("BCV is awesome, blocking(" + blocking + ") exec " + cmd); } @Override @@ -123,9 +123,8 @@ public class SecurityMan extends SecurityManager { @Override public void checkExit(int status) { - if(!BytecodeViewer.canExit) - { - throw new SecurityException("BCV is awesome, blocking System.exit("+status+");"); + if (!BytecodeViewer.canExit) { + throw new SecurityException("BCV is awesome, blocking System.exit(" + status + ");"); } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/Settings.java b/src/main/java/the/bytecode/club/bytecodeviewer/Settings.java index a0c6dfc1..5b3a55f9 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/Settings.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/Settings.java @@ -1,7 +1,6 @@ package the.bytecode.club.bytecodeviewer; import javax.swing.JFrame; - import me.konloch.kontainer.io.DiskReader; import me.konloch.kontainer.io.DiskWriter; @@ -34,86 +33,165 @@ public class Settings { public static void saveSettings() { try { DiskWriter.replaceFile(BytecodeViewer.settingsName, "BCV: " + BytecodeViewer.VERSION, false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.rbr.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.rsy.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.din.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.dc4.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.das.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.hes.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.hdc.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.dgs.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.ner.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.den.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.rgn.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.bto.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.nns.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.uto.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.udv.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.rer.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.fdi.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.asc.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.decodeenumswitch.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.sugarenums.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.decodestringswitch.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.arrayiter.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.collectioniter.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.innerclasses.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.removeboilerplate.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.removeinnerclasssynthetics.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.decodelambdas.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.hidebridgemethods.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.liftconstructorinit.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.removedeadmethods.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.removebadgenerics.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.sugarasserts.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.sugarboxing.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.showversion.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.decodefinally.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.tidymonitors.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.lenient.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.dumpclasspath.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.comments.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.forcetopsort.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.forcetopsortaggress.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.stringbuffer.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.stringbuilder.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.silent.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.recover.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.eclipse.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.override.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.showinferrable.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.aexagg.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.forcecondpropagate.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.hideutf.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.hidelongstrings.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.commentmonitor.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.allowcorrecting.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.labelledblocks.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.j14classobj.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.hidelangimports.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.recoverytypeclash.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.recoverytypehints.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.forceturningifs.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.forloopaggcapture.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.forceexceptionprune.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.chckbxmntmShowDebugLine.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.chckbxmntmSimplifyMemberReferences.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.mnMergeVariables.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_1.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_2.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_3.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_4.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_5.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_6.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_7.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_8.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_9.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_10.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_11.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.chckbxmntmAppendBrackets.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.debugHelpers.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.rbr.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.rsy.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.din.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.dc4.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.das.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.hes.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.hdc.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.dgs.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.ner.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.den.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.rgn.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.bto.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.nns.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.uto.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.udv.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.rer.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.fdi.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.asc.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.decodeenumswitch.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.sugarenums.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.decodestringswitch.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.arrayiter.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.collectioniter.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.innerclasses.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.removeboilerplate.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.removeinnerclasssynthetics.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.decodelambdas.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.hidebridgemethods.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.liftconstructorinit.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.removedeadmethods.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.removebadgenerics.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.sugarasserts.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.sugarboxing.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.showversion.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.decodefinally.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.tidymonitors.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.lenient.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.dumpclasspath.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.comments.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.forcetopsort.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.forcetopsortaggress.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.stringbuffer.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.stringbuilder.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.silent.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.recover.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.eclipse.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.override.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.showinferrable.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.aexagg.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.forcecondpropagate.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.hideutf.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.hidelongstrings.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.commentmonitor.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.allowcorrecting.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.labelledblocks.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.j14classobj.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.hidelangimports.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.recoverytypeclash.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.recoverytypehints.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.forceturningifs.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.forloopaggcapture.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.forceexceptionprune.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.chckbxmntmShowDebugLine.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.chckbxmntmSimplifyMemberReferences.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.mnMergeVariables.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_1.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_2.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_3.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_4.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_5.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_6.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_7.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_8.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_9.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_10.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_11.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.chckbxmntmAppendBrackets.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.debugHelpers.isSelected()), false); DiskWriter.writeNewLine(BytecodeViewer.settingsName, "deprecated", false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_12.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.chckbxmntmNewCheckItem_12.isSelected()), false); if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1None.getModel())) DiskWriter.writeNewLine(BytecodeViewer.settingsName, "0", false); else if (BytecodeViewer.viewer.panelGroup1.isSelected(BytecodeViewer.viewer.panel1Proc.getModel())) @@ -189,36 +267,59 @@ public class Settings { else if (BytecodeViewer.viewer.panelGroup3.isSelected(BytecodeViewer.viewer.asmText3.getModel())) DiskWriter.writeNewLine(BytecodeViewer.settingsName, "11", false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.refreshOnChange.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.isMaximized), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.refreshOnChange.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.isMaximized), + false); DiskWriter.writeNewLine(BytecodeViewer.settingsName, "deprecated", false); DiskWriter.writeNewLine(BytecodeViewer.settingsName, "deprecated", false); DiskWriter.writeNewLine(BytecodeViewer.settingsName, BytecodeViewer.lastDirectory, false); DiskWriter.writeNewLine(BytecodeViewer.settingsName, BytecodeViewer.python, false); DiskWriter.writeNewLine(BytecodeViewer.settingsName, BytecodeViewer.rt, false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.panel1Proc_E.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.panel1CFR_E.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.panel1Fern_E.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.panel1Krakatau_E.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.panel1Smali_E.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.panel2Proc_E.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.panel2CFR_E.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.panel2Fern_E.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.panel2Krakatau_E.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.panel2Smali_E.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.panel3Proc_E.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.panel3CFR_E.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.panel3Fern_E.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.panel3Krakatau_E.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.panel3Smali_E.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.decodeAPKResources.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.panel1Proc_E.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.panel1CFR_E.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.panel1Fern_E.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.panel1Krakatau_E.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.panel1Smali_E.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.panel2Proc_E.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.panel2CFR_E.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.panel2Fern_E.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.panel2Krakatau_E.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.panel2Smali_E.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.panel3Proc_E.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.panel3CFR_E.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.panel3Fern_E.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.panel3Krakatau_E.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.panel3Smali_E.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.decodeAPKResources.isSelected()), false); DiskWriter.writeNewLine(BytecodeViewer.settingsName, BytecodeViewer.library, false); DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.pingback), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.panel1JDGUI_E.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.panel2JDGUI_E.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.panel3JDGUI_E.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.fontSpinner.getValue()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.deleteForeignLibraries), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.panel1JDGUI_E.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.panel2JDGUI_E.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.panel3JDGUI_E.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.fontSpinner.getValue()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.deleteForeignLibraries), false); if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionDex.getModel())) DiskWriter.writeNewLine(BytecodeViewer.settingsName, "0", false); else if (BytecodeViewer.viewer.apkConversionGroup.isSelected(BytecodeViewer.viewer.apkConversionEnjarify.getModel())) @@ -226,14 +327,21 @@ public class Settings { DiskWriter.writeNewLine(BytecodeViewer.settingsName, BytecodeViewer.python3, false); DiskWriter.writeNewLine(BytecodeViewer.settingsName, BytecodeViewer.javac, false); DiskWriter.writeNewLine(BytecodeViewer.settingsName, BytecodeViewer.java, false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.compileOnSave.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.autoCompileOnRefresh.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.compileOnSave.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.autoCompileOnRefresh.isSelected()), false); DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.warnForEditing), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.showFileInTabTitle.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.forcePureAsciiAsText.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.synchronizedViewing.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.showClassMethods.isSelected()), false); - DiskWriter.writeNewLine(BytecodeViewer.settingsName, String.valueOf(BytecodeViewer.viewer.ren.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.showFileInTabTitle.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.forcePureAsciiAsText.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.synchronizedViewing.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.showClassMethods.isSelected()), false); + DiskWriter.writeNewLine(BytecodeViewer.settingsName, + String.valueOf(BytecodeViewer.viewer.ren.isSelected()), false); } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); } @@ -339,7 +447,8 @@ public class Settings { else if (decompiler == 7) BytecodeViewer.viewer.panelGroup1.setSelected(BytecodeViewer.viewer.panel1Krakatau.getModel(), true); else if (decompiler == 8) - BytecodeViewer.viewer.panelGroup1.setSelected(BytecodeViewer.viewer.panel1KrakatauBytecode.getModel(), true); + BytecodeViewer.viewer.panelGroup1.setSelected(BytecodeViewer.viewer.panel1KrakatauBytecode.getModel() + , true); else if (decompiler == 9) BytecodeViewer.viewer.panelGroup1.setSelected(BytecodeViewer.viewer.panel1JDGUI.getModel(), true); else if (decompiler == 10) @@ -365,7 +474,8 @@ public class Settings { else if (decompiler == 7) BytecodeViewer.viewer.panelGroup2.setSelected(BytecodeViewer.viewer.panel2Krakatau.getModel(), true); else if (decompiler == 8) - BytecodeViewer.viewer.panelGroup2.setSelected(BytecodeViewer.viewer.panel2KrakatauBytecode.getModel(), true); + BytecodeViewer.viewer.panelGroup2.setSelected(BytecodeViewer.viewer.panel2KrakatauBytecode.getModel() + , true); else if (decompiler == 9) BytecodeViewer.viewer.panelGroup2.setSelected(BytecodeViewer.viewer.panel2JDGUI.getModel(), true); else if (decompiler == 10) @@ -391,7 +501,8 @@ public class Settings { else if (decompiler == 7) BytecodeViewer.viewer.panelGroup3.setSelected(BytecodeViewer.viewer.panel3Krakatau.getModel(), true); else if (decompiler == 8) - BytecodeViewer.viewer.panelGroup3.setSelected(BytecodeViewer.viewer.panel3KrakatauBytecode.getModel(), true); + BytecodeViewer.viewer.panelGroup3.setSelected(BytecodeViewer.viewer.panel3KrakatauBytecode.getModel() + , true); else if (decompiler == 9) BytecodeViewer.viewer.panelGroup3.setSelected(BytecodeViewer.viewer.panel3JDGUI.getModel(), true); else if (decompiler == 10) @@ -428,12 +539,14 @@ public class Settings { BytecodeViewer.viewer.panel3Smali_E.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 105, false))); BytecodeViewer.viewer.decodeAPKResources.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 106, false))); BytecodeViewer.library = DiskReader.loadString(BytecodeViewer.settingsName, 107, false); - BytecodeViewer.pingback = Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 108, false)); + BytecodeViewer.pingback = Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 108, + false)); BytecodeViewer.viewer.panel1JDGUI_E.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 109, false))); BytecodeViewer.viewer.panel2JDGUI_E.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 110, false))); BytecodeViewer.viewer.panel3JDGUI_E.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 111, false))); BytecodeViewer.viewer.fontSpinner.setValue(Integer.parseInt(DiskReader.loadString(BytecodeViewer.settingsName, 112, false))); - BytecodeViewer.deleteForeignLibraries = Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 113, false)); + BytecodeViewer.deleteForeignLibraries = + Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 113, false)); decompiler = Integer.parseInt(DiskReader.loadString(BytecodeViewer.settingsName, 114, false)); if (decompiler == 0) BytecodeViewer.viewer.apkConversionGroup.setSelected(BytecodeViewer.viewer.apkConversionDex.getModel(), true); @@ -444,7 +557,8 @@ public class Settings { BytecodeViewer.java = DiskReader.loadString(BytecodeViewer.settingsName, 117, false); BytecodeViewer.viewer.compileOnSave.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 118, false))); BytecodeViewer.viewer.autoCompileOnRefresh.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 119, false))); - BytecodeViewer.warnForEditing = Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 120, false)); + BytecodeViewer.warnForEditing = Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, + 120, false)); BytecodeViewer.viewer.showFileInTabTitle.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 121, false))); BytecodeViewer.displayParentInTab = BytecodeViewer.viewer.showFileInTabTitle.isSelected(); BytecodeViewer.viewer.forcePureAsciiAsText.setSelected(Boolean.parseBoolean(DiskReader.loadString(BytecodeViewer.settingsName, 122, false))); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/api/ASMUtil_OLD.java b/src/main/java/the/bytecode/club/bytecodeviewer/api/ASMUtil_OLD.java index 2e70f768..2cb0ea7f 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/api/ASMUtil_OLD.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/api/ASMUtil_OLD.java @@ -1,7 +1,6 @@ package the.bytecode.club.bytecodeviewer.api; import java.util.List; - import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldInsnNode; @@ -11,7 +10,6 @@ import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TypeInsnNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; /*************************************************************************** @@ -146,7 +144,7 @@ public final class ASMUtil_OLD { MethodNode m = (MethodNode) o; if (m.localVariables != null) { - for (LocalVariableNode node : (List) m.localVariables) { + for (LocalVariableNode node : m.localVariables) { node.desc = node.desc.replace(oldName, newName); } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/api/BytecodeViewer.java b/src/main/java/the/bytecode/club/bytecodeviewer/api/BytecodeViewer.java index 64c2323a..e47df1fe 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/api/BytecodeViewer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/api/BytecodeViewer.java @@ -8,12 +8,10 @@ import java.util.Enumeration; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; - import org.objectweb.asm.tree.ClassNode; - -import the.bytecode.club.bytecodeviewer.util.JarUtils; import the.bytecode.club.bytecodeviewer.decompilers.Decompiler; import the.bytecode.club.bytecodeviewer.plugin.preinstalled.EZInjection; +import the.bytecode.club.bytecodeviewer.util.JarUtils; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -82,7 +80,7 @@ public class BytecodeViewer { List> ret = new ArrayList>(); while (e.hasMoreElements()) { - JarEntry je = (JarEntry) e.nextElement(); + JarEntry je = e.nextElement(); if (je.isDirectory() || !je.getName().endsWith(".class")) continue; String className = je.getName().replace("/", ".").replace(".class", ""); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/api/ClassNodeLoader.java b/src/main/java/the/bytecode/club/bytecodeviewer/api/ClassNodeLoader.java index 6d431fd2..37d461ce 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/api/ClassNodeLoader.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/api/ClassNodeLoader.java @@ -8,7 +8,6 @@ import java.security.cert.Certificate; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; - import org.objectweb.asm.ClassWriter; import org.objectweb.asm.tree.ClassNode; @@ -36,7 +35,7 @@ import org.objectweb.asm.tree.ClassNode; public final class ClassNodeLoader extends ClassLoader { - private HashMap classes = new HashMap(); + private final HashMap classes = new HashMap(); /** * Adds the provided class node to the class loader diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/api/ExceptionUI.java b/src/main/java/the/bytecode/club/bytecodeviewer/api/ExceptionUI.java index 5f2532a4..8df9e550 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/api/ExceptionUI.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/api/ExceptionUI.java @@ -5,11 +5,9 @@ import java.awt.Color; import java.awt.Dimension; import java.io.PrintWriter; import java.io.StringWriter; - import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTextArea; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.Resources; @@ -93,7 +91,7 @@ public class ExceptionUI extends JFrame { ", Fat Jar: " + BytecodeViewer.FAT_JAR + ", OS: " + System.getProperty("os.name") + ", Java: " + System.getProperty("java.version") + - BytecodeViewer.nl + BytecodeViewer.nl + sw.toString()); + BytecodeViewer.nl + BytecodeViewer.nl + sw); this.setLocationRelativeTo(null); this.setVisible(true); } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/api/Plugin.java b/src/main/java/the/bytecode/club/bytecodeviewer/api/Plugin.java index a4e825eb..a4d7edf0 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/api/Plugin.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/api/Plugin.java @@ -1,9 +1,7 @@ package the.bytecode.club.bytecodeviewer.api; import java.util.ArrayList; - import org.objectweb.asm.tree.ClassNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; /*************************************************************************** diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/api/PluginConsole.java b/src/main/java/the/bytecode/club/bytecodeviewer/api/PluginConsole.java index a9d70e34..d73efb6d 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/api/PluginConsole.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/api/PluginConsole.java @@ -1,30 +1,24 @@ package the.bytecode.club.bytecodeviewer.api; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JFrame; -import javax.swing.JTextField; - +import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; - -import javax.swing.JScrollPane; - -import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; - -import javax.swing.JTextArea; - -import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.Resources; - +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFrame; import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JTextField; import javax.swing.text.DefaultHighlighter; import javax.swing.text.Highlighter; import javax.swing.text.JTextComponent; +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.Resources; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -219,7 +213,7 @@ public class PluginConsole extends JFrame { } } - private DefaultHighlighter.DefaultHighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter( + private final DefaultHighlighter.DefaultHighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter( new Color(255, 62, 150)); public void highlight(JTextComponent textComp, String pattern) { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/compilers/JavaCompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/compilers/JavaCompiler.java index a7ce7372..7f2eaa35 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/compilers/JavaCompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/compilers/JavaCompiler.java @@ -5,7 +5,6 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; - import me.konloch.kontainer.io.DiskWriter; import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.util.JarUtils; @@ -39,12 +38,17 @@ public class JavaCompiler extends Compiler { @Override public byte[] compile(String contents, String name) { - String fileStart = BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(12) + BytecodeViewer.fs; - String fileStart2 = BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(12) + BytecodeViewer.fs; + String fileStart = + BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(12) + BytecodeViewer.fs; + String fileStart2 = + BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(12) + BytecodeViewer.fs; File java = new File(fileStart + BytecodeViewer.fs + name + ".java"); File clazz = new File(fileStart2 + BytecodeViewer.fs + name + ".class"); - File cp = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "cpath_" + MiscUtils.randomString(12) + ".jar"); - File tempD = new File(fileStart + BytecodeViewer.fs + name.substring(0, name.length() - name.split("/")[name.split("/").length - 1].length())); + File cp = + new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "cpath_" + MiscUtils.randomString(12) + + ".jar"); + File tempD = new File(fileStart + BytecodeViewer.fs + name.substring(0, + name.length() - name.split("/")[name.split("/").length - 1].length())); tempD.mkdirs(); new File(fileStart2).mkdirs(); @@ -78,7 +82,8 @@ public class JavaCompiler extends Compiler { pb = new ProcessBuilder( BytecodeViewer.javac, "-d", fileStart2, - "-classpath", cp.getAbsolutePath() + System.getProperty("path.separator") + BytecodeViewer.library, + "-classpath", + cp.getAbsolutePath() + System.getProperty("path.separator") + BytecodeViewer.library, java.getAbsolutePath() ); } @@ -86,26 +91,19 @@ public class JavaCompiler extends Compiler { Process process = pb.start(); BytecodeViewer.createdProcesses.add(process); - Thread failSafe = new Thread() - { + Thread failSafe = new Thread() { @Override - public void run() - { + public void run() { long started = System.currentTimeMillis(); - while(System.currentTimeMillis()-started <= 10_000) - { - try - { + while (System.currentTimeMillis() - started <= 10_000) { + try { Thread.sleep(100); - } - catch (InterruptedException e) - { + } catch (InterruptedException e) { e.printStackTrace(); } } - if(process.isAlive()) - { + if (process.isAlive()) { System.out.println("Force killing javac process, assuming it's gotten stuck"); process.destroyForcibly().destroy(); } @@ -120,8 +118,7 @@ public class JavaCompiler extends Compiler { InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String line; - while ((line = br.readLine()) != null) - { + while ((line = br.readLine()) != null) { log += BytecodeViewer.nl + line; } br.close(); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/compilers/KrakatauAssembler.java b/src/main/java/the/bytecode/club/bytecodeviewer/compilers/KrakatauAssembler.java index 43c63dbe..a760a2b8 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/compilers/KrakatauAssembler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/compilers/KrakatauAssembler.java @@ -4,7 +4,6 @@ import java.io.BufferedReader; import java.io.File; import java.io.InputStream; import java.io.InputStreamReader; - import me.konloch.kontainer.io.DiskWriter; import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.util.JarUtils; @@ -30,87 +29,90 @@ import the.bytecode.club.bytecodeviewer.util.MiscUtils; /** * Krakatau Java assembler, requires Python 2.7 - * - * @author Konloch * + * @author Konloch */ public class KrakatauAssembler extends Compiler { - @Override - public byte[] compile(String contents, String name) { - if(BytecodeViewer.python.equals("")) { - BytecodeViewer.showMessage("You need to set your Python (or PyPy for speed) 2.7 executable path."); - BytecodeViewer.viewer.pythonC(); - } - - if(BytecodeViewer.python.equals("")) { - BytecodeViewer.showMessage("You need to set Python!"); - return null; - } + @Override + public byte[] compile(String contents, String name) { + if (BytecodeViewer.python.equals("")) { + BytecodeViewer.showMessage("You need to set your Python (or PyPy for speed) 2.7 executable path."); + BytecodeViewer.viewer.pythonC(); + } - String origName = name; - name = MiscUtils.randomString(20); + if (BytecodeViewer.python.equals("")) { + BytecodeViewer.showMessage("You need to set Python!"); + return null; + } - File tempD = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32) + BytecodeViewer.fs); - tempD.mkdir(); - - File tempJ = new File(tempD.getAbsolutePath() + BytecodeViewer.fs+name+".j"); - DiskWriter.replaceFile(tempJ.getAbsolutePath(), contents, true); - - final File tempDirectory = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32) + BytecodeViewer.fs); - tempDirectory.mkdir(); - final File tempJar = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp"+MiscUtils.randomString(32)+".jar"); - JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), tempJar.getAbsolutePath()); - - BytecodeViewer.sm.stopBlocking(); + String origName = name; + name = MiscUtils.randomString(20); + + File tempD = + new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32) + BytecodeViewer.fs); + tempD.mkdir(); + + File tempJ = new File(tempD.getAbsolutePath() + BytecodeViewer.fs + name + ".j"); + DiskWriter.replaceFile(tempJ.getAbsolutePath(), contents, true); + + final File tempDirectory = + new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32) + BytecodeViewer.fs); + tempDirectory.mkdir(); + final File tempJar = + new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(32) + + ".jar"); + JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), tempJar.getAbsolutePath()); + + BytecodeViewer.sm.stopBlocking(); String log = ""; - try { - ProcessBuilder pb = new ProcessBuilder( - BytecodeViewer.python, - "-O", //love you storyyeller <3 - BytecodeViewer.krakatauWorkingDirectory + BytecodeViewer.fs + "assemble.py", - "-out", - tempDirectory.getAbsolutePath(), - tempJ.getAbsolutePath() - ); + try { + ProcessBuilder pb = new ProcessBuilder( + BytecodeViewer.python, + "-O", //love you storyyeller <3 + BytecodeViewer.krakatauWorkingDirectory + BytecodeViewer.fs + "assemble.py", + "-out", + tempDirectory.getAbsolutePath(), + tempJ.getAbsolutePath() + ); - Process process = pb.start(); - BytecodeViewer.createdProcesses.add(process); - - //Read out dir output - InputStream is = process.getInputStream(); - InputStreamReader isr = new InputStreamReader(is); - BufferedReader br = new BufferedReader(isr); - String line; - while ((line = br.readLine()) != null) { - log += BytecodeViewer.nl + line; - } - br.close(); - - log += BytecodeViewer.nl+BytecodeViewer.nl+"Error:"+BytecodeViewer.nl+BytecodeViewer.nl; - is = process.getErrorStream(); - isr = new InputStreamReader(is); - br = new BufferedReader(isr); - while ((line = br.readLine()) != null) { - log += BytecodeViewer.nl + line; - } - br.close(); - - int exitValue = process.waitFor(); - log += BytecodeViewer.nl+BytecodeViewer.nl+"Exit Value is " + exitValue; - System.out.println(log); + Process process = pb.start(); + BytecodeViewer.createdProcesses.add(process); - byte[] b = org.apache.commons.io.FileUtils.readFileToByteArray(new File(tempDirectory.getAbsolutePath() + BytecodeViewer.fs + origName + ".class")); - tempDirectory.delete(); - tempJar.delete(); - return b; - } catch(Exception e) { - e.printStackTrace(); - new the.bytecode.club.bytecodeviewer.api.ExceptionUI(log); - } finally { - BytecodeViewer.sm.setBlocking(); - } - - return null; - } + //Read out dir output + InputStream is = process.getInputStream(); + InputStreamReader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr); + String line; + while ((line = br.readLine()) != null) { + log += BytecodeViewer.nl + line; + } + br.close(); + + log += BytecodeViewer.nl + BytecodeViewer.nl + "Error:" + BytecodeViewer.nl + BytecodeViewer.nl; + is = process.getErrorStream(); + isr = new InputStreamReader(is); + br = new BufferedReader(isr); + while ((line = br.readLine()) != null) { + log += BytecodeViewer.nl + line; + } + br.close(); + + int exitValue = process.waitFor(); + log += BytecodeViewer.nl + BytecodeViewer.nl + "Exit Value is " + exitValue; + System.out.println(log); + + byte[] b = org.apache.commons.io.FileUtils.readFileToByteArray(new File(tempDirectory.getAbsolutePath() + BytecodeViewer.fs + origName + ".class")); + tempDirectory.delete(); + tempJar.delete(); + return b; + } catch (Exception e) { + e.printStackTrace(); + new the.bytecode.club.bytecodeviewer.api.ExceptionUI(log); + } finally { + BytecodeViewer.sm.setBlocking(); + } + + return null; + } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/compilers/SmaliAssembler.java b/src/main/java/the/bytecode/club/bytecodeviewer/compilers/SmaliAssembler.java index 7cd8c0a0..7d7fdae8 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/compilers/SmaliAssembler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/compilers/SmaliAssembler.java @@ -1,7 +1,6 @@ package the.bytecode.club.bytecodeviewer.compilers; import java.io.File; - import me.konloch.kontainer.io.DiskWriter; import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.util.Dex2Jar; @@ -55,7 +54,8 @@ public class SmaliAssembler extends Compiler { } try { - com.googlecode.d2j.smali.SmaliCmd.main(new String[]{tempSmaliFolder.getAbsolutePath()});//, "-o", tempDex.getAbsolutePath()}); + com.googlecode.d2j.smali.SmaliCmd.main(new String[]{tempSmaliFolder.getAbsolutePath()});//, "-o", tempDex + // .getAbsolutePath()}); } catch (Exception e) { e.printStackTrace(); new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/ASMTextifierDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/ASMTextifierDecompiler.java index a7afb48f..17abfe95 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/ASMTextifierDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/ASMTextifierDecompiler.java @@ -1,11 +1,10 @@ package the.bytecode.club.bytecodeviewer.decompilers; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.util.Textifier; -import org.objectweb.asm.util.TraceClassVisitor; - import java.io.PrintWriter; import java.io.StringWriter; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.util.Textifier; +import org.objectweb.asm.util.TraceClassVisitor; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -31,15 +30,15 @@ import java.io.StringWriter; * @author Thiakil */ public class ASMTextifierDecompiler extends Decompiler { - @Override - public String decompileClassNode(ClassNode cn, byte[] b) { - StringWriter writer = new StringWriter(); - cn.accept(new TraceClassVisitor(null, new Textifier(), new PrintWriter(writer))); - return writer.toString(); - } + @Override + public String decompileClassNode(ClassNode cn, byte[] b) { + StringWriter writer = new StringWriter(); + cn.accept(new TraceClassVisitor(null, new Textifier(), new PrintWriter(writer))); + return writer.toString(); + } - @Override - public void decompileToZip(String sourceJar, String zipName) { + @Override + public void decompileToZip(String sourceJar, String zipName) { - } + } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/CFRDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/CFRDecompiler.java index f2573514..0bd0af6f 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/CFRDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/CFRDecompiler.java @@ -14,11 +14,8 @@ import java.util.LinkedList; import java.util.Random; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; - import me.konloch.kontainer.io.DiskReader; - import org.objectweb.asm.tree.ClassNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.util.MiscUtils; @@ -50,36 +47,33 @@ public class CFRDecompiler extends Decompiler { private static final String[] WINDOWS_IS_GREAT = new String[] { - "CON", - "PRN", - "AUX", - "NUL", - "COM1", - "COM2", - "COM3", - "COM4", - "COM5", - "COM6", - "COM7", - "COM8", - "COM9", - "LPT1", - "LPT2", - "LPT3", - "LPT4", - "LPT5", - "LPT6", - "LPT7", - "LPT8", - "LPT9" + "CON", + "PRN", + "AUX", + "NUL", + "COM1", + "COM2", + "COM3", + "COM4", + "COM5", + "COM6", + "COM7", + "COM8", + "COM9", + "LPT1", + "LPT2", + "LPT3", + "LPT4", + "LPT5", + "LPT6", + "LPT7", + "LPT8", + "LPT9" }; - public static String windowsFun(String base) - { - for(String s : WINDOWS_IS_GREAT) - { - if(base.contains(s.toLowerCase())) - { + public static String windowsFun(String base) { + for (String s : WINDOWS_IS_GREAT) { + if (base.contains(s.toLowerCase())) { base = base.replace(s.toLowerCase(), "BCV"); } } @@ -126,23 +120,21 @@ public class CFRDecompiler extends Decompiler { org.benf.cfr.reader.Main.main(generateMainMethod(tempClass.getAbsolutePath(), fuckery)); }*/ - try - { + try { org.benf.cfr.reader.Main.main(generateMainMethod(tempClass.getAbsolutePath(), fuckery)); - } - catch(StackOverflowError | Exception e) - { + } catch (StackOverflowError | Exception e) { StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); e.printStackTrace(); - exception = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString(); + exception = + "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw; } tempClass.delete(); File file = new File(fuckery); - if(file.exists()) + if (file.exists()) return findFile(file.listFiles()); return "CFR error! Send the stacktrace to Konloch at http://the.bytecode.club or konloch@gmail.com" + BytecodeViewer.nl + BytecodeViewer.nl + "Suggested Fix: Click refresh class, if it fails again try another decompiler." + BytecodeViewer.nl + BytecodeViewer.nl + exception; @@ -175,13 +167,17 @@ public class CFRDecompiler extends Decompiler { e.printStackTrace(new PrintWriter(sw)); e.printStackTrace(); - String exception = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString(); - return "CFR error! Send the stacktrace to Konloch at http://the.bytecode.club or konloch@gmail.com" + BytecodeViewer.nl + BytecodeViewer.nl + "Suggested Fix: Click refresh class, if it fails again try another decompiler." + BytecodeViewer.nl + BytecodeViewer.nl + exception; + String exception = + "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw; + return "CFR error! Send the stacktrace to Konloch at http://the.bytecode.club or konloch@gmail" + + ".com" + BytecodeViewer.nl + BytecodeViewer.nl + "Suggested Fix: Click refresh class, " + + "if it fails again try another decompiler." + BytecodeViewer.nl + BytecodeViewer.nl + exception; } return s; } } - return "CFR error!" + BytecodeViewer.nl + BytecodeViewer.nl + "Suggested Fix: Click refresh class, if it fails again try another decompiler."; + return "CFR error!" + BytecodeViewer.nl + BytecodeViewer.nl + "Suggested Fix: Click refresh class, if it " + + "fails again try another decompiler."; } public String[] generateMainMethod(String filePath, String outputPath) { @@ -301,8 +297,7 @@ public class CFRDecompiler extends Decompiler { byte[] buffer = new byte[1024]; @Override - public void decompileToZip(String sourceJar, String zipName) - { + public void decompileToZip(String sourceJar, String zipName) { File tempZip = new File(sourceJar); String fileStart = BytecodeViewer.tempDirectory + BytecodeViewer.fs; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/Decompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/Decompiler.java index 0d72a675..f2113a18 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/Decompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/Decompiler.java @@ -1,7 +1,6 @@ package the.bytecode.club.bytecodeviewer.decompilers; import org.objectweb.asm.tree.ClassNode; - import the.bytecode.club.bytecodeviewer.decompilers.bytecode.ClassNodeDecompiler; /*************************************************************************** diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/FernFlowerDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/FernFlowerDecompiler.java index 7dfac2a7..cc7274c7 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/FernFlowerDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/FernFlowerDecompiler.java @@ -5,15 +5,12 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; - import me.konloch.kontainer.io.DiskReader; - import org.apache.commons.lang3.ArrayUtils; import org.objectweb.asm.tree.ClassNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.util.MiscUtils; import the.bytecode.club.bytecodeviewer.Resources; +import the.bytecode.club.bytecodeviewer.util.MiscUtils; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -49,16 +46,14 @@ public class FernFlowerDecompiler extends Decompiler { File f = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + BytecodeViewer.fs); f.mkdir(); - try - { + try { org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler.main(generateMainMethod(tempZip.getAbsolutePath(), BytecodeViewer.tempDirectory + "./temp/")); - } - catch(StackOverflowError | Exception e) - { + } catch (StackOverflowError | Exception e) { } - File tempZip2 = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + BytecodeViewer.fs + tempZip.getName()); + File tempZip2 = + new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + BytecodeViewer.fs + tempZip.getName()); if (tempZip2.exists()) tempZip2.renameTo(new File(zipName)); @@ -67,7 +62,7 @@ public class FernFlowerDecompiler extends Decompiler { @Override public String decompileClassNode(final ClassNode cn, byte[] b) { - String start = BytecodeViewer.tempDirectory + BytecodeViewer.fs+MiscUtils.getUniqueName("", ".class"); + String start = BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.getUniqueName("", ".class"); final File tempClass = new File(start + ".class"); @@ -83,7 +78,8 @@ public class FernFlowerDecompiler extends Decompiler { e.printStackTrace(new PrintWriter(sw)); e.printStackTrace(); - exception = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString(); + exception = + "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw; } @@ -91,7 +87,8 @@ public class FernFlowerDecompiler extends Decompiler { try { ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll( new String[]{BytecodeViewer.getJavaCommand(), "-jar", Resources.findLibrary("fernflower")}, - generateMainMethod(tempClass.getAbsolutePath(), new File(BytecodeViewer.tempDirectory).getAbsolutePath()) + generateMainMethod(tempClass.getAbsolutePath(), + new File(BytecodeViewer.tempDirectory).getAbsolutePath()) )); BytecodeViewer.sm.stopBlocking(); Process p = pb.start(); @@ -102,21 +99,17 @@ public class FernFlowerDecompiler extends Decompiler { } finally { BytecodeViewer.sm.setBlocking(); } - } - else - { - try - { + } else { + try { org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler.main(generateMainMethod(tempClass.getAbsolutePath(), new File(BytecodeViewer.tempDirectory).getAbsolutePath())); - } - catch(StackOverflowError | Exception e) - { + } catch (StackOverflowError | Exception e) { StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); e.printStackTrace(); - exception = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString(); + exception = + "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw; } } @@ -136,7 +129,7 @@ public class FernFlowerDecompiler extends Decompiler { e.printStackTrace(new PrintWriter(sw)); e.printStackTrace(); - exception += BytecodeViewer.nl + BytecodeViewer.nl + sw.toString(); + exception += BytecodeViewer.nl + BytecodeViewer.nl + sw; } } return "FernFlower error! Send the stacktrace to Konloch at http://the.bytecode.club or konloch@gmail.com" + BytecodeViewer.nl + BytecodeViewer.nl + "Suggested Fix: Click refresh class, if it fails again try another decompiler." + BytecodeViewer.nl + BytecodeViewer.nl + exception; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/JADXDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/JADXDecompiler.java index 5e7b699d..bfe48811 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/JADXDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/JADXDecompiler.java @@ -2,18 +2,17 @@ package the.bytecode.club.bytecodeviewer.decompilers; import jadx.api.JadxArgs; import jadx.api.JadxDecompiler; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Random; import me.konloch.kontainer.io.DiskReader; import org.objectweb.asm.tree.ClassNode; import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.util.MiscUtils; -import java.io.*; -import java.util.Deque; -import java.util.LinkedList; -import java.util.Random; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * @@ -38,8 +37,7 @@ import java.util.zip.ZipOutputStream; * @author Konloch */ -public class JADXDecompiler extends Decompiler -{ +public class JADXDecompiler extends Decompiler { @Override public String decompileClassNode(ClassNode cn, byte[] b) { String fileStart = BytecodeViewer.tempDirectory + BytecodeViewer.fs; @@ -58,8 +56,7 @@ public class JADXDecompiler extends Decompiler } File fuckery = new File(fuckery(fileStart)); - try - { + try { JadxArgs args = new JadxArgs(); args.getInputFiles().add(tempClass); args.setOutDir(fuckery); @@ -67,19 +64,18 @@ public class JADXDecompiler extends Decompiler JadxDecompiler jadx = new JadxDecompiler(args); jadx.load(); jadx.save(); - } - catch(StackOverflowError | Exception e) - { + } catch (StackOverflowError | Exception e) { StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); e.printStackTrace(); - exception = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString(); + exception = + "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw; } tempClass.delete(); - if(fuckery.exists()) + if (fuckery.exists()) return findFile(fuckery.listFiles()); return "JADX error! Send the stacktrace to Konloch at http://the.bytecode.club or konloch@gmail.com" + BytecodeViewer.nl + BytecodeViewer.nl + "Suggested Fix: Click refresh class, if it fails again try another decompiler." + BytecodeViewer.nl + BytecodeViewer.nl + exception; @@ -114,18 +110,21 @@ public class JADXDecompiler extends Decompiler e.printStackTrace(new PrintWriter(sw)); e.printStackTrace(); - String exception = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString(); - return "JADX error! Send the stacktrace to Konloch at http://the.bytecode.club or konloch@gmail.com" + BytecodeViewer.nl + BytecodeViewer.nl + "Suggested Fix: Click refresh class, if it fails again try another decompiler." + BytecodeViewer.nl + BytecodeViewer.nl + exception; + String exception = + "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw; + return "JADX error! Send the stacktrace to Konloch at http://the.bytecode.club or konloch@gmail" + + ".com" + BytecodeViewer.nl + BytecodeViewer.nl + "Suggested Fix: Click refresh class, " + + "if it fails again try another decompiler." + BytecodeViewer.nl + BytecodeViewer.nl + exception; } return s; } } - return "CFR error!" + BytecodeViewer.nl + BytecodeViewer.nl + "Suggested Fix: Click refresh class, if it fails again try another decompiler."; + return "CFR error!" + BytecodeViewer.nl + BytecodeViewer.nl + "Suggested Fix: Click refresh class, if it " + + "fails again try another decompiler."; } @Override - public void decompileToZip(String sourceJar, String zipName) - { + public void decompileToZip(String sourceJar, String zipName) { } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/JDGUIDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/JDGUIDecompiler.java index 4359327f..85b0a4a8 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/JDGUIDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/JDGUIDecompiler.java @@ -6,18 +6,15 @@ import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; - import jd.cli.loader.DirectoryLoader; import jd.cli.preferences.CommonPreferences; +import jd.cli.printer.text.PlainTextPrinter; import jd.cli.util.ClassFileUtil; import jd.core.process.DecompilerImpl; import me.konloch.kontainer.io.DiskReader; - import org.objectweb.asm.tree.ClassNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.util.MiscUtils; -import jd.cli.printer.text.PlainTextPrinter; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -50,7 +47,8 @@ public class JDGUIDecompiler extends Decompiler { public String decompileClassNode(ClassNode cn, byte[] b) { String exception = ""; try { - final File tempDirectory = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32) + BytecodeViewer.fs); + final File tempDirectory = + new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32) + BytecodeViewer.fs); tempDirectory.mkdir(); final File tempClass = new File(tempDirectory.getAbsolutePath() + BytecodeViewer.fs + cn.name + ".class"); final File tempJava = new File(tempDirectory.getAbsolutePath() + BytecodeViewer.fs + cn.name + ".java"); @@ -76,7 +74,8 @@ public class JDGUIDecompiler extends Decompiler { } - String pathToClass = tempClass.getAbsolutePath().replace('/', File.separatorChar).replace('\\', File.separatorChar); + String pathToClass = tempClass.getAbsolutePath().replace('/', File.separatorChar).replace('\\', + File.separatorChar); String directoryPath = ClassFileUtil.ExtractDirectoryPath(pathToClass); String internalPath = ClassFileUtil.ExtractInternalPath(directoryPath, pathToClass); @@ -112,7 +111,8 @@ public class JDGUIDecompiler extends Decompiler { e.printStackTrace(new PrintWriter(sw)); e.printStackTrace(); - exception = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString(); + exception = + "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw; } return "JD-GUI error! Send the stacktrace to Konloch at http://the.bytecode.club or konloch@gmail.com" + BytecodeViewer.nl + BytecodeViewer.nl + "Suggested Fix: Click refresh class, if it fails again try another decompiler." + BytecodeViewer.nl + BytecodeViewer.nl + exception; } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDecompiler.java index 5c5659b3..9ac11ed8 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDecompiler.java @@ -6,11 +6,8 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringWriter; - import me.konloch.kontainer.io.DiskReader; - import org.objectweb.asm.tree.ClassNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.util.JarUtils; import the.bytecode.club.bytecodeviewer.util.MiscUtils; @@ -49,8 +46,7 @@ public class KrakatauDecompiler extends Decompiler { return ";" + BytecodeViewer.library; } - public String decompileClassNode(File krakatauTempJar, File krakatauTempDir, ClassNode cn, byte[] b) - { + public String decompileClassNode(File krakatauTempJar, File krakatauTempDir, ClassNode cn, byte[] b) { if (BytecodeViewer.python.equals("")) { BytecodeViewer.showMessage("You need to set your Python (or PyPy for speed) 2.7 executable path."); BytecodeViewer.viewer.pythonC(); @@ -58,7 +54,8 @@ public class KrakatauDecompiler extends Decompiler { BytecodeViewer.rtCheck(); if (BytecodeViewer.rt.equals("")) { - BytecodeViewer.showMessage("You need to set your JRE RT Library.\r\n(C:\\Program Files (x86)\\Java\\jre7\\lib\\rt.jar)"); + BytecodeViewer.showMessage("You need to set your JRE RT Library.\r\n(C:\\Program Files (x86)" + + "\\Java\\jre7\\lib\\rt.jar)"); BytecodeViewer.viewer.rtC(); } @@ -72,7 +69,8 @@ public class KrakatauDecompiler extends Decompiler { return "Set your paths"; } - String s = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + "Please send this to konloch@gmail.com. " + BytecodeViewer.nl + BytecodeViewer.nl; + String s = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + + "Please send this to konloch@gmail.com. " + BytecodeViewer.nl + BytecodeViewer.nl; BytecodeViewer.sm.stopBlocking(); try { @@ -122,7 +120,7 @@ public class KrakatauDecompiler extends Decompiler { StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); e.printStackTrace(); - s += BytecodeViewer.nl + "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString(); + s += BytecodeViewer.nl + "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw; } finally { BytecodeViewer.sm.setBlocking(); } @@ -131,14 +129,14 @@ public class KrakatauDecompiler extends Decompiler { } @Override - public String decompileClassNode(ClassNode cn, byte[] b) - { + public String decompileClassNode(ClassNode cn, byte[] b) { if (BytecodeViewer.python.equals("")) { BytecodeViewer.showMessage("You need to set your Python (or PyPy for speed) 2.7 executable path."); BytecodeViewer.viewer.pythonC(); } if (BytecodeViewer.rt.equals("")) { - BytecodeViewer.showMessage("You need to set your JRE RT Library.\r\n(C:\\Program Files (x86)\\Java\\jre7\\lib\\rt.jar)"); + BytecodeViewer.showMessage("You need to set your JRE RT Library.\r\n(C:\\Program Files (x86)" + + "\\Java\\jre7\\lib\\rt.jar)"); BytecodeViewer.viewer.rtC(); } @@ -152,11 +150,15 @@ public class KrakatauDecompiler extends Decompiler { return "Set your paths"; } - String s = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + "Please send this to konloch@gmail.com. " + BytecodeViewer.nl + BytecodeViewer.nl; + String s = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + + "Please send this to konloch@gmail.com. " + BytecodeViewer.nl + BytecodeViewer.nl; - final File tempDirectory = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32) + BytecodeViewer.fs); + final File tempDirectory = + new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32) + BytecodeViewer.fs); tempDirectory.mkdir(); - final File tempJar = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(32) + ".jar"); + final File tempJar = + new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(32) + + ".jar"); JarUtils.saveAsJarClassesOnly(BytecodeViewer.getLoadedClasses(), tempJar.getAbsolutePath()); BytecodeViewer.sm.stopBlocking(); @@ -210,7 +212,7 @@ public class KrakatauDecompiler extends Decompiler { StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); e.printStackTrace(); - s += BytecodeViewer.nl + "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString(); + s += BytecodeViewer.nl + "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw; } finally { BytecodeViewer.sm.setBlocking(); } @@ -225,7 +227,8 @@ public class KrakatauDecompiler extends Decompiler { } BytecodeViewer.rtCheck(); if (BytecodeViewer.rt.equals("")) { - BytecodeViewer.showMessage("You need to set your JRE RT Library.\r\n(C:\\Program Files (x86)\\Java\\jre7\\lib\\rt.jar)"); + BytecodeViewer.showMessage("You need to set your JRE RT Library.\r\n(C:\\Program Files (x86)" + + "\\Java\\jre7\\lib\\rt.jar)"); BytecodeViewer.viewer.rtC(); } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDisassembler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDisassembler.java index 8057a07e..ea76b204 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDisassembler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/KrakatauDisassembler.java @@ -6,11 +6,8 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringWriter; - import me.konloch.kontainer.io.DiskReader; - import org.objectweb.asm.tree.ClassNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.util.JarUtils; import the.bytecode.club.bytecodeviewer.util.MiscUtils; @@ -53,7 +50,8 @@ public class KrakatauDisassembler extends Decompiler { return "Set your paths"; } - String s = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + "Please send this to konloch@gmail.com. " + BytecodeViewer.nl + BytecodeViewer.nl; + String s = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + + "Please send this to konloch@gmail.com. " + BytecodeViewer.nl + BytecodeViewer.nl; BytecodeViewer.sm.stopBlocking(); try { @@ -101,7 +99,7 @@ public class KrakatauDisassembler extends Decompiler { StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); e.printStackTrace(); - s += BytecodeViewer.nl + "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString(); + s += BytecodeViewer.nl + "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw; } finally { BytecodeViewer.sm.setBlocking(); } @@ -120,11 +118,15 @@ public class KrakatauDisassembler extends Decompiler { return "Set your paths"; } - String s = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + "Please send this to konloch@gmail.com. " + BytecodeViewer.nl + BytecodeViewer.nl; + String s = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + + "Please send this to konloch@gmail.com. " + BytecodeViewer.nl + BytecodeViewer.nl; - final File tempDirectory = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32) + BytecodeViewer.fs); + final File tempDirectory = + new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32) + BytecodeViewer.fs); tempDirectory.mkdir(); - final File tempJar = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(32) + ".jar"); + final File tempJar = + new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp" + MiscUtils.randomString(32) + + ".jar"); JarUtils.saveAsJarClassesOnly(BytecodeViewer.getLoadedClasses(), tempJar.getAbsolutePath()); BytecodeViewer.sm.stopBlocking(); @@ -173,7 +175,7 @@ public class KrakatauDisassembler extends Decompiler { StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); e.printStackTrace(); - s += BytecodeViewer.nl + "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString(); + s += BytecodeViewer.nl + "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw; } finally { BytecodeViewer.sm.setBlocking(); } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/ProcyonDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/ProcyonDecompiler.java index 7be7742b..db1964b0 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/ProcyonDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/ProcyonDecompiler.java @@ -1,5 +1,17 @@ package the.bytecode.club.bytecodeviewer.decompilers; +import com.strobel.assembler.InputTypeLoader; +import com.strobel.assembler.metadata.Buffer; +import com.strobel.assembler.metadata.ITypeLoader; +import com.strobel.assembler.metadata.JarTypeLoader; +import com.strobel.assembler.metadata.MetadataSystem; +import com.strobel.assembler.metadata.TypeDefinition; +import com.strobel.assembler.metadata.TypeReference; +import com.strobel.core.StringUtilities; +import com.strobel.decompiler.DecompilationOptions; +import com.strobel.decompiler.DecompilerSettings; +import com.strobel.decompiler.PlainTextOutput; +import com.strobel.decompiler.languages.java.JavaFormattingOptions; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; @@ -18,22 +30,7 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.zip.ZipException; import java.util.zip.ZipOutputStream; - import org.objectweb.asm.tree.ClassNode; - -import com.strobel.core.StringUtilities; -import com.strobel.decompiler.DecompilationOptions; -import com.strobel.decompiler.DecompilerSettings; -import com.strobel.decompiler.PlainTextOutput; -import com.strobel.decompiler.languages.java.JavaFormattingOptions; -import com.strobel.assembler.InputTypeLoader; -import com.strobel.assembler.metadata.Buffer; -import com.strobel.assembler.metadata.ITypeLoader; -import com.strobel.assembler.metadata.JarTypeLoader; -import com.strobel.assembler.metadata.MetadataSystem; -import com.strobel.assembler.metadata.TypeDefinition; -import com.strobel.assembler.metadata.TypeReference; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.util.EncodeUtils; import the.bytecode.club.bytecodeviewer.util.MiscUtils; @@ -142,7 +139,8 @@ public class ProcyonDecompiler extends Decompiler { e.printStackTrace(new PrintWriter(sw)); e.printStackTrace(); - exception = "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString(); + exception = + "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw; } return "Procyon error! Send the stacktrace to Konloch at http://the.bytecode.club or konloch@gmail.com" + BytecodeViewer.nl + BytecodeViewer.nl + "Suggested Fix: Click refresh class, if it fails again try another decompiler." + BytecodeViewer.nl + BytecodeViewer.nl + exception; } @@ -164,8 +162,8 @@ public class ProcyonDecompiler extends Decompiler { try (JarFile jfile = new JarFile(inFile); FileOutputStream dest = new FileOutputStream(outFile); BufferedOutputStream buffDest = new BufferedOutputStream(dest); - ZipOutputStream out = new ZipOutputStream(buffDest);) { - byte data[] = new byte[1024]; + ZipOutputStream out = new ZipOutputStream(buffDest)) { + byte[] data = new byte[1024]; DecompilerSettings settings = getDecompilerSettings(); LuytenTypeLoader typeLoader = new LuytenTypeLoader(); MetadataSystem metadataSystem = new MetadataSystem(typeLoader); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/SmaliDisassembler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/SmaliDisassembler.java index 21057472..7e9c04a1 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/SmaliDisassembler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/SmaliDisassembler.java @@ -1,17 +1,17 @@ package the.bytecode.club.bytecodeviewer.decompilers; -import java.io.*; - +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; import me.konloch.kontainer.io.DiskReader; - import org.apache.commons.io.FileUtils; import org.objectweb.asm.tree.ClassNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.util.Dex2Jar; import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.MiscUtils; -import the.bytecode.club.bytecodeviewer.util.ZipUtils; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -63,32 +63,26 @@ public class SmaliDisassembler extends Decompiler { Dex2Jar.saveAsDex(tempClass, tempDex, true); - try - { + try { com.googlecode.d2j.smali.BaksmaliCmd.main(new String[]{tempDex.getAbsolutePath()}); - } - catch(Exception e) - { + } catch (Exception e) { StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); e.printStackTrace(); - exception += "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString(); + exception += "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw; } File rename = new File(tempDex.getName().replaceFirst("\\.dex", "-out")); - try - { + try { FileUtils.moveDirectory(rename, tempSmali); - } - catch (IOException e) - { + } catch (IOException e) { StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); e.printStackTrace(); - exception += "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString(); + exception += "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw; } File outputSmali = null; @@ -112,15 +106,16 @@ public class SmaliDisassembler extends Decompiler { e.printStackTrace(new PrintWriter(sw)); e.printStackTrace(); - exception += "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString(); + exception += "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw; } - return "Smali Disassembler error! Send the stacktrace to Konloch at http://the.bytecode.club or konloch@gmail.com" + BytecodeViewer.nl + BytecodeViewer.nl + "Suggested Fix: Click refresh class, if it fails again try another decompiler." + BytecodeViewer.nl + BytecodeViewer.nl + exception; + return "Smali Disassembler error! Send the stacktrace to Konloch at http://the.bytecode.club or konloch@gmail" + + ".com" + BytecodeViewer.nl + BytecodeViewer.nl + "Suggested Fix: Click refresh class, if it fails " + + "again try another decompiler." + BytecodeViewer.nl + BytecodeViewer.nl + exception; } @Override - public String decompileClassNode(ClassNode cn, byte[] b) - { + public String decompileClassNode(ClassNode cn, byte[] b) { return null; } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/ClassNodeDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/ClassNodeDecompiler.java index d4a54a32..81dfa9f8 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/ClassNodeDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/ClassNodeDecompiler.java @@ -2,14 +2,12 @@ package the.bytecode.club.bytecodeviewer.decompilers.bytecode; import java.util.ArrayList; import java.util.List; - import org.objectweb.asm.Attribute; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.InnerClassNode; import org.objectweb.asm.tree.MethodNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.decompilers.Decompiler; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/FieldNodeDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/FieldNodeDecompiler.java index faa613df..236340a9 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/FieldNodeDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/FieldNodeDecompiler.java @@ -2,7 +2,6 @@ package the.bytecode.club.bytecodeviewer.decompilers.bytecode; import java.util.ArrayList; import java.util.List; - import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.FieldNode; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/InstructionPattern.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/InstructionPattern.java index 4d2fac7f..0d116027 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/InstructionPattern.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/InstructionPattern.java @@ -1,20 +1,5 @@ package the.bytecode.club.bytecodeviewer.decompilers.bytecode; -import java.util.Arrays; - -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.FieldInsnNode; -import org.objectweb.asm.tree.IincInsnNode; -import org.objectweb.asm.tree.InsnNode; -import org.objectweb.asm.tree.JumpInsnNode; -import org.objectweb.asm.tree.LabelNode; -import org.objectweb.asm.tree.LdcInsnNode; -import org.objectweb.asm.tree.MethodInsnNode; -import org.objectweb.asm.tree.MultiANewArrayInsnNode; -import org.objectweb.asm.tree.TypeInsnNode; -import org.objectweb.asm.tree.VarInsnNode; - import eu.bibl.banalysis.filter.InstructionFilter; import eu.bibl.banalysis.filter.OpcodeFilter; import eu.bibl.banalysis.filter.insn.FieldInstructionFilter; @@ -26,6 +11,19 @@ import eu.bibl.banalysis.filter.insn.MethodInstructionFilter; import eu.bibl.banalysis.filter.insn.MultiANewArrayInstructionFilter; import eu.bibl.banalysis.filter.insn.TypeInstructionFilter; import eu.bibl.banalysis.filter.insn.VarInstructionFilter; +import java.util.Arrays; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.IincInsnNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MultiANewArrayInsnNode; +import org.objectweb.asm.tree.TypeInsnNode; +import org.objectweb.asm.tree.VarInsnNode; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -124,7 +122,7 @@ public class InstructionPattern implements Opcodes { /** * @return Last pattern sequence match equivilent from the inputted - * {@link AbstractInsnNode}s. + * {@link AbstractInsnNode}s. */ public AbstractInsnNode[] getLastMatch() { return lastMatch; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/InstructionPrinter.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/InstructionPrinter.java index 8e1210df..c9733bc9 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/InstructionPrinter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/InstructionPrinter.java @@ -1,5 +1,6 @@ package the.bytecode.club.bytecodeviewer.decompilers.bytecode; +import eu.bibl.banalysis.asm.desc.OpcodeInfo; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; @@ -10,14 +11,27 @@ import java.util.HashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; - import org.apache.commons.lang3.StringEscapeUtils; import org.objectweb.asm.Type; -import org.objectweb.asm.tree.*; - -import org.objectweb.asm.tree.analysis.Frame; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.FrameNode; +import org.objectweb.asm.tree.IincInsnNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.IntInsnNode; +import org.objectweb.asm.tree.InvokeDynamicInsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.LineNumberNode; +import org.objectweb.asm.tree.LookupSwitchInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.MultiANewArrayInsnNode; +import org.objectweb.asm.tree.TableSwitchInsnNode; +import org.objectweb.asm.tree.TypeInsnNode; +import org.objectweb.asm.tree.VarInsnNode; import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import eu.bibl.banalysis.asm.desc.OpcodeInfo; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -46,8 +60,8 @@ public class InstructionPrinter { /** * The MethodNode to print **/ - private MethodNode mNode; - private TypeAndName[] args; + private final MethodNode mNode; + private final TypeAndName[] args; protected int[] pattern; protected boolean match; @@ -138,7 +152,7 @@ public class InstructionPrinter { line = printMultiANewArrayInsNode((MultiANewArrayInsnNode) ain); } else { line += "UNADDED OPCODE: " + nameOpcode(ain.getOpcode()) + " " - + ain.toString(); + + ain; } if (!line.equals("")) { if (match) @@ -255,32 +269,27 @@ public class InstructionPrinter { } } - protected String printIincInsnNode(IincInsnNode iin) - { + protected String printIincInsnNode(IincInsnNode iin) { return nameOpcode(iin.getOpcode()) + " " + iin.var + " " + iin.incr; } - protected String printTableSwitchInsnNode(TableSwitchInsnNode tin) - { + protected String printTableSwitchInsnNode(TableSwitchInsnNode tin) { String line = nameOpcode(tin.getOpcode()) + " \n"; List labels = tin.labels; int count = 0; - for (int i = tin.min; i < tin.max + 1; i++) - { + for (int i = tin.min; i < tin.max + 1; i++) { line += " val: " + i + " -> " + "L" + resolveLabel((LabelNode) labels.get(count++)) + "\n"; } line += " default" + " -> L" + resolveLabel(tin.dflt) + ""; return line; } - protected String printLookupSwitchInsnNode(LookupSwitchInsnNode lin) - { + protected String printLookupSwitchInsnNode(LookupSwitchInsnNode lin) { String line = nameOpcode(lin.getOpcode()) + ": \n"; List keys = lin.keys; List labels = lin.labels; - for (int i = 0; i < keys.size(); i++) - { + for (int i = 0; i < keys.size(); i++) { int key = (Integer) keys.get(i); LabelNode label = (LabelNode) labels.get(i); line += " val: " + key + " -> " + "L" + resolveLabel(label) + "\n"; @@ -293,7 +302,7 @@ public class InstructionPrinter { protected String printInvokeDynamicInsNode(InvokeDynamicInsnNode idin) { StringBuilder sb = new StringBuilder(); sb.append(nameOpcode(idin.getOpcode()) + " " + idin.bsm.getOwner() + '.' + idin.bsm.getName() + idin.bsm.getDesc() - + " : " + idin.name + idin.desc); + + " : " + idin.name + idin.desc); if (idin.bsmArgs != null) { for (Object o : idin.bsmArgs) { @@ -305,10 +314,9 @@ public class InstructionPrinter { return sb.toString(); } - protected String printMultiANewArrayInsNode(MultiANewArrayInsnNode mana) - { + protected String printMultiANewArrayInsNode(MultiANewArrayInsnNode mana) { StringBuilder sb = new StringBuilder(); - sb.append(nameOpcode(mana.getOpcode()) + " " + mana.dims + " : " + mana.desc); + sb.append(nameOpcode(mana.getOpcode()) + " " + mana.dims + " : " + mana.desc); return sb.toString(); } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/InstructionSearcher.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/InstructionSearcher.java index a3312d2f..4f9ed2fc 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/InstructionSearcher.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/InstructionSearcher.java @@ -2,7 +2,6 @@ package the.bytecode.club.bytecodeviewer.decompilers.bytecode; import java.util.ArrayList; import java.util.List; - import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.FrameNode; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/MethodNodeDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/MethodNodeDecompiler.java index fdb333cc..6e3a58d0 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/MethodNodeDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/bytecode/MethodNodeDecompiler.java @@ -3,7 +3,6 @@ package the.bytecode.club.bytecodeviewer.decompilers.bytecode; import java.util.ArrayList; import java.util.Arrays; import java.util.List; - import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AnnotationNode; @@ -11,9 +10,7 @@ import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TryCatchBlockNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.decompilers.bytecode.TypeAndName; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/AboutWindow.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/AboutWindow.java index e7a04c9a..07bd7755 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/AboutWindow.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/AboutWindow.java @@ -1,19 +1,15 @@ package the.bytecode.club.bytecodeviewer.gui; -import javax.swing.JFrame; - import java.awt.CardLayout; +import java.awt.Color; import java.awt.Font; import java.awt.Toolkit; - +import javax.swing.JFrame; +import javax.swing.JScrollPane; import javax.swing.JTextArea; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.Resources; -import java.awt.Color; -import javax.swing.JScrollPane; - /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * @@ -61,7 +57,9 @@ public class AboutWindow extends JFrame { public void setVisible(boolean b) { super.setVisible(b); textArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); - textArea.setText("Bytecode Viewer " + BytecodeViewer.VERSION + " is an open source program developed and maintained by Konloch (konloch@gmail.com) 100% free and open sourced licensed under GPL v3 CopyLeft\r\n\r\n" + + textArea.setText("Bytecode Viewer " + BytecodeViewer.VERSION + " is an open source program developed and " + + "maintained by Konloch (konloch@gmail.com) 100% free and open sourced licensed under GPL v3 " + + "CopyLeft\r\n\r\n" + "Settings:" + BytecodeViewer.nl + " Preview Copy: " + BytecodeViewer.PREVIEW_COPY + BytecodeViewer.nl + " Fat Jar: " + BytecodeViewer.FAT_JAR + BytecodeViewer.nl + @@ -80,9 +78,11 @@ public class AboutWindow extends JFrame { " -help Displays the help menu" + BytecodeViewer.nl + " -list Displays the available decompilers" + BytecodeViewer.nl + " -decompiler Selects the decompiler, procyon by default" + BytecodeViewer.nl + - " -i Selects the input file (Jar, Class, APK, ZIP, DEX all work automatically)" + BytecodeViewer.nl + + " -i Selects the input file (Jar, Class, APK, ZIP, DEX all work " + + "automatically)" + BytecodeViewer.nl + " -o Selects the output file (Java or Java-Bytecode)" + BytecodeViewer.nl + - " -t Must either be the fully qualified classname or \"all\" to decompile all as zip" + BytecodeViewer.nl + + " -t Must either be the fully qualified classname or \"all\" to decompile" + + " all as zip" + BytecodeViewer.nl + " -nowait Doesn't wait for the user to read the CLI messages" + BytecodeViewer.nl + BytecodeViewer.nl + "Keybinds:" + BytecodeViewer.nl + " CTRL + O: Open/add new jar/class/apk" + BytecodeViewer.nl + @@ -91,7 +91,13 @@ public class AboutWindow extends JFrame { " CTRL + T: Compile" + BytecodeViewer.nl + " CTRL + S: Save classes as zip" + BytecodeViewer.nl + " CTRL + R: Run (EZ-Inject) - dynamically load the classes and invoke a main class" + - "\r\n\r\nCode from various projects has been used, including but not limited to:\r\n J-RET by WaterWolf\r\n JHexPane by Sam Koivu\r\n RSynaxPane by Robert Futrell\r\n Commons IO by Apache\r\n ASM by OW2\r\n FernFlower by Stiver\r\n Procyon by Mstrobel\r\n CFR by Lee Benfield\r\n CFIDE by Bibl\r\n Smali by JesusFreke\r\n Dex2Jar by pxb1..?\r\n Krakatau by Storyyeller\r\n JD-GUI + JD-Core by The Java-Decompiler Team\r\n Enjarify by Storyyeller\r\n\r\nIf you're interested in Java Reverse Engineering, join The Bytecode Club - https://the.bytecode.club"); + "\r\n\r\nCode from various projects has been used, including but not limited to:\r\n J-RET by " + + "WaterWolf\r\n JHexPane by Sam Koivu\r\n RSynaxPane by Robert Futrell\r\n Commons IO by " + + "Apache\r\n ASM by OW2\r\n FernFlower by Stiver\r\n Procyon by Mstrobel\r\n CFR by Lee " + + "Benfield\r\n CFIDE by Bibl\r\n Smali by JesusFreke\r\n Dex2Jar by pxb1..?\r\n Krakatau by " + + "Storyyeller\r\n JD-GUI + JD-Core by The Java-Decompiler Team\r\n Enjarify by " + + "Storyyeller\r\n\r\nIf you're interested in Java Reverse Engineering, join The Bytecode Club - " + + "https://the.bytecode.club"); } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/ClassViewer.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/ClassViewer.java index dc5bd0fe..39673f1c 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/ClassViewer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/ClassViewer.java @@ -1,6 +1,13 @@ package the.bytecode.club.bytecodeviewer.gui; -import java.awt.*; +import com.jhe.hexed.JHexEditor; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; @@ -13,28 +20,43 @@ import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; - -import javax.swing.*; -import javax.swing.text.*; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSplitPane; +import javax.swing.JTextField; +import javax.swing.JViewport; +import javax.swing.SwingUtilities; +import javax.swing.text.AbstractDocument; +import javax.swing.text.BadLocationException; +import javax.swing.text.BoxView; +import javax.swing.text.ComponentView; +import javax.swing.text.DefaultHighlighter; +import javax.swing.text.Element; +import javax.swing.text.Highlighter; +import javax.swing.text.IconView; +import javax.swing.text.JTextComponent; +import javax.swing.text.LabelView; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyledEditorKit; +import javax.swing.text.View; +import javax.swing.text.ViewFactory; import javax.swing.text.html.ParagraphView; - import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import org.fife.ui.rtextarea.RTextScrollPane; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; - -import com.jhe.hexed.JHexEditor; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.Resources; import the.bytecode.club.bytecodeviewer.Settings; import the.bytecode.club.bytecodeviewer.decompilers.Decompiler; +import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.MethodParser; -import static the.bytecode.club.bytecodeviewer.util.MethodParser.*; +import static the.bytecode.club.bytecodeviewer.util.MethodParser.Method; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -61,8 +83,7 @@ import static the.bytecode.club.bytecodeviewer.util.MethodParser.*; * @author WaterWolf */ -public class ClassViewer extends Viewer -{ +public class ClassViewer extends Viewer { private static final long serialVersionUID = -8650495368920680024L; ArrayList lnData = new ArrayList(); String name; @@ -99,10 +120,8 @@ public class ClassViewer extends Viewer * * @author Konloch */ - public void search(int pane, String search, boolean next) - { - try - { + public void search(int pane, String search, boolean next) { + try { Component[] com = null; if (pane == 0) // bytecode com = panel1.getComponents(); @@ -114,15 +133,12 @@ public class ClassViewer extends Viewer if (com == null) // someone fucked up, lets prevent a nullpointer. return; - for (Component c : com) - { - if (c instanceof RTextScrollPane) - { + for (Component c : com) { + if (c instanceof RTextScrollPane) { RSyntaxTextArea area = (RSyntaxTextArea) ((RTextScrollPane) c) .getViewport().getComponent(0); - if (search.isEmpty()) - { + if (search.isEmpty()) { highlight(pane, area, ""); return; } @@ -143,25 +159,18 @@ public class ClassViewer extends Viewer int firstPos = -1; boolean found = false; - if (next) - { - for (String s : test) - { + if (next) { + for (String s : test) { if (pane == 0 && !check1.isSelected() || - pane == 1 && !check2.isSelected()) - { + pane == 1 && !check2.isSelected()) { s = s.toLowerCase(); search = search.toLowerCase(); } - if (currentLine == startLine) - { + if (currentLine == startLine) { canSearch = true; - } - else if (s.contains(search)) - { - if (canSearch) - { + } else if (s.contains(search)) { + if (canSearch) { area.setCaretPosition(area.getDocument() .getDefaultRootElement() .getElement(currentLine - 1) @@ -182,12 +191,9 @@ public class ClassViewer extends Viewer .getDefaultRootElement() .getElement(firstPos - 1).getStartOffset()); } - } - else - { + } else { canSearch = true; - for (String s : test) - { + for (String s : test) { if (pane == 0 && !check1.isSelected() || pane == 1 && !check2.isSelected() || pane == 2 && !check3.isSelected()) { @@ -195,8 +201,7 @@ public class ClassViewer extends Viewer search = search.toLowerCase(); } - if (s.contains(search)) - { + if (s.contains(search)) { if (lastGoodLine != -1 && canSearch) area.setCaretPosition(area.getDocument() .getDefaultRootElement() @@ -214,8 +219,7 @@ public class ClassViewer extends Viewer if (lastGoodLine != -1 && area.getDocument() .getDefaultRootElement() - .getElementIndex(area.getCaretPosition()) + 1 == startLine) - { + .getElementIndex(area.getCaretPosition()) + 1 == startLine) { area.setCaretPosition(area.getDocument() .getDefaultRootElement() .getElement(lastGoodLine - 1) @@ -225,14 +229,12 @@ public class ClassViewer extends Viewer highlight(pane, area, search); } } - } - catch (Exception e) - { + } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); } } - private DefaultHighlighter.DefaultHighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter( + private final DefaultHighlighter.DefaultHighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter( new Color(255, 62, 150)); public void highlight(int pane, JTextComponent textComp, String pattern) { @@ -519,7 +521,8 @@ public class ClassViewer extends Viewer } }); scrollPane.setColumnHeaderView(new JLabel("Procyon Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -539,12 +542,9 @@ public class ClassViewer extends Viewer panelArea.setText(Decompiler.cfr.decompileClassNode(cn, b)); panelArea.setCaretPosition(0); panelArea.setEditable(isPanel1Editable()); - panelArea.addKeyListener(new KeyListener() - { - public void keyPressed(KeyEvent e) - { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) - { + panelArea.addKeyListener(new KeyListener() { + public void keyPressed(KeyEvent e) { + if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { field1.requestFocus(); } @@ -552,22 +552,19 @@ public class ClassViewer extends Viewer } @Override - public void keyReleased(KeyEvent arg0) - { + public void keyReleased(KeyEvent arg0) { } @Override - public void keyTyped(KeyEvent arg0) - { + public void keyTyped(KeyEvent arg0) { } }); scrollPane.setColumnHeaderView(new JLabel("CFR Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); - SwingUtilities.invokeLater(new Runnable() - { - public void run() - { + SwingUtilities.invokeLater(new Runnable() { + public void run() { panel1.add(scrollPane); } }); @@ -584,12 +581,9 @@ public class ClassViewer extends Viewer panelArea.setText(Decompiler.fernflower.decompileClassNode(cn, b)); panelArea.setCaretPosition(0); panelArea.setEditable(isPanel1Editable()); - panelArea.addKeyListener(new KeyListener() - { - public void keyPressed(KeyEvent e) - { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) - { + panelArea.addKeyListener(new KeyListener() { + public void keyPressed(KeyEvent e) { + if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { field1.requestFocus(); } @@ -597,22 +591,19 @@ public class ClassViewer extends Viewer } @Override - public void keyReleased(KeyEvent arg0) - { + public void keyReleased(KeyEvent arg0) { } @Override - public void keyTyped(KeyEvent arg0) - { + public void keyTyped(KeyEvent arg0) { } }); scrollPane.setColumnHeaderView(new JLabel("FernFlower Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); - SwingUtilities.invokeLater(new Runnable() - { - public void run() - { + SwingUtilities.invokeLater(new Runnable() { + public void run() { panel1.add(scrollPane); } }); @@ -629,12 +620,9 @@ public class ClassViewer extends Viewer panelArea.setText(Decompiler.bytecode.decompileClassNode(cn, b)); panelArea.setCaretPosition(0); panelArea.setEditable(false); - panelArea.addKeyListener(new KeyListener() - { - public void keyPressed(KeyEvent e) - { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) - { + panelArea.addKeyListener(new KeyListener() { + public void keyPressed(KeyEvent e) { + if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { field1.requestFocus(); } @@ -642,22 +630,19 @@ public class ClassViewer extends Viewer } @Override - public void keyReleased(KeyEvent arg0) - { + public void keyReleased(KeyEvent arg0) { } @Override - public void keyTyped(KeyEvent arg0) - { + public void keyTyped(KeyEvent arg0) { } }); scrollPane.setColumnHeaderView(new JLabel("Bytecode Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); - SwingUtilities.invokeLater(new Runnable() - { - public void run() - { + SwingUtilities.invokeLater(new Runnable() { + public void run() { panel1.add(scrollPane); } }); @@ -667,12 +652,11 @@ public class ClassViewer extends Viewer final ClassWriter cw = new ClassWriter(0); cn.accept(cw); final JHexEditor hex = new JHexEditor(cw.toByteArray()); - hex.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + hex.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); - SwingUtilities.invokeLater(new Runnable() - { - public void run() - { + SwingUtilities.invokeLater(new Runnable() { + public void run() { panel1.add(hex); } }); @@ -688,12 +672,9 @@ public class ClassViewer extends Viewer panelArea.setCaretPosition(0); panelArea.setEditable(isPanel1Editable()); smali1 = panelArea; - smali1.addKeyListener(new KeyListener() - { - public void keyPressed(KeyEvent e) - { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) - { + smali1.addKeyListener(new KeyListener() { + public void keyPressed(KeyEvent e) { + if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { field1.requestFocus(); } @@ -701,22 +682,19 @@ public class ClassViewer extends Viewer } @Override - public void keyReleased(KeyEvent arg0) - { + public void keyReleased(KeyEvent arg0) { } @Override - public void keyTyped(KeyEvent arg0) - { + public void keyTyped(KeyEvent arg0) { } }); scrollPane.setColumnHeaderView(new JLabel("Smali Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); - SwingUtilities.invokeLater(new Runnable() - { - public void run() - { + SwingUtilities.invokeLater(new Runnable() { + public void run() { panel1.add(scrollPane); } }); @@ -731,12 +709,9 @@ public class ClassViewer extends Viewer panelArea.setText(Decompiler.krakatau.decompileClassNode(tempFiles[0], tempFiles[1], cn, b)); panelArea.setCaretPosition(0); panelArea.setEditable(isPanel1Editable()); - panelArea.addKeyListener(new KeyListener() - { - public void keyPressed(KeyEvent e) - { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) - { + panelArea.addKeyListener(new KeyListener() { + public void keyPressed(KeyEvent e) { + if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { field1.requestFocus(); } @@ -744,22 +719,19 @@ public class ClassViewer extends Viewer } @Override - public void keyReleased(KeyEvent arg0) - { + public void keyReleased(KeyEvent arg0) { } @Override - public void keyTyped(KeyEvent arg0) - { + public void keyTyped(KeyEvent arg0) { } }); scrollPane.setColumnHeaderView(new JLabel("Krakatau Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); - SwingUtilities.invokeLater(new Runnable() - { - public void run() - { + SwingUtilities.invokeLater(new Runnable() { + public void run() { panel1.add(scrollPane); } }); @@ -778,12 +750,9 @@ public class ClassViewer extends Viewer panelArea.setCaretPosition(0); panelArea.setEditable(isPanel1Editable()); krakatau1 = panelArea; - krakatau1.addKeyListener(new KeyListener() - { - public void keyPressed(KeyEvent e) - { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) - { + krakatau1.addKeyListener(new KeyListener() { + public void keyPressed(KeyEvent e) { + if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { field1.requestFocus(); } @@ -791,22 +760,19 @@ public class ClassViewer extends Viewer } @Override - public void keyReleased(KeyEvent arg0) - { + public void keyReleased(KeyEvent arg0) { } @Override - public void keyTyped(KeyEvent arg0) - { + public void keyTyped(KeyEvent arg0) { } }); scrollPane.setColumnHeaderView(new JLabel("Krakatau Disassembler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); - SwingUtilities.invokeLater(new Runnable() - { - public void run() - { + SwingUtilities.invokeLater(new Runnable() { + public void run() { panel1.add(scrollPane); } }); @@ -821,12 +787,9 @@ public class ClassViewer extends Viewer panelArea.setText(Decompiler.jdgui.decompileClassNode(cn, b)); panelArea.setCaretPosition(0); panelArea.setEditable(isPanel1Editable()); - panelArea.addKeyListener(new KeyListener() - { - public void keyPressed(KeyEvent e) - { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) - { + panelArea.addKeyListener(new KeyListener() { + public void keyPressed(KeyEvent e) { + if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { field1.requestFocus(); } @@ -834,22 +797,19 @@ public class ClassViewer extends Viewer } @Override - public void keyReleased(KeyEvent arg0) - { + public void keyReleased(KeyEvent arg0) { } @Override - public void keyTyped(KeyEvent arg0) - { + public void keyTyped(KeyEvent arg0) { } }); scrollPane.setColumnHeaderView(new JLabel("JD-GUI Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); - SwingUtilities.invokeLater(new Runnable() - { - public void run() - { + SwingUtilities.invokeLater(new Runnable() { + public void run() { panel1.add(scrollPane); } }); @@ -866,12 +826,9 @@ public class ClassViewer extends Viewer panelArea.setText(Decompiler.jadx.decompileClassNode(cn, b)); panelArea.setCaretPosition(0); panelArea.setEditable(isPanel1Editable()); - panelArea.addKeyListener(new KeyListener() - { - public void keyPressed(KeyEvent e) - { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) - { + panelArea.addKeyListener(new KeyListener() { + public void keyPressed(KeyEvent e) { + if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { field1.requestFocus(); } @@ -879,22 +836,19 @@ public class ClassViewer extends Viewer } @Override - public void keyReleased(KeyEvent arg0) - { + public void keyReleased(KeyEvent arg0) { } @Override - public void keyTyped(KeyEvent arg0) - { + public void keyTyped(KeyEvent arg0) { } }); scrollPane.setColumnHeaderView(new JLabel("JADX Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); - SwingUtilities.invokeLater(new Runnable() - { - public void run() - { + SwingUtilities.invokeLater(new Runnable() { + public void run() { panel1.add(scrollPane); } }); @@ -910,12 +864,9 @@ public class ClassViewer extends Viewer panelArea.setText(Decompiler.textifier.decompileClassNode(cn, b)); panelArea.setCaretPosition(0); panelArea.setEditable(false); - panelArea.addKeyListener(new KeyListener() - { - public void keyPressed(KeyEvent e) - { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) - { + panelArea.addKeyListener(new KeyListener() { + public void keyPressed(KeyEvent e) { + if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { field1.requestFocus(); } @@ -923,22 +874,19 @@ public class ClassViewer extends Viewer } @Override - public void keyReleased(KeyEvent arg0) - { + public void keyReleased(KeyEvent arg0) { } @Override - public void keyTyped(KeyEvent arg0) - { + public void keyTyped(KeyEvent arg0) { } }); scrollPane.setColumnHeaderView(new JLabel("ASM Textified - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); - SwingUtilities.invokeLater(new Runnable() - { - public void run() - { + SwingUtilities.invokeLater(new Runnable() { + public void run() { panel1.add(scrollPane); } }); @@ -995,7 +943,8 @@ public class ClassViewer extends Viewer } }); scrollPane.setColumnHeaderView(new JLabel("Procyon Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -1033,7 +982,8 @@ public class ClassViewer extends Viewer } }); scrollPane.setColumnHeaderView(new JLabel("CFR Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -1071,7 +1021,8 @@ public class ClassViewer extends Viewer } }); scrollPane.setColumnHeaderView(new JLabel("FernFlower Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -1109,7 +1060,8 @@ public class ClassViewer extends Viewer } }); scrollPane.setColumnHeaderView(new JLabel("Bytecode Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -1123,7 +1075,8 @@ public class ClassViewer extends Viewer final ClassWriter cw = new ClassWriter(0); cn.accept(cw); final JHexEditor hex = new JHexEditor(cw.toByteArray()); - hex.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + hex.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -1160,7 +1113,8 @@ public class ClassViewer extends Viewer } }); scrollPane.setColumnHeaderView(new JLabel("Smali Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -1197,7 +1151,8 @@ public class ClassViewer extends Viewer } }); scrollPane.setColumnHeaderView(new JLabel("Krakatau Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -1236,7 +1191,8 @@ public class ClassViewer extends Viewer } }); scrollPane.setColumnHeaderView(new JLabel("Krakatau Disassembler")); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -1273,7 +1229,8 @@ public class ClassViewer extends Viewer } }); scrollPane.setColumnHeaderView(new JLabel("JD-GUI Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -1293,12 +1250,9 @@ public class ClassViewer extends Viewer panelArea.setText(Decompiler.jadx.decompileClassNode(cn, b)); panelArea.setCaretPosition(0); panelArea.setEditable(isPanel2Editable()); - panelArea.addKeyListener(new KeyListener() - { - public void keyPressed(KeyEvent e) - { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) - { + panelArea.addKeyListener(new KeyListener() { + public void keyPressed(KeyEvent e) { + if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { field1.requestFocus(); } @@ -1306,22 +1260,19 @@ public class ClassViewer extends Viewer } @Override - public void keyReleased(KeyEvent arg0) - { + public void keyReleased(KeyEvent arg0) { } @Override - public void keyTyped(KeyEvent arg0) - { + public void keyTyped(KeyEvent arg0) { } }); scrollPane.setColumnHeaderView(new JLabel("JADX Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); - SwingUtilities.invokeLater(new Runnable() - { - public void run() - { + SwingUtilities.invokeLater(new Runnable() { + public void run() { panel2.add(scrollPane); } }); @@ -1337,12 +1288,9 @@ public class ClassViewer extends Viewer panelArea.setText(Decompiler.textifier.decompileClassNode(cn, b)); panelArea.setCaretPosition(0); panelArea.setEditable(false); - panelArea.addKeyListener(new KeyListener() - { - public void keyPressed(KeyEvent e) - { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) - { + panelArea.addKeyListener(new KeyListener() { + public void keyPressed(KeyEvent e) { + if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { field2.requestFocus(); } @@ -1350,22 +1298,19 @@ public class ClassViewer extends Viewer } @Override - public void keyReleased(KeyEvent arg0) - { + public void keyReleased(KeyEvent arg0) { } @Override - public void keyTyped(KeyEvent arg0) - { + public void keyTyped(KeyEvent arg0) { } }); scrollPane.setColumnHeaderView(new JLabel("ASM Textified - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); - SwingUtilities.invokeLater(new Runnable() - { - public void run() - { + SwingUtilities.invokeLater(new Runnable() { + public void run() { panel2.add(scrollPane); } }); @@ -1421,7 +1366,8 @@ public class ClassViewer extends Viewer } }); scrollPane.setColumnHeaderView(new JLabel("Procyon Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -1460,7 +1406,8 @@ public class ClassViewer extends Viewer } }); scrollPane.setColumnHeaderView(new JLabel("CFR Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -1499,7 +1446,8 @@ public class ClassViewer extends Viewer } }); scrollPane.setColumnHeaderView(new JLabel("FernFlower Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -1537,7 +1485,8 @@ public class ClassViewer extends Viewer } }); scrollPane.setColumnHeaderView(new JLabel("Bytecode Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -1550,7 +1499,8 @@ public class ClassViewer extends Viewer final ClassWriter cw = new ClassWriter(0); cn.accept(cw); final JHexEditor hex = new JHexEditor(cw.toByteArray()); - hex.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + hex.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -1588,7 +1538,8 @@ public class ClassViewer extends Viewer } }); scrollPane.setColumnHeaderView(new JLabel("Smali Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -1626,7 +1577,8 @@ public class ClassViewer extends Viewer }); scrollPane.setColumnHeaderView(new JLabel("Krakatau Decompiler - Editable: " + panelArea.isEditable())); java3 = panelArea; - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -1663,7 +1615,8 @@ public class ClassViewer extends Viewer } }); scrollPane.setColumnHeaderView(new JLabel("Krakatau Disassembler")); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -1701,7 +1654,8 @@ public class ClassViewer extends Viewer }); scrollPane.setColumnHeaderView(new JLabel("JD-GUI Decompiler - Editable: " + panelArea.isEditable())); java3 = panelArea; - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -1719,12 +1673,9 @@ public class ClassViewer extends Viewer panelArea.setText(Decompiler.jadx.decompileClassNode(cn, b)); panelArea.setCaretPosition(0); panelArea.setEditable(isPanel3Editable()); - panelArea.addKeyListener(new KeyListener() - { - public void keyPressed(KeyEvent e) - { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) - { + panelArea.addKeyListener(new KeyListener() { + public void keyPressed(KeyEvent e) { + if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { field1.requestFocus(); } @@ -1732,22 +1683,19 @@ public class ClassViewer extends Viewer } @Override - public void keyReleased(KeyEvent arg0) - { + public void keyReleased(KeyEvent arg0) { } @Override - public void keyTyped(KeyEvent arg0) - { + public void keyTyped(KeyEvent arg0) { } }); scrollPane.setColumnHeaderView(new JLabel("JADX Decompiler - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); - SwingUtilities.invokeLater(new Runnable() - { - public void run() - { + SwingUtilities.invokeLater(new Runnable() { + public void run() { panel3.add(scrollPane); } }); @@ -1763,12 +1711,9 @@ public class ClassViewer extends Viewer panelArea.setText(Decompiler.textifier.decompileClassNode(cn, b)); panelArea.setCaretPosition(0); panelArea.setEditable(false); - panelArea.addKeyListener(new KeyListener() - { - public void keyPressed(KeyEvent e) - { - if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) - { + panelArea.addKeyListener(new KeyListener() { + public void keyPressed(KeyEvent e) { + if ((e.getKeyCode() == KeyEvent.VK_F) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) { field3.requestFocus(); } @@ -1776,22 +1721,19 @@ public class ClassViewer extends Viewer } @Override - public void keyReleased(KeyEvent arg0) - { + public void keyReleased(KeyEvent arg0) { } @Override - public void keyTyped(KeyEvent arg0) - { + public void keyTyped(KeyEvent arg0) { } }); scrollPane.setColumnHeaderView(new JLabel("ASM Textified - Editable: " + panelArea.isEditable())); - panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, (int) BytecodeViewer.viewer.fontSpinner.getValue())); + panelArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, + (int) BytecodeViewer.viewer.fontSpinner.getValue())); - SwingUtilities.invokeLater(new Runnable() - { - public void run() - { + SwingUtilities.invokeLater(new Runnable() { + public void run() { panel3.add(scrollPane); } }); @@ -1810,21 +1752,15 @@ public class ClassViewer extends Viewer } }; - Thread t = new Thread() - { + Thread t = new Thread() { @Override - public void run() - { + public void run() { BytecodeViewer.viewer.setIcon(true); - while(BytecodeViewer.currentlyDumping) - { + while (BytecodeViewer.currentlyDumping) { //wait until it's not dumping - try - { + try { Thread.sleep(100); - } - catch (InterruptedException e) - { + } catch (InterruptedException e) { e.printStackTrace(); } } @@ -1842,14 +1778,13 @@ public class ClassViewer extends Viewer }; t.start(); - if(isPanel1Editable() || isPanel2Editable() || isPanel3Editable()) - { - if(!BytecodeViewer.warnForEditing) - { + if (isPanel1Editable() || isPanel2Editable() || isPanel3Editable()) { + if (!BytecodeViewer.warnForEditing) { BytecodeViewer.warnForEditing = true; - if(!BytecodeViewer.viewer.autoCompileOnRefresh.isSelected() && !BytecodeViewer.viewer.compileOnSave.isSelected()) - { - BytecodeViewer.showMessage("Make sure to compile (File>Compile or Ctrl + T) whenever you want to test or export your changes.\nYou can set compile automatically on refresh or on save in the settings menu."); + if (!BytecodeViewer.viewer.autoCompileOnRefresh.isSelected() && !BytecodeViewer.viewer.compileOnSave.isSelected()) { + BytecodeViewer.showMessage("Make sure to compile (File>Compile or Ctrl + T) whenever you want to " + + "test or export your changes.\nYou can set compile automatically on refresh or on save " + + "in the settings menu."); Settings.saveSettings(); } } @@ -2041,8 +1976,7 @@ public class ClassViewer extends Viewer pane3 = 11; } - public boolean isPanel1Editable() - { + public boolean isPanel1Editable() { setPanes(); if (pane1 == 1 && BytecodeViewer.viewer.panel1Proc_E.isSelected()) @@ -2055,11 +1989,7 @@ public class ClassViewer extends Viewer return true; if (pane1 == 9 && BytecodeViewer.viewer.panel1JDGUI_E.isSelected()) return true; - if ((pane1 == 7 || pane1 == 8) && BytecodeViewer.viewer.panel1Krakatau_E.isSelected()) - return true; - - - return false; + return (pane1 == 7 || pane1 == 8) && BytecodeViewer.viewer.panel1Krakatau_E.isSelected(); } public boolean isPanel2Editable() { @@ -2075,11 +2005,7 @@ public class ClassViewer extends Viewer return true; if (pane2 == 9 && BytecodeViewer.viewer.panel2JDGUI_E.isSelected()) return true; - if ((pane2 == 7 || pane2 == 8) && BytecodeViewer.viewer.panel2Krakatau_E.isSelected()) - return true; - - - return false; + return (pane2 == 7 || pane2 == 8) && BytecodeViewer.viewer.panel2Krakatau_E.isSelected(); } public boolean isPanel3Editable() { @@ -2095,11 +2021,7 @@ public class ClassViewer extends Viewer return true; if (pane3 == 9 && BytecodeViewer.viewer.panel3JDGUI_E.isSelected()) return true; - if ((pane3 == 7 || pane3 == 8) && BytecodeViewer.viewer.panel3Krakatau_E.isSelected()) - return true; - - - return false; + return (pane3 == 7 || pane3 == 8) && BytecodeViewer.viewer.panel3Krakatau_E.isSelected(); } /** @@ -2139,9 +2061,6 @@ public class ClassViewer extends Viewer } - - - public static void selectMethod(RSyntaxTextArea area, int methodLine) { if (methodLine != area.getCaretLineNumber()) { setCaretLine(area, methodLine); @@ -2151,21 +2070,19 @@ public class ClassViewer extends Viewer public static void selectMethod(ClassViewer classViewer, int paneId, Method method) { RSyntaxTextArea area = null; - switch(paneId) - { - case 0: - area = classViewer.t1.panelArea; - break; - case 1: - area = classViewer.t2.panelArea; - break; - case 2: - area = classViewer.t3.panelArea; - break; + switch (paneId) { + case 0: + area = classViewer.t1.panelArea; + break; + case 1: + area = classViewer.t2.panelArea; + break; + case 2: + area = classViewer.t3.panelArea; + break; } - if (area != null) - { + if (area != null) { MethodParser methods = classViewer.methods.get(paneId); if (methods != null) { int methodLine = methods.findMethod(method); @@ -2223,6 +2140,7 @@ public class ClassViewer extends Viewer public static void setCaretLine(RSyntaxTextArea area, int line) { try { area.setCaretPosition(area.getLineStartOffset(line)); - } catch (BadLocationException ignored) {} + } catch (BadLocationException ignored) { + } } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/DelayTabbedPaneThread.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/DelayTabbedPaneThread.java index 8dbc2ba0..81e363e3 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/DelayTabbedPaneThread.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/DelayTabbedPaneThread.java @@ -1,48 +1,37 @@ package the.bytecode.club.bytecodeviewer.gui; -import the.bytecode.club.bytecodeviewer.BytecodeViewer; - -import javax.swing.*; -import java.awt.*; +import java.awt.Color; +import javax.swing.SwingUtilities; /** * @author Konloch */ -public class DelayTabbedPaneThread extends Thread -{ +public class DelayTabbedPaneThread extends Thread { public boolean stopped = false; - private TabbedPane pane; + private final TabbedPane pane; - public DelayTabbedPaneThread(TabbedPane pane) - { + public DelayTabbedPaneThread(TabbedPane pane) { this.pane = pane; } @Override - public void run() - { - try - { + public void run() { + try { sleep(200); - } - catch (InterruptedException e) - { + } catch (InterruptedException e) { e.printStackTrace(); } - if(!stopped) - { - SwingUtilities.invokeLater(new Runnable() - { + if (!stopped) { + SwingUtilities.invokeLater(new Runnable() { @Override - public void run() - { - if(stopped) + public void run() { + if (stopped) return; pane.label.setOpaque(true); pane.label.setBackground(Color.MAGENTA); pane.label.updateUI(); - } + } }); } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/ExportJar.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/ExportJar.java index 5ded38eb..5bd3740a 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/ExportJar.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/ExportJar.java @@ -1,20 +1,17 @@ package the.bytecode.club.bytecodeviewer.gui; -import javax.swing.JFrame; import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.BoxLayout; import javax.swing.JButton; - +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.util.JarUtils; -import java.awt.event.ActionListener; -import java.awt.event.ActionEvent; - -import javax.swing.BoxLayout; -import javax.swing.JScrollPane; -import javax.swing.JLabel; -import javax.swing.JTextArea; - /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/FileNavigationPane.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/FileNavigationPane.java index 0aeb5414..a7c5723e 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/FileNavigationPane.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/FileNavigationPane.java @@ -1,6 +1,45 @@ package the.bytecode.club.bytecodeviewer.gui; import com.sun.java.swing.plaf.windows.WindowsTreeUI; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.font.FontRenderContext; +import java.awt.geom.Rectangle2D; +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Map.Entry; +import javax.swing.AbstractAction; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.JTree; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.MutableTreeNode; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; import org.objectweb.asm.tree.ClassNode; import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.Resources; @@ -9,18 +48,6 @@ import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.util.FileDrop; import the.bytecode.club.bytecodeviewer.util.LazyNameUtil; -import javax.swing.*; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; -import javax.swing.tree.*; -import java.awt.*; -import java.awt.event.*; -import java.awt.font.FontRenderContext; -import java.awt.geom.Rectangle2D; -import java.io.File; -import java.util.*; -import java.util.Map.Entry; - /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * @@ -70,7 +97,7 @@ public class FileNavigationPane extends VisibleComponent implements final String qt = quickSearch.getText(); quickSearch.setText(""); - if(qt.isEmpty()) //NOPE + if (qt.isEmpty()) //NOPE return; @@ -99,16 +126,16 @@ public class FileNavigationPane extends VisibleComponent implements for (int c = 0; c < curNode.getChildCount(); c++) { final MyTreeNode child = (MyTreeNode) curNode.getChildAt(c); - System.out.println(pathName + ":" + ((String) child.getUserObject())); + System.out.println(pathName + ":" + child.getUserObject()); - if (((String) child.getUserObject()).equals(pathName)) { + if (child.getUserObject().equals(pathName)) { curNode = child; if (isLast) { System.out.println("Found! " + curNode); found++; - if(found >= 30) - { - BytecodeViewer.showMessage("Uh oh, there could be more results but you've triggered the 30 classes at once limit. Try refining your search."); + if (found >= 30) { + BytecodeViewer.showMessage("Uh oh, there could be more results but you've " + + "triggered the 30 classes at once limit. Try refining your search."); return; } final TreePath pathn = new TreePath(curNode.getPath()); @@ -134,7 +161,7 @@ public class FileNavigationPane extends VisibleComponent implements MyTreeNode node = enums.nextElement(); if (node.isLeaf()) { if (((String) (node.getUserObject())).toLowerCase().contains(path[path.length - 1].toLowerCase())) { - TreeNode pathArray[] = node.getPath(); + TreeNode[] pathArray = node.getPath(); int k = 0; StringBuilder fullPath = new StringBuilder(); while (pathArray != null @@ -150,9 +177,10 @@ public class FileNavigationPane extends VisibleComponent implements if (fullPathString != null && fullPathString.toLowerCase().contains(qt.toLowerCase())) { System.out.println("Found! " + node); found++; - if(found >= 30) - { - BytecodeViewer.showMessage("Uh oh, there could be more results but you've triggered the 30 classes at once limit. Try refining your search."); + if (found >= 30) { + BytecodeViewer.showMessage("Uh oh, there could be more results but you've" + + " triggered the 30 classes at once limit. Try refining your " + + "search."); return; } final TreePath pathn = new TreePath(node.getPath()); @@ -303,27 +331,20 @@ public class FileNavigationPane extends VisibleComponent implements @Override public void keyPressed(KeyEvent e) { - System.out.println((int)e.getKeyChar()); - if (e.getKeyCode() == KeyEvent.VK_ENTER) - { - if (e.getSource() instanceof MyTree) - { + System.out.println((int) e.getKeyChar()); + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + if (e.getSource() instanceof MyTree) { MyTree tree = (MyTree) e.getSource(); openPath(tree.getSelectionPath()); } - } - else if((int)e.getKeyChar() != 0 &&(int)e.getKeyChar() != 8 &&(int)e.getKeyChar() != 127 && (int)e.getKeyChar() != 65535 && !e.isControlDown() && !e.isAltDown()) - { + } else if ((int) e.getKeyChar() != 0 && (int) e.getKeyChar() != 8 && (int) e.getKeyChar() != 127 && (int) e.getKeyChar() != 65535 && !e.isControlDown() && !e.isAltDown()) { quickSearch.grabFocus(); quickSearch.setText("" + e.getKeyChar()); cancel = true; - } - else if(e.isControlDown() && (int)e.getKeyChar() == 6) //ctrl + f + } else if (e.isControlDown() && (int) e.getKeyChar() == 6) //ctrl + f { quickSearch.grabFocus(); - } - else - { + } else { cancel = true; } } @@ -608,8 +629,7 @@ public class FileNavigationPane extends VisibleComponent implements tree.updateUI(); } - public void openPath(TreePath path) - { + public void openPath(TreePath path) { if (path == null || path.getPathCount() == 1) { return; } @@ -625,26 +645,25 @@ public class FileNavigationPane extends VisibleComponent implements String cheapHax = path.getPathComponent(1).toString(); FileContainer container = null; - for(FileContainer c : BytecodeViewer.files) - { - if(c.name.equals(cheapHax)) + for (FileContainer c : BytecodeViewer.files) { + if (c.name.equals(cheapHax)) container = c; } String name = nameBuffer.toString(); - if (name.endsWith(".class")) - { + if (name.endsWith(".class")) { - final ClassNode cn = BytecodeViewer.getClassNode(container, name.substring(0, name.length() - ".class".length())); + final ClassNode cn = BytecodeViewer.getClassNode(container, name.substring(0, + name.length() - ".class".length())); if (cn != null) { openClassFileToWorkSpace(container, nameBuffer.toString(), cn); - } - else - { - openFileToWorkSpace(container, nameBuffer.toString(), BytecodeViewer.getFileContents(nameBuffer.toString())); + } else { + openFileToWorkSpace(container, nameBuffer.toString(), + BytecodeViewer.getFileContents(nameBuffer.toString())); } } else { - openFileToWorkSpace(container, nameBuffer.toString(), BytecodeViewer.getFileContents(nameBuffer.toString())); + openFileToWorkSpace(container, nameBuffer.toString(), + BytecodeViewer.getFileContents(nameBuffer.toString())); } } @@ -667,7 +686,8 @@ public class FileNavigationPane extends VisibleComponent implements selected, expanded, leaf, row, hasFocus); if (value != null && value instanceof the.bytecode.club.bytecodeviewer.gui.FileNavigationPane.MyTreeNode) { - the.bytecode.club.bytecodeviewer.gui.FileNavigationPane.MyTreeNode node = (the.bytecode.club.bytecodeviewer.gui.FileNavigationPane.MyTreeNode) value; + the.bytecode.club.bytecodeviewer.gui.FileNavigationPane.MyTreeNode node = + (the.bytecode.club.bytecodeviewer.gui.FileNavigationPane.MyTreeNode) value; String name = node.toString().toLowerCase(); if (name.endsWith(".jar") || name.endsWith(".war")) { @@ -684,7 +704,8 @@ public class FileNavigationPane extends VisibleComponent implements setIcon(Resources.cplusplusIcon); } else if (name.endsWith(".apk") || name.endsWith(".dex")) { setIcon(Resources.androidIcon); - } else if (name.endsWith(".png") || name.endsWith(".jpg") || name.endsWith(".jpeg") || name.endsWith(".bmp") || name.endsWith(".gif")) { + } else if (name.endsWith(".png") || name.endsWith(".jpg") || name.endsWith(".jpeg") || name.endsWith( + ".bmp") || name.endsWith(".gif")) { setIcon(Resources.imageIcon); } else if (name.endsWith(".class")) { setIcon(Resources.classIcon); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/FileViewer.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/FileViewer.java index 9ac8b638..427a25d0 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/FileViewer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/FileViewer.java @@ -1,5 +1,6 @@ package the.bytecode.club.bytecodeviewer.gui; +import com.jhe.hexed.JHexEditor; import java.awt.BorderLayout; import java.awt.Color; import java.awt.event.ActionEvent; @@ -13,7 +14,7 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; - +import java.nio.charset.StandardCharsets; import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JButton; @@ -25,17 +26,13 @@ import javax.swing.JTextField; import javax.swing.text.DefaultHighlighter; import javax.swing.text.Highlighter; import javax.swing.text.JTextComponent; - import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import org.fife.ui.rtextarea.RTextScrollPane; import org.imgscalr.Scalr; - -import com.jhe.hexed.JHexEditor; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.util.FileContainer; import the.bytecode.club.bytecodeviewer.Resources; +import the.bytecode.club.bytecodeviewer.util.FileContainer; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -66,7 +63,7 @@ public class FileViewer extends Viewer { private static final long serialVersionUID = 6103372882168257164L; String name; - private byte[] contents; + private final byte[] contents; RSyntaxTextArea panelArea = new RSyntaxTextArea(); JPanel panel = new JPanel(new BorderLayout()); JPanel panel2 = new JPanel(new BorderLayout()); @@ -114,9 +111,11 @@ public class FileViewer extends Viewer { public void mouseWheelMoved(MouseWheelEvent e) { int notches = e.getWheelRotation(); if (notches < 0) { - image = Scalr.resize(image, Scalr.Method.SPEED, image.getWidth() + 10, image.getHeight() + 10); + image = Scalr.resize(image, Scalr.Method.SPEED, image.getWidth() + 10, + image.getHeight() + 10); } else { - image = Scalr.resize(image, Scalr.Method.SPEED, image.getWidth() - 10, image.getHeight() - 10); + image = Scalr.resize(image, Scalr.Method.SPEED, image.getWidth() - 10, + image.getHeight() - 10); } panel2.removeAll(); JLabel label = new JLabel("", new ImageIcon(image), JLabel.CENTER); @@ -128,9 +127,7 @@ public class FileViewer extends Viewer { } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); } - } - else if(BytecodeViewer.viewer.forcePureAsciiAsText.isSelected()) - { + } else if (BytecodeViewer.viewer.forcePureAsciiAsText.isSelected()) { JHexEditor hex = new JHexEditor(contents); panel2.add(hex); return; @@ -207,7 +204,7 @@ public class FileViewer extends Viewer { panel2.add(scrollPane); } - static CharsetEncoder asciiEncoder = Charset.forName("US-ASCII").newEncoder(); // or "ISO-8859-1" for ISO Latin 1 + static CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder(); // or "ISO-8859-1" for ISO Latin 1 public static boolean isPureAscii(String v) { return asciiEncoder.canEncode(v); @@ -357,7 +354,7 @@ public class FileViewer extends Viewer { } } - private DefaultHighlighter.DefaultHighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter( + private final DefaultHighlighter.DefaultHighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter( new Color(255, 62, 150)); public void highlight(JTextComponent textComp, String pattern) { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/GraphicialReflectionKit.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/GraphicialReflectionKit.java index 77907878..d5752566 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/GraphicialReflectionKit.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/GraphicialReflectionKit.java @@ -1,11 +1,10 @@ package the.bytecode.club.bytecodeviewer.gui; -import javax.swing.JFrame; -import java.awt.Dimension; -import javax.swing.JTabbedPane; import java.awt.BorderLayout; +import java.awt.Dimension; +import javax.swing.JFrame; import javax.swing.JPanel; - +import javax.swing.JTabbedPane; import the.bytecode.club.bytecodeviewer.Resources; /*************************************************************************** diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java index 0b908f91..9a5bc204 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/MainViewerGUI.java @@ -6,11 +6,14 @@ import java.awt.Dimension; import java.awt.Frame; import java.awt.KeyEventDispatcher; import java.awt.KeyboardFocusManager; -import java.awt.event.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import java.io.File; import java.util.ArrayList; import java.util.List; - import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.JCheckBoxMenuItem; @@ -23,26 +26,36 @@ import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JRadioButtonMenuItem; import javax.swing.JSeparator; +import javax.swing.JSpinner; import javax.swing.JSplitPane; +import javax.swing.SpinnerNumberModel; import javax.swing.SwingUtilities; import javax.swing.filechooser.FileFilter; - import me.konloch.kontainer.io.DiskWriter; - import org.objectweb.asm.ClassWriter; import org.objectweb.asm.tree.ClassNode; - -import the.bytecode.club.bytecodeviewer.*; +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.Resources; +import the.bytecode.club.bytecodeviewer.Settings; import the.bytecode.club.bytecodeviewer.decompilers.Decompiler; import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameClasses; import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameFields; import the.bytecode.club.bytecodeviewer.obfuscators.rename.RenameMethods; import the.bytecode.club.bytecodeviewer.plugin.PluginManager; -import the.bytecode.club.bytecodeviewer.plugin.preinstalled.*; -import the.bytecode.club.bytecodeviewer.util.*; - -import javax.swing.JSpinner; -import javax.swing.SpinnerNumberModel; +import the.bytecode.club.bytecodeviewer.plugin.preinstalled.AllatoriStringDecrypter; +import the.bytecode.club.bytecodeviewer.plugin.preinstalled.CodeSequenceDiagram; +import the.bytecode.club.bytecodeviewer.plugin.preinstalled.ShowAllStrings; +import the.bytecode.club.bytecodeviewer.plugin.preinstalled.ShowMainMethods; +import the.bytecode.club.bytecodeviewer.plugin.preinstalled.StackFramesRemover; +import the.bytecode.club.bytecodeviewer.plugin.preinstalled.ZKMStringDecrypter; +import the.bytecode.club.bytecodeviewer.plugin.preinstalled.ZStringArrayDecrypter; +import the.bytecode.club.bytecodeviewer.util.APKTool; +import the.bytecode.club.bytecodeviewer.util.Dex2Jar; +import the.bytecode.club.bytecodeviewer.util.FileChangeNotifier; +import the.bytecode.club.bytecodeviewer.util.FileContainer; +import the.bytecode.club.bytecodeviewer.util.JarUtils; +import the.bytecode.club.bytecodeviewer.util.LazyNameUtil; +import the.bytecode.club.bytecodeviewer.util.MiscUtils; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -67,8 +80,7 @@ import javax.swing.SpinnerNumberModel; * * @author Konloch */ -public class MainViewerGUI extends JFrame implements FileChangeNotifier -{ +public class MainViewerGUI extends JFrame implements FileChangeNotifier { public static final long serialVersionUID = 1851409230530948543L; public JCheckBoxMenuItem debugHelpers = new JCheckBoxMenuItem("Debug Helpers"); @@ -161,14 +173,16 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier public final JCheckBoxMenuItem forloopaggcapture = new JCheckBoxMenuItem("For Loop AGG Capture"); public final JCheckBoxMenuItem forceexceptionprune = new JCheckBoxMenuItem("Force Exception Prune"); public final JCheckBoxMenuItem chckbxmntmShowDebugLine = new JCheckBoxMenuItem("Show Debug Line Numbers"); - public final JCheckBoxMenuItem chckbxmntmSimplifyMemberReferences = new JCheckBoxMenuItem("Simplify Member References"); + public final JCheckBoxMenuItem chckbxmntmSimplifyMemberReferences = new JCheckBoxMenuItem("Simplify Member " + + "References"); public final JCheckBoxMenuItem mnMergeVariables = new JCheckBoxMenuItem("Merge Variables"); public final JCheckBoxMenuItem chckbxmntmNewCheckItem_1 = new JCheckBoxMenuItem("Unicode Output Enabled"); public final JCheckBoxMenuItem chckbxmntmNewCheckItem_2 = new JCheckBoxMenuItem("Retain Pointless Switches"); public final JCheckBoxMenuItem chckbxmntmNewCheckItem_3 = new JCheckBoxMenuItem("Include Line Numbers In Bytecode"); public final JCheckBoxMenuItem chckbxmntmNewCheckItem_4 = new JCheckBoxMenuItem("Include Error Diagnostics"); public final JCheckBoxMenuItem chckbxmntmNewCheckItem_5 = new JCheckBoxMenuItem("Retain Redundant Casts"); - public final JCheckBoxMenuItem chckbxmntmNewCheckItem_6 = new JCheckBoxMenuItem("Always Generate Exception Variable For Catch Blocks"); + public final JCheckBoxMenuItem chckbxmntmNewCheckItem_6 = new JCheckBoxMenuItem("Always Generate Exception " + + "Variable For Catch Blocks"); public final JCheckBoxMenuItem chckbxmntmNewCheckItem_7 = new JCheckBoxMenuItem("Show Synthetic Members"); public final JCheckBoxMenuItem chckbxmntmNewCheckItem_8 = new JCheckBoxMenuItem("Force Explicit Type Arguments"); public final JCheckBoxMenuItem chckbxmntmNewCheckItem_9 = new JCheckBoxMenuItem("Force Explicit Imports"); @@ -207,10 +221,8 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier public boolean isMaximized = false; - public void removed(boolean busy) - { - if (busy) - { + public void removed(boolean busy) { + if (busy) { this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); for (Component c : this.getComponents()) c.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); @@ -218,20 +230,16 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier sp1.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); sp2.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - for (VisibleComponent c : rfComps) - { + for (VisibleComponent c : rfComps) { c.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - if (c instanceof WorkPane) - { + if (c instanceof WorkPane) { WorkPane w = (WorkPane) c; for (Component c2 : w.tabs.getComponents()) c2.setCursor(Cursor .getPredefinedCursor(Cursor.WAIT_CURSOR)); } } - } - else - { + } else { this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); for (Component c : this.getComponents()) c.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); @@ -239,11 +247,9 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier sp1.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); sp2.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - for (VisibleComponent c : rfComps) - { + for (VisibleComponent c : rfComps) { c.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - if (c instanceof WorkPane) - { + if (c instanceof WorkPane) { WorkPane w = (WorkPane) c; for (Component c2 : w.tabs.getComponents()) c2.setCursor(Cursor @@ -253,11 +259,9 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier } } - public class Test implements KeyEventDispatcher - { + public class Test implements KeyEventDispatcher { @Override - public boolean dispatchKeyEvent(KeyEvent e) - { + public boolean dispatchKeyEvent(KeyEvent e) { BytecodeViewer.checkHotKey(e); return false; } @@ -358,38 +362,25 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier public final JRadioButtonMenuItem panel3Bytecode = new JRadioButtonMenuItem("Bytecode"); public final JRadioButtonMenuItem panel3Hexcode = new JRadioButtonMenuItem("Hexcode"); - public synchronized void setIcon(final boolean busy) - { - SwingUtilities.invokeLater(new Runnable() - { + public synchronized void setIcon(final boolean busy) { + SwingUtilities.invokeLater(new Runnable() { @Override - public void run() - { - if (busy) - { - for (int i = 0; i < 10; i++) - { - if (waitIcons[i].getIcon() == null) - { - try - { + public void run() { + if (busy) { + for (int i = 0; i < 10; i++) { + if (waitIcons[i].getIcon() == null) { + try { waitIcons[i].setIcon(Resources.busyIcon); - } - catch (NullPointerException e) - { + } catch (NullPointerException e) { waitIcons[i].setIcon(Resources.busyB64Icon); } waitIcons[i].updateUI(); break; } } - } - else - { - for (int i = 0; i < 10; i++) - { - if (waitIcons[i].getIcon() != null) - { + } else { + for (int i = 0; i < 10; i++) { + if (waitIcons[i].getIcon() != null) { waitIcons[i].setIcon(null); waitIcons[i].updateUI(); break; @@ -435,7 +426,8 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier private final JMenu visualSettings = new JMenu("Visual Settings"); public final JSpinner fontSpinner = new JSpinner(); private final JSeparator separator_36 = new JSeparator(); - private final JCheckBoxMenuItem chckbxmntmDeleteForeignOutdatedLibs = new JCheckBoxMenuItem("Delete Foreign/Outdated Libs"); + private final JCheckBoxMenuItem chckbxmntmDeleteForeignOutdatedLibs = new JCheckBoxMenuItem("Delete " + + "Foreign/Outdated Libs"); private final JSeparator separator_37 = new JSeparator(); private final JSeparator separator_38 = new JSeparator(); private final JMenu mnApkConversion = new JMenu("APK Conversion"); @@ -448,50 +440,37 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier private final JSeparator separator_40 = new JSeparator(); private final JMenuItem mntmSetJavacExecutable = new JMenuItem("Set Javac Executable"); - public void calledAfterLoad() - { + public void calledAfterLoad() { chckbxmntmDeleteForeignOutdatedLibs.setSelected(BytecodeViewer.deleteForeignLibraries); } - public MainViewerGUI() - { + public MainViewerGUI() { mnNewMenu_5.setVisible(false); KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new Test()); - this.addWindowStateListener(new WindowAdapter() - { + this.addWindowStateListener(new WindowAdapter() { @Override - public void windowStateChanged(WindowEvent evt) - { + public void windowStateChanged(WindowEvent evt) { int oldState = evt.getOldState(); int newState = evt.getNewState(); - if ((oldState & Frame.ICONIFIED) == 0 && (newState & Frame.ICONIFIED) != 0) - { + if ((oldState & Frame.ICONIFIED) == 0 && (newState & Frame.ICONIFIED) != 0) { //System.out.println("Frame was iconized"); - } - else if ((oldState & Frame.ICONIFIED) != 0 && (newState & Frame.ICONIFIED) == 0) - { + } else if ((oldState & Frame.ICONIFIED) != 0 && (newState & Frame.ICONIFIED) == 0) { //System.out.println("Frame was deiconized"); } - if ((oldState & Frame.MAXIMIZED_BOTH) == 0 && (newState & Frame.MAXIMIZED_BOTH) != 0) - { + if ((oldState & Frame.MAXIMIZED_BOTH) == 0 && (newState & Frame.MAXIMIZED_BOTH) != 0) { isMaximized = true; - } - else if ((oldState & Frame.MAXIMIZED_BOTH) != 0 && (newState & Frame.MAXIMIZED_BOTH) == 0) - { + } else if ((oldState & Frame.MAXIMIZED_BOTH) != 0 && (newState & Frame.MAXIMIZED_BOTH) == 0) { isMaximized = false; } } }); this.setIconImages(Resources.iconList); - ActionListener listener = new ActionListener() - { + ActionListener listener = new ActionListener() { @Override - public void actionPerformed(ActionEvent arg0) - { - if (refreshOnChange.isSelected()) - { + public void actionPerformed(ActionEvent arg0) { + if (refreshOnChange.isSelected()) { if (workPane.getCurrentViewer() == null) return; @@ -522,76 +501,61 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier JMenu mnNewMenu = new JMenu("File"); menuBar.add(mnNewMenu); - mntmNewWorkspace.addActionListener(new ActionListener() - { + mntmNewWorkspace.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent arg0) - { + public void actionPerformed(ActionEvent arg0) { BytecodeViewer.resetWorkSpace(true); } }); JMenuItem mntmLoadJar = new JMenuItem("Add.."); - mntmLoadJar.addActionListener(new ActionListener() - { + mntmLoadJar.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent e) - { + public void actionPerformed(ActionEvent e) { final JFileChooser fc = new JFileChooser(); - try - { + try { File f = new File(BytecodeViewer.lastDirectory); if (f.exists()) fc.setSelectedFile(f); - } - catch (Exception e2) - { + } catch (Exception e2) { } fc.setDialogTitle("Select File or Folder to open in BCV"); fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); fc.setAcceptAllFileFilterUsed(true); - fc.setFileFilter(new FileFilter() - { + fc.setFileFilter(new FileFilter() { @Override - public boolean accept(File f) - { + public boolean accept(File f) { if (f.isDirectory()) return true; String extension = MiscUtils.extension(f.getAbsolutePath()); if (extension != null) - if (extension.equals("jar") || extension.equals("zip") + return extension.equals("jar") || extension.equals("zip") || extension.equals("class") || extension.equals("apk") - || extension.equals("dex") || extension.equals("war") || extension.equals("jsp")) - return true; + || extension.equals("dex") || extension.equals("war") || extension.equals("jsp"); return false; } @Override - public String getDescription() - { + public String getDescription() { return "APKs, DEX, Class Files or Zip/Jar/War Archives"; } }); int returnVal = fc.showOpenDialog(BytecodeViewer.viewer); - if (returnVal == JFileChooser.APPROVE_OPTION) - { + if (returnVal == JFileChooser.APPROVE_OPTION) { BytecodeViewer.lastDirectory = fc.getSelectedFile().getAbsolutePath(); - try - { + try { BytecodeViewer.viewer.setIcon(true); BytecodeViewer.openFiles(new File[]{fc.getSelectedFile()}, true); BytecodeViewer.viewer.setIcon(false); - } - catch (Exception e1) - { + } catch (Exception e1) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1); } } @@ -606,48 +570,38 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier JMenuItem mntmSave = new JMenuItem("Save As Zip.."); mntmSave.setActionCommand(""); - mntmSave.addActionListener(new ActionListener() - { + mntmSave.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent arg0) - { - if (BytecodeViewer.getLoadedClasses().isEmpty()) - { + public void actionPerformed(ActionEvent arg0) { + if (BytecodeViewer.getLoadedClasses().isEmpty()) { BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file."); return; } - Thread t = new Thread() - { - public void run() - { + Thread t = new Thread() { + public void run() { if (compileOnSave.isSelected() && !BytecodeViewer.compile(false)) return; JFileChooser fc = new JFileChooser(); - fc.setFileFilter(new FileFilter() - { + fc.setFileFilter(new FileFilter() { @Override - public boolean accept(File f) - { + public boolean accept(File f) { return f.isDirectory() || MiscUtils.extension(f.getAbsolutePath()).equals("zip"); } @Override - public String getDescription() - { + public String getDescription() { return "Zip Archives"; } }); fc.setFileHidingEnabled(false); fc.setAcceptAllFileFilterUsed(false); int returnVal = fc.showSaveDialog(MainViewerGUI.this); - if (returnVal == JFileChooser.APPROVE_OPTION) - { + if (returnVal == JFileChooser.APPROVE_OPTION) { File file = fc.getSelectedFile(); if (!file.getAbsolutePath().endsWith(".zip")) file = new File(file.getAbsolutePath() + ".zip"); - if (file.exists()) - { + if (file.exists()) { JOptionPane pane = new JOptionPane( "Are you sure you wish to overwrite this existing file?"); Object[] options = new String[]{"Yes", "No"}; @@ -661,12 +615,9 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier if (options[k].equals(obj)) result = k; - if (result == 0) - { + if (result == 0) { file.delete(); - } - else - { + } else { return; } } @@ -674,11 +625,9 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier final File file2 = file; BytecodeViewer.viewer.setIcon(true); - Thread t = new Thread() - { + Thread t = new Thread() { @Override - public void run() - { + public void run() { JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), file2.getAbsolutePath()); BytecodeViewer.viewer.setIcon(false); @@ -693,10 +642,8 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier }); mnNewMenu.add(separator_39); - mntmReloadResources.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent arg0) - { + mntmReloadResources.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { JOptionPane pane = new JOptionPane("Are you sure you wish to reload the resources?"); Object[] options = new String[]{"Yes", "No"}; pane.setOptions(options); @@ -708,13 +655,11 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier if (options[k].equals(obj)) result = k; - if (result == 0) - { + if (result == 0) { LazyNameUtil.reset(); ArrayList reopen = new ArrayList(); - for (FileContainer container : BytecodeViewer.files) - { + for (FileContainer container : BytecodeViewer.files) { File newFile = new File(container.file.getParent() + BytecodeViewer.fs + container.name); if (!container.file.getAbsolutePath().equals(newFile.getAbsolutePath()) && (container.file.getAbsolutePath().endsWith(".apk") || container.file.getAbsolutePath().endsWith(".dex"))) //APKs & dex get renamed @@ -727,8 +672,7 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier BytecodeViewer.files.clear(); - for (File f : reopen) - { + for (File f : reopen) { BytecodeViewer.openFiles(new File[]{f}, false); } @@ -740,49 +684,39 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier mnNewMenu.add(mntmReloadResources); mnNewMenu.add(separator_3); - mntmNewMenuItem_3.addActionListener(new ActionListener() - { + mntmNewMenuItem_3.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent e) - { - if (BytecodeViewer.getLoadedClasses().isEmpty()) - { + public void actionPerformed(ActionEvent e) { + if (BytecodeViewer.getLoadedClasses().isEmpty()) { BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file."); return; } - Thread t = new Thread() - { - public void run() - { + Thread t = new Thread() { + public void run() { if (compileOnSave.isSelected() && !BytecodeViewer.compile(false)) return; JFileChooser fc = new JFileChooser(); - fc.setFileFilter(new FileFilter() - { + fc.setFileFilter(new FileFilter() { @Override - public boolean accept(File f) - { + public boolean accept(File f) { return f.isDirectory() || MiscUtils.extension(f.getAbsolutePath()).equals("zip"); } @Override - public String getDescription() - { + public String getDescription() { return "Zip Archives"; } }); fc.setFileHidingEnabled(false); fc.setAcceptAllFileFilterUsed(false); int returnVal = fc.showSaveDialog(MainViewerGUI.this); - if (returnVal == JFileChooser.APPROVE_OPTION) - { + if (returnVal == JFileChooser.APPROVE_OPTION) { File file = fc.getSelectedFile(); String path = file.getAbsolutePath(); if (!path.endsWith(".jar")) path = path + ".jar"; - if (new File(path).exists()) - { + if (new File(path).exists()) { JOptionPane pane = new JOptionPane( "Are you sure you wish to overwrite this existing file?"); Object[] options = new String[]{"Yes", "No"}; @@ -796,12 +730,9 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier if (options[k].equals(obj)) result = k; - if (result == 0) - { + if (result == 0) { file.delete(); - } - else - { + } else { return; } } @@ -813,28 +744,21 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier t.start(); } }); - compileButton.addActionListener(new ActionListener() - { + compileButton.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent arg0) - { - Thread t = new Thread() - { - public void run() - { + public void actionPerformed(ActionEvent arg0) { + Thread t = new Thread() { + public void run() { BytecodeViewer.compile(true); } }; t.start(); } }); - mntmRun.addActionListener(new ActionListener() - { + mntmRun.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent e) - { - if (BytecodeViewer.getLoadedClasses().isEmpty()) - { + public void actionPerformed(ActionEvent e) { + if (BytecodeViewer.getLoadedClasses().isEmpty()) { BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file."); return; } @@ -849,43 +773,34 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier mnNewMenu.add(separator_18); mnNewMenu.add(mntmNewMenuItem_3); - mntmSaveAsDEX.addActionListener(new ActionListener() - { + mntmSaveAsDEX.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent arg0) - { - if (BytecodeViewer.getLoadedClasses().isEmpty()) - { + public void actionPerformed(ActionEvent arg0) { + if (BytecodeViewer.getLoadedClasses().isEmpty()) { BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file."); return; } - Thread t = new Thread() - { - public void run() - { + Thread t = new Thread() { + public void run() { if (compileOnSave.isSelected() && !BytecodeViewer.compile(false)) return; JFileChooser fc = new JFileChooser(); - fc.setFileFilter(new FileFilter() - { + fc.setFileFilter(new FileFilter() { @Override - public boolean accept(File f) - { + public boolean accept(File f) { return f.isDirectory() || MiscUtils.extension(f.getAbsolutePath()).equals("dex"); } @Override - public String getDescription() - { + public String getDescription() { return "Android DEX Files"; } }); fc.setFileHidingEnabled(false); fc.setAcceptAllFileFilterUsed(false); int returnVal = fc.showSaveDialog(MainViewerGUI.this); - if (returnVal == JFileChooser.APPROVE_OPTION) - { + if (returnVal == JFileChooser.APPROVE_OPTION) { final File file = fc.getSelectedFile(); String output = file.getAbsolutePath(); if (!output.endsWith(".dex")) @@ -893,8 +808,7 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier final File file2 = new File(output); - if (file2.exists()) - { + if (file2.exists()) { JOptionPane pane = new JOptionPane( "Are you sure you wish to overwrite this existing file?"); Object[] options = new String[]{"Yes", "No"}; @@ -908,30 +822,24 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier if (options[k].equals(obj)) result = k; - if (result == 0) - { + if (result == 0) { file.delete(); - } - else - { + } else { return; } } - Thread t = new Thread() - { + Thread t = new Thread() { @Override - public void run() - { + public void run() { BytecodeViewer.viewer.setIcon(true); - final String input = BytecodeViewer.tempDirectory + BytecodeViewer.fs + BytecodeViewer.getRandomizedName() + ".jar"; + final String input = + BytecodeViewer.tempDirectory + BytecodeViewer.fs + BytecodeViewer.getRandomizedName() + ".jar"; JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), input); - Thread t = new Thread() - { + Thread t = new Thread() { @Override - public void run() - { + public void run() { Dex2Jar.saveAsDex(new File(input), file2); BytecodeViewer.viewer.setIcon(false); @@ -947,13 +855,10 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier t.start(); } }); - mntmSaveAsAPK.addActionListener(new ActionListener() - { + mntmSaveAsAPK.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent arg0) - { - if (BytecodeViewer.getLoadedClasses().isEmpty()) - { + public void actionPerformed(ActionEvent arg0) { + if (BytecodeViewer.getLoadedClasses().isEmpty()) { BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file."); return; } @@ -964,21 +869,17 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier List validContainersNames = new ArrayList<>(); FileContainer container = null; - for(FileContainer fileContainer : containers) - { - if(fileContainer.APKToolContents != null && fileContainer.APKToolContents.exists()) - { + for (FileContainer fileContainer : containers) { + if (fileContainer.APKToolContents != null && fileContainer.APKToolContents.exists()) { validContainersNames.add(fileContainer.name); validContainers.add(fileContainer); } } - if(!validContainers.isEmpty()) - { + if (!validContainers.isEmpty()) { container = validContainers.get(0); - if(validContainers.size() >= 2) - { + if (validContainers.size() >= 2) { JOptionPane pane = new JOptionPane("Which file would you like to export as an APK?"); Object[] options = validContainersNames.toArray(new String[0]); @@ -993,41 +894,35 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier container = containers.get(result); } - } - else - { - BytecodeViewer.showMessage("You can only export as APK from a valid APK file. Make sure Settings>Decode Resources is ticked on.\n\nTip: Try exporting as DEX, it doesn't rely on decoded APK resources"); + } else { + BytecodeViewer.showMessage("You can only export as APK from a valid APK file. Make sure " + + "Settings>Decode Resources is ticked on.\n\nTip: Try exporting as DEX, it doesn't rely on " ++ "decoded APK resources"); return; } final FileContainer finalContainer = container; - Thread t = new Thread() - { - public void run() - { + Thread t = new Thread() { + public void run() { if (compileOnSave.isSelected() && !BytecodeViewer.compile(false)) return; JFileChooser fc = new JFileChooser(); - fc.setFileFilter(new FileFilter() - { + fc.setFileFilter(new FileFilter() { @Override - public boolean accept(File f) - { + public boolean accept(File f) { return f.isDirectory() || MiscUtils.extension(f.getAbsolutePath()).equals("apk"); } @Override - public String getDescription() - { + public String getDescription() { return "Android APK"; } }); fc.setFileHidingEnabled(false); fc.setAcceptAllFileFilterUsed(false); int returnVal = fc.showSaveDialog(MainViewerGUI.this); - if (returnVal == JFileChooser.APPROVE_OPTION) - { + if (returnVal == JFileChooser.APPROVE_OPTION) { final File file = fc.getSelectedFile(); String output = file.getAbsolutePath(); if (!output.endsWith(".apk")) @@ -1035,8 +930,7 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier final File file2 = new File(output); - if (file2.exists()) - { + if (file2.exists()) { JOptionPane pane = new JOptionPane( "Are you sure you wish to overwrite this existing file?"); Object[] options = new String[]{"Yes", "No"}; @@ -1050,30 +944,24 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier if (options[k].equals(obj)) result = k; - if (result == 0) - { + if (result == 0) { file.delete(); - } - else - { + } else { return; } } - Thread t = new Thread() - { + Thread t = new Thread() { @Override - public void run() - { + public void run() { BytecodeViewer.viewer.setIcon(true); - final String input = BytecodeViewer.tempDirectory + BytecodeViewer.fs + BytecodeViewer.getRandomizedName() + ".jar"; + final String input = + BytecodeViewer.tempDirectory + BytecodeViewer.fs + BytecodeViewer.getRandomizedName() + ".jar"; JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), input); - Thread t = new Thread() - { + Thread t = new Thread() { @Override - public void run() - { + public void run() { APKTool.buildAPK(new File(input), file2, finalContainer); BytecodeViewer.viewer.setIcon(false); @@ -1093,49 +981,39 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier //mnNewMenu.add(mntmSaveAsAPK); mnNewMenu.add(mntmSaveAsDEX); mnNewMenu.add(mntmSave); - mntmNewMenuItem.addActionListener(new ActionListener() - { + mntmNewMenuItem.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent arg0) - { - if (BytecodeViewer.getLoadedClasses().isEmpty()) - { + public void actionPerformed(ActionEvent arg0) { + if (BytecodeViewer.getLoadedClasses().isEmpty()) { BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file."); return; } - Thread t = new Thread() - { - public void run() - { + Thread t = new Thread() { + public void run() { if (compileOnSave.isSelected() && !BytecodeViewer.compile(false)) return; JFileChooser fc = new JFileChooser(); - fc.setFileFilter(new FileFilter() - { + fc.setFileFilter(new FileFilter() { @Override - public boolean accept(File f) - { + public boolean accept(File f) { return f.isDirectory() || MiscUtils.extension(f.getAbsolutePath()).equals("zip"); } @Override - public String getDescription() - { + public String getDescription() { return "Zip Archives"; } }); fc.setFileHidingEnabled(false); fc.setAcceptAllFileFilterUsed(false); int returnVal = fc.showSaveDialog(MainViewerGUI.this); - if (returnVal == JFileChooser.APPROVE_OPTION) - { + if (returnVal == JFileChooser.APPROVE_OPTION) { File file = fc.getSelectedFile(); if (!file.getAbsolutePath().endsWith(".zip")) file = new File(file.getAbsolutePath() + ".zip"); - if (file.exists()) - { + if (file.exists()) { JOptionPane pane = new JOptionPane( "Are you sure you wish to overwrite this existing file?"); Object[] options = new String[]{"Yes", "No"}; @@ -1149,12 +1027,9 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier if (options[k].equals(obj)) result = k; - if (result == 0) - { + if (result == 0) { file.delete(); - } - else - { + } else { return; } } @@ -1180,140 +1055,106 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier BytecodeViewer.viewer.setIcon(true); - File tempZip = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp_" + BytecodeViewer.getRandomizedName() + ".jar"); + File tempZip = + new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp_" + BytecodeViewer.getRandomizedName() + ".jar"); if (tempZip.exists()) tempZip.delete(); JarUtils.saveAsJarClassesOnly(BytecodeViewer.getLoadedClasses(), tempZip.getAbsolutePath()); - if (result == 0) - { - Thread t = new Thread() - { + if (result == 0) { + Thread t = new Thread() { @Override - public void run() - { - try - { - Decompiler.procyon.decompileToZip(tempZip.getAbsolutePath(), MiscUtils.append(javaSucks, "-proycon.zip")); + public void run() { + try { + Decompiler.procyon.decompileToZip(tempZip.getAbsolutePath(), + MiscUtils.append(javaSucks, "-proycon.zip")); BytecodeViewer.viewer.setIcon(false); - } - catch (Exception e) - { + } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); } } }; t.start(); - Thread t2 = new Thread() - { + Thread t2 = new Thread() { @Override - public void run() - { - try - { + public void run() { + try { BytecodeViewer.viewer.setIcon(true); - Decompiler.cfr.decompileToZip(tempZip.getAbsolutePath(), MiscUtils.append(javaSucks, "-CFR.zip")); + Decompiler.cfr.decompileToZip(tempZip.getAbsolutePath(), + MiscUtils.append(javaSucks, "-CFR.zip")); BytecodeViewer.viewer.setIcon(false); - } - catch (Exception e) - { + } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); } } }; t2.start(); - Thread t3 = new Thread() - { + Thread t3 = new Thread() { @Override - public void run() - { - try - { + public void run() { + try { BytecodeViewer.viewer.setIcon(true); - Decompiler.fernflower.decompileToZip(tempZip.getAbsolutePath(), MiscUtils.append(javaSucks, "-fernflower.zip")); + Decompiler.fernflower.decompileToZip(tempZip.getAbsolutePath(), + MiscUtils.append(javaSucks, "-fernflower.zip")); BytecodeViewer.viewer.setIcon(false); - } - catch (Exception e) - { + } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); } } }; t3.start(); - Thread t4 = new Thread() - { + Thread t4 = new Thread() { @Override - public void run() - { - try - { + public void run() { + try { BytecodeViewer.viewer.setIcon(true); - Decompiler.krakatau.decompileToZip(tempZip.getAbsolutePath(), MiscUtils.append(javaSucks, "-kraktau.zip")); + Decompiler.krakatau.decompileToZip(tempZip.getAbsolutePath(), + MiscUtils.append(javaSucks, "-kraktau.zip")); BytecodeViewer.viewer.setIcon(false); - } - catch (Exception e) - { + } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); } } }; t4.start(); } - if (result == 1) - { - Thread t = new Thread() - { + if (result == 1) { + Thread t = new Thread() { @Override - public void run() - { - try - { + public void run() { + try { Decompiler.procyon.decompileToZip(tempZip.getAbsolutePath(), path); BytecodeViewer.viewer.setIcon(false); - } - catch (Exception e) - { + } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); } } }; t.start(); } - if (result == 2) - { - Thread t = new Thread() - { + if (result == 2) { + Thread t = new Thread() { @Override - public void run() - { - try - { + public void run() { + try { Decompiler.cfr.decompileToZip(tempZip.getAbsolutePath(), path); BytecodeViewer.viewer.setIcon(false); - } - catch (Exception e) - { + } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); } } }; t.start(); } - if (result == 3) - { - Thread t = new Thread() - { + if (result == 3) { + Thread t = new Thread() { @Override - public void run() - { - try - { + public void run() { + try { Decompiler.fernflower.decompileToZip(tempZip.getAbsolutePath(), path); BytecodeViewer.viewer.setIcon(false); - } - catch (Exception e) - { + } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); } } @@ -1321,20 +1162,14 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier t.start(); } - if (result == 4) - { - Thread t = new Thread() - { + if (result == 4) { + Thread t = new Thread() { @Override - public void run() - { - try - { + public void run() { + try { Decompiler.krakatau.decompileToZip(tempZip.getAbsolutePath(), path); BytecodeViewer.viewer.setIcon(false); - } - catch (Exception e) - { + } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); } } @@ -1342,8 +1177,7 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier t.start(); } - if (result == 5) - { + if (result == 5) { BytecodeViewer.viewer.setIcon(false); } } @@ -1352,21 +1186,16 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier t.start(); } }); - mntmNewMenuItem_12.addActionListener(new ActionListener() - { + mntmNewMenuItem_12.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent arg0) - { - if (workPane.getCurrentViewer() == null) - { + public void actionPerformed(ActionEvent arg0) { + if (workPane.getCurrentViewer() == null) { BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file."); return; } - Thread t = new Thread() - { - public void run() - { + Thread t = new Thread() { + public void run() { if (compileOnSave.isSelected() && !BytecodeViewer.compile(false)) return; @@ -1376,33 +1205,28 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier return; JFileChooser fc = new JFileChooser(); - fc.setFileFilter(new FileFilter() - { + fc.setFileFilter(new FileFilter() { @Override - public boolean accept(File f) - { + public boolean accept(File f) { return f.isDirectory() || MiscUtils.extension(f.getAbsolutePath()).equals("java"); } @Override - public String getDescription() - { + public String getDescription() { return "Java Source Files"; } }); fc.setFileHidingEnabled(false); fc.setAcceptAllFileFilterUsed(false); int returnVal = fc.showSaveDialog(MainViewerGUI.this); - if (returnVal == JFileChooser.APPROVE_OPTION) - { + if (returnVal == JFileChooser.APPROVE_OPTION) { File file = fc.getSelectedFile(); BytecodeViewer.viewer.setIcon(true); final String path = MiscUtils.append(file, ".java"); // cheap hax cause // string is final - if (new File(path).exists()) - { + if (new File(path).exists()) { JOptionPane pane = new JOptionPane( "Are you sure you wish to overwrite this existing file?"); Object[] options = new String[]{"Yes", "No"}; @@ -1416,12 +1240,9 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier if (options[k].equals(obj)) result = k; - if (result == 0) - { + if (result == 0) { file.delete(); - } - else - { + } else { return; } } @@ -1440,74 +1261,54 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier if (options[k].equals(obj)) result = k; - if (result == 0) - { - Thread t = new Thread() - { + if (result == 0) { + Thread t = new Thread() { @Override - public void run() - { - try - { + public void run() { + try { ClassNode cn = BytecodeViewer.getClassNode(s); final ClassWriter cw = new ClassWriter(0); - try - { + try { cn.accept(cw); - } - catch (Exception e) - { + } catch (Exception e) { e.printStackTrace(); - try - { + try { Thread.sleep(200); cn.accept(cw); - } - catch (InterruptedException e1) - { + } catch (InterruptedException e1) { } } - try - { - DiskWriter.replaceFile(MiscUtils.append(file, "-proycon.java"), Decompiler.procyon.decompileClassNode(cn, cw.toByteArray()), false); - } - catch (Exception e) - { + try { + DiskWriter.replaceFile(MiscUtils.append(file, "-proycon.java"), + Decompiler.procyon.decompileClassNode(cn, cw.toByteArray()), false); + } catch (Exception e) { e.printStackTrace(); } - try - { - DiskWriter.replaceFile(MiscUtils.append(file, "-CFR.java"), Decompiler.cfr.decompileClassNode(cn, cw.toByteArray()), false); - } - catch (Exception e) - { + try { + DiskWriter.replaceFile(MiscUtils.append(file, "-CFR.java"), + Decompiler.cfr.decompileClassNode(cn, cw.toByteArray()), false); + } catch (Exception e) { e.printStackTrace(); } - try - { - DiskWriter.replaceFile(MiscUtils.append(file, "-fernflower.java"), Decompiler.fernflower.decompileClassNode(cn, cw.toByteArray()), false); - } - catch (Exception e) - { + try { + DiskWriter.replaceFile(MiscUtils.append(file, "-fernflower.java"), + Decompiler.fernflower.decompileClassNode(cn, cw.toByteArray()), false); + } catch (Exception e) { e.printStackTrace(); } - try - { - DiskWriter.replaceFile(MiscUtils.append(file, "-kraktau.java"), Decompiler.krakatau.decompileClassNode(cn, cw.toByteArray()), false); - } - catch (Exception e) - { + try { + DiskWriter.replaceFile(MiscUtils.append(file, "-kraktau.java"), + Decompiler.krakatau.decompileClassNode(cn, cw.toByteArray()), false); + } catch (Exception e) { e.printStackTrace(); } BytecodeViewer.viewer.setIcon(false); - } - catch (Exception e) - { + } catch (Exception e) { BytecodeViewer.viewer.setIcon(false); new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); } @@ -1515,39 +1316,28 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier }; t.start(); } - if (result == 1) - { - Thread t = new Thread() - { + if (result == 1) { + Thread t = new Thread() { @Override - public void run() - { - try - { + public void run() { + try { ClassNode cn = BytecodeViewer.getClassNode(s); final ClassWriter cw = new ClassWriter(0); - try - { + try { cn.accept(cw); - } - catch (Exception e) - { + } catch (Exception e) { e.printStackTrace(); - try - { + try { Thread.sleep(200); cn.accept(cw); - } - catch (InterruptedException e1) - { + } catch (InterruptedException e1) { } } - String contents = Decompiler.procyon.decompileClassNode(cn, cw.toByteArray()); + String contents = Decompiler.procyon.decompileClassNode(cn, + cw.toByteArray()); DiskWriter.replaceFile(path, contents, false); BytecodeViewer.viewer.setIcon(false); - } - catch (Exception e) - { + } catch (Exception e) { BytecodeViewer.viewer.setIcon(false); new the.bytecode.club.bytecodeviewer.api.ExceptionUI( e); @@ -1556,39 +1346,27 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier }; t.start(); } - if (result == 2) - { - Thread t = new Thread() - { + if (result == 2) { + Thread t = new Thread() { @Override - public void run() - { - try - { + public void run() { + try { ClassNode cn = BytecodeViewer.getClassNode(s); final ClassWriter cw = new ClassWriter(0); - try - { + try { cn.accept(cw); - } - catch (Exception e) - { + } catch (Exception e) { e.printStackTrace(); - try - { + try { Thread.sleep(200); cn.accept(cw); - } - catch (InterruptedException e1) - { + } catch (InterruptedException e1) { } } String contents = Decompiler.cfr.decompileClassNode(cn, cw.toByteArray()); DiskWriter.replaceFile(path, contents, false); BytecodeViewer.viewer.setIcon(false); - } - catch (Exception e) - { + } catch (Exception e) { BytecodeViewer.viewer.setIcon(false); new the.bytecode.club.bytecodeviewer.api.ExceptionUI( e); @@ -1597,40 +1375,29 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier }; t.start(); } - if (result == 3) - { - Thread t = new Thread() - { + if (result == 3) { + Thread t = new Thread() { @Override - public void run() - { - try - { + public void run() { + try { ClassNode cn = BytecodeViewer.getClassNode(s); final ClassWriter cw = new ClassWriter(0); - try - { + try { cn.accept(cw); - } - catch (Exception e) - { + } catch (Exception e) { e.printStackTrace(); - try - { + try { Thread.sleep(200); if (cn != null) cn.accept(cw); - } - catch (InterruptedException e1) - { + } catch (InterruptedException e1) { } } - String contents = Decompiler.fernflower.decompileClassNode(cn, cw.toByteArray()); + String contents = Decompiler.fernflower.decompileClassNode(cn, + cw.toByteArray()); DiskWriter.replaceFile(path, contents, false); BytecodeViewer.viewer.setIcon(false); - } - catch (Exception e) - { + } catch (Exception e) { BytecodeViewer.viewer.setIcon(false); new the.bytecode.club.bytecodeviewer.api.ExceptionUI( e); @@ -1639,44 +1406,32 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier }; t.start(); } - if (result == 4) - { - Thread t = new Thread() - { + if (result == 4) { + Thread t = new Thread() { @Override - public void run() - { - try - { + public void run() { + try { ClassNode cn = BytecodeViewer.getClassNode(s); final ClassWriter cw = new ClassWriter(0); - try - { + try { cn.accept(cw); - } - catch (Exception e) - { + } catch (Exception e) { e.printStackTrace(); - try - { + try { Thread.sleep(200); cn.accept(cw); - } - catch (InterruptedException e1) - { + } catch (InterruptedException e1) { } } - if (LazyNameUtil.SAME_NAME_JAR_WORKSPACE) - { + if (LazyNameUtil.SAME_NAME_JAR_WORKSPACE) { } - String contents = Decompiler.krakatau.decompileClassNode(cn, cw.toByteArray()); + String contents = Decompiler.krakatau.decompileClassNode(cn, + cw.toByteArray()); DiskWriter.replaceFile(path, contents, false); BytecodeViewer.viewer.setIcon(false); - } - catch (Exception e) - { + } catch (Exception e) { BytecodeViewer.viewer.setIcon(false); new the.bytecode.club.bytecodeviewer.api.ExceptionUI( e); @@ -1685,8 +1440,7 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier }; t.start(); } - if (result == 5) - { + if (result == 5) { BytecodeViewer.viewer.setIcon(false); } } @@ -1707,11 +1461,9 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier JSeparator separator_1 = new JSeparator(); mnNewMenu.add(separator_1); - mntmAbout.addActionListener(new ActionListener() - { + mntmAbout.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent arg0) - { + public void actionPerformed(ActionEvent arg0) { aboutWindow.setVisible(true); } }); @@ -1719,11 +1471,9 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier mnNewMenu.add(mntmAbout); JMenuItem mntmExit = new JMenuItem("Exit"); - mntmExit.addActionListener(new ActionListener() - { + mntmExit.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent arg0) - { + public void actionPerformed(ActionEvent arg0) { JOptionPane pane = new JOptionPane( "Are you sure you want to exit?"); Object[] options = new String[]{"Yes", "No"}; @@ -1737,8 +1487,7 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier if (options[k].equals(obj)) result = k; - if (result == 0) - { + if (result == 0) { BytecodeViewer.canExit = true; System.exit(0); } @@ -1999,23 +1748,19 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier chckbxmntmNewCheckItem_12.setSelected(true); mnSettings.add(chckbxmntmNewCheckItem_12); - chckbxmntmDeleteForeignOutdatedLibs.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent arg0) - { - if (!chckbxmntmDeleteForeignOutdatedLibs.isSelected()) - { - BytecodeViewer.showMessage("WARNING: With this being toggled off outdated libraries will NOT be removed. It's also a security issue. ONLY TURN IT OFF IF YOU KNOW WHAT YOU'RE DOING."); + chckbxmntmDeleteForeignOutdatedLibs.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + if (!chckbxmntmDeleteForeignOutdatedLibs.isSelected()) { + BytecodeViewer.showMessage("WARNING: With this being toggled off outdated libraries will NOT be " + + "removed. It's also a security issue. ONLY TURN IT OFF IF YOU KNOW WHAT YOU'RE DOING."); } BytecodeViewer.deleteForeignLibraries = chckbxmntmDeleteForeignOutdatedLibs.isSelected(); } }); mnSettings.add(forcePureAsciiAsText); forcePureAsciiAsText.setSelected(true); - forcePureAsciiAsText.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent arg0) - { + forcePureAsciiAsText.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { Settings.saveSettings(); } }); @@ -2026,28 +1771,22 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier mnSettings.add(separator_36);*/ - mntmSetPythonDirectory.addActionListener(new ActionListener() - { + mntmSetPythonDirectory.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent arg0) - { + public void actionPerformed(ActionEvent arg0) { pythonC(); } }); mnSettings.add(mntmSetPythonDirectory); - mntmSetJreRt.addActionListener(new ActionListener() - { + mntmSetJreRt.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent arg0) - { + public void actionPerformed(ActionEvent arg0) { rtC(); } }); - mntmSetPythonx.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent arg0) - { + mntmSetPythonx.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { pythonC3(); } }); @@ -2055,20 +1794,16 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier mnSettings.add(mntmSetPythonx); mnSettings.add(mntmSetJreRt); - mntmSetOpitonalLibrary.addActionListener(new ActionListener() - { + mntmSetOpitonalLibrary.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent arg0) - { + public void actionPerformed(ActionEvent arg0) { library(); } }); mnSettings.add(mntmSetOpitonalLibrary); - mntmSetJavacExecutable.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent arg0) - { + mntmSetJavacExecutable.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { javac(); } }); @@ -2294,14 +2029,12 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier mnBytecodeDecompilerSettings.add(chckbxmntmAppendBrackets); menuBar.add(mnNewMenu_5); - mntmNewMenuItem_6.addActionListener(new ActionListener() - { + mntmNewMenuItem_6.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent arg0) - { - if (BytecodeViewer.runningObfuscation) - { - BytecodeViewer.showMessage("You're currently running an obfuscation task, wait for this to finish."); + public void actionPerformed(ActionEvent arg0) { + if (BytecodeViewer.runningObfuscation) { + BytecodeViewer.showMessage("You're currently running an obfuscation task, wait for this to finish" + + "."); return; } new RenameFields().start(); @@ -2320,14 +2053,12 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier mnNewMenu_5.add(mntmNewMenuItem_8); mnNewMenu_5.add(mntmNewMenuItem_6); - mntmNewMenuItem_7.addActionListener(new ActionListener() - { + mntmNewMenuItem_7.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent arg0) - { - if (BytecodeViewer.runningObfuscation) - { - BytecodeViewer.showMessage("You're currently running an obfuscation task, wait for this to finish."); + public void actionPerformed(ActionEvent arg0) { + if (BytecodeViewer.runningObfuscation) { + BytecodeViewer.showMessage("You're currently running an obfuscation task, wait for this to finish" + + "."); return; } new RenameMethods().start(); @@ -2337,14 +2068,12 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier }); mnNewMenu_5.add(mntmNewMenuItem_7); - mntmNewMenuItem_11.addActionListener(new ActionListener() - { + mntmNewMenuItem_11.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent arg0) - { - if (BytecodeViewer.runningObfuscation) - { - BytecodeViewer.showMessage("You're currently running an obfuscation task, wait for this to finish."); + public void actionPerformed(ActionEvent arg0) { + if (BytecodeViewer.runningObfuscation) { + BytecodeViewer.showMessage("You're currently running an obfuscation task, wait for this to finish" + + "."); return; } new RenameClasses().start(); @@ -2366,13 +2095,10 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier mnNewMenu_1.add(separator_4); mnNewMenu_1.add(mnRecentPlugins); mnNewMenu_1.add(separator_5); - mntmCodeSequenceDiagram.addActionListener(new ActionListener() - { + mntmCodeSequenceDiagram.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent arg0) - { - if (BytecodeViewer.getLoadedClasses().isEmpty()) - { + public void actionPerformed(ActionEvent arg0) { + if (BytecodeViewer.getLoadedClasses().isEmpty()) { BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file."); return; } @@ -2384,13 +2110,10 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier mnNewMenu_1.add(mntmNewMenuItem_1); mnNewMenu_1.add(mntmShowMainMethods); mnNewMenu_1.add(mntmShowAllStrings); - mntmReplaceStrings.addActionListener(new ActionListener() - { + mntmReplaceStrings.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent arg0) - { - if (BytecodeViewer.getLoadedClasses().isEmpty()) - { + public void actionPerformed(ActionEvent arg0) { + if (BytecodeViewer.getLoadedClasses().isEmpty()) { BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file."); return; } @@ -2401,20 +2124,16 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier mnNewMenu_1.add(mntmReplaceStrings); mnNewMenu_1.add(mntmNewMenuItem_2); mnNewMenu_1.add(mntmStartZkmString); - mntmZstringarrayDecrypter.addActionListener(new ActionListener() - { + mntmZstringarrayDecrypter.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent arg0) - { + public void actionPerformed(ActionEvent arg0) { PluginManager.runPlugin(new ZStringArrayDecrypter()); } }); - mntmStackFramesRemover.addActionListener(new ActionListener() - { + mntmStackFramesRemover.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent e) - { + public void actionPerformed(ActionEvent e) { PluginManager.runPlugin(new StackFramesRemover()); } }); @@ -2423,19 +2142,16 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier mnNewMenu_1.add(mntmStackFramesRemover); waitIcons = new JMenuItem[10]; - for (int i = 0; i < 10; i++) - { + for (int i = 0; i < 10; i++) { waitIcons[i] = new JMenuItem(""); waitIcons[i].setMaximumSize(new Dimension(20, 50)); waitIcons[i].setEnabled(false); menuBar.add(waitIcons[i]); } - mntmStartExternalPlugin.addActionListener(new ActionListener() - { + mntmStartExternalPlugin.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent arg0) - { + public void actionPerformed(ActionEvent arg0) { JFileChooser fc = new JFileChooser(); fc.setFileFilter(PluginManager.fileFilter()); fc.setFileHidingEnabled(false); @@ -2443,70 +2159,58 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier int returnVal = fc.showOpenDialog(BytecodeViewer.viewer); if (returnVal == JFileChooser.APPROVE_OPTION) - try - { + try { BytecodeViewer.viewer.setIcon(true); BytecodeViewer.startPlugin(fc.getSelectedFile()); BytecodeViewer.viewer.setIcon(false); - } - catch (Exception e1) - { + } catch (Exception e1) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1); } } }); - mntmStartZkmString.addActionListener(new ActionListener() - { + mntmStartZkmString.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent e) - { + public void actionPerformed(ActionEvent e) { PluginManager.runPlugin(new ZKMStringDecrypter()); } }); - mntmNewMenuItem_2.addActionListener(new ActionListener() - { + mntmNewMenuItem_2.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent e) - { + public void actionPerformed(ActionEvent e) { PluginManager.runPlugin(new AllatoriStringDecrypter()); } }); - mntmNewMenuItem_1.addActionListener(new ActionListener() - { + mntmNewMenuItem_1.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent e) - { - if (BytecodeViewer.getLoadedClasses().isEmpty()) - { + public void actionPerformed(ActionEvent e) { + if (BytecodeViewer.getLoadedClasses().isEmpty()) { BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file."); return; } new MaliciousCodeScannerOptions().setVisible(true); } }); - mntmShowAllStrings.addActionListener(new ActionListener() - { + mntmShowAllStrings.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent e) - { + public void actionPerformed(ActionEvent e) { PluginManager.runPlugin(new ShowAllStrings()); } }); - mntmShowMainMethods.addActionListener(new ActionListener() - { + mntmShowMainMethods.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent e) - { + public void actionPerformed(ActionEvent e) { PluginManager.runPlugin(new ShowMainMethods()); } }); setSize(new Dimension(800, 400)); if (BytecodeViewer.PREVIEW_COPY) - setTitle("Bytecode Viewer " + BytecodeViewer.VERSION + " Preview - https://bytecodeviewer.com | https://the.bytecode.club - @Konloch"); + setTitle("Bytecode Viewer " + BytecodeViewer.VERSION + " Preview - https://bytecodeviewer.com | " ++ "https://the.bytecode.club - @Konloch"); else - setTitle("Bytecode Viewer " + BytecodeViewer.VERSION + " - https://bytecodeviewer.com | https://the.bytecode.club - @Konloch"); + setTitle("Bytecode Viewer " + BytecodeViewer.VERSION + " - https://bytecodeviewer.com | https://the" + + ".bytecode.club - @Konloch"); getContentPane().setLayout( new BoxLayout(getContentPane(), BoxLayout.X_AXIS)); @@ -2585,10 +2289,8 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier visualSettings.add(mnFontSize); visualSettings.add(showFileInTabTitle); showFileInTabTitle.setSelected(false); - showFileInTabTitle.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent arg0) - { + showFileInTabTitle.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { BytecodeViewer.displayParentInTab = BytecodeViewer.viewer.showFileInTabTitle.isSelected(); Settings.saveSettings(); } @@ -2608,48 +2310,38 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier @Override - public void openClassFile(final FileContainer container, final String name, final ClassNode cn) - { - for (final VisibleComponent vc : rfComps) - { + public void openClassFile(final FileContainer container, final String name, final ClassNode cn) { + for (final VisibleComponent vc : rfComps) { vc.openClassFile(container, name, cn); } } @Override - public void openFile(final FileContainer container, final String name, byte[] content) - { - for (final VisibleComponent vc : rfComps) - { + public void openFile(final FileContainer container, final String name, byte[] content) { + for (final VisibleComponent vc : rfComps) { vc.openFile(container, name, content); } } @SuppressWarnings("unchecked") - public static T getComponent(final Class clazz) - { - for (final VisibleComponent vc : rfComps) - { + public static T getComponent(final Class clazz) { + for (final VisibleComponent vc : rfComps) { if (vc.getClass() == clazz) return (T) vc; } return null; } - public void pythonC() - { + public void pythonC() { JFileChooser fc = new JFileChooser(); - fc.setFileFilter(new FileFilter() - { + fc.setFileFilter(new FileFilter() { @Override - public boolean accept(File f) - { + public boolean accept(File f) { return true; } @Override - public String getDescription() - { + public String getDescription() { return "Python (Or PyPy for speed) 2.7 Executable"; } }); @@ -2658,30 +2350,23 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier int returnVal = fc.showOpenDialog(BytecodeViewer.viewer); if (returnVal == JFileChooser.APPROVE_OPTION) - try - { + try { BytecodeViewer.python = fc.getSelectedFile().getAbsolutePath(); - } - catch (Exception e1) - { + } catch (Exception e1) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1); } } - public void javac() - { + public void javac() { JFileChooser fc = new JFileChooser(); - fc.setFileFilter(new FileFilter() - { + fc.setFileFilter(new FileFilter() { @Override - public boolean accept(File f) - { + public boolean accept(File f) { return true; } @Override - public String getDescription() - { + public String getDescription() { return "Javac Executable (Requires JDK 'C:/programfiles/Java/JDK_xx/bin/javac.exe)"; } }); @@ -2690,30 +2375,23 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier int returnVal = fc.showOpenDialog(BytecodeViewer.viewer); if (returnVal == JFileChooser.APPROVE_OPTION) - try - { + try { BytecodeViewer.javac = fc.getSelectedFile().getAbsolutePath(); - } - catch (Exception e1) - { + } catch (Exception e1) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1); } } - public void java() - { + public void java() { JFileChooser fc = new JFileChooser(); - fc.setFileFilter(new FileFilter() - { + fc.setFileFilter(new FileFilter() { @Override - public boolean accept(File f) - { + public boolean accept(File f) { return true; } @Override - public String getDescription() - { + public String getDescription() { return "Java Executable (Inside Of JRE/JDK 'C:/programfiles/Java/JDK_xx/bin/java.exe')"; } }); @@ -2722,30 +2400,23 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier int returnVal = fc.showOpenDialog(BytecodeViewer.viewer); if (returnVal == JFileChooser.APPROVE_OPTION) - try - { + try { BytecodeViewer.java = fc.getSelectedFile().getAbsolutePath(); - } - catch (Exception e1) - { + } catch (Exception e1) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1); } } - public void pythonC3() - { + public void pythonC3() { JFileChooser fc = new JFileChooser(); - fc.setFileFilter(new FileFilter() - { + fc.setFileFilter(new FileFilter() { @Override - public boolean accept(File f) - { + public boolean accept(File f) { return true; } @Override - public String getDescription() - { + public String getDescription() { return "Python (Or PyPy for speed) 3.x Executable"; } }); @@ -2754,30 +2425,23 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier int returnVal = fc.showOpenDialog(BytecodeViewer.viewer); if (returnVal == JFileChooser.APPROVE_OPTION) - try - { + try { BytecodeViewer.python3 = fc.getSelectedFile().getAbsolutePath(); - } - catch (Exception e1) - { + } catch (Exception e1) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1); } } - public void library() - { + public void library() { JFileChooser fc = new JFileChooser(); - fc.setFileFilter(new FileFilter() - { + fc.setFileFilter(new FileFilter() { @Override - public boolean accept(File f) - { + public boolean accept(File f) { return f.isDirectory(); } @Override - public String getDescription() - { + public String getDescription() { return "Optional Library Folder"; } }); @@ -2787,31 +2451,24 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier int returnVal = fc.showOpenDialog(BytecodeViewer.viewer); if (returnVal == JFileChooser.APPROVE_OPTION) - try - { + try { BytecodeViewer.library = fc.getSelectedFile().getAbsolutePath(); - } - catch (Exception e1) - { + } catch (Exception e1) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1); } } - public void rtC() - { + public void rtC() { JFileChooser fc = new JFileChooser(); - fc.setFileFilter(new FileFilter() - { + fc.setFileFilter(new FileFilter() { @Override - public boolean accept(File f) - { + public boolean accept(File f) { return true; } @Override - public String getDescription() - { + public String getDescription() { return "JRE RT Library"; } }); @@ -2820,12 +2477,9 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier int returnVal = fc.showOpenDialog(BytecodeViewer.viewer); if (returnVal == JFileChooser.APPROVE_OPTION) - try - { + try { BytecodeViewer.rt = fc.getSelectedFile().getAbsolutePath(); - } - catch (Exception e1) - { + } catch (Exception e1) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e1); } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/MaliciousCodeScannerOptions.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/MaliciousCodeScannerOptions.java index 14ba67b2..7fca8829 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/MaliciousCodeScannerOptions.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/MaliciousCodeScannerOptions.java @@ -1,19 +1,15 @@ package the.bytecode.club.bytecodeviewer.gui; -import javax.swing.JFrame; - import java.awt.Dimension; - -import javax.swing.JCheckBox; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import javax.swing.JButton; - +import javax.swing.JCheckBox; +import javax.swing.JFrame; import the.bytecode.club.bytecodeviewer.Resources; import the.bytecode.club.bytecodeviewer.plugin.PluginManager; import the.bytecode.club.bytecodeviewer.plugin.preinstalled.MaliciousCodeScanner; -import java.awt.event.ActionListener; -import java.awt.event.ActionEvent; - /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/PaneUpdaterThread.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/PaneUpdaterThread.java index 2f3bc9f2..ae4451a5 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/PaneUpdaterThread.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/PaneUpdaterThread.java @@ -18,19 +18,29 @@ package the.bytecode.club.bytecodeviewer.gui; * along with this program. If not, see . * ***************************************************************************/ -import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; -import org.fife.ui.rtextarea.RTextScrollPane; -import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.util.MethodParser; - -import javax.swing.*; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.util.regex.Matcher; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JViewport; +import javax.swing.ListCellRenderer; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import java.awt.*; -import java.awt.event.*; -import java.util.regex.Matcher; +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; +import org.fife.ui.rtextarea.RTextScrollPane; +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.util.MethodParser; import static the.bytecode.club.bytecodeviewer.gui.TabbedPane.BLANK; @@ -41,8 +51,7 @@ import static the.bytecode.club.bytecodeviewer.gui.TabbedPane.BLANK; * @author DreamSworK */ -public abstract class PaneUpdaterThread extends Thread -{ +public abstract class PaneUpdaterThread extends Thread { public ClassViewer viewer; public RSyntaxTextArea panelArea; public RTextScrollPane scrollPane; @@ -56,32 +65,26 @@ public abstract class PaneUpdaterThread extends Thread public void run() { doShit(); synchronizePane(); - //attachCtrlMouseWheelZoom(scrollPane, panelArea); //freezes the UI for some reason, probably cause BCV is doing dumb shit with the swing thread + //attachCtrlMouseWheelZoom(scrollPane, panelArea); //freezes the UI for some reason, probably cause BCV is + // doing dumb shit with the swing thread } - public void attachCtrlMouseWheelZoom(RTextScrollPane scrollPane, RSyntaxTextArea panelArea) - { - if(scrollPane == null) + public void attachCtrlMouseWheelZoom(RTextScrollPane scrollPane, RSyntaxTextArea panelArea) { + if (scrollPane == null) return; - scrollPane.addMouseWheelListener(new MouseWheelListener() - { + scrollPane.addMouseWheelListener(new MouseWheelListener() { @Override - public void mouseWheelMoved(MouseWheelEvent e) - { - if(panelArea == null || panelArea.getText().isEmpty()) + public void mouseWheelMoved(MouseWheelEvent e) { + if (panelArea == null || panelArea.getText().isEmpty()) return; - if ((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0) - { + if ((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0) { Font font = panelArea.getFont(); int size = font.getSize(); - if(e.getWheelRotation() > 0) - { //Up + if (e.getWheelRotation() > 0) { //Up panelArea.setFont(new Font(font.getName(), font.getStyle(), --size >= 2 ? --size : 2)); - } - else - { //Down + } else { //Down panelArea.setFont(new Font(font.getName(), font.getStyle(), ++size)); } } @@ -90,37 +93,27 @@ public abstract class PaneUpdaterThread extends Thread }); } - public final CaretListener caretListener = new CaretListener() - { + public final CaretListener caretListener = new CaretListener() { @Override - public void caretUpdate(CaretEvent e) - { + public void caretUpdate(CaretEvent e) { MethodParser methods = viewer.methods.get(paneId); - if (methods != null) - { + if (methods != null) { int methodLine = methods.findActiveMethod(panelArea.getCaretLineNumber()); - if (methodLine != -1) - { - if (BytecodeViewer.viewer.showClassMethods.isSelected()) - { - if (methodsList != null) - { - if (methodLine != (int) methodsList.getSelectedItem()) - { + if (methodLine != -1) { + if (BytecodeViewer.viewer.showClassMethods.isSelected()) { + if (methodsList != null) { + if (methodLine != (int) methodsList.getSelectedItem()) { methodsList.setSelectedItem(methodLine); } } } - if (BytecodeViewer.viewer.synchronizedViewing.isSelected()) - { + if (BytecodeViewer.viewer.synchronizedViewing.isSelected()) { int panes = 2; - if(viewer.panel3 != null) + if (viewer.panel3 != null) panes = 3; - for (int i = 0; i < panes; i++) - { - if (i != paneId) - { + for (int i = 0; i < panes; i++) { + if (i != paneId) { ClassViewer.selectMethod(viewer, i, methods.getMethod(methodLine)); } } @@ -134,7 +127,7 @@ public abstract class PaneUpdaterThread extends Thread @Override public void stateChanged(ChangeEvent e) { int panes = 2; - if(viewer.panel3 != null) + if (viewer.panel3 != null) panes = 3; if (BytecodeViewer.viewer.synchronizedViewing.isSelected()) { @@ -142,7 +135,8 @@ public abstract class PaneUpdaterThread extends Thread int caretLine = panelArea.getCaretLineNumber(); int maxViewLine = ClassViewer.getMaxViewLine(panelArea); int activeViewLine = ClassViewer.getViewLine(panelArea); - int activeLine = (activeViewLine == maxViewLine && caretLine > maxViewLine) ? caretLine : activeViewLine; + int activeLine = (activeViewLine == maxViewLine && caretLine > maxViewLine) ? caretLine : + activeViewLine; int activeLineDelta = -1; MethodParser.Method activeMethod = null; MethodParser activeMethods = viewer.methods.get(paneId); @@ -155,22 +149,20 @@ public abstract class PaneUpdaterThread extends Thread } } for (int i = 0; i < panes; i++) { - if (i != paneId) - { + if (i != paneId) { int setLine = -1; RSyntaxTextArea area = null; - switch(i) - { - case 0: - area = viewer.t1.panelArea; - break; - case 1: - area = viewer.t2.panelArea; - break; - case 2: - area = viewer.t3.panelArea; - break; + switch (i) { + case 0: + area = viewer.t1.panelArea; + break; + case 1: + area = viewer.t2.panelArea; + break; + case 2: + area = viewer.t3.panelArea; + break; } if (area != null) { @@ -185,8 +177,7 @@ public abstract class PaneUpdaterThread extends Thread } } } - } - else if (activeLine != ClassViewer.getViewLine(area)) { + } else if (activeLine != ClassViewer.getViewLine(area)) { setLine = activeLine; } if (setLine >= 0) { @@ -200,14 +191,13 @@ public abstract class PaneUpdaterThread extends Thread } }; - class MethodsRenderer extends JLabel implements ListCellRenderer - { + class MethodsRenderer extends JLabel implements ListCellRenderer { public MethodsRenderer() { setOpaque(true); } - public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) - { + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, + boolean cellHasFocus) { MethodParser methods = viewer.methods.get(paneId); MethodParser.Method method = methods.getMethod((Integer) value); setText(method.toString()); @@ -215,27 +205,23 @@ public abstract class PaneUpdaterThread extends Thread } } - public void synchronizePane() - { + public void synchronizePane() { JViewport viewport = scrollPane.getViewport(); viewport.addChangeListener(viewportListener); panelArea.addCaretListener(caretListener); final MethodParser methods = viewer.methods.get(paneId); - for (int i = 0; i < panelArea.getLineCount(); i++) - { + for (int i = 0; i < panelArea.getLineCount(); i++) { String lineText = ClassViewer.getLineText(panelArea, i); Matcher regexMatcher = MethodParser.regex.matcher(lineText); - if (regexMatcher.find()) - { + if (regexMatcher.find()) { String methodName = regexMatcher.group("name"); String methodParams = regexMatcher.group("params"); methods.addMethod(i, methodName, methodParams); } } - if (BytecodeViewer.viewer.showClassMethods.isSelected()) - { + if (BytecodeViewer.viewer.showClassMethods.isSelected()) { if (!methods.isEmpty()) { methodsList = new JComboBox<>(); for (Integer line : methods.getMethodsLines()) { @@ -248,20 +234,19 @@ public abstract class PaneUpdaterThread extends Thread int line = (int) methodsList.getSelectedItem(); RSyntaxTextArea area = null; - switch(paneId) - { - case 0: - area = viewer.t1.panelArea; - break; - case 1: - area = viewer.t2.panelArea; - break; - case 2: - area = viewer.t3.panelArea; - break; + switch (paneId) { + case 0: + area = viewer.t1.panelArea; + break; + case 1: + area = viewer.t2.panelArea; + break; + case 2: + area = viewer.t3.panelArea; + break; } - if(area != null) + if (area != null) ClassViewer.selectMethod(area, line); } }); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/ReplaceStringsOptions.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/ReplaceStringsOptions.java index 441907ea..3e857640 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/ReplaceStringsOptions.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/ReplaceStringsOptions.java @@ -1,21 +1,17 @@ package the.bytecode.club.bytecodeviewer.gui; import java.awt.Dimension; - -import javax.swing.JFrame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JTextField; - import the.bytecode.club.bytecodeviewer.Resources; import the.bytecode.club.bytecodeviewer.plugin.PluginManager; import the.bytecode.club.bytecodeviewer.plugin.preinstalled.ReplaceStrings; -import java.awt.event.ActionListener; -import java.awt.event.ActionEvent; - -import javax.swing.JCheckBox; - /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * @@ -84,7 +80,8 @@ public class ReplaceStringsOptions extends JFrame { final JCheckBox chckbxNewCheckBox = new JCheckBox( "Replace All Contains"); chckbxNewCheckBox - .setToolTipText("If it's unticked, it will check if the string equals, if its ticked it will check if it contains, then replace the original LDC part of the string."); + .setToolTipText("If it's unticked, it will check if the string equals, if its ticked it will check if" + + " it contains, then replace the original LDC part of the string."); chckbxNewCheckBox.setBounds(6, 7, 232, 23); getContentPane().add(chckbxNewCheckBox); btnNewButton.addActionListener(new ActionListener() { @@ -99,7 +96,7 @@ public class ReplaceStringsOptions extends JFrame { } private static final long serialVersionUID = -2662514582647810868L; - private JTextField textField; - private JTextField textField_1; - private JTextField textField_2; + private final JTextField textField; + private final JTextField textField_1; + private final JTextField textField_2; } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/RunOptions.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/RunOptions.java index a240b2f0..8be95601 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/RunOptions.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/RunOptions.java @@ -1,27 +1,20 @@ package the.bytecode.club.bytecodeviewer.gui; -import javax.swing.JFrame; - import java.awt.Dimension; - -import javax.swing.JCheckBox; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import javax.swing.JButton; - +import javax.swing.JCheckBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JTextField; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.Resources; import the.bytecode.club.bytecodeviewer.plugin.PluginManager; import the.bytecode.club.bytecodeviewer.plugin.preinstalled.EZInjection; -import java.awt.event.ActionListener; -import java.awt.event.ActionEvent; - -import javax.swing.JTextField; - -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.MethodNode; - -import javax.swing.JLabel; - /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * @@ -157,8 +150,8 @@ public class RunOptions extends JFrame { } private static final long serialVersionUID = -2662514582647810868L; - private JTextField txtThebytecodeclubexamplemainlstring; - private JCheckBox debugMethodCalls; - private JTextField textField; - private JTextField textField_1; + private final JTextField txtThebytecodeclubexamplemainlstring; + private final JCheckBox debugMethodCalls; + private final JTextField textField; + private final JTextField textField_1; } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/SearchingPane.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/SearchingPane.java index e5f79386..10dd0b04 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/SearchingPane.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/SearchingPane.java @@ -8,7 +8,6 @@ import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; - import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JCheckBox; @@ -21,11 +20,16 @@ import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreePath; - import org.objectweb.asm.tree.ClassNode; - -import the.bytecode.club.bytecodeviewer.*; -import the.bytecode.club.bytecodeviewer.searching.*; +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.searching.BackgroundSearchThread; +import the.bytecode.club.bytecodeviewer.searching.FieldCallSearch; +import the.bytecode.club.bytecodeviewer.searching.LDCSearch; +import the.bytecode.club.bytecodeviewer.searching.MethodCallSearch; +import the.bytecode.club.bytecodeviewer.searching.RegexInsnFinder; +import the.bytecode.club.bytecodeviewer.searching.RegexSearch; +import the.bytecode.club.bytecodeviewer.searching.SearchResultNotifier; +import the.bytecode.club.bytecodeviewer.searching.SearchTypeDetails; import the.bytecode.club.bytecodeviewer.util.FileChangeNotifier; import the.bytecode.club.bytecodeviewer.util.FileContainer; @@ -55,8 +59,7 @@ import the.bytecode.club.bytecodeviewer.util.FileContainer; */ @SuppressWarnings("rawtypes") -public class SearchingPane extends VisibleComponent -{ +public class SearchingPane extends VisibleComponent { private static final long serialVersionUID = -1098524689236993932L; @@ -71,19 +74,16 @@ public class SearchingPane extends VisibleComponent JComboBox searchRadiusBox; public JButton search = new JButton("Search"); - BackgroundSearchThread t = new BackgroundSearchThread(true) - { + BackgroundSearchThread t = new BackgroundSearchThread(true) { @Override - public void doSearch() - { + public void doSearch() { // empty } }; @SuppressWarnings("unchecked") - public SearchingPane(final FileChangeNotifier fcn) - { + public SearchingPane(final FileChangeNotifier fcn) { super("Search"); this.fcn = fcn; @@ -97,8 +97,7 @@ public class SearchingPane extends VisibleComponent searchRadiusOpt.add(new JLabel("Search from "), BorderLayout.WEST); DefaultComboBoxModel model = new DefaultComboBoxModel(); - for (final SearchRadius st : SearchRadius.values()) - { + for (final SearchRadius st : SearchRadius.values()) { model.addElement(st); } @@ -109,19 +108,16 @@ public class SearchingPane extends VisibleComponent searchOpts.add(searchRadiusOpt); model = new DefaultComboBoxModel(); - for (final SearchType st : SearchType.values()) - { + for (final SearchType st : SearchType.values()) { model.addElement(st); } typeBox = new JComboBox(model); final JPanel searchOptPanel = new JPanel(); - final ItemListener il = new ItemListener() - { + final ItemListener il = new ItemListener() { @Override - public void itemStateChanged(final ItemEvent arg0) - { + public void itemStateChanged(final ItemEvent arg0) { searchOptPanel.removeAll(); searchType = (SearchType) typeBox.getSelectedItem(); searchOptPanel.add(searchType.details.getPanel()); @@ -147,11 +143,9 @@ public class SearchingPane extends VisibleComponent optionPanel.add(p2, BorderLayout.CENTER); - search.addActionListener(new ActionListener() - { + search.addActionListener(new ActionListener() { @Override - public void actionPerformed(final ActionEvent arg0) - { + public void actionPerformed(final ActionEvent arg0) { search(); } }); @@ -165,27 +159,25 @@ public class SearchingPane extends VisibleComponent getContentPane().add(new JScrollPane(optionPanel), BorderLayout.NORTH); getContentPane().add(new JScrollPane(tree), BorderLayout.CENTER); - this.tree.addTreeSelectionListener(new TreeSelectionListener() - { + this.tree.addTreeSelectionListener(new TreeSelectionListener() { @Override - public void valueChanged(final TreeSelectionEvent arg0) - { - if(arg0.getPath().getPathComponent(0).equals("Results")) + public void valueChanged(final TreeSelectionEvent arg0) { + if (arg0.getPath().getPathComponent(0).equals("Results")) return; String cheapHax = arg0.getPath().getPathComponent(1).toString(); String path = arg0.getPath().getPathComponent(1).toString(); - String containerName = path.split(">",2)[0]; - String className = path.split(">",2)[1].split("\\.")[0]; + String containerName = path.split(">", 2)[0]; + String className = path.split(">", 2)[1].split("\\.")[0]; FileContainer container = BytecodeViewer.getFileContainer(containerName); final ClassNode fN = container.getClassNode(className); - if (fN != null) - { - MainViewerGUI.getComponent(FileNavigationPane.class).openClassFileToWorkSpace(container, className + ".class", fN); + if (fN != null) { + MainViewerGUI.getComponent(FileNavigationPane.class).openClassFileToWorkSpace(container, + className + ".class", fN); } } }); @@ -194,8 +186,7 @@ public class SearchingPane extends VisibleComponent } - public void search() - { + public void search() { treeRoot.removeAllChildren(); searchType = (SearchType) typeBox.getSelectedItem(); final SearchRadius radius = (SearchRadius) searchRadiusBox @@ -213,7 +204,8 @@ public class SearchingPane extends VisibleComponent public void doSearch() { try { - Pattern.compile(RegexInsnFinder.processRegex(RegexSearch.searchText.getText()), Pattern.MULTILINE); + Pattern.compile(RegexInsnFinder.processRegex(RegexSearch.searchText.getText()), + Pattern.MULTILINE); } catch (PatternSyntaxException ex) { BytecodeViewer.showMessage("You have an error in your regex syntax."); } @@ -236,7 +228,8 @@ public class SearchingPane extends VisibleComponent t.start(); } else { // this should really never be called. BytecodeViewer - .showMessage("You currently have a search performing in the background, please wait for that to finish."); + .showMessage("You currently have a search performing in the background, please wait for that " + + "to finish."); } } else if (radius == SearchRadius.Current_Class) { final Viewer cv = MainViewerGUI.getComponent(WorkPane.class).getCurrentViewer(); @@ -260,7 +253,7 @@ public class SearchingPane extends VisibleComponent } public enum SearchRadius { - All_Classes, Current_Class; + All_Classes, Current_Class } public void resetWorkspace() { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/SystemErrConsole.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/SystemErrConsole.java index 07914466..e753cc8e 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/SystemErrConsole.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/SystemErrConsole.java @@ -1,16 +1,8 @@ package the.bytecode.club.bytecodeviewer.gui; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JFrame; -import javax.swing.JTextField; - +import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; - -import javax.swing.JScrollPane; - -import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; @@ -18,16 +10,18 @@ import java.awt.event.KeyListener; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; - -import javax.swing.JTextArea; - -import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.Resources; - +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFrame; import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JTextField; import javax.swing.text.DefaultHighlighter; import javax.swing.text.Highlighter; import javax.swing.text.JTextComponent; +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.Resources; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -60,7 +54,7 @@ public class SystemErrConsole extends JFrame { JScrollPane scrollPane = new JScrollPane(); public JCheckBox check = new JCheckBox("Exact"); final JTextField field = new JTextField(); - private PrintStream originalOut; + private final PrintStream originalOut; public SystemErrConsole(String title) { this.setIconImages(Resources.iconList); @@ -154,7 +148,7 @@ public class SystemErrConsole extends JFrame { if (s.startsWith("File '")) { String[] split = s.split("'"); String start = split[0] + "'" + split[1] + "', "; - s = s.substring(start.length(), s.length()); + s = s.substring(start.length()); } replace += s + BytecodeViewer.nl; } @@ -255,7 +249,7 @@ public class SystemErrConsole extends JFrame { } } - private DefaultHighlighter.DefaultHighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter( + private final DefaultHighlighter.DefaultHighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter( new Color(255, 62, 150)); public void highlight(JTextComponent textComp, String pattern) { @@ -311,8 +305,8 @@ public class SystemErrConsole extends JFrame { } class CustomOutputStream extends OutputStream { - private StringBuilder sb = new StringBuilder(); - private JTextArea textArea; + private final StringBuilder sb = new StringBuilder(); + private final JTextArea textArea; public CustomOutputStream(JTextArea textArea) { this.textArea = textArea; @@ -324,7 +318,7 @@ public class SystemErrConsole extends JFrame { @Override public void write(int b) throws IOException { - sb.append(String.valueOf((char) b)); + sb.append((char) b); } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/TabbedPane.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/TabbedPane.java index d9426eaf..e8fb5ce2 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/TabbedPane.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/TabbedPane.java @@ -1,14 +1,18 @@ package the.bytecode.club.bytecodeviewer.gui; -import the.bytecode.club.bytecodeviewer.BytecodeViewer; - -import java.awt.*; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; - import javax.swing.AbstractButton; import javax.swing.BorderFactory; import javax.swing.JButton; @@ -18,6 +22,7 @@ import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JTabbedPane; import javax.swing.plaf.basic.BasicButtonUI; +import the.bytecode.club.bytecodeviewer.BytecodeViewer; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -46,15 +51,15 @@ import javax.swing.plaf.basic.BasicButtonUI; public class TabbedPane extends JPanel { private static final long serialVersionUID = -4774885688297538774L; - public static final Color BLANK = new Color(0,0,0,0); + public static final Color BLANK = new Color(0, 0, 0, 0); private final JTabbedPane pane; public final JLabel label; private final JButton button = new TabButton(); private static long zero = System.currentTimeMillis(); - private long startedDragging = 0; + private final long startedDragging = 0; private boolean dragging = false; private DelayTabbedPaneThread probablyABadIdea; - private TabbedPane THIS = this; + private final TabbedPane THIS = this; public String tabName; public String fileContainerName; @@ -149,10 +154,21 @@ public class TabbedPane extends JPanel { } } - @Override public void mouseEntered(MouseEvent arg0) { } - @Override public void mouseExited(MouseEvent arg0) { } - @Override public void mousePressed(MouseEvent arg0) { } - @Override public void mouseReleased(MouseEvent e) { } + @Override + public void mouseEntered(MouseEvent arg0) { + } + + @Override + public void mouseExited(MouseEvent arg0) { + } + + @Override + public void mousePressed(MouseEvent arg0) { + } + + @Override + public void mouseReleased(MouseEvent e) { + } }); /*this.addMouseListener(new MouseListener() { @Override public void mouseClicked(MouseEvent e) {} @@ -194,46 +210,37 @@ public class TabbedPane extends JPanel { });*/ } - private void stopDragging(int mouseX, int mouseY) - { - if(System.currentTimeMillis()-startedDragging >= 210) - { + private void stopDragging(int mouseX, int mouseY) { + if (System.currentTimeMillis() - startedDragging >= 210) { Rectangle bounds = new Rectangle(1, 1, mouseX, mouseY); - System.out.println("debug-5: " + mouseX+", " + mouseY); + System.out.println("debug-5: " + mouseX + ", " + mouseY); int totalTabs = BytecodeViewer.viewer.workPane.tabs.getTabCount(); int index = -1; - for(int i = 0; i < totalTabs; i++) - { + for (int i = 0; i < totalTabs; i++) { Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i); - if(c != null && bounds.intersects(c.getBounds())) - { + if (c != null && bounds.intersects(c.getBounds())) { index = i; //replace this tabs position } } - if(index == -1) - { - for (int i = 0; i < totalTabs; i++) - { + if (index == -1) { + for (int i = 0; i < totalTabs; i++) { Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i); //do some check to see if it's past the X or Y - if(c != null) - { + if (c != null) { System.out.println("debug-6: " + c.getBounds()); } } } - if(index != -1) - { + if (index != -1) { BytecodeViewer.viewer.workPane.tabs.remove(this); BytecodeViewer.viewer.workPane.tabs.setTabComponentAt(index, this); } } dragging = false; label.setBackground(BLANK); - if(probablyABadIdea != null) - { + if (probablyABadIdea != null) { probablyABadIdea.stopped = true; } label.updateUI(); @@ -276,8 +283,7 @@ public class TabbedPane extends JPanel { // paint the cross @Override - protected void paintComponent(final Graphics g) - { + protected void paintComponent(final Graphics g) { super.paintComponent(g); final Graphics2D g2 = (Graphics2D) g.create(); // shift the image for pressed buttons diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/Viewer.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/Viewer.java index 65dad216..b219cc36 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/Viewer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/Viewer.java @@ -1,7 +1,6 @@ package the.bytecode.club.bytecodeviewer.gui; import javax.swing.JPanel; - import org.objectweb.asm.tree.ClassNode; import the.bytecode.club.bytecodeviewer.util.FileContainer; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/VisibleComponent.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/VisibleComponent.java index 883f525d..ed44fe39 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/VisibleComponent.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/VisibleComponent.java @@ -1,9 +1,7 @@ package the.bytecode.club.bytecodeviewer.gui; import javax.swing.JInternalFrame; - import org.objectweb.asm.tree.ClassNode; - import the.bytecode.club.bytecodeviewer.util.FileChangeNotifier; import the.bytecode.club.bytecodeviewer.util.FileContainer; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/WorkPane.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/WorkPane.java index 1c5b94ed..31dd3244 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/WorkPane.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/WorkPane.java @@ -1,15 +1,25 @@ package the.bytecode.club.bytecodeviewer.gui; -import java.awt.*; -import java.awt.event.*; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.FlowLayout; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ContainerEvent; +import java.awt.event.ContainerListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; import java.util.HashMap; - -import javax.swing.*; +import javax.swing.JButton; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JTabbedPane; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; - import org.objectweb.asm.tree.ClassNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.util.FileChangeNotifier; import the.bytecode.club.bytecodeviewer.util.FileContainer; @@ -34,293 +44,284 @@ import the.bytecode.club.bytecodeviewer.util.FileContainer; /** * The pane that contains all of the classes as tabs. - * + * * @author Konloch * @author WaterWolf - * */ public class WorkPane extends VisibleComponent implements ActionListener { - private static final long serialVersionUID = 6542337997679487946L; + private static final long serialVersionUID = 6542337997679487946L; - FileChangeNotifier fcn; - public JTabbedPane tabs; + FileChangeNotifier fcn; + public JTabbedPane tabs; - JPanel buttonPanel; - JButton refreshClass; + JPanel buttonPanel; + JButton refreshClass; - HashMap workingOn = new HashMap(); + HashMap workingOn = new HashMap(); - public static int SyntaxFontHeight = 12; + public static int SyntaxFontHeight = 12; - public WorkPane(final FileChangeNotifier fcn) { - super("WorkPanel"); - setTitle("Work Space"); + public WorkPane(final FileChangeNotifier fcn) { + super("WorkPanel"); + setTitle("Work Space"); - this.tabs = new JTabbedPane(); - this.fcn = fcn; + this.tabs = new JTabbedPane(); + this.fcn = fcn; - JPopupMenu pop_up = new JPopupMenu() - { - @Override - public void setVisible(boolean b) { - super.setVisible(b); - } - }; - JMenuItem closealltab = new JMenuItem("Close All But This"); - JMenuItem closetab = new JMenuItem("Close Tab"); - closetab.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { + JPopupMenu pop_up = new JPopupMenu() { + @Override + public void setVisible(boolean b) { + super.setVisible(b); + } + }; + JMenuItem closealltab = new JMenuItem("Close All But This"); + JMenuItem closetab = new JMenuItem("Close Tab"); + closetab.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { /*String name = e.getActionCommand().split(": ")[1]; final int i = pane.indexOfTab(name); if (i != -1) pane.remove(i);*/ - } - }); - closealltab.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - String name = e.getActionCommand().split(": ")[1]; - System.out.println("debug-3: "+name); - boolean removedAll = false; - while (!removedAll) { - int thisID = tabs.indexOfTab(name); - if (tabs.getTabCount() <= 1) { - removedAll = true; - return; - } - if (thisID != 0) - tabs.remove(0); - else - tabs.remove(1); - } - } - }); - tabs.addMouseListener(new MouseListener() { - @Override public void mouseClicked(MouseEvent e) {} - @Override public void mouseEntered(MouseEvent arg0) { - } - @Override public void mouseExited(MouseEvent arg0) { - } - @Override public void mousePressed(MouseEvent e) { - if(e.getButton() == 3) - { - if(BytecodeViewer.BLOCK_TAB_MENU) - return; + } + }); + closealltab.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + String name = e.getActionCommand().split(": ")[1]; + System.out.println("debug-3: " + name); + boolean removedAll = false; + while (!removedAll) { + int thisID = tabs.indexOfTab(name); + if (tabs.getTabCount() <= 1) { + removedAll = true; + return; + } + if (thisID != 0) + tabs.remove(0); + else + tabs.remove(1); + } + } + }); + tabs.addMouseListener(new MouseListener() { + @Override + public void mouseClicked(MouseEvent e) { + } - Rectangle bounds = new Rectangle(1, 1, e.getX(), e.getY()); - Point point = tabs.getMousePosition(); - System.out.println("debug-1: " +point); - for(int i = 0; i < BytecodeViewer.viewer.workPane.tabs.getTabCount(); i++) - { - Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i); - if(c != null && bounds.intersects(c.getBounds())) - { - pop_up.setVisible(true); - closealltab.setText("Close All But This: " + ((TabbedPane)c).tabName); - closetab.setText("Close Tab: " + ((TabbedPane)c).tabName); - //do something with this shit - //BytecodeViewer.viewer.workPane.tabs.setSelectedIndex(i); - } - else - { - pop_up.setVisible(false); - } - } + @Override + public void mouseEntered(MouseEvent arg0) { + } - System.out.println("debug-2: " +e.getX()+", "+e.getY()); - } - } - @Override public void mouseReleased(MouseEvent e) { - } - }); + @Override + public void mouseExited(MouseEvent arg0) { + } - pop_up.add(closealltab); - pop_up.add(closetab); + @Override + public void mousePressed(MouseEvent e) { + if (e.getButton() == 3) { + if (BytecodeViewer.BLOCK_TAB_MENU) + return; + + Rectangle bounds = new Rectangle(1, 1, e.getX(), e.getY()); + Point point = tabs.getMousePosition(); + System.out.println("debug-1: " + point); + for (int i = 0; i < BytecodeViewer.viewer.workPane.tabs.getTabCount(); i++) { + Component c = BytecodeViewer.viewer.workPane.tabs.getTabComponentAt(i); + if (c != null && bounds.intersects(c.getBounds())) { + pop_up.setVisible(true); + closealltab.setText("Close All But This: " + ((TabbedPane) c).tabName); + closetab.setText("Close Tab: " + ((TabbedPane) c).tabName); + //do something with this shit + //BytecodeViewer.viewer.workPane.tabs.setSelectedIndex(i); + } else { + pop_up.setVisible(false); + } + } + + System.out.println("debug-2: " + e.getX() + ", " + e.getY()); + } + } + + @Override + public void mouseReleased(MouseEvent e) { + } + }); + + pop_up.add(closealltab); + pop_up.add(closetab); - if(!BytecodeViewer.BLOCK_TAB_MENU) - tabs.setComponentPopupMenu(pop_up); + if (!BytecodeViewer.BLOCK_TAB_MENU) + tabs.setComponentPopupMenu(pop_up); - getContentPane().setLayout(new BorderLayout()); + getContentPane().setLayout(new BorderLayout()); - getContentPane().add(tabs, BorderLayout.CENTER); + getContentPane().add(tabs, BorderLayout.CENTER); - buttonPanel = new JPanel(new FlowLayout()); + buttonPanel = new JPanel(new FlowLayout()); - refreshClass = new JButton("Refresh"); - refreshClass.addActionListener(this); + refreshClass = new JButton("Refresh"); + refreshClass.addActionListener(this); - buttonPanel.add(refreshClass); + buttonPanel.add(refreshClass); - buttonPanel.setVisible(false); - getContentPane().add(buttonPanel, BorderLayout.SOUTH); + buttonPanel.setVisible(false); + getContentPane().add(buttonPanel, BorderLayout.SOUTH); - tabs.addContainerListener(new ContainerListener() { + tabs.addContainerListener(new ContainerListener() { - @Override - public void componentAdded(final ContainerEvent e) { - } + @Override + public void componentAdded(final ContainerEvent e) { + } - @Override - public void componentRemoved(final ContainerEvent e) { - final Component c = e.getChild(); - if (c instanceof ClassViewer) { - String containerName = ((ClassViewer) c).container.name+">"; - String fileName = ((ClassViewer) c).name; + @Override + public void componentRemoved(final ContainerEvent e) { + final Component c = e.getChild(); + if (c instanceof ClassViewer) { + String containerName = ((ClassViewer) c).container.name + ">"; + String fileName = ((ClassViewer) c).name; - if(fileName.startsWith(containerName)) - { - workingOn.remove(fileName); - } - else - { - workingOn.remove(containerName+fileName); - } - } - if (c instanceof FileViewer) - { - String containerName = ((FileViewer) c).container.name+">"; - String fileName = ((FileViewer) c).name; + if (fileName.startsWith(containerName)) { + workingOn.remove(fileName); + } else { + workingOn.remove(containerName + fileName); + } + } + if (c instanceof FileViewer) { + String containerName = ((FileViewer) c).container.name + ">"; + String fileName = ((FileViewer) c).name; - if(fileName.startsWith(containerName)) - { - workingOn.remove(fileName); - } - else - { - workingOn.remove(containerName+fileName); - } - } - } + if (fileName.startsWith(containerName)) { + workingOn.remove(fileName); + } else { + workingOn.remove(containerName + fileName); + } + } + } - }); - tabs.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(final ChangeEvent arg0) { - buttonPanel.setVisible(tabs.getSelectedIndex() != -1); - } - }); + }); + tabs.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(final ChangeEvent arg0) { + buttonPanel.setVisible(tabs.getSelectedIndex() != -1); + } + }); - this.setVisible(true); + this.setVisible(true); - } + } - int tabCount = 0; + int tabCount = 0; - public void addWorkingFile(final FileContainer container, String name, final ClassNode cn) { - String workingName = container.name+">"+name; - String containerName = name; + public void addWorkingFile(final FileContainer container, String name, final ClassNode cn) { + String workingName = container.name + ">" + name; + String containerName = name; - if(BytecodeViewer.displayParentInTab) - containerName = container.name+">"+name; + if (BytecodeViewer.displayParentInTab) + containerName = container.name + ">" + name; - if (!workingOn.containsKey(workingName)) { - final JPanel tabComp = new ClassViewer(container, containerName, cn); - tabs.add(tabComp); - final int tabCount = tabs.indexOfComponent(tabComp); - workingOn.put(workingName, tabCount); - TabbedPane tabbedPane = new TabbedPane(container.name, name,tabs); - ((ClassViewer) tabComp).tabbedPane = tabbedPane; - tabs.setTabComponentAt(tabCount, tabbedPane); - tabs.setSelectedIndex(tabCount); - } else { - tabs.setSelectedIndex(workingOn.get(workingName)); - } - } - - public void addFile(final FileContainer container, String name, byte[] contents) { - String workingName = container.name+">"+name; + if (!workingOn.containsKey(workingName)) { + final JPanel tabComp = new ClassViewer(container, containerName, cn); + tabs.add(tabComp); + final int tabCount = tabs.indexOfComponent(tabComp); + workingOn.put(workingName, tabCount); + TabbedPane tabbedPane = new TabbedPane(container.name, name, tabs); + ((ClassViewer) tabComp).tabbedPane = tabbedPane; + tabs.setTabComponentAt(tabCount, tabbedPane); + tabs.setSelectedIndex(tabCount); + } else { + tabs.setSelectedIndex(workingOn.get(workingName)); + } + } - if(BytecodeViewer.displayParentInTab) - name = container.name+">"+name; + public void addFile(final FileContainer container, String name, byte[] contents) { + String workingName = container.name + ">" + name; - if(contents == null) //a directory - return; - - if (!workingOn.containsKey(workingName)) { - final Component tabComp = new FileViewer(container, name, contents); - tabs.add(tabComp); - final int tabCount = tabs.indexOfComponent(tabComp); - workingOn.put(workingName, tabCount); + if (BytecodeViewer.displayParentInTab) + name = container.name + ">" + name; - TabbedPane tabbedPane = new TabbedPane(null, name,tabs); - ((FileViewer) tabComp).tabbedPane = tabbedPane; - tabs.setTabComponentAt(tabCount, tabbedPane); - tabs.setSelectedIndex(tabCount); - } else { - try - { - tabs.setSelectedIndex(workingOn.get(workingName)); - } - catch(java.lang.IndexOutOfBoundsException e) - { - //workingOn.remove(workingName); - e.printStackTrace(); - } - catch(Exception e) - { - e.printStackTrace(); - } - } - } + if (contents == null) //a directory + return; - @Override - public void openClassFile(final FileContainer container, final String name, final ClassNode cn) { - addWorkingFile(container, name, cn); - } + if (!workingOn.containsKey(workingName)) { + final Component tabComp = new FileViewer(container, name, contents); + tabs.add(tabComp); + final int tabCount = tabs.indexOfComponent(tabComp); + workingOn.put(workingName, tabCount); - @Override - public void openFile(final FileContainer container, final String name, byte[] content) { - addFile(container, name, content); - } + TabbedPane tabbedPane = new TabbedPane(null, name, tabs); + ((FileViewer) tabComp).tabbedPane = tabbedPane; + tabs.setTabComponentAt(tabCount, tabbedPane); + tabs.setSelectedIndex(tabCount); + } else { + try { + tabs.setSelectedIndex(workingOn.get(workingName)); + } catch (java.lang.IndexOutOfBoundsException e) { + //workingOn.remove(workingName); + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } - public Viewer getCurrentViewer() { - return (Viewer) tabs.getSelectedComponent(); - } + @Override + public void openClassFile(final FileContainer container, final String name, final ClassNode cn) { + addWorkingFile(container, name, cn); + } - public java.awt.Component[] getLoadedViewers() { - return (java.awt.Component[])tabs.getComponents(); - } - - @Override - public void actionPerformed(final ActionEvent arg0) { - Thread t = new Thread() { - public void run() { - if(BytecodeViewer.viewer.autoCompileOnRefresh.isSelected()) - try { - if(!BytecodeViewer.compile(false)) - return; - } catch(java.lang.NullPointerException e) { - - } - final JButton src = (JButton) arg0.getSource(); - if (src == refreshClass) { - final Component tabComp = tabs.getSelectedComponent(); - if (tabComp != null) { - if(tabComp instanceof ClassViewer) { - src.setEnabled(false); - BytecodeViewer.viewer.setIcon(true); - ((ClassViewer) tabComp).startPaneUpdater(src); - BytecodeViewer.viewer.setIcon(false); - } else if(tabComp instanceof FileViewer) { - src.setEnabled(false); - BytecodeViewer.viewer.setIcon(true); - ((FileViewer) tabComp).refresh(src); - BytecodeViewer.viewer.setIcon(false); - } - } - } - } - }; - t.start(); - } + @Override + public void openFile(final FileContainer container, final String name, byte[] content) { + addFile(container, name, content); + } - public void resetWorkspace() { - tabs.removeAll(); - tabs.updateUI(); - } + public Viewer getCurrentViewer() { + return (Viewer) tabs.getSelectedComponent(); + } + + public java.awt.Component[] getLoadedViewers() { + return tabs.getComponents(); + } + + @Override + public void actionPerformed(final ActionEvent arg0) { + Thread t = new Thread() { + public void run() { + if (BytecodeViewer.viewer.autoCompileOnRefresh.isSelected()) + try { + if (!BytecodeViewer.compile(false)) + return; + } catch (java.lang.NullPointerException e) { + + } + final JButton src = (JButton) arg0.getSource(); + if (src == refreshClass) { + final Component tabComp = tabs.getSelectedComponent(); + if (tabComp != null) { + if (tabComp instanceof ClassViewer) { + src.setEnabled(false); + BytecodeViewer.viewer.setIcon(true); + ((ClassViewer) tabComp).startPaneUpdater(src); + BytecodeViewer.viewer.setIcon(false); + } else if (tabComp instanceof FileViewer) { + src.setEnabled(false); + BytecodeViewer.viewer.setIcon(true); + ((FileViewer) tabComp).refresh(src); + BytecodeViewer.viewer.setIcon(false); + } + } + } + } + }; + t.start(); + } + + public void resetWorkspace() { + tabs.removeAll(); + tabs.updateUI(); + } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/JavaObfuscator.java b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/JavaObfuscator.java index c9337dbf..892b710c 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/JavaObfuscator.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/JavaObfuscator.java @@ -1,7 +1,6 @@ package the.bytecode.club.bytecodeviewer.obfuscators; import java.util.ArrayList; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.util.MiscUtils; @@ -53,7 +52,7 @@ public abstract class JavaObfuscator extends Thread { public static int MAX_STRING_LENGTH = 25; public static int MIN_STRING_LENGTH = 5; - private ArrayList names = new ArrayList(); + private final ArrayList names = new ArrayList(); protected String generateUniqueName(int length) { boolean found = false; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/RenameClasses.java b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/RenameClasses.java index 12987bbd..a0b94527 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/RenameClasses.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/RenameClasses.java @@ -1,7 +1,6 @@ package the.bytecode.club.bytecodeviewer.obfuscators; import org.objectweb.asm.tree.ClassNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.api.ASMUtil_OLD; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/RenameFields.java b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/RenameFields.java index a610aef7..69399bda 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/RenameFields.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/RenameFields.java @@ -2,7 +2,6 @@ package the.bytecode.club.bytecodeviewer.obfuscators; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.api.ASMUtil_OLD; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/RenameMethods.java b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/RenameMethods.java index e5b71601..fd0d59e5 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/RenameMethods.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/RenameMethods.java @@ -3,7 +3,6 @@ package the.bytecode.club.bytecodeviewer.obfuscators; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.api.ASMUtil_OLD; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/HookMap.java b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/HookMap.java index a45b400b..8ed11123 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/HookMap.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/HookMap.java @@ -2,7 +2,6 @@ package the.bytecode.club.bytecodeviewer.obfuscators.mapping; import java.util.ArrayList; import java.util.List; - import the.bytecode.club.bytecodeviewer.obfuscators.mapping.data.FieldMappingData; import the.bytecode.club.bytecodeviewer.obfuscators.mapping.data.MappingData; import the.bytecode.club.bytecodeviewer.obfuscators.mapping.data.MethodMappingData; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/RefactorMapper.java b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/RefactorMapper.java index 8eb15356..38bb3a3a 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/RefactorMapper.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/RefactorMapper.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - import the.bytecode.club.bytecodeviewer.obfuscators.mapping.data.FieldMappingData; import the.bytecode.club.bytecodeviewer.obfuscators.mapping.data.MappingData; import the.bytecode.club.bytecodeviewer.obfuscators.mapping.data.MethodMappingData; @@ -37,7 +36,7 @@ public class RefactorMapper extends Remapper { protected final Map sortedFields; protected final List mappingList; - private StringBuilder builder; + private final StringBuilder builder; public RefactorMapper(HookMap hookMap) { sortedClasses = new HashMap<>(); @@ -70,7 +69,7 @@ public class RefactorMapper extends Remapper { @Override public String map(String type) { if (sortedClasses.containsKey(type)) { - String map = new String(type + " --> " + sortedClasses.get(type).getRefactoredName() + "\n"); + String map = type + " --> " + sortedClasses.get(type).getRefactoredName() + "\n"; if (!mappingList.contains(map)) mappingList.add(map); @@ -83,7 +82,8 @@ public class RefactorMapper extends Remapper { public String mapFieldName(String owner, String name, String desc) { String obfKey = owner + "$$$$" + name + "$$$$" + desc; if (sortedFields.containsKey(obfKey)) { - String map = new String(owner + "." + name + " --> " + owner + sortedFields.get(obfKey).getName().getRefactoredName() + "\n"); + String map = + owner + "." + name + " --> " + owner + sortedFields.get(obfKey).getName().getRefactoredName() + "\n"; if (!mappingList.contains(map)) mappingList.add(map); name = sortedFields.get(obfKey).getName().getRefactoredName(); @@ -95,7 +95,8 @@ public class RefactorMapper extends Remapper { public String mapMethodName(String owner, String name, String desc) { String obfKey = owner + "$$$$" + name + "$$$$" + desc; if (sortedMethods.containsKey(obfKey)) { - String map = new String(owner + "." + name + " --> " + owner + sortedMethods.get(obfKey).getMethodName().getRefactoredName() + "\n"); + String map = + owner + "." + name + " --> " + owner + sortedMethods.get(obfKey).getMethodName().getRefactoredName() + "\n"; if (!mappingList.contains(map)) mappingList.add(map); name = sortedMethods.get(obfKey).getMethodName().getRefactoredName(); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/Refactorer.java b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/Refactorer.java index 53923843..726614f0 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/Refactorer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/Refactorer.java @@ -2,11 +2,9 @@ package the.bytecode.club.bytecodeviewer.obfuscators.mapping; import java.util.HashMap; import java.util.Map; - import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.tree.ClassNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; /*************************************************************************** @@ -52,7 +50,7 @@ public class Refactorer { String oldName = cn.name; ClassReader cr = new ClassReader(getClassNodeBytes(cn)); ClassWriter cw = new ClassWriter(cr, 0); - RemappingClassAdapter rca = new RemappingClassAdapter(cw, (RefactorMapper) mapper); + RemappingClassAdapter rca = new RemappingClassAdapter(cw, mapper); cr.accept(rca, ClassReader.EXPAND_FRAMES); cr = new ClassReader(cw.toByteArray()); cn = new ClassNode(); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/Remapper.java b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/Remapper.java index a509d98c..eb5f05a5 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/Remapper.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/Remapper.java @@ -48,40 +48,39 @@ import org.objectweb.asm.signature.SignatureWriter; * * @author Eugene Kuleshov */ -public abstract class Remapper extends org.objectweb.asm.commons.Remapper -{ +public abstract class Remapper extends org.objectweb.asm.commons.Remapper { public String mapDesc(String desc) { Type t = Type.getType(desc); switch (t.getSort()) { - case Type.ARRAY: - String s = mapDesc(t.getElementType().getDescriptor()); - for (int i = 0; i < t.getDimensions(); ++i) { - s = '[' + s; - } - return s; - case Type.OBJECT: - String newType = map(t.getInternalName()); - if (newType != null) { - return 'L' + newType + ';'; - } + case Type.ARRAY: + String s = mapDesc(t.getElementType().getDescriptor()); + for (int i = 0; i < t.getDimensions(); ++i) { + s = '[' + s; + } + return s; + case Type.OBJECT: + String newType = map(t.getInternalName()); + if (newType != null) { + return 'L' + newType + ';'; + } } return desc; } private Type mapType(Type t) { switch (t.getSort()) { - case Type.ARRAY: - String s = mapDesc(t.getElementType().getDescriptor()); - for (int i = 0; i < t.getDimensions(); ++i) { - s = '[' + s; - } - return Type.getType(s); - case Type.OBJECT: - s = map(t.getInternalName()); - return s != null ? Type.getObjectType(s) : t; - case Type.METHOD: - return Type.getMethodType(mapMethodDesc(t.getDescriptor())); + case Type.ARRAY: + String s = mapDesc(t.getElementType().getDescriptor()); + for (int i = 0; i < t.getDimensions(); ++i) { + s = '[' + s; + } + return Type.getType(s); + case Type.OBJECT: + s = map(t.getInternalName()); + return s != null ? Type.getObjectType(s) : t; + case Type.METHOD: + return Type.getMethodType(mapMethodDesc(t.getDescriptor())); } return t; } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/data/FieldMappingData.java b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/data/FieldMappingData.java index a93d869d..e658ac45 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/data/FieldMappingData.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/data/FieldMappingData.java @@ -91,10 +91,7 @@ public class FieldMappingData { } else if (!fieldOwner.equals(other.fieldOwner)) return false; if (name == null) { - if (other.name != null) - return false; - } else if (!name.equals(other.name)) - return false; - return true; + return other.name == null; + } else return name.equals(other.name); } } \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/data/MappingData.java b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/data/MappingData.java index d747dfec..0108047f 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/data/MappingData.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/data/MappingData.java @@ -74,10 +74,7 @@ public class MappingData { } else if (!obfuscatedName.equals(other.obfuscatedName)) return false; if (refactoredName == null) { - if (other.refactoredName != null) - return false; - } else if (!refactoredName.equals(other.refactoredName)) - return false; - return true; + return other.refactoredName == null; + } else return refactoredName.equals(other.refactoredName); } } \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/data/MethodMappingData.java b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/data/MethodMappingData.java index a9e15037..db30fffc 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/data/MethodMappingData.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/mapping/data/MethodMappingData.java @@ -91,10 +91,7 @@ public class MethodMappingData { } else if (!methodName.equals(other.methodName)) return false; if (methodOwner == null) { - if (other.methodOwner != null) - return false; - } else if (!methodOwner.equals(other.methodOwner)) - return false; - return true; + return other.methodOwner == null; + } else return methodOwner.equals(other.methodOwner); } } \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/rename/RenameClasses.java b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/rename/RenameClasses.java index a544f8d0..1c8e1fe3 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/rename/RenameClasses.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/rename/RenameClasses.java @@ -3,7 +3,6 @@ package the.bytecode.club.bytecodeviewer.obfuscators.rename; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.obfuscators.JavaObfuscator; import the.bytecode.club.bytecodeviewer.obfuscators.mapping.data.MappingData; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/rename/RenameFields.java b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/rename/RenameFields.java index 5e08c45e..270f45b7 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/rename/RenameFields.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/rename/RenameFields.java @@ -2,7 +2,6 @@ package the.bytecode.club.bytecodeviewer.obfuscators.rename; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.obfuscators.JavaObfuscator; import the.bytecode.club.bytecodeviewer.obfuscators.mapping.data.FieldMappingData; @@ -45,7 +44,8 @@ public class RenameFields extends JavaObfuscator { String newName = generateUniqueName(stringLength); - BytecodeViewer.refactorer.getHooks().addField(new FieldMappingData(c.name, new MappingData(f.name, newName), f.desc)); + BytecodeViewer.refactorer.getHooks().addField(new FieldMappingData(c.name, new MappingData(f.name, + newName), f.desc)); /*ASMUtil_OLD.renameFieldNode(c.name, f.name, f.desc, null, newName, null); f.name = newName;*/ diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/rename/RenameMethods.java b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/rename/RenameMethods.java index fa1f4901..e77d7dcf 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/rename/RenameMethods.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/obfuscators/rename/RenameMethods.java @@ -3,7 +3,6 @@ package the.bytecode.club.bytecodeviewer.obfuscators.rename; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.obfuscators.JavaObfuscator; import the.bytecode.club.bytecodeviewer.obfuscators.mapping.data.MappingData; @@ -68,7 +67,8 @@ public class RenameMethods extends JavaObfuscator { && !m.name.equals("")) { String newName = generateUniqueName(stringLength); - BytecodeViewer.refactorer.getHooks().addMethod(new MethodMappingData(c.name, new MappingData(m.name, newName), m.desc)); + BytecodeViewer.refactorer.getHooks().addMethod(new MethodMappingData(c.name, + new MappingData(m.name, newName), m.desc)); /*ASMUtil_OLD.renameMethodNode(c.name, m.name, m.desc, null, newName, null);*/ diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/PluginLaunchStrategy.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/PluginLaunchStrategy.java index 3e1b729b..ed648c7c 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/PluginLaunchStrategy.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/PluginLaunchStrategy.java @@ -1,7 +1,6 @@ package the.bytecode.club.bytecodeviewer.plugin; import java.io.File; - import the.bytecode.club.bytecodeviewer.api.Plugin; /*************************************************************************** @@ -26,7 +25,7 @@ import the.bytecode.club.bytecodeviewer.api.Plugin; * @author Bibl (don't ban me pls) * @created 1 Jun 2015 */ -public abstract interface PluginLaunchStrategy { +public interface PluginLaunchStrategy { - public abstract Plugin run(File file) throws Throwable; + Plugin run(File file) throws Throwable; } \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/PluginManager.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/PluginManager.java index 65e0bb5e..281744ba 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/PluginManager.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/PluginManager.java @@ -4,17 +4,15 @@ import java.io.File; import java.util.HashMap; import java.util.Map; import java.util.Set; - import javax.swing.filechooser.FileFilter; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.util.MiscUtils; import the.bytecode.club.bytecodeviewer.api.Plugin; import the.bytecode.club.bytecodeviewer.plugin.strategies.CompiledJavaPluginLaunchStrategy; import the.bytecode.club.bytecodeviewer.plugin.strategies.GroovyPluginLaunchStrategy; import the.bytecode.club.bytecodeviewer.plugin.strategies.JavaPluginLaunchStrategy; import the.bytecode.club.bytecodeviewer.plugin.strategies.PythonPluginLaunchStrategy; import the.bytecode.club.bytecodeviewer.plugin.strategies.RubyPluginLaunchStrategy; +import the.bytecode.club.bytecodeviewer.util.MiscUtils; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -45,7 +43,8 @@ import the.bytecode.club.bytecodeviewer.plugin.strategies.RubyPluginLaunchStrate */ public final class PluginManager { - private static final Map launchStrategies = new HashMap(); + private static final Map launchStrategies = new HashMap(); private static final PluginFileFilter filter = new PluginFileFilter(); private static Plugin pluginInstance; @@ -76,7 +75,8 @@ public final class PluginManager { pluginInstance = newPluginInstance; pluginInstance.start(); // start the thread } else if (!pluginInstance.isFinished()) { - BytecodeViewer.showMessage("There is currently another plugin running right now, please wait for that to finish executing."); + BytecodeViewer.showMessage("There is currently another plugin running right now, please wait for that to " + + "finish executing."); } } @@ -91,7 +91,8 @@ public final class PluginManager { PluginLaunchStrategy strategy = launchStrategies.get(ext); if (strategy == null) { - throw new RuntimeException(String.format("No launch strategy for extension %s (%s)", ext, f.getAbsolutePath())); + throw new RuntimeException(String.format("No launch strategy for extension %s (%s)", ext, + f.getAbsolutePath())); } Plugin p = strategy.run(f); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/AllatoriStringDecrypter.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/AllatoriStringDecrypter.java index 95f5b782..fe984741 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/AllatoriStringDecrypter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/AllatoriStringDecrypter.java @@ -1,9 +1,7 @@ package the.bytecode.club.bytecodeviewer.plugin.preinstalled; import java.util.ArrayList; - import org.objectweb.asm.tree.ClassNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.api.Plugin; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/CodeSequenceDiagram.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/CodeSequenceDiagram.java index 7755ee6c..6a425661 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/CodeSequenceDiagram.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/CodeSequenceDiagram.java @@ -1,21 +1,17 @@ package the.bytecode.club.bytecodeviewer.plugin.preinstalled; +import com.mxgraph.swing.mxGraphComponent; +import com.mxgraph.view.mxGraph; import java.awt.Font; import java.awt.font.FontRenderContext; import java.awt.geom.AffineTransform; import java.util.ArrayList; - import javax.swing.JFrame; import javax.swing.UIManager; - import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; - -import com.mxgraph.swing.mxGraphComponent; -import com.mxgraph.view.mxGraph; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.Resources; import the.bytecode.club.bytecodeviewer.api.Plugin; @@ -87,16 +83,18 @@ public class CodeSequenceDiagram extends Plugin { int testY = 0; double magicNumber = 5.8; - for (MethodNode m : (ArrayList) c.methods) { + for (MethodNode m : c.methods) { String mIdentifier = c.name + "." + m.name + m.desc; - Object node = graph.insertVertex(parent, null, mIdentifier, testX, testY, mIdentifier.length() * magicNumber, 30); + Object node = graph.insertVertex(parent, null, mIdentifier, testX, testY, + mIdentifier.length() * magicNumber, 30); Object attach = node; testX += (int) (font.getStringBounds(mIdentifier, frc).getWidth()) + 60; for (AbstractInsnNode i : m.instructions.toArray()) { if (i instanceof MethodInsnNode) { MethodInsnNode mi = (MethodInsnNode) i; String identifier = mi.owner + "." + mi.name + mi.desc; - Object node2 = graph.insertVertex(parent, null, identifier, testX, testY, identifier.length() * 5, 30); + Object node2 = graph.insertVertex(parent, null, identifier, testX, testY, + identifier.length() * 5, 30); testX += (int) (font.getStringBounds(identifier, frc).getWidth()) + 60; graph.insertEdge(parent, null, null, attach, node2); attach = node2; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/EZInjection.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/EZInjection.java index 02cc4b37..9efe5c87 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/EZInjection.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/EZInjection.java @@ -4,14 +4,12 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.Method; import java.util.ArrayList; - import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.api.BytecodeHook; import the.bytecode.club.bytecodeviewer.api.Plugin; @@ -49,13 +47,18 @@ import the.bytecode.club.bytecodeviewer.gui.GraphicialReflectionKit; public class EZInjection extends Plugin { public static ArrayList hookArray = new ArrayList(); - private static String version = "1.0"; - private static PluginConsole gui = new PluginConsole("EZ Injection v" + version); - private boolean accessModifiers, injectHooks, invokeMethod, useProxy, - launchKit, console; + private static final String version = "1.0"; + private static final PluginConsole gui = new PluginConsole("EZ Injection v" + version); + private final boolean accessModifiers; + private final boolean injectHooks; + private final boolean invokeMethod; + private final boolean useProxy; + private final boolean launchKit; + private final boolean console; public static boolean sandboxSystem, sandboxRuntime, printCmdL; private static boolean debugHooks, all = false; - private String invokeMethodInformation, proxy; + private final String invokeMethodInformation; + private final String proxy; private static String[] debugClasses; @@ -231,7 +234,8 @@ public class EZInjection extends Plugin { MethodInsnNode mn = (MethodInsnNode) m.instructions .get(1); if (mn.owner - .equals(EZInjection.class.getName().replace(".", "/")))//"the/bytecode/club/bytecodeviewer/plugins/EZInjection")) // already been injected + .equals(EZInjection.class.getName().replace(".", "/")))//"the/bytecode/club + // /bytecodeviewer/plugins/EZInjection")) // already been injected inject = false; } if (inject) { @@ -239,7 +243,8 @@ public class EZInjection extends Plugin { m.instructions .insert(new MethodInsnNode( Opcodes.INVOKESTATIC, - EZInjection.class.getName().replace(".", "/"),//"the/bytecode/club/bytecodeviewer/plugins/EZInjection", + EZInjection.class.getName().replace(".", "/"),//"the/bytecode/club + // /bytecodeviewer/plugins/EZInjection", "hook", "(Ljava/lang/String;)V")); m.instructions.insert(new LdcInsnNode(classNode.name + "." + m.name + m.desc)); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/MaliciousCodeScanner.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/MaliciousCodeScanner.java index 76cebb99..eddf8546 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/MaliciousCodeScanner.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/MaliciousCodeScanner.java @@ -1,7 +1,6 @@ package the.bytecode.club.bytecodeviewer.plugin.preinstalled; import java.util.ArrayList; - import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; @@ -11,7 +10,6 @@ import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.api.Plugin; import the.bytecode.club.bytecodeviewer.api.PluginConsole; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/ReplaceStrings.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/ReplaceStrings.java index d12e248a..06ac4567 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/ReplaceStrings.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/ReplaceStrings.java @@ -1,14 +1,12 @@ package the.bytecode.club.bytecodeviewer.plugin.preinstalled; import java.util.ArrayList; - import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodNode; - import the.bytecode.club.bytecodeviewer.api.Plugin; import the.bytecode.club.bytecodeviewer.api.PluginConsole; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/ShowAllStrings.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/ShowAllStrings.java index dc512e6a..4eaf1164 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/ShowAllStrings.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/ShowAllStrings.java @@ -1,14 +1,12 @@ package the.bytecode.club.bytecodeviewer.plugin.preinstalled; import java.util.ArrayList; - import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.api.Plugin; import the.bytecode.club.bytecodeviewer.api.PluginConsole; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/ShowMainMethods.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/ShowMainMethods.java index 541c7a52..2aa09a58 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/ShowMainMethods.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/ShowMainMethods.java @@ -1,11 +1,9 @@ package the.bytecode.club.bytecodeviewer.plugin.preinstalled; import java.util.ArrayList; - import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; - import the.bytecode.club.bytecodeviewer.api.Plugin; import the.bytecode.club.bytecodeviewer.api.PluginConsole; @@ -34,8 +32,7 @@ import the.bytecode.club.bytecodeviewer.api.PluginConsole; * @author Sh1ftchg */ -public class ShowMainMethods extends Plugin -{ +public class ShowMainMethods extends Plugin { private static final int PUBLIC_STATIC = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC; @Override @@ -46,10 +43,8 @@ public class ShowMainMethods extends Plugin for (Object o : classNode.methods.toArray()) { MethodNode m = (MethodNode) o; - if ((m.access & (PUBLIC_STATIC)) == PUBLIC_STATIC) - { - if (m.name.equals("main") && m.desc.equals("([Ljava/lang/String;)V")) - { + if ((m.access & (PUBLIC_STATIC)) == PUBLIC_STATIC) { + if (m.name.equals("main") && m.desc.equals("([Ljava/lang/String;)V")) { sb.append(classNode.name); sb.append("."); sb.append(m.name); @@ -60,12 +55,9 @@ public class ShowMainMethods extends Plugin } } - if(sb.length() == 0) - { + if (sb.length() == 0) { frame.appendText("No main methods found."); - } - else - { + } else { frame.appendText(sb.toString()); } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/StackFramesRemover.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/StackFramesRemover.java index d123e35f..5b1d1219 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/StackFramesRemover.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/StackFramesRemover.java @@ -1,5 +1,7 @@ package the.bytecode.club.bytecodeviewer.plugin.preinstalled; +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicInteger; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FrameNode; @@ -7,9 +9,6 @@ import org.objectweb.asm.tree.MethodNode; import the.bytecode.club.bytecodeviewer.api.Plugin; import the.bytecode.club.bytecodeviewer.api.PluginConsole; -import java.util.ArrayList; -import java.util.concurrent.atomic.AtomicInteger; - public class StackFramesRemover extends Plugin { @Override diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/ZKMStringDecrypter.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/ZKMStringDecrypter.java index 47bdcb62..05c0113a 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/ZKMStringDecrypter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/ZKMStringDecrypter.java @@ -1,12 +1,10 @@ package the.bytecode.club.bytecodeviewer.plugin.preinstalled; +import java.util.ArrayList; import org.objectweb.asm.tree.ClassNode; - import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.api.Plugin; -import java.util.ArrayList; - /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/ZStringArrayDecrypter.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/ZStringArrayDecrypter.java index 037ba2ad..5a0b61ee 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/ZStringArrayDecrypter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/preinstalled/ZStringArrayDecrypter.java @@ -1,17 +1,14 @@ package the.bytecode.club.bytecodeviewer.plugin.preinstalled; -import org.objectweb.asm.tree.ClassNode; - -import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.api.Plugin; -import the.bytecode.club.bytecodeviewer.api.PluginConsole; - import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; - import javax.swing.JDialog; import javax.swing.JOptionPane; +import org.objectweb.asm.tree.ClassNode; +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.api.Plugin; +import the.bytecode.club.bytecodeviewer.api.PluginConsole; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/CompiledJavaPluginLaunchStrategy.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/CompiledJavaPluginLaunchStrategy.java index 069b15ac..430c5c19 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/CompiledJavaPluginLaunchStrategy.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/CompiledJavaPluginLaunchStrategy.java @@ -8,13 +8,11 @@ import java.util.Map; import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; - import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; - -import the.bytecode.club.bytecodeviewer.util.JarUtils; import the.bytecode.club.bytecodeviewer.api.Plugin; import the.bytecode.club.bytecodeviewer.plugin.PluginLaunchStrategy; +import the.bytecode.club.bytecodeviewer.util.JarUtils; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -84,8 +82,9 @@ public class CompiledJavaPluginLaunchStrategy implements PluginLaunchStrategy { String name = entry.getName(); if (name.endsWith(".class")) { byte[] bytes = JarUtils.getBytes(jis); - String magic = String.format("%02X", bytes[0]) + String.format("%02X", bytes[1]) + String.format("%02X", bytes[2]) + String.format("%02X", bytes[3]); - if (magic.toLowerCase().equals("cafebabe")) { + String magic = String.format("%02X", bytes[0]) + String.format("%02X", bytes[1]) + String.format( + "%02X", bytes[2]) + String.format("%02X", bytes[3]); + if (magic.equalsIgnoreCase("cafebabe")) { try { ClassReader cr = new ClassReader(bytes); ClassNode cn = new ClassNode(); @@ -146,8 +145,8 @@ public class CompiledJavaPluginLaunchStrategy implements PluginLaunchStrategy { public static class LoadingClassLoader extends ClassLoader { private final LoadedNodeData data; - private Map cache; - private Map> ccache; + private final Map cache; + private final Map> ccache; private final Class pluginKlass; public LoadingClassLoader(LoadedNodeData data, Set set) throws Throwable { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/GroovyPluginLaunchStrategy.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/GroovyPluginLaunchStrategy.java index 0bba7967..039b00b7 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/GroovyPluginLaunchStrategy.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/GroovyPluginLaunchStrategy.java @@ -3,10 +3,8 @@ package the.bytecode.club.bytecodeviewer.plugin.strategies; import java.io.File; import java.io.FileReader; import java.io.Reader; - import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; - import the.bytecode.club.bytecodeviewer.api.Plugin; import the.bytecode.club.bytecodeviewer.plugin.PluginLaunchStrategy; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/JavaPluginLaunchStrategy.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/JavaPluginLaunchStrategy.java index 3ede0af7..9dda32bb 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/JavaPluginLaunchStrategy.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/JavaPluginLaunchStrategy.java @@ -1,11 +1,8 @@ package the.bytecode.club.bytecodeviewer.plugin.strategies; import java.io.File; - import me.konloch.kontainer.io.DiskReader; - import org.codehaus.janino.SimpleCompiler; - import the.bytecode.club.bytecodeviewer.api.Plugin; import the.bytecode.club.bytecodeviewer.plugin.PluginLaunchStrategy; @@ -34,15 +31,15 @@ import the.bytecode.club.bytecodeviewer.plugin.PluginLaunchStrategy; */ public class JavaPluginLaunchStrategy implements PluginLaunchStrategy { - private static SimpleCompiler compiler = new SimpleCompiler(); + private static final SimpleCompiler compiler = new SimpleCompiler(); @Override public Plugin run(File file) throws Throwable { compiler.cook(DiskReader.loadAsString(file.getAbsolutePath())); - System.out.println(file.getName().substring(0, (int) (file.getName().length() - (".java".length())))); - Class clazz = (Class) Class.forName( - file.getName().substring(0, (int) file.getName().length() - ".java".length()), + System.out.println(file.getName().substring(0, file.getName().length() - (".java".length()))); + Class clazz = Class.forName( + file.getName().substring(0, file.getName().length() - ".java".length()), true, compiler.getClassLoader() ); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/PythonPluginLaunchStrategy.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/PythonPluginLaunchStrategy.java index c209d949..c71fad55 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/PythonPluginLaunchStrategy.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/PythonPluginLaunchStrategy.java @@ -3,10 +3,8 @@ package the.bytecode.club.bytecodeviewer.plugin.strategies; import java.io.File; import java.io.FileReader; import java.io.Reader; - import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; - import the.bytecode.club.bytecodeviewer.api.Plugin; import the.bytecode.club.bytecodeviewer.plugin.PluginLaunchStrategy; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/RubyPluginLaunchStrategy.java b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/RubyPluginLaunchStrategy.java index 7841046f..8325b4c5 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/RubyPluginLaunchStrategy.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/plugin/strategies/RubyPluginLaunchStrategy.java @@ -3,10 +3,8 @@ package the.bytecode.club.bytecodeviewer.plugin.strategies; import java.io.File; import java.io.FileReader; import java.io.Reader; - import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; - import the.bytecode.club.bytecodeviewer.api.Plugin; import the.bytecode.club.bytecodeviewer.plugin.PluginLaunchStrategy; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/searching/EnterKeyEvent.java b/src/main/java/the/bytecode/club/bytecodeviewer/searching/EnterKeyEvent.java index 5889f723..1653e650 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/searching/EnterKeyEvent.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/searching/EnterKeyEvent.java @@ -1,23 +1,25 @@ package the.bytecode.club.bytecodeviewer.searching; -import the.bytecode.club.bytecodeviewer.BytecodeViewer; - import java.awt.event.KeyEvent; import java.awt.event.KeyListener; +import the.bytecode.club.bytecodeviewer.BytecodeViewer; -public class EnterKeyEvent implements KeyListener -{ +public class EnterKeyEvent implements KeyListener { public static final EnterKeyEvent SINGLETON = new EnterKeyEvent(); - @Override public void keyTyped(KeyEvent e) { } + @Override + public void keyTyped(KeyEvent e) { + } - @Override public void keyPressed(KeyEvent e) { - if(e.getKeyCode() == KeyEvent.VK_ENTER) - { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { BytecodeViewer.viewer.s.search(); } } - @Override public void keyReleased(KeyEvent e) { } + @Override + public void keyReleased(KeyEvent e) { + } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/searching/FieldCallSearch.java b/src/main/java/the/bytecode/club/bytecodeviewer/searching/FieldCallSearch.java index 6bda3c7a..b4df0522 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/searching/FieldCallSearch.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/searching/FieldCallSearch.java @@ -1,21 +1,18 @@ package the.bytecode.club.bytecodeviewer.searching; +import eu.bibl.banalysis.asm.desc.OpcodeInfo; import java.awt.GridLayout; import java.util.Iterator; import java.util.ListIterator; - import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; - import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.MethodNode; - -import eu.bibl.banalysis.asm.desc.OpcodeInfo; import the.bytecode.club.bytecodeviewer.util.FileContainer; /*************************************************************************** @@ -49,8 +46,7 @@ public class FieldCallSearch implements SearchTypeDetails { JPanel myPanel = null; - public FieldCallSearch() - { + public FieldCallSearch() { mOwner = new JTextField(""); mOwner.addKeyListener(EnterKeyEvent.SINGLETON); mName = new JTextField(""); @@ -75,7 +71,8 @@ public class FieldCallSearch implements SearchTypeDetails { } @Override - public void search(final FileContainer container, final ClassNode node, final SearchResultNotifier srn, boolean exact) { + public void search(final FileContainer container, final ClassNode node, final SearchResultNotifier srn, + boolean exact) { final Iterator methods = node.methods.iterator(); String owner = mOwner.getText(); if (owner.isEmpty()) { @@ -119,7 +116,7 @@ public class FieldCallSearch implements SearchTypeDetails { } catch (java.lang.ArrayIndexOutOfBoundsException e) { } - srn.notifyOfResult(container.name+">"+node.name + srn.notifyOfResult(container.name + ">" + node.name + "." + method.name + desc2 @@ -145,7 +142,7 @@ public class FieldCallSearch implements SearchTypeDetails { } catch (java.lang.ArrayIndexOutOfBoundsException e) { } - srn.notifyOfResult(container.name+">"+node.name + srn.notifyOfResult(container.name + ">" + node.name + "." + method.name + desc2 diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/searching/LDCSearch.java b/src/main/java/the/bytecode/club/bytecodeviewer/searching/LDCSearch.java index b2a79b8e..aa420699 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/searching/LDCSearch.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/searching/LDCSearch.java @@ -3,11 +3,9 @@ package the.bytecode.club.bytecodeviewer.searching; import java.awt.GridLayout; import java.util.Iterator; import java.util.ListIterator; - import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; - import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; @@ -47,8 +45,7 @@ public class LDCSearch implements SearchTypeDetails { JTextField searchText = null; JPanel myPanel = null; - public LDCSearch() - { + public LDCSearch() { searchText = new JTextField(""); searchText.addKeyListener(EnterKeyEvent.SINGLETON); } @@ -65,8 +62,8 @@ public class LDCSearch implements SearchTypeDetails { } @Override - public void search(final FileContainer container, final ClassNode node, final SearchResultNotifier srn, boolean exact) - { + public void search(final FileContainer container, final ClassNode node, final SearchResultNotifier srn, + boolean exact) { final Iterator methods = node.methods.iterator(); final String srchText = searchText.getText(); if (srchText.isEmpty()) @@ -91,9 +88,8 @@ public class LDCSearch implements SearchTypeDetails { } - if ((exact && ldcString.equals(srchText)) || (!exact && ldcString.contains(srchText))) - { - srn.notifyOfResult(container.name+">"+node.name + "." + method.name + if ((exact && ldcString.equals(srchText)) || (!exact && ldcString.contains(srchText))) { + srn.notifyOfResult(container.name + ">" + node.name + "." + method.name + desc2 + " -> \"" + ldcString + "\" > " + ldcObject.cst.getClass().getCanonicalName()); @@ -113,7 +109,7 @@ public class LDCSearch implements SearchTypeDetails { } if (field.value instanceof String) { - srn.notifyOfResult(container.name+">"+node.name + "." + field.name + desc2 + srn.notifyOfResult(container.name + ">" + node.name + "." + field.name + desc2 + " -> \"" + field.value + "\" > field"); } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/searching/MethodCallSearch.java b/src/main/java/the/bytecode/club/bytecodeviewer/searching/MethodCallSearch.java index bd2a00d9..5dc209e1 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/searching/MethodCallSearch.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/searching/MethodCallSearch.java @@ -1,21 +1,18 @@ package the.bytecode.club.bytecodeviewer.searching; +import eu.bibl.banalysis.asm.desc.OpcodeInfo; import java.awt.GridLayout; import java.util.Iterator; import java.util.ListIterator; - import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; - import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; - -import eu.bibl.banalysis.asm.desc.OpcodeInfo; import the.bytecode.club.bytecodeviewer.util.FileContainer; /*************************************************************************** @@ -48,8 +45,7 @@ public class MethodCallSearch implements SearchTypeDetails { JTextField mOwner = new JTextField(""), mName = new JTextField(""), mDesc = new JTextField(""); JPanel myPanel = null; - public MethodCallSearch() - { + public MethodCallSearch() { mOwner = new JTextField(""); mOwner.addKeyListener(EnterKeyEvent.SINGLETON); mName = new JTextField(""); @@ -74,7 +70,8 @@ public class MethodCallSearch implements SearchTypeDetails { } @Override - public void search(final FileContainer container, final ClassNode node, final SearchResultNotifier srn, boolean exact) { + public void search(final FileContainer container, final ClassNode node, final SearchResultNotifier srn, + boolean exact) { final Iterator methods = node.methods.iterator(); String owner = mOwner.getText(); if (owner.isEmpty()) { @@ -119,7 +116,7 @@ public class MethodCallSearch implements SearchTypeDetails { } catch (java.lang.ArrayIndexOutOfBoundsException e) { } - srn.notifyOfResult(container.name+">"+node.name + srn.notifyOfResult(container.name + ">" + node.name + "." + method.name + desc2 @@ -144,7 +141,7 @@ public class MethodCallSearch implements SearchTypeDetails { } catch (java.lang.ArrayIndexOutOfBoundsException e) { } - srn.notifyOfResult(container.name+">"+node.name + srn.notifyOfResult(container.name + ">" + node.name + "." + method.name + desc2 diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/searching/RegexInsnFinder.java b/src/main/java/the/bytecode/club/bytecodeviewer/searching/RegexInsnFinder.java index 6afa92f8..0dbc4770 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/searching/RegexInsnFinder.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/searching/RegexInsnFinder.java @@ -7,7 +7,6 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; - import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldInsnNode; @@ -48,7 +47,7 @@ import org.objectweb.asm.tree.VarInsnNode; public class RegexInsnFinder { - private static String[] opcodes = new String[]{"NOP", "ACONST_NULL", + private static final String[] opcodes = new String[]{"NOP", "ACONST_NULL", "ICONST_M1", "ICONST_0", "ICONST_1", "ICONST_2", "ICONST_3", "ICONST_4", "ICONST_5", "LCONST_0", "LCONST_1", "FCONST_0", "FCONST_1", "FCONST_2", "DCONST_0", "DCONST_1", "BIPUSH", "SIPUSH", @@ -83,33 +82,33 @@ public class RegexInsnFinder { "INSTANCEOF", "MONITORENTER", "MONITOREXIT", "WIDE", "MULTIANEWARRAY", "IFNULL", "IFNONNULL", "GOTO_W", "JSR_W"}; - private static String[] opcodesVar = new String[]{"ILOAD", "LLOAD", + private static final String[] opcodesVar = new String[]{"ILOAD", "LLOAD", "FLOAD", "DLOAD", "ALOAD", "ISTORE", "LSTORE", "FSTORE", "DSTORE", "ASTORE", "RET"}; - private static String opcodeVars = buildRegexItems(opcodesVar); + private static final String opcodeVars = buildRegexItems(opcodesVar); - private static String[] opcodesInt = new String[]{"BIPUSH", "SIPUSH", + private static final String[] opcodesInt = new String[]{"BIPUSH", "SIPUSH", "NEWARRAY"}; - private static String opcodesInts = buildRegexItems(opcodesInt); + private static final String opcodesInts = buildRegexItems(opcodesInt); - private static String[] opcodesField = new String[]{"GETSTATIC", + private static final String[] opcodesField = new String[]{"GETSTATIC", "PUTSTATIC", "GETFIELD", "PUTFIELD"}; - private static String opcodesFields = buildRegexItems(opcodesField); + private static final String opcodesFields = buildRegexItems(opcodesField); - private static String[] opcodesMethod = new String[]{"INVOKEVIRTUAL", + private static final String[] opcodesMethod = new String[]{"INVOKEVIRTUAL", "INVOKESPECIAL", "INVOKESTATIC", "INVOKEINTERFACE", "INVOKEDYNAMIC"}; - private static String opcodesMethods = buildRegexItems(opcodesMethod); + private static final String opcodesMethods = buildRegexItems(opcodesMethod); - private static String[] opcodesType = new String[]{"NEW", "ANEWARRAY", + private static final String[] opcodesType = new String[]{"NEW", "ANEWARRAY", "ARRAYLENGTH", "CHECKCAST", "INSTANCEOF"}; - private static String opcodesTypes = buildRegexItems(opcodesType); + private static final String opcodesTypes = buildRegexItems(opcodesType); - private static String[] opcodesIf = new String[]{"IFEQ", "IFNE", "IFLT", + private static final String[] opcodesIf = new String[]{"IFEQ", "IFNE", "IFLT", "IFGE", "IFGT", "IFLE", "IF_ICMPEQ", "IF_ICMPNE", "IF_ICMPLT", "IF_ICMPGE", "IF_ICMPGT", "IF_ICMPLE", "IF_ACMPEQ", "IF_ACMPNE"}; - private static String opcodesIfs = buildRegexItems(opcodesIf, false, false); + private static final String opcodesIfs = buildRegexItems(opcodesIf, false, false); - private static String[] opcodesAny = new String[]{"NOP", "ACONST_NULL", + private static final String[] opcodesAny = new String[]{"NOP", "ACONST_NULL", "ICONST_M1", "ICONST_0", "ICONST_1", "ICONST_2", "ICONST_3", "ICONST_4", "ICONST_5", "LCONST_0", "LCONST_1", "FCONST_0", "FCONST_1", "FCONST_2", "DCONST_0", "DCONST_1", "BIPUSH", "SIPUSH", @@ -135,7 +134,7 @@ public class RegexInsnFinder { "INVOKEDYNAMIC", "NEW", "NEWARRAY", "ANEWARRAY", "ARRAYLENGTH", "ATHROW", "CHECKCAST", "INSTANCEOF", "MONITORENTER", "MONITOREXIT", "MULTIANEWARRAY", "IFNULL", "IFNONNULL"}; - private static String opcodesAnys = buildRegexItems(opcodesAny, false, + private static final String opcodesAnys = buildRegexItems(opcodesAny, false, false); private static String buildRegexItems(final String[] items, @@ -282,9 +281,7 @@ public class RegexInsnFinder { } String insnString = getInsString(ain); boolean result = pattern.matcher(insnString).find(); - if(result) { - return true; - } + return result; } return false; }); @@ -293,41 +290,41 @@ public class RegexInsnFinder { private static String getInsString(AbstractInsnNode ain) { String insnString = ""; switch (ain.getType()) { - case AbstractInsnNode.INT_INSN: - final IntInsnNode iin = (IntInsnNode) ain; - insnString += "{" + iin.operand + "}"; - break; - case AbstractInsnNode.LDC_INSN: - final LdcInsnNode lin = (LdcInsnNode) ain; - insnString += "{" + lin.cst.toString().replace("}", "\\}") - + "}"; - break; - case AbstractInsnNode.VAR_INSN: - final VarInsnNode vin = (VarInsnNode) ain; - insnString += "_" + vin.var; - break; - case AbstractInsnNode.IINC_INSN: - final IincInsnNode iiin = (IincInsnNode) ain; - insnString += "{" + iiin.var + "," + iiin.incr + "}"; - break; - case AbstractInsnNode.FIELD_INSN: - final FieldInsnNode fin = (FieldInsnNode) ain; - insnString += "{" + fin.desc + "," + fin.owner + "," - + fin.name + "}"; - break; - case AbstractInsnNode.METHOD_INSN: - final MethodInsnNode min = (MethodInsnNode) ain; - insnString += "{" + min.desc + "," + min.owner + "," - + min.name + "}"; - break; - case AbstractInsnNode.TYPE_INSN: - final TypeInsnNode tin = (TypeInsnNode) ain; - insnString += "{" + tin.desc + "}"; - break; - case AbstractInsnNode.MULTIANEWARRAY_INSN: - final MultiANewArrayInsnNode manain = (MultiANewArrayInsnNode) ain; - insnString += "{" + manain.dims + "," + manain.desc + "}"; - break; + case AbstractInsnNode.INT_INSN: + final IntInsnNode iin = (IntInsnNode) ain; + insnString += "{" + iin.operand + "}"; + break; + case AbstractInsnNode.LDC_INSN: + final LdcInsnNode lin = (LdcInsnNode) ain; + insnString += "{" + lin.cst.toString().replace("}", "\\}") + + "}"; + break; + case AbstractInsnNode.VAR_INSN: + final VarInsnNode vin = (VarInsnNode) ain; + insnString += "_" + vin.var; + break; + case AbstractInsnNode.IINC_INSN: + final IincInsnNode iiin = (IincInsnNode) ain; + insnString += "{" + iiin.var + "," + iiin.incr + "}"; + break; + case AbstractInsnNode.FIELD_INSN: + final FieldInsnNode fin = (FieldInsnNode) ain; + insnString += "{" + fin.desc + "," + fin.owner + "," + + fin.name + "}"; + break; + case AbstractInsnNode.METHOD_INSN: + final MethodInsnNode min = (MethodInsnNode) ain; + insnString += "{" + min.desc + "," + min.owner + "," + + min.name + "}"; + break; + case AbstractInsnNode.TYPE_INSN: + final TypeInsnNode tin = (TypeInsnNode) ain; + insnString += "{" + tin.desc + "}"; + break; + case AbstractInsnNode.MULTIANEWARRAY_INSN: + final MultiANewArrayInsnNode manain = (MultiANewArrayInsnNode) ain; + insnString += "{" + manain.dims + "," + manain.desc + "}"; + break; } return insnString; } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/searching/RegexSearch.java b/src/main/java/the/bytecode/club/bytecodeviewer/searching/RegexSearch.java index aeba614f..4332d821 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/searching/RegexSearch.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/searching/RegexSearch.java @@ -3,11 +3,9 @@ package the.bytecode.club.bytecodeviewer.searching; import java.awt.GridLayout; import java.util.Iterator; import java.util.regex.Pattern; - import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; - import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; @@ -45,8 +43,7 @@ public class RegexSearch implements SearchTypeDetails { public static JTextField searchText; JPanel myPanel = null; - public RegexSearch() - { + public RegexSearch() { searchText = new JTextField(""); searchText.addKeyListener(EnterKeyEvent.SINGLETON); } @@ -54,10 +51,8 @@ public class RegexSearch implements SearchTypeDetails { private static RegexInsnFinder regexFinder; @Override - public JPanel getPanel() - { - if (myPanel == null) - { + public JPanel getPanel() { + if (myPanel == null) { myPanel = new JPanel(new GridLayout(1, 2)); myPanel.add(new JLabel("Search Regex: ")); myPanel.add(searchText); @@ -67,8 +62,8 @@ public class RegexSearch implements SearchTypeDetails { } @Override - public void search(final FileContainer container, final ClassNode node, final SearchResultNotifier srn, boolean exact) - { + public void search(final FileContainer container, final ClassNode node, final SearchResultNotifier srn, + boolean exact) { final Iterator methods = node.methods.iterator(); final String srchText = searchText.getText(); @@ -76,26 +71,21 @@ public class RegexSearch implements SearchTypeDetails { return; Pattern pattern = Pattern.compile(processRegex(srchText), Pattern.MULTILINE); - while (methods.hasNext()) - { + while (methods.hasNext()) { final MethodNode method = methods.next(); - if (RegexInsnFinder.staticScan(node, method, pattern)) - { + if (RegexInsnFinder.staticScan(node, method, pattern)) { String desc2 = method.desc; - try - { + try { desc2 = Type.getType(method.desc).toString(); if (desc2 == null || desc2.equals("null")) desc2 = method.desc; - } - catch (java.lang.ArrayIndexOutOfBoundsException e) - { + } catch (java.lang.ArrayIndexOutOfBoundsException e) { } - srn.notifyOfResult(container.name+">"+node.name + "." + method.name + desc2); + srn.notifyOfResult(container.name + ">" + node.name + "." + method.name + desc2); } } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/searching/SearchResultNotifier.java b/src/main/java/the/bytecode/club/bytecodeviewer/searching/SearchResultNotifier.java index f5af520b..5ecbc5af 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/searching/SearchResultNotifier.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/searching/SearchResultNotifier.java @@ -26,5 +26,5 @@ package the.bytecode.club.bytecodeviewer.searching; */ public interface SearchResultNotifier { - public void notifyOfResult(String debug); + void notifyOfResult(String debug); } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/searching/SearchTypeDetails.java b/src/main/java/the/bytecode/club/bytecodeviewer/searching/SearchTypeDetails.java index 2f65cb55..d6cbc52b 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/searching/SearchTypeDetails.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/searching/SearchTypeDetails.java @@ -1,7 +1,6 @@ package the.bytecode.club.bytecodeviewer.searching; import javax.swing.JPanel; - import org.objectweb.asm.tree.ClassNode; import the.bytecode.club.bytecodeviewer.util.FileContainer; @@ -30,7 +29,7 @@ import the.bytecode.club.bytecodeviewer.util.FileContainer; */ public interface SearchTypeDetails { - public JPanel getPanel(); + JPanel getPanel(); - public void search(FileContainer container, ClassNode node, SearchResultNotifier srn, boolean exact); + void search(FileContainer container, ClassNode node, SearchResultNotifier srn, boolean exact); } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/APKTool.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/APKTool.java index c7528b9a..484c0a92 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/APKTool.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/APKTool.java @@ -1,17 +1,8 @@ package the.bytecode.club.bytecodeviewer.util; -import java.io.*; -import java.nio.file.Files; -import java.util.Map; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; -import java.util.zip.ZipOutputStream; - -import me.konloch.kontainer.io.DiskWriter; +import java.io.File; import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; import the.bytecode.club.bytecodeviewer.BytecodeViewer; -import the.bytecode.club.bytecodeviewer.SecurityMan; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -38,12 +29,14 @@ public class APKTool { public static synchronized void decodeResources(File input, File output, FileContainer container) { try { - File dir = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32)+BytecodeViewer.fs+"Decoded Resources"); + File dir = + new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32) + BytecodeViewer.fs + "Decoded Resources"); dir.mkdirs(); File tempAPKPath = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(12)); tempAPKPath.mkdirs(); - brut.apktool.Main.main(new String[]{"r", "--frame-path", tempAPKPath.getAbsolutePath(), "d", input.getAbsolutePath(), "-o", dir.getAbsolutePath(), "-f"}); + brut.apktool.Main.main(new String[]{"r", "--frame-path", tempAPKPath.getAbsolutePath(), "d", + input.getAbsolutePath(), "-o", dir.getAbsolutePath(), "-f"}); File zip = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(12) + ".zip"); ZipUtils.zipFolderAPKTool(dir.getAbsolutePath(), zip.getAbsolutePath()); @@ -58,32 +51,29 @@ public class APKTool { } } - public static synchronized void buildAPK(File input, File output, FileContainer container) - { + public static synchronized void buildAPK(File input, File output, FileContainer container) { String name = container.file.getName().toLowerCase(); String temp = BytecodeViewer.tempDirectory + BytecodeViewer.fs; - File tempDir = new File(temp+BytecodeViewer.fs+BytecodeViewer.getRandomizedName()+BytecodeViewer.fs); + File tempDir = new File(temp + BytecodeViewer.fs + BytecodeViewer.getRandomizedName() + BytecodeViewer.fs); tempDir.mkdirs(); File tempAPKPath = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(12)); tempAPKPath.mkdirs(); - try - { - File smaliFolder = new File(container.APKToolContents.getAbsolutePath()+BytecodeViewer.fs+"smali"); + try { + File smaliFolder = new File(container.APKToolContents.getAbsolutePath() + BytecodeViewer.fs + "smali"); FileUtils.deleteDirectory(smaliFolder); //save entire jar as smali files System.out.println("Building!"); BytecodeViewer.sm.stopBlocking(); - brut.apktool.Main.main(new String[]{"b", container.APKToolContents.getAbsolutePath(), "--frame-path", tempAPKPath.getAbsolutePath(), "-o", output.getAbsolutePath()}); + brut.apktool.Main.main(new String[]{"b", container.APKToolContents.getAbsolutePath(), "--frame-path", + tempAPKPath.getAbsolutePath(), "-o", output.getAbsolutePath()}); BytecodeViewer.sm.setBlocking(); tempAPKPath.delete(); - } - catch (Exception e) - { + } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/Dex2Jar.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/Dex2Jar.java index cc96b861..60569995 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/Dex2Jar.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/Dex2Jar.java @@ -1,21 +1,6 @@ package the.bytecode.club.bytecodeviewer.util; -import me.konloch.kontainer.io.DiskReader; -import me.konloch.kontainer.io.DiskWriter; -import org.apache.commons.io.IOUtils; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.tree.ClassNode; -import the.bytecode.club.bytecodeviewer.BytecodeViewer; - -import java.io.*; -import java.nio.file.Files; -import java.util.Map; -import java.util.jar.JarEntry; -import java.util.jar.JarInputStream; -import java.util.jar.JarOutputStream; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; -import java.util.zip.ZipOutputStream; +import java.io.File; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -51,8 +36,9 @@ public class Dex2Jar { */ public static synchronized void dex2Jar(File input, File output) { try { - com.googlecode.dex2jar.tools.Dex2jarCmd.main(new String[]{input.getAbsolutePath()}); - String realOutput = input.getName().replaceAll("\\.dex", "-dex2jar.jar").replaceAll("\\.apk", "-dex2jar.jar"); + com.googlecode.dex2jar.tools.Dex2jarCmd.main(input.getAbsolutePath()); + String realOutput = input.getName().replaceAll("\\.dex", "-dex2jar.jar").replaceAll("\\.apk", "-dex2jar" + + ".jar"); File realOutputF = new File(realOutput); realOutputF.renameTo(output); File realOutputF2 = new File(realOutput); @@ -75,33 +61,29 @@ public class Dex2Jar { public static synchronized void saveAsDex(File input, File output, boolean delete) { try { - com.googlecode.dex2jar.tools.Jar2Dex.main(new String[]{input.getAbsolutePath()}); - File currentDexLocation = new File("./"+input.getName()); + com.googlecode.dex2jar.tools.Jar2Dex.main(input.getAbsolutePath()); + File currentDexLocation = new File("./" + input.getName()); - if(currentDexLocation.getAbsolutePath().toLowerCase().endsWith(".jar")) - { - currentDexLocation = new File(currentDexLocation.getAbsolutePath().replaceFirst("\\.jar", "-jar2dex.dex")); - } - else if(currentDexLocation.getAbsolutePath().toLowerCase().endsWith(".apk")) - { - currentDexLocation = new File(currentDexLocation.getAbsolutePath().replaceFirst("\\.apk", "-jar2dex.dex")); - } - else if(currentDexLocation.getAbsolutePath().toLowerCase().endsWith(".dex")) - { - currentDexLocation = new File(currentDexLocation.getAbsolutePath().replaceFirst("\\.dex", "-jar2dex.dex")); - } - else if(currentDexLocation.getAbsolutePath().toLowerCase().endsWith(".zip")) - { - currentDexLocation = new File(currentDexLocation.getAbsolutePath().replaceFirst("\\.zip", "-jar2dex.dex")); - } - else if(currentDexLocation.getAbsolutePath().toLowerCase().endsWith(".class")) - { - currentDexLocation = new File(currentDexLocation.getAbsolutePath().replaceFirst("\\.class", "-jar2dex.dex")); + if (currentDexLocation.getAbsolutePath().toLowerCase().endsWith(".jar")) { + currentDexLocation = new File(currentDexLocation.getAbsolutePath().replaceFirst("\\.jar", "-jar2dex" + + ".dex")); + } else if (currentDexLocation.getAbsolutePath().toLowerCase().endsWith(".apk")) { + currentDexLocation = new File(currentDexLocation.getAbsolutePath().replaceFirst("\\.apk", "-jar2dex" + + ".dex")); + } else if (currentDexLocation.getAbsolutePath().toLowerCase().endsWith(".dex")) { + currentDexLocation = new File(currentDexLocation.getAbsolutePath().replaceFirst("\\.dex", "-jar2dex" + + ".dex")); + } else if (currentDexLocation.getAbsolutePath().toLowerCase().endsWith(".zip")) { + currentDexLocation = new File(currentDexLocation.getAbsolutePath().replaceFirst("\\.zip", "-jar2dex" + + ".dex")); + } else if (currentDexLocation.getAbsolutePath().toLowerCase().endsWith(".class")) { + currentDexLocation = new File(currentDexLocation.getAbsolutePath().replaceFirst("\\.class", "-jar2dex" + + ".dex")); } currentDexLocation.renameTo(output); - if(delete) + if (delete) input.delete(); } catch (Exception e) { new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/EncodeUtils.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/EncodeUtils.java index 9fffedad..211790b8 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/EncodeUtils.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/EncodeUtils.java @@ -1,11 +1,10 @@ package the.bytecode.club.bytecodeviewer.util; -import org.apache.commons.lang3.StringUtils; - import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.commons.lang3.StringUtils; /** * Encoding Convert Utils @@ -17,7 +16,7 @@ public class EncodeUtils { public static String stringToUnicode(String s) { try { - StringBuilder out = new StringBuilder(""); + StringBuilder out = new StringBuilder(); byte[] bytes = s.getBytes("unicode"); for (int i = 0; i < bytes.length - 1; i += 2) { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/Enjarify.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/Enjarify.java index 11eae1ed..f586ba1d 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/Enjarify.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/Enjarify.java @@ -1,8 +1,7 @@ package the.bytecode.club.bytecodeviewer.util; -import the.bytecode.club.bytecodeviewer.BytecodeViewer; - import java.io.File; +import the.bytecode.club.bytecodeviewer.BytecodeViewer; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/FileChangeNotifier.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/FileChangeNotifier.java index c4cc6b09..1af817c2 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/FileChangeNotifier.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/FileChangeNotifier.java @@ -27,7 +27,7 @@ import org.objectweb.asm.tree.ClassNode; */ public interface FileChangeNotifier { - public void openClassFile(final FileContainer container, String name, ClassNode cn); + void openClassFile(final FileContainer container, String name, ClassNode cn); - public void openFile(final FileContainer container, String name, byte[] contents); + void openFile(final FileContainer container, String name, byte[] contents); } \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/FileContainer.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/FileContainer.java index 096fb52d..7327dad4 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/FileContainer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/FileContainer.java @@ -3,7 +3,6 @@ package the.bytecode.club.bytecodeviewer.util; import java.io.File; import java.util.ArrayList; import java.util.HashMap; - import org.objectweb.asm.tree.ClassNode; /*************************************************************************** diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/FileDrop.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/FileDrop.java index 4620a1f0..ac864a27 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/FileDrop.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/FileDrop.java @@ -81,7 +81,7 @@ public class FileDrop { private static Boolean supportsDnD; // Default border color - private static java.awt.Color defaultBorderColor = new java.awt.Color(0f, + private static final java.awt.Color defaultBorderColor = new java.awt.Color(0f, 0f, 1f, 0.25f); /** @@ -446,7 +446,7 @@ public class FileDrop { } // end supportsDnD // BEGIN 2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support added. - private static String ZERO_CHAR_STRING = "" + (char) 0; + private static final String ZERO_CHAR_STRING = "" + (char) 0; private static File[] createFileArray(final BufferedReader bReader, final PrintStream out) { @@ -641,7 +641,7 @@ public class FileDrop { * * @since 1.1 */ - public static interface Listener { + public interface Listener { /** * This method is called when files have been successfully dropped. @@ -649,7 +649,7 @@ public class FileDrop { * @param files An array of Files that were dropped. * @since 1.0 */ - public abstract void filesDropped(java.io.File[] files); + void filesDropped(java.io.File[] files); } // end inner-interface Listener @@ -909,11 +909,9 @@ public class FileDrop { return true; // String - if (flavor.equals(java.awt.datatransfer.DataFlavor.stringFlavor)) - return true; + return flavor.equals(DataFlavor.stringFlavor); // We can't do anything else - return false; } // end isDataFlavorSupported /* ******** I N N E R I N T E R F A C E F E T C H E R ******** */ @@ -932,7 +930,7 @@ public class FileDrop { * @copyright 2001 * @since 1.1 */ - public static interface Fetcher { + public interface Fetcher { /** * Return the object being encapsulated in the * {@link TransferableObject}. @@ -940,7 +938,7 @@ public class FileDrop { * @return The dropped object * @since 1.1 */ - public abstract Object getObject(); + Object getObject(); } // end inner interface Fetcher } // end class TransferableObject diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/JRTExtractor.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/JRTExtractor.java index a5e3d4bd..13d0c69e 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/JRTExtractor.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/JRTExtractor.java @@ -14,46 +14,49 @@ package the.bytecode.club.bytecodeviewer.util; // See the License for the specific language governing permissions and // limitations under the License. -import java.net.*; -import java.nio.file.*; -import java.util.*; -import java.util.zip.*; +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; -public class JRTExtractor -{ - public static void extractRT(String path) throws Throwable - { - FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); +public class JRTExtractor { + public static void extractRT(String path) throws Throwable { + FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); - try(ZipOutputStream zipStream = new ZipOutputStream(Files.newOutputStream(Paths.get(path)))) - { - Files.walk(fs.getPath("/")).forEach(p -> { - if (!Files.isRegularFile(p)) {return;} + try (ZipOutputStream zipStream = new ZipOutputStream(Files.newOutputStream(Paths.get(path)))) { + Files.walk(fs.getPath("/")).forEach(p -> { + if (!Files.isRegularFile(p)) { + return; + } - try - { - byte[] data = Files.readAllBytes(p); + try { + byte[] data = Files.readAllBytes(p); - List list = new ArrayList<>(); - p.iterator().forEachRemaining(p2 -> list.add(p2.toString())); - assert list.remove(0).equals("modules"); + List list = new ArrayList<>(); + p.iterator().forEachRemaining(p2 -> list.add(p2.toString())); + assert list.remove(0).equals("modules"); - if (!list.get(list.size()-1).equals("module-info.class")) - { - list.remove(0); - } + if (!list.get(list.size() - 1).equals("module-info.class")) { + list.remove(0); + } - list.remove(0); - String outPath = String.join("/", list); + list.remove(0); + String outPath = String.join("/", list); - if(!outPath.endsWith("module-info.class")) - { - ZipEntry ze = new ZipEntry(outPath); - zipStream.putNextEntry(ze); - zipStream.write(data); - } - } catch (Throwable t) {throw new RuntimeException(t);} - }); - } - } + if (!outPath.endsWith("module-info.class")) { + ZipEntry ze = new ZipEntry(outPath); + zipStream.putNextEntry(ze); + zipStream.write(data); + } + } catch (Throwable t) { + throw new RuntimeException(t); + } + }); + } + } } \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/JarUtils.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/JarUtils.java index 960cba1d..166cb061 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/JarUtils.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/JarUtils.java @@ -1,6 +1,11 @@ package the.bytecode.club.bytecodeviewer.util; -import java.io.*; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -11,9 +16,7 @@ import java.util.jar.JarOutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipInputStream; - import me.konloch.kontainer.io.DiskWriter; - import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipFile; import org.apache.commons.io.FilenameUtils; @@ -52,7 +55,7 @@ public class JarUtils { /** * Loads the classes and resources from the input jar file * - * @param jarFile the input jar file + * @param jarFile the input jar file * @throws IOException */ public static void put(final File jarFile) throws IOException { @@ -69,8 +72,10 @@ public class JarUtils { if (!entry.isDirectory()) files.put(name, bytes); } else { - String cafebabe = String.format("%02X", bytes[0]) + String.format("%02X", bytes[1]) + String.format("%02X", bytes[2]) + String.format("%02X", bytes[3]); - if (cafebabe.toLowerCase().equals("cafebabe")) { + String cafebabe = + String.format("%02X", bytes[0]) + String.format("%02X", bytes[1]) + String.format("%02X", + bytes[2]) + String.format("%02X", bytes[3]); + if (cafebabe.equalsIgnoreCase("cafebabe")) { try { final ClassNode cn = getNode(bytes); container.classes.add(cn); @@ -98,9 +103,9 @@ public class JarUtils { BytecodeViewer.files.add(container); } - public static void put2(final File jarFile) throws IOException - { - //if this ever fails, worst case import Sun's jarsigner code from JDK 7 re-sign the jar to rebuild the CRC, should also rebuild the archive byte offsets + public static void put2(final File jarFile) throws IOException { + //if this ever fails, worst case import Sun's jarsigner code from JDK 7 re-sign the jar to rebuild the CRC, + // should also rebuild the archive byte offsets FileContainer container = new FileContainer(jarFile); HashMap files = new HashMap<>(); @@ -110,45 +115,31 @@ public class JarUtils { String fileBaseName = FilenameUtils.getBaseName(path.getFileName().toString()); Path destFolderPath = Paths.get(path.getParent().toString(), fileBaseName); - try (ZipFile zipFile = new ZipFile(jarFile)) - { + try (ZipFile zipFile = new ZipFile(jarFile)) { Enumeration entries = zipFile.getEntries(); - while (entries.hasMoreElements()) - { + while (entries.hasMoreElements()) { ZipArchiveEntry entry = entries.nextElement(); Path entryPath = destFolderPath.resolve(entry.getName()); String name = entry.getName(); - if (entry.isDirectory()) - { + if (entry.isDirectory()) { //directory - } - else - { - try (InputStream in = zipFile.getInputStream(entry)) - { + } else { + try (InputStream in = zipFile.getInputStream(entry)) { final byte[] bytes = getBytes(in); - if(!name.endsWith(".class")) - { + if (!name.endsWith(".class")) { files.put(name, bytes); - } - else - { - String cafebabe = String.format("%02X", bytes[0]) + String.format("%02X", bytes[1]) + String.format("%02X", bytes[2]) + String.format("%02X", bytes[3]); - if (cafebabe.toLowerCase().equals("cafebabe")) - { - try - { + } else { + String cafebabe = + String.format("%02X", bytes[0]) + String.format("%02X", bytes[1]) + String.format("%02X", bytes[2]) + String.format("%02X", bytes[3]); + if (cafebabe.equalsIgnoreCase("cafebabe")) { + try { final ClassNode cn = getNode(bytes); container.classes.add(cn); - } - catch (Exception e) - { + } catch (Exception e) { e.printStackTrace(); } - } - else - { + } else { files.put(name, bytes); } } @@ -172,8 +163,10 @@ public class JarUtils { final String name = entry.getName(); if (name.endsWith(".class")) { byte[] bytes = getBytes(jis); - String cafebabe = String.format("%02X", bytes[0]) + String.format("%02X", bytes[1]) + String.format("%02X", bytes[2]) + String.format("%02X", bytes[3]); - if (cafebabe.toLowerCase().equals("cafebabe")) { + String cafebabe = + String.format("%02X", bytes[0]) + String.format("%02X", bytes[1]) + String.format("%02X", + bytes[2]) + String.format("%02X", bytes[3]); + if (cafebabe.equalsIgnoreCase("cafebabe")) { try { final ClassNode cn = getNode(bytes); classes.add(cn); @@ -348,7 +341,7 @@ public class JarUtils { * Saves a jar without the manifest * * @param nodeList The loaded ClassNodes - * @param dir the exact jar output path + * @param dir the exact jar output path */ public static void saveAsJarClassesOnlyToDir(ArrayList nodeList, String dir) { try { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/LazyNameUtil.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/LazyNameUtil.java index 5e7e8c1a..9c4fa51f 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/LazyNameUtil.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/LazyNameUtil.java @@ -18,22 +18,19 @@ package the.bytecode.club.bytecodeviewer.util; * along with this program. If not, see . * ***************************************************************************/ +import java.util.HashMap; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; -import java.util.HashMap; - /** * @author Konloch */ -public class LazyNameUtil -{ +public class LazyNameUtil { public static boolean SAME_NAME_JAR_WORKSPACE = false; private static final HashMap nameMap = new HashMap<>(); - public static void reset() - { + public static void reset() { nameMap.clear(); } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/MethodParser.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/MethodParser.java index 66d3ffc0..cdb42f4a 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/MethodParser.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/MethodParser.java @@ -10,10 +10,8 @@ import java.util.regex.Pattern; * Methods parser. * * @author DreamSworK - * */ -public class MethodParser -{ +public class MethodParser { public static class Method { public String name; @@ -30,9 +28,10 @@ public class MethodParser } } - public static final Pattern regex = Pattern.compile("\\s*(?:static|public|private|protected|final|abstract)[\\w\\s.<>\\[\\]]*\\s+(?[\\w.]+)\\s*\\((?[\\w\\s,.<>\\[\\]$?]*)\\)"); + public static final Pattern regex = Pattern.compile("\\s*(?:static|public|private|protected|final|abstract)" + + "[\\w\\s.<>\\[\\]]*\\s+(?[\\w.]+)\\s*\\((?[\\w\\s,.<>\\[\\]$?]*)\\)"); - private TreeMap methods = new TreeMap<>(); + private final TreeMap methods = new TreeMap<>(); private static String removeBrackets(String string) { if (string.indexOf('<') != -1 && string.indexOf('>') != -1) { @@ -51,7 +50,7 @@ public class MethodParser public void addMethod(int line, String name, String params) { if (!name.isEmpty()) { - name = getLastPart(name,'.'); + name = getLastPart(name, '.'); String[] args = {}; if (!params.isEmpty()) { params = removeBrackets(params); @@ -62,8 +61,8 @@ public class MethodParser String[] strings = args[i].split(" "); args[i] = strings[strings.length - 2]; } - args[i] = getLastPart(args[i],'.'); - args[i] = getLastPart(args[i],'$'); + args[i] = getLastPart(args[i], '.'); + args[i] = getLastPart(args[i], '$'); } } Method method = new Method(name, Arrays.asList(args)); @@ -107,7 +106,7 @@ public class MethodParser } public int findMethod(String name, List params) { - for (Map.Entry entry: methods.entrySet()) { + for (Map.Entry entry : methods.entrySet()) { if (name.equals(entry.getValue().name) && params.size() == entry.getValue().params.size()) { if (params.equals(entry.getValue().params)) { return entry.getKey(); @@ -135,9 +134,9 @@ public class MethodParser Map.Entry low = methods.floorEntry(line); Map.Entry high = methods.ceilingEntry(line); if (low != null && high != null) { - return Math.abs(line - low.getKey()) < Math.abs(line - high.getKey()) ? low.getKey() : high.getKey(); - } - else if (low != null || high != null) { + return Math.abs(line - low.getKey()) < Math.abs(line - high.getKey()) ? low.getKey() : + high.getKey(); + } else if (low != null || high != null) { return low != null ? low.getKey() : high.getKey(); } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/MiscUtils.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/MiscUtils.java index 31fc840e..c8ec6009 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/MiscUtils.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/MiscUtils.java @@ -35,7 +35,7 @@ import java.util.Random; public class MiscUtils { private static final String AB = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; private static final String AN = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - private static Random rnd = new Random(); + private static final Random rnd = new Random(); /** * Returns a random string without numbers @@ -140,7 +140,7 @@ public class MiscUtils { /** * @author JoshTheWolfe */ - @SuppressWarnings({ "unchecked" }) + @SuppressWarnings({"unchecked"}) public static void updateEnv(String name, String val) throws ReflectiveOperationException { Map env = System.getenv(); Field field = env.getClass().getDeclaredField("m"); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/NewlineOutputStream.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/NewlineOutputStream.java index 1d4336b3..e65d8200 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/NewlineOutputStream.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/NewlineOutputStream.java @@ -1,6 +1,10 @@ package the.bytecode.club.bytecodeviewer.util; -import java.io.*; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -38,12 +42,7 @@ public class NewlineOutputStream extends FilterOutputStream { String s = System.getProperty("line.separator"); if (s == null || s.length() <= 0) s = "\n"; - try { - newline = s.getBytes("iso-8859-1"); // really us-ascii - } catch (UnsupportedEncodingException ex) { - // should never happen - newline = new byte[]{(byte) '\n'}; - } + newline = s.getBytes(StandardCharsets.ISO_8859_1); // really us-ascii } } @@ -59,11 +58,11 @@ public class NewlineOutputStream extends FilterOutputStream { lastb = b; } - public void write(byte b[]) throws IOException { + public void write(byte[] b) throws IOException { write(b, 0, b.length); } - public void write(byte b[], int off, int len) throws IOException { + public void write(byte[] b, int off, int len) throws IOException { for (int i = 0; i < len; i++) { write(b[off + i]); } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/util/ZipUtils.java b/src/main/java/the/bytecode/club/bytecodeviewer/util/ZipUtils.java index 85de7ffa..d7b301dd 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/util/ZipUtils.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/util/ZipUtils.java @@ -1,6 +1,10 @@ package the.bytecode.club.bytecodeviewer.util; -import java.io.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.util.Enumeration; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -33,7 +37,7 @@ public final class ZipUtils { /** * Unzip files to path. * - * @param jarPath the zip file name + * @param jarPath the zip file name * @param destinationDir the file extract path * @throws IOException Signals that an I/O exception has occurred. */ @@ -57,14 +61,13 @@ public final class ZipUtils { //now create all files for (Enumeration enums = jar.entries(); enums.hasMoreElements(); ) { - JarEntry entry = (JarEntry) enums.nextElement(); + JarEntry entry = enums.nextElement(); String fileName = destinationDir + File.separator + entry.getName(); File f = new File(fileName); File parent = f.getParentFile(); - if(!parent.exists()) - { + if (!parent.exists()) { parent.mkdirs(); } @@ -160,20 +163,21 @@ public final class ZipUtils { } } - public static void addFileToZipAPKTool(String path, String srcFile, ZipOutputStream zip) throws Exception - { + public static void addFileToZipAPKTool(String path, String srcFile, ZipOutputStream zip) throws Exception { File folder = new File(srcFile); String check = path.toLowerCase(); - //if(check.startsWith("decoded unknown") || check.startsWith("decoded lib") || check.startsWith("decoded assets") || check.startsWith("decoded original") || check.startsWith("decoded smali") || check.startsWith("decoded apktool.yml")) - if(check.startsWith("decoded original") || check.startsWith("decoded smali") || check.startsWith("decoded apktool.yml")) + //if(check.startsWith("decoded unknown") || check.startsWith("decoded lib") || check.startsWith("decoded + // assets") || check.startsWith("decoded original") || check.startsWith("decoded smali") || check.startsWith + // ("decoded apktool.yml")) + if (check.startsWith("decoded original") || check.startsWith("decoded smali") || check.startsWith("decoded " + + "apktool.yml")) return; //if(path.equals("original") || path.equals("classes.dex") || path.equals("apktool.yml")) // continue; - if (folder.isDirectory()) - { + if (folder.isDirectory()) { addFolderToZipAPKTool(path, srcFile, zip); } else { byte[] buf = new byte[1024]; @@ -184,8 +188,7 @@ public final class ZipUtils { entry = new ZipEntry(path + "/" + folder.getName()); zip.putNextEntry(entry); - while ((len = in.read(buf)) > 0) - { + while ((len = in.read(buf)) > 0) { zip.write(buf, 0, len); } in.close(); @@ -205,14 +208,11 @@ public final class ZipUtils { } } - public static void addFolderToZipAPKTool(String path, String srcFolder, ZipOutputStream zip) throws Exception - { + public static void addFolderToZipAPKTool(String path, String srcFolder, ZipOutputStream zip) throws Exception { File folder = new File(srcFolder); - for (String fileName : folder.list()) - { - if (path.equals("")) - { + for (String fileName : folder.list()) { + if (path.equals("")) { addFileToZipAPKTool(folder.getName(), srcFolder + "/" + fileName, zip); } else { addFileToZipAPKTool(path + "/" + folder.getName(), srcFolder + "/" + fileName, zip);