Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public class DecompiledClass {
- private Runtime.Version ver;
- private List<Constant> constants;
- private AccessFlags flags;
- Constant thisClass;
- private Constant superClass;
- private List<Constant> interfaces;
- List<DecompiledField> fields;
- List<DecompiledMethod> methods;
- private List<Attribute> attributes;
- private boolean isInnerClass;
- @Override
- public String toFormattedString (boolean head) {
- if (!head) return this.toFormattedString(0);
- if (this.hasAttribute("SourceFile"))
- return this.readFromSourceFile();
- String header = "";
- List<String> packages = List.<String>of();
- String tc = this.thisClass.get(this.constants).toString();
- if (tc.contains("/"))
- header = header.concat("<font color=purple>package</font> " + tc.substring(0, tc.lastIndexOf("/") - 1).replaceAll("/", ".") + ";\n\n");
- String sc = this.superClass.get(this.constants).toString();
- if (!(sc.substring(0, sc.lastIndexOf("/") - 1) == "java/lang"))
- packages.add(sc);
- for (Constant c : this.constants)
- if (c.get(this.constants) instanceof ClassReference cr)
- if (!(cr.toString().substring(0, tc.lastIndexOf("/") - 1) == "java/lang"))
- packages.add(cr.toString().replaceAll("/", "."));
- for (String s : packages.stream().sorted().toList())
- header = header.concat(packages.get(packages.indexOf(s) == 1 ? 1 : packages.indexOf(s) - 1).split("/")[0] != s.split("/")[0] ? "\n" : "" + "<font color=purple>import</font> " + s.replaceAll("/", ".") + ";\n");
- return header + "\n" + this.toString(0);
- }
- public String toString (int indentFactor) {
- String header = "";
- if (this.hasAttribute("Synthetic") || this.flags.isSynthetic()) {
- for (int i = 0; i <= indentFactor)
- header = header.concat(" ");
- header = header.concat("<font color=silver>// Synthetic class: not present in the actual source code</font>\n\n");
- }
- if (this.hasAttribute("Deprecated")) {
- for (int i = 0; i <= indentFactor)
- header = header.concat(" ");
- header = header.concat("<font color=green>@Deprecated</font>");
- }
- for (DecompiledAnnotation a : this.getAnnotations()) {
- if (header.contains("<font color=green>@" + a.getName())) break;
- for (int i = 0; i <= indentFactor)
- header = header.concat(" ");
- header = header.concat("<font color=green>@" + a.getName());
- if (a.hasParams()) {
- header = header.concat("(");
- boolean b = false;
- if (a.hasMultipleParams()) {
- for (String s : a.getParams().keySet()) {
- header = header.concat((b ? ", " : "") + s + " = " + a.getParams().get(s));
- b = true;
- }
- }
- header = header.concat(a.getParams().get(a.getParams().keySet().stream().toList().get(0)) + ")");
- }
- header = header.concat("</font>\n");
- }
- for (int i = 0; i <= indentFactor)
- header = header.concat(" ");
- if (this.flags.isPublic()) {
- header = header.concat("<font color=purple>public ");
- } else if (this.flags.isProtected() && this.isInnerClass) {
- header = header.concat("<font color=purple>protected ");
- } else if (this.flags.isPrivate() && this.isInnerClass) {
- header = header.concat("<font color=purple>private ");
- } else {
- header = header.concat("<font color=purple>");
- }
- if (this.flags.isAbstract() && !this.flags.isInterface()) header = header.concat("abstract ");
- if (this.flags.isStatic() && this.isInnerClass) header = header.concat("static ");
- if (this.flags.isFinal()) header = header.concat("final ");
- if (this.flags.isInterface()) {
- header = header.concat("interface ");
- } else if (this.flags.isEnum()) {
- if (this.ver.feature < 5) throw new DecompilationException("Class defined as enum, which was not added until Java 5");
- header = header.concat("enum ");
- } else if (this.flags.isAnnotation()) {
- if (this.ver.feature < 5) throw new DecompilationException("Class defined as an annotation type, which was not added until Java 5");
- header = header.concat("@interface ");
- } else {
- header = header.concat("class ");
- }
- header = header.concat("</font><font color=blue><b>" + tc.substring(tc.lastIndexOf("/") + 1) + "<b></font> ");
- if (sc != "java/lang/Object") header = header.concat("<font color=purple>extends </font>" + shortenClassName(sc) + " ");
- if (this.interfaces.size() > 0)
- header = header.concat("<font color=purple>" + (this.flags.isInterface() ? "extends " : "implements ") + "</font");
- for (Constant c : this.interfaces)
- header = header.concat(shortenClassName(((ClassReference)c.get(this.constants)).toString()) + ", ");
- header = header.concat("{");
- for (DecompiledField f : this.fields)
- header = header.concat(f.toFormattedString(4 + indentFactor, this.constants));
- for (DecompiledMethod m : this.methods)
- header = header.concat(m.toFormattedString(4 + indentFactor, this.constants));
- header = header.concat("\n}");
- return header;
- }
- }
- public class DecompiledMethod {
- private String name;
- private MethodDescriptor desc;
- private AccessFlags flags;
- private List<Attribute> attributes;
- private List<Constant> constants;
- private DecompiledClass container = null;
- public String toFormattedString (int indentFactor) {
- if (this.name == "<clinit>") return this.toFormattedStringAsClassInit(indentFactor);
- if (this.name == "<init>") return this.toFormattedStringAsInstanceInit(indentFactor);
- String header = "";
- if (this.hasAttribute("Synthetic") || this.flags.isSynthetic()) {
- for (int i = 0; i <= indentFactor)
- header = header.concat(" ");
- header = header.concat("<font color=silver>// Synthetic method: not present in the actual source code</font>\n\n");
- }
- if (this.hasAttribute("Deprecated")) {
- for (int i = 0; i <= indentFactor)
- header = header.concat(" ");
- header = header.concat("<font color=green>@Deprecated</font>");
- }
- for (DecompiledAnnotation a : this.getAnnotations()) {
- if (header.contains("<font color=green>@" + a.getName())) break;
- for (int i = 0; i <= indentFactor)
- header = header.concat(" ");
- header = header.concat("<font color=green>@" + a.getName());
- if (a.hasParams()) {
- header = header.concat("(");
- boolean b = false;
- if (a.hasMultipleParams()) {
- for (String s : a.getParams().keySet()) {
- header = header.concat((b ? ", " : "") + s + " = " + a.getParams().get(s));
- b = true;
- }
- }
- header = header.concat(a.getParams().get(a.getParams().keySet().stream().toList().get(0)) + ")");
- }
- header = header.concat("</font>\n");
- }
- for (int i = 0; i <= indentFactor)
- header = header.concat(" ");
- if (this.flags.isPublic()) {
- header = header.concat("<font color=purple>public ");
- } else if (this.flags.isProtected()) {
- header = header.concat("<font color=purple>protected ");
- } else if (this.flags.isPrivate()) {
- header = header.concat("<font color=purple>private ");
- } else {
- header = header.concat("<font color=purple>");
- }
- if (this.flags.isStatic())
- header = header.concat("static ");
- if (this.flags.isFinal())
- header = header.concat("final ");
- if (this.flags.isAbstract())
- header = header.concat("abstract ");
- if (this.flags.isNative())
- header = header.concat("native ");
- if (this.flags.isSynchronized())
- header = header.concat("synchronized ");
- if (this.flags.isStrict())
- header = header.concat("strictfp ");
- if (this.hasTypeVariables())
- header = header.concat(this.formatTypeVariablesFormatted());
- header = header.concat((highlightedDataType(this.desc.getReturnString()) ? "<font color=lime>" + this.desc.getReturnString() + "</font>" : this.desc.getReturnString()) + " ");
- header = header.concat("<b>" + this.name + "</b> (");
- boolean attachLeadingComma = false;
- for (int i = 0; i <= this.desc.getParamStrings()) {
- header = header.concat((attachLeadingComma ? ", " : "") + (highlightedDataType(this.desc.getParamStrings().get(i)) ? "<font color=lime>" + this.desc.getParamStrings().get(i) + "</font>" : this.desc.getParamStrings().get(i) + " arg" + i);
- attachLeadingComma = true;
- }
- header = header.concat(") ");
- attachLeadingComma = false;
- if (this.getExceptions().size() > 0) {
- header = header.concat("<font color=purple>throws</font> ");
- for (String s : this.getExceptions())
- header = header.concat((attachLeadingComma ? ", " : "") + s.replaceAll("/", "."));
- header = header.concat(" ");
- }
- header = header.concat("{\n");
- header = header.concat(this.getCode().toFormattedString(4 + indentFactor, this.constants));
- header = header.concat("}\n");
- return header;
- }
- public String toStringAsClassInit (int indentFactor) {
- String header = "";
- if (this.hasAttribute("Synthetic") || this.flags.isSynthetic()) {
- for (int i = 0; i <= indentFactor)
- header = header.concat(" ");
- header = header.concat("<font color=silver>// Synthetic method: not present in the actual source code</font>\n\n");
- }
- for (DecompiledAnnotation a : this.getAnnotations()) {
- if (header.contains("<font color=green>@" + a.getName())) break;
- for (int i = 0; i <= indentFactor)
- header = header.concat(" ");
- header = header.concat("<font color=green>@" + a.getName());
- if (a.hasParams()) {
- header = header.concat("(");
- boolean b = false;
- if (a.hasMultipleParams()) {
- for (String s : a.getParams().keySet()) {
- header = header.concat((b ? ", " : "") + s + " = " + a.getParams().get(s));
- b = true;
- }
- }
- header = header.concat(a.getParams().get(a.getParams().keySet().stream().toList().get(0)) + ")");
- }
- header = header.concat("</font>\n");
- }
- for (int i = 0; i <= indentFactor)
- header = header.concat(" ");
- if (!this.flags.isStatic()) throw new DecompilationException ("Non-static class initializer");
- header = header.concat("<font color=purple>static</font> ");
- header = header.concat("{\n");
- header = header.concat(this.getCode().toFormattedString(4 + indentFactor, this.constants));
- header = header.concat("}\n");
- return header;
- }
- public String toStringAsInstanceInit (int indentFactor) {
- String header = "";
- if (this.hasAttribute("Synthetic") || this.flags.isSynthetic()) {
- for (int i = 0; i <= indentFactor)
- header = header.concat(" ");
- header = header.concat("// Synthetic method: not present in the actual source code\n\n");
- }
- if (this.hasAttribute("Deprecated")) {
- for (int i = 0; i <= indentFactor)
- header = header.concat(" ");
- header = header.concat("@Deprecated");
- }
- for (DecompiledAnnotation a : this.getAnnotations()) {
- if (header.contains("@" + a.getName())) break;
- for (int i = 0; i <= indentFactor)
- header = header.concat(" ");
- header = header.concat("@" + a.getName());
- if (a.hasParams()) {
- header = header.concat("(");
- boolean b = false;
- if (a.hasMultipleParams()) {
- for (String s : a.getParams().keySet()) {
- header = header.concat((b ? ", " : "") + s + " = " + a.getParams().get(s));
- b = true;
- }
- }
- header = header.concat(a.getParams().get(a.getParams().keySet().stream().toList().get(0)) + ")");
- }
- }
- for (int i = 0; i <= indentFactor)
- header = header.concat(" ");
- if (this.flags.isPublic()) {
- header = header.concat("public ");
- } else if (this.flags.isProtected()) {
- header = header.concat("protected ");
- } else if (this.flags.isPrivate()) {
- header = header.concat("private ");
- }
- if (this.hasTypeVariables())
- header = header.concat(this.formatTypeVariables());
- header = header.concat(this.container.thisClass.get(this.constants).toString() + " (");
- boolean attachLeadingComma = false;
- for (int i = 0; i <= this.desc.getParamStrings()) {
- header = header.concat((attachLeadingComma ? ", " : "") + this.desc.getParamStrings().get(i) + " arg" + i);
- attachLeadingComma = true;
- }
- header = header.concat(") ");
- attachLeadingComma = false;
- if (this.getExceptions().size() > 0) {
- header = header.concat("throws ");
- for (String s : this.getExceptions())
- header = header.concat((attachLeadingComma ? ", " : "") + s.replaceAll("/", "."));
- header = header.concat(" ");
- }
- header = header.concat("{\n");
- header = header.concat(this.getCode().toString(4 + indentFactor, this.constants, this.attributes));
- header = header.concat("}\n");
- return header;
- }
- public void init (DecompiledClass c) {
- if (this.container != null) this.container = c;
- }
- public List<DecompiledAnnotation> getAnnotations () {
- List<DecompiledAnnotation> annotations = List.<DecompiledAnnotation>of();
- if (this.hasAttribute("RuntimeVisibleAnnotations")) {
- int length = ((short)data[6]) << 8 | ((short)data[7]);
- for (int i = 0; i <= length; i++)
- annotations.add(parseAnnotation(new ByteArrayInputStream(this.getAttribute("RuntimeVisibleAnnotations").getRawData()), this.constants));
- }
- return annotations;
- }
- public DecompiledAnnotation parseAnnotation (byte[] data, List<Constant> constants) {
- int cumulativeOffset = 8;
- Map<String, String> ev;
- int typeIndex = ((short)data[0 + cumulativeOffset++]) << 8 | ((short)data[0 + cumulativeOffset++]);
- int evPairCount = ((short)data[0 + cumulativeOffset++]) << 8 | ((short)data[0 + cumulativeOffset++]);
- ev = Map.<String, AnnotationValue>of();
- for (int j = 0; j <= evPairCount; j++) {
- String name = this.constants.get(((short)data[0 + cumulativeOffset++]) << 8 | ((short)data[0 + cumulativeOffset++])).get(this.constants).toString();
- ev.put(name, parseAnnotationValue(data, cumulativeOffset, constants));
- }
- return new DecompiledAnnotation(((ClassReference)constants.get(typeIndex).get(this.constants)).toString().replaceAll("/", "."), ev);
- }
- public String parseAnnotationValue (byte[] data, int cumulativeOffset, List<Constant> constants) {
- char type = (char)data[0 + cumulativeOffset++];
- switch (type) {
- case 'e':
- DecompiledField.Descriptor type = DecompiledField.Descriptor.parse(this.constants.get(((short)data[0 + cumulativeOffset++]) << 8 | ((short)data[0 + cumulativeOffset++])).get(this.constants).toString());
- String shortName = this.constants.get(((short)data[0 + cumulativeOffset++]) << 8 | ((short)data[0 + cumulativeOffset++])).get(this.constants).toString();
- return type.getTypeString().concat(".").concat(shortName);
- case 'c':
- DecompiledField.Descriptor type = DecompiledField.Descriptor.parse(this.constants.get(((short)data[0 + cumulativeOffset++]) << 8 | ((short)data[0 + cumulativeOffset++])).get(this.constants).toString());
- return type.getTypeString() + ".class";
- case '@':
- byte[] subdata = new byte[data.length];
- System.arraycopy(data, cumulativeOffset + 1, subdata, 0, data.length);
- DecompiledAnnotation a = parseAnnotation(subdata);
- String header = "@" + a.getName();
- if (a.hasParams()) {
- header = header.concat("(");
- boolean b = false;
- if (a.hasMultipleParams()) {
- for (String s : a.getParams().keySet()) {
- header = header.concat((b ? ", " : "") + s + " = " + a.getParams().get(s));
- b = true;
- }
- }
- header = header.concat(a.getParams().get(a.getParams().keySet().stream().toList().get(0)) + ")");
- }
- return header;
- case '[':
- List<String> arrayValues = List.<String>of();
- for (int i = 0; i <= ((short)data[0 + cumulativeOffset++]) << 8 | ((short)data[0 + cumulativeOffset++]); i++)
- arrayValues.add(parseAnnotationValue(data, cumulativeOffset, constants));
- String total = "{";
- boolean h = false;
- for (String s : arrayValues) {
- total = total.concat((h ? ", " : "") + s);
- h = true;
- }
- return total.concat("}");
- default:
- return constants.get(((short)data[0 + cumulativeOffset++]) << 8 | ((short)data[0 + cumulativeOffset++])).get(this.constants).toString();
- }
- }
- public boolean hasAttribute (String name) {
- for (Attribute a : this.attributes)
- if (a.getName() == name)
- return true;
- return false;
- }
- public Attribute getAttribute (String name) {
- for (Attribute a : this.attributes)
- if (a.getName() == name)
- return a;
- throw new java.util.NoSuchElementException("Attribute with name " + name + " does not exist.");
- }
- public CodeAttribute getCode () {
- try {
- return new CodeAttribute(this.getAttribute("Code"));
- } catch (java.util.NoSuchElementException nsee) {
- throw new DecompilationException("Method with no body found.", nsee);
- }
- }
- public List<String> getExceptions () {
- try {
- List<String> exc = List.<String>of();
- ByteArrayInputStream data = new ByteArrayInputStream(this.getAttribute("Exceptions").getRawData());
- data.skip(6);
- int length = ((short) data.read()) >> 8 | ((short) data.read());
- for (int i = 0; i <= length; i++)
- exc.add(this.constants.get(((short) data.read()) >> 8 | ((short) data.read())).get(this.constants).toString());
- } catch (java.util.NoSuchElementException nsee) {
- return List.<String>of();
- }
- }
- public boolean hasTypeVariables () {
- return this.hasAttribute("Signature") && (this.constants.get(((short) this.getAttribute("Signature").getRawData()[6]) | ((short) this.getAttribute("Signature").getRawData()[7])).get(this.constants).toString()).contains("<");
- }
- public String formatTypeVariables () {
- String sig = this.constants.get(((short) this.getAttribute("Signature").getRawData()[6]) | ((short) this.getAttribute("Signature").getRawData()[7])).get(this.constants).toString();
- }
- public static class Descriptor {
- private final String returnString;
- private final List<String> paramStrings;
- private Descriptor (String r, List<String> p) {
- this.returnString = r;
- this.paramStrings = p;
- }
- public static Descriptor parse (String s) {
- String params = s.substring(1, s.indexOf(")") - 1);
- String returnType = s.substring(s.indexOf(")") + 1);
- List<String> paramList = List.<String>of();
- while (params.length() >= 0) {
- switch (params.charAt(0)) {
- case 'B':
- paramList.add("byte");
- params = params.substring(1);
- break;
- case 'C':
- paramList.add("char");
- params = params.substring(1);
- break;
- case 'D':
- paramList.add("double");
- params = params.substring(1);
- break;
- case 'F':
- paramList.add("float");
- params = params.substring(1);
- break;
- case 'I':
- paramList.add("int");
- params = params.substring(1);
- break;
- case 'J':
- paramList.add("long");
- params = params.substring(1);
- break;
- case 'L':
- String classpath = params.substring(1, params.substring(1).indexOf(";") - 1);
- paramList.add(classpath.substring(classpath.lastIndexOf("/")));
- params = params.substring(params.substring(1).indexOf(";") + 1);
- break;
- case 'S':
- paramList.add("short");
- params = params.substring(1);
- break;
- case 'V':
- paramList.add("void");
- params = params.substring(1);
- break;
- case 'Z':
- paramList.add("boolean");
- params = params.substring(1);
- break;
- case '[':
- paramList.add(DecompiledField.Descriptor.parse(params.substring(1)).getTypeString().concat("[]"));
- params = params.substring(DecompiledField.Descriptor.length(params));
- break;
- default:
- throw new DecompilationException("Invalid method descriptor: " + s);
- }
- }
- return new Descriptor(returnType, paramList);
- }
- public String getReturnString () {
- return this.returnString;
- }
- public List<String> getParamStrings () {
- return this.paramStrings;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement