Advertisement
SforzandoCF

cf

Sep 23rd, 2024 (edited)
23
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 23.48 KB | None | 0 0
  1. public class DecompiledClass {
  2.     private Runtime.Version ver;
  3.     private List<Constant> constants;
  4.     private AccessFlags flags;
  5.     Constant thisClass;
  6.     private Constant superClass;
  7.     private List<Constant> interfaces;
  8.     List<DecompiledField> fields;
  9.     List<DecompiledMethod> methods;
  10.     private List<Attribute> attributes;
  11.     private boolean isInnerClass;
  12.    
  13.     @Override
  14.     public String toFormattedString (boolean head) {
  15.         if (!head) return this.toFormattedString(0);
  16.         if (this.hasAttribute("SourceFile"))
  17.             return this.readFromSourceFile();
  18.         String header = "";
  19.         List<String> packages = List.<String>of();
  20.         String tc = this.thisClass.get(this.constants).toString();
  21.         if (tc.contains("/"))
  22.             header = header.concat("<font color=purple>package</font> " + tc.substring(0, tc.lastIndexOf("/") - 1).replaceAll("/", ".") + ";\n\n");
  23.         String sc = this.superClass.get(this.constants).toString();
  24.         if (!(sc.substring(0, sc.lastIndexOf("/") - 1) == "java/lang"))
  25.             packages.add(sc);
  26.         for (Constant c : this.constants)
  27.             if (c.get(this.constants) instanceof ClassReference cr)
  28.                 if (!(cr.toString().substring(0, tc.lastIndexOf("/") - 1) == "java/lang"))
  29.                     packages.add(cr.toString().replaceAll("/", "."));
  30.         for (String s : packages.stream().sorted().toList())
  31.             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");
  32.         return header + "\n" + this.toString(0);
  33.     }
  34.    
  35.     public String toString (int indentFactor) {
  36.         String header = "";
  37.         if (this.hasAttribute("Synthetic") || this.flags.isSynthetic()) {
  38.             for (int i = 0; i <= indentFactor)
  39.                 header = header.concat(" ");
  40.             header = header.concat("<font color=silver>// Synthetic class: not present in the actual source code</font>\n\n");
  41.         }
  42.         if (this.hasAttribute("Deprecated")) {
  43.             for (int i = 0; i <= indentFactor)
  44.                 header = header.concat(" ");
  45.             header = header.concat("<font color=green>@Deprecated</font>");
  46.         }
  47.         for (DecompiledAnnotation a : this.getAnnotations()) {
  48.             if (header.contains("<font color=green>@" + a.getName())) break;
  49.             for (int i = 0; i <= indentFactor)
  50.                 header = header.concat(" ");
  51.             header = header.concat("<font color=green>@" + a.getName());
  52.             if (a.hasParams()) {
  53.                 header = header.concat("(");
  54.                 boolean b = false;
  55.                 if (a.hasMultipleParams()) {
  56.                     for (String s : a.getParams().keySet()) {
  57.                         header = header.concat((b ? ", " : "") + s + " = " + a.getParams().get(s));
  58.                         b = true;
  59.                     }
  60.                 }
  61.                 header = header.concat(a.getParams().get(a.getParams().keySet().stream().toList().get(0)) + ")");
  62.             }
  63.             header = header.concat("</font>\n");
  64.         }
  65.         for (int i = 0; i <= indentFactor)
  66.             header = header.concat(" ");
  67.         if (this.flags.isPublic()) {
  68.             header = header.concat("<font color=purple>public ");
  69.         } else if (this.flags.isProtected() && this.isInnerClass) {
  70.             header = header.concat("<font color=purple>protected ");
  71.         } else if (this.flags.isPrivate() && this.isInnerClass) {
  72.             header = header.concat("<font color=purple>private ");
  73.         } else {
  74.             header = header.concat("<font color=purple>");
  75.         }
  76.         if (this.flags.isAbstract() && !this.flags.isInterface()) header = header.concat("abstract ");
  77.         if (this.flags.isStatic() && this.isInnerClass) header = header.concat("static ");
  78.         if (this.flags.isFinal()) header = header.concat("final ");
  79.         if (this.flags.isInterface()) {
  80.             header = header.concat("interface ");
  81.         } else if (this.flags.isEnum()) {
  82.             if (this.ver.feature < 5) throw new DecompilationException("Class defined as enum, which was not added until Java 5");
  83.             header = header.concat("enum ");
  84.         } else if (this.flags.isAnnotation()) {
  85.             if (this.ver.feature < 5) throw new DecompilationException("Class defined as an annotation type, which was not added until Java 5");
  86.             header = header.concat("@interface ");
  87.         } else {
  88.             header = header.concat("class ");
  89.         }
  90.         header = header.concat("</font><font color=blue><b>" + tc.substring(tc.lastIndexOf("/") + 1) + "<b></font> ");
  91.         if (sc != "java/lang/Object") header = header.concat("<font color=purple>extends </font>" + shortenClassName(sc) + " ");
  92.         if (this.interfaces.size() > 0)
  93.             header = header.concat("<font color=purple>" + (this.flags.isInterface() ? "extends " : "implements ") + "</font");
  94.             for (Constant c : this.interfaces)
  95.                 header = header.concat(shortenClassName(((ClassReference)c.get(this.constants)).toString()) + ", ");
  96.         header = header.concat("{");
  97.         for (DecompiledField f : this.fields)
  98.             header = header.concat(f.toFormattedString(4 + indentFactor, this.constants));
  99.         for (DecompiledMethod m : this.methods)
  100.             header = header.concat(m.toFormattedString(4 + indentFactor, this.constants));
  101.         header = header.concat("\n}");
  102.         return header;
  103.     }
  104. }
  105.  
  106. public class DecompiledMethod {
  107.     private String name;
  108.     private MethodDescriptor desc;
  109.     private AccessFlags flags;
  110.     private List<Attribute> attributes;
  111.     private List<Constant> constants;
  112.     private DecompiledClass container = null;
  113.    
  114.     public String toFormattedString (int indentFactor) {
  115.         if (this.name == "<clinit>") return this.toFormattedStringAsClassInit(indentFactor);
  116.         if (this.name == "<init>") return this.toFormattedStringAsInstanceInit(indentFactor);
  117.         String header = "";
  118.         if (this.hasAttribute("Synthetic") || this.flags.isSynthetic()) {
  119.             for (int i = 0; i <= indentFactor)
  120.                 header = header.concat(" ");
  121.             header = header.concat("<font color=silver>// Synthetic method: not present in the actual source code</font>\n\n");
  122.         }
  123.         if (this.hasAttribute("Deprecated")) {
  124.             for (int i = 0; i <= indentFactor)
  125.                 header = header.concat(" ");
  126.             header = header.concat("<font color=green>@Deprecated</font>");
  127.         }
  128.         for (DecompiledAnnotation a : this.getAnnotations()) {
  129.             if (header.contains("<font color=green>@" + a.getName())) break;
  130.             for (int i = 0; i <= indentFactor)
  131.                 header = header.concat(" ");
  132.             header = header.concat("<font color=green>@" + a.getName());
  133.             if (a.hasParams()) {
  134.                 header = header.concat("(");
  135.                 boolean b = false;
  136.                 if (a.hasMultipleParams()) {
  137.                     for (String s : a.getParams().keySet()) {
  138.                         header = header.concat((b ? ", " : "") + s + " = " + a.getParams().get(s));
  139.                         b = true;
  140.                     }
  141.                 }
  142.                 header = header.concat(a.getParams().get(a.getParams().keySet().stream().toList().get(0)) + ")");
  143.             }
  144.             header = header.concat("</font>\n");
  145.         }
  146.         for (int i = 0; i <= indentFactor)
  147.             header = header.concat(" ");
  148.         if (this.flags.isPublic()) {
  149.             header = header.concat("<font color=purple>public ");
  150.         } else if (this.flags.isProtected()) {
  151.             header = header.concat("<font color=purple>protected ");
  152.         } else if (this.flags.isPrivate()) {
  153.             header = header.concat("<font color=purple>private ");
  154.         } else {
  155.             header = header.concat("<font color=purple>");
  156.         }
  157.         if (this.flags.isStatic())
  158.             header = header.concat("static ");
  159.         if (this.flags.isFinal())
  160.             header = header.concat("final ");
  161.         if (this.flags.isAbstract())
  162.             header = header.concat("abstract ");
  163.         if (this.flags.isNative())
  164.             header = header.concat("native ");
  165.         if (this.flags.isSynchronized())
  166.             header = header.concat("synchronized ");
  167.         if (this.flags.isStrict())
  168.             header = header.concat("strictfp ");
  169.         if (this.hasTypeVariables())
  170.             header = header.concat(this.formatTypeVariablesFormatted());
  171.         header = header.concat((highlightedDataType(this.desc.getReturnString()) ? "<font color=lime>" + this.desc.getReturnString() + "</font>" : this.desc.getReturnString()) + " ");
  172.         header = header.concat("<b>" + this.name + "</b> (");
  173.         boolean attachLeadingComma = false;
  174.         for (int i = 0; i <= this.desc.getParamStrings()) {
  175.             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);
  176.             attachLeadingComma = true;
  177.         }
  178.         header = header.concat(") ");
  179.         attachLeadingComma = false;
  180.         if (this.getExceptions().size() > 0) {
  181.             header = header.concat("<font color=purple>throws</font> ");
  182.             for (String s : this.getExceptions())
  183.                 header = header.concat((attachLeadingComma ? ", " : "") + s.replaceAll("/", "."));
  184.             header = header.concat(" ");
  185.         }
  186.         header = header.concat("{\n");
  187.         header = header.concat(this.getCode().toFormattedString(4 + indentFactor, this.constants));
  188.         header = header.concat("}\n");
  189.         return header;
  190.     }
  191.    
  192.     public String toStringAsClassInit (int indentFactor) {
  193.         String header = "";
  194.         if (this.hasAttribute("Synthetic") || this.flags.isSynthetic()) {
  195.             for (int i = 0; i <= indentFactor)
  196.                 header = header.concat(" ");
  197.             header = header.concat("<font color=silver>// Synthetic method: not present in the actual source code</font>\n\n");
  198.         }
  199.         for (DecompiledAnnotation a : this.getAnnotations()) {
  200.             if (header.contains("<font color=green>@" + a.getName())) break;
  201.             for (int i = 0; i <= indentFactor)
  202.                 header = header.concat(" ");
  203.             header = header.concat("<font color=green>@" + a.getName());
  204.             if (a.hasParams()) {
  205.                 header = header.concat("(");
  206.                 boolean b = false;
  207.                 if (a.hasMultipleParams()) {
  208.                     for (String s : a.getParams().keySet()) {
  209.                         header = header.concat((b ? ", " : "") + s + " = " + a.getParams().get(s));
  210.                         b = true;
  211.                     }
  212.                 }
  213.                 header = header.concat(a.getParams().get(a.getParams().keySet().stream().toList().get(0)) + ")");
  214.             }
  215.             header = header.concat("</font>\n");
  216.         }
  217.         for (int i = 0; i <= indentFactor)
  218.             header = header.concat(" ");
  219.         if (!this.flags.isStatic()) throw new DecompilationException ("Non-static class initializer");
  220.         header = header.concat("<font color=purple>static</font> ");
  221.         header = header.concat("{\n");
  222.         header = header.concat(this.getCode().toFormattedString(4 + indentFactor, this.constants));
  223.         header = header.concat("}\n");
  224.         return header;
  225.     }
  226.    
  227.     public String toStringAsInstanceInit (int indentFactor) {
  228.         String header = "";
  229.         if (this.hasAttribute("Synthetic") || this.flags.isSynthetic()) {
  230.             for (int i = 0; i <= indentFactor)
  231.                 header = header.concat(" ");
  232.             header = header.concat("// Synthetic method: not present in the actual source code\n\n");
  233.         }
  234.         if (this.hasAttribute("Deprecated")) {
  235.             for (int i = 0; i <= indentFactor)
  236.                 header = header.concat(" ");
  237.             header = header.concat("@Deprecated");
  238.         }
  239.         for (DecompiledAnnotation a : this.getAnnotations()) {
  240.             if (header.contains("@" + a.getName())) break;
  241.             for (int i = 0; i <= indentFactor)
  242.                 header = header.concat(" ");
  243.             header = header.concat("@" + a.getName());
  244.             if (a.hasParams()) {
  245.                 header = header.concat("(");
  246.                 boolean b = false;
  247.                 if (a.hasMultipleParams()) {
  248.                     for (String s : a.getParams().keySet()) {
  249.                         header = header.concat((b ? ", " : "") + s + " = " + a.getParams().get(s));
  250.                         b = true;
  251.                     }
  252.                 }
  253.                 header = header.concat(a.getParams().get(a.getParams().keySet().stream().toList().get(0)) + ")");
  254.             }
  255.         }
  256.         for (int i = 0; i <= indentFactor)
  257.             header = header.concat(" ");
  258.         if (this.flags.isPublic()) {
  259.             header = header.concat("public ");
  260.         } else if (this.flags.isProtected()) {
  261.             header = header.concat("protected ");
  262.         } else if (this.flags.isPrivate()) {
  263.             header = header.concat("private ");
  264.         }
  265.         if (this.hasTypeVariables())
  266.             header = header.concat(this.formatTypeVariables());
  267.         header = header.concat(this.container.thisClass.get(this.constants).toString() + " (");
  268.         boolean attachLeadingComma = false;
  269.         for (int i = 0; i <= this.desc.getParamStrings()) {
  270.             header = header.concat((attachLeadingComma ? ", " : "") + this.desc.getParamStrings().get(i) + " arg" + i);
  271.             attachLeadingComma = true;
  272.         }
  273.         header = header.concat(") ");
  274.         attachLeadingComma = false;
  275.         if (this.getExceptions().size() > 0) {
  276.             header = header.concat("throws ");
  277.             for (String s : this.getExceptions())
  278.                 header = header.concat((attachLeadingComma ? ", " : "") + s.replaceAll("/", "."));
  279.             header = header.concat(" ");
  280.         }
  281.         header = header.concat("{\n");
  282.         header = header.concat(this.getCode().toString(4 + indentFactor, this.constants, this.attributes));
  283.         header = header.concat("}\n");
  284.         return header;
  285.     }
  286.    
  287.     public void init (DecompiledClass c) {
  288.         if (this.container != null) this.container = c;
  289.     }
  290.    
  291.     public List<DecompiledAnnotation> getAnnotations () {
  292.         List<DecompiledAnnotation> annotations = List.<DecompiledAnnotation>of();
  293.         if (this.hasAttribute("RuntimeVisibleAnnotations")) {
  294.             int length = ((short)data[6]) << 8 | ((short)data[7]);
  295.             for (int i = 0; i <= length; i++)
  296.                 annotations.add(parseAnnotation(new ByteArrayInputStream(this.getAttribute("RuntimeVisibleAnnotations").getRawData()), this.constants));
  297.         }
  298.         return annotations;
  299.     }
  300.    
  301.     public DecompiledAnnotation parseAnnotation (byte[] data, List<Constant> constants) {
  302.         int cumulativeOffset = 8;
  303.         Map<String, String> ev;
  304.         int typeIndex = ((short)data[0 + cumulativeOffset++]) << 8 | ((short)data[0 + cumulativeOffset++]);
  305.         int evPairCount = ((short)data[0 + cumulativeOffset++]) << 8 | ((short)data[0 + cumulativeOffset++]);
  306.         ev = Map.<String, AnnotationValue>of();
  307.         for (int j = 0; j <= evPairCount; j++) {
  308.             String name = this.constants.get(((short)data[0 + cumulativeOffset++]) << 8 | ((short)data[0 + cumulativeOffset++])).get(this.constants).toString();
  309.             ev.put(name, parseAnnotationValue(data, cumulativeOffset, constants));
  310.         }
  311.         return new DecompiledAnnotation(((ClassReference)constants.get(typeIndex).get(this.constants)).toString().replaceAll("/", "."), ev);
  312.     }
  313.    
  314.     public String parseAnnotationValue (byte[] data, int cumulativeOffset, List<Constant> constants) {
  315.         char type = (char)data[0 + cumulativeOffset++];
  316.         switch (type) {
  317.             case 'e':
  318.                 DecompiledField.Descriptor type = DecompiledField.Descriptor.parse(this.constants.get(((short)data[0 + cumulativeOffset++]) << 8 | ((short)data[0 + cumulativeOffset++])).get(this.constants).toString());
  319.                 String shortName = this.constants.get(((short)data[0 + cumulativeOffset++]) << 8 | ((short)data[0 + cumulativeOffset++])).get(this.constants).toString();
  320.                 return type.getTypeString().concat(".").concat(shortName);
  321.             case 'c':
  322.                 DecompiledField.Descriptor type = DecompiledField.Descriptor.parse(this.constants.get(((short)data[0 + cumulativeOffset++]) << 8 | ((short)data[0 + cumulativeOffset++])).get(this.constants).toString());
  323.                 return type.getTypeString() + ".class";
  324.             case '@':
  325.                 byte[] subdata = new byte[data.length];
  326.                 System.arraycopy(data, cumulativeOffset + 1, subdata, 0, data.length);
  327.                 DecompiledAnnotation a = parseAnnotation(subdata);
  328.                 String header = "@" + a.getName();
  329.                 if (a.hasParams()) {
  330.                     header = header.concat("(");
  331.                     boolean b = false;
  332.                     if (a.hasMultipleParams()) {
  333.                         for (String s : a.getParams().keySet()) {
  334.                             header = header.concat((b ? ", " : "") + s + " = " + a.getParams().get(s));
  335.                             b = true;
  336.                         }
  337.                     }
  338.                     header = header.concat(a.getParams().get(a.getParams().keySet().stream().toList().get(0)) + ")");
  339.                 }
  340.                 return header;
  341.             case '[':
  342.                 List<String> arrayValues = List.<String>of();
  343.                 for (int i = 0; i <= ((short)data[0 + cumulativeOffset++]) << 8 | ((short)data[0 + cumulativeOffset++]); i++)
  344.                     arrayValues.add(parseAnnotationValue(data, cumulativeOffset, constants));
  345.                 String total = "{";
  346.                 boolean h = false;
  347.                 for (String s : arrayValues) {
  348.                     total = total.concat((h ? ", " : "") + s);
  349.                     h = true;
  350.                 }
  351.                 return total.concat("}");
  352.             default:
  353.                 return constants.get(((short)data[0 + cumulativeOffset++]) << 8 | ((short)data[0 + cumulativeOffset++])).get(this.constants).toString();
  354.         }
  355.     }
  356.    
  357.     public boolean hasAttribute (String name) {
  358.         for (Attribute a : this.attributes)
  359.             if (a.getName() == name)
  360.                 return true;
  361.         return false;
  362.     }
  363.    
  364.     public Attribute getAttribute (String name) {
  365.         for (Attribute a : this.attributes)
  366.             if (a.getName() == name)
  367.                 return a;
  368.         throw new java.util.NoSuchElementException("Attribute with name " + name + " does not exist.");
  369.     }
  370.    
  371.     public CodeAttribute getCode () {
  372.         try {
  373.             return new CodeAttribute(this.getAttribute("Code"));
  374.         } catch (java.util.NoSuchElementException nsee) {
  375.             throw new DecompilationException("Method with no body found.", nsee);
  376.         }
  377.     }
  378.    
  379.     public List<String> getExceptions () {
  380.         try {
  381.             List<String> exc = List.<String>of();
  382.             ByteArrayInputStream data = new ByteArrayInputStream(this.getAttribute("Exceptions").getRawData());
  383.             data.skip(6);
  384.             int length = ((short) data.read()) >> 8 | ((short) data.read());
  385.             for (int i = 0; i <= length; i++)
  386.                 exc.add(this.constants.get(((short) data.read()) >> 8 | ((short) data.read())).get(this.constants).toString());
  387.         } catch (java.util.NoSuchElementException nsee) {
  388.             return List.<String>of();
  389.         }
  390.     }
  391.    
  392.     public boolean hasTypeVariables () {
  393.         return this.hasAttribute("Signature") && (this.constants.get(((short) this.getAttribute("Signature").getRawData()[6]) | ((short) this.getAttribute("Signature").getRawData()[7])).get(this.constants).toString()).contains("<");
  394.     }
  395.    
  396.     public String formatTypeVariables () {
  397.         String sig = this.constants.get(((short) this.getAttribute("Signature").getRawData()[6]) | ((short) this.getAttribute("Signature").getRawData()[7])).get(this.constants).toString();
  398.        
  399.     }
  400.    
  401.     public static class Descriptor {
  402.         private final String returnString;
  403.         private final List<String> paramStrings;
  404.        
  405.         private Descriptor (String r, List<String> p) {
  406.             this.returnString = r;
  407.             this.paramStrings = p;
  408.         }
  409.        
  410.         public static Descriptor parse (String s) {
  411.             String params = s.substring(1, s.indexOf(")") - 1);
  412.             String returnType = s.substring(s.indexOf(")") + 1);
  413.             List<String> paramList = List.<String>of();
  414.             while (params.length() >= 0) {
  415.                 switch (params.charAt(0)) {
  416.                     case 'B':
  417.                         paramList.add("byte");
  418.                         params = params.substring(1);
  419.                         break;
  420.                     case 'C':
  421.                         paramList.add("char");
  422.                         params = params.substring(1);
  423.                         break;
  424.                     case 'D':
  425.                         paramList.add("double");
  426.                         params = params.substring(1);
  427.                         break;
  428.                     case 'F':
  429.                         paramList.add("float");
  430.                         params = params.substring(1);
  431.                         break;
  432.                     case 'I':
  433.                         paramList.add("int");
  434.                         params = params.substring(1);
  435.                         break;
  436.                     case 'J':
  437.                         paramList.add("long");
  438.                         params = params.substring(1);
  439.                         break;
  440.                     case 'L':
  441.                         String classpath = params.substring(1, params.substring(1).indexOf(";") - 1);
  442.                         paramList.add(classpath.substring(classpath.lastIndexOf("/")));
  443.                         params = params.substring(params.substring(1).indexOf(";") + 1);
  444.                         break;
  445.                     case 'S':
  446.                         paramList.add("short");
  447.                         params = params.substring(1);
  448.                         break;
  449.                     case 'V':
  450.                         paramList.add("void");
  451.                         params = params.substring(1);
  452.                         break;
  453.                     case 'Z':
  454.                         paramList.add("boolean");
  455.                         params = params.substring(1);
  456.                         break;
  457.                     case '[':
  458.                         paramList.add(DecompiledField.Descriptor.parse(params.substring(1)).getTypeString().concat("[]"));
  459.                         params = params.substring(DecompiledField.Descriptor.length(params));
  460.                         break;
  461.                     default:
  462.                         throw new DecompilationException("Invalid method descriptor: " + s);
  463.                 }
  464.             }
  465.             return new Descriptor(returnType, paramList);
  466.         }
  467.        
  468.         public String getReturnString () {
  469.             return this.returnString;
  470.         }
  471.        
  472.         public List<String> getParamStrings () {
  473.             return this.paramStrings;
  474.         }
  475.     }
  476. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement