added dropInfo

Decompiler, JodeApplet and JodeWindow moved into decompile package
makeDeclaration now transmits the done set over class borders


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1201 379699f6-c40d-0410-875b-85095c16579e
branch_1_1
jochen 25 years ago
parent 47b22fdb21
commit c5b840847b
  1. 1
      jode/jode/decompiler/Analyzer.java
  2. 41
      jode/jode/decompiler/Applet.java
  3. 38
      jode/jode/decompiler/ClassAnalyzer.java.in
  4. 8
      jode/jode/decompiler/FieldAnalyzer.java.in
  5. 3
      jode/jode/decompiler/LocalInfo.java
  6. 2
      jode/jode/decompiler/LocalVariableTable.java
  7. 328
      jode/jode/decompiler/Main.java
  8. 6
      jode/jode/decompiler/Makefile.am
  9. 95
      jode/jode/decompiler/MethodAnalyzer.java.in
  10. 66
      jode/jode/decompiler/Options.java
  11. 21
      jode/jode/decompiler/TabbedPrintWriter.java
  12. 310
      jode/jode/decompiler/Window.java

@ -22,6 +22,5 @@ package jode.decompiler;
public interface Analyzer { public interface Analyzer {
public void analyze(); public void analyze();
public void makeDeclaration();
public void dumpSource(TabbedPrintWriter writer) throws java.io.IOException; public void dumpSource(TabbedPrintWriter writer) throws java.io.IOException;
} }

@ -0,0 +1,41 @@
/* Applet Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.decompiler;
public class Applet extends java.applet.Applet {
Window jodeWin = new Window(this);
///#ifdef AWT10
/// public boolean action(Event e, Object arg) {
/// jodeWin.action(e, arg);
/// return true;
/// }
///#endif
public void init() {
String cp = getParameter("classpath");
if (cp != null)
jodeWin.setClasspath(cp);
String cls = getParameter("class");
if (cls != null)
jodeWin.setClass(cls);
}
}

@ -19,7 +19,6 @@
package jode.decompiler; package jode.decompiler;
import jode.GlobalOptions; import jode.GlobalOptions;
import jode.Decompiler;
import jode.type.MethodType; import jode.type.MethodType;
import jode.type.Type; import jode.type.Type;
import jode.bytecode.ClassInfo; import jode.bytecode.ClassInfo;
@ -32,6 +31,7 @@ import jode.expr.ThisOperator;
import jode.flow.TransformConstructors; import jode.flow.TransformConstructors;
import jode.flow.StructuredBlock; import jode.flow.StructuredBlock;
import jode.flow.FlowBlock; import jode.flow.FlowBlock;
import jode.flow.VariableSet;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
@ -40,6 +40,7 @@ import java.util.Enumeration;
import java.io.IOException; import java.io.IOException;
import @COLLECTIONS@.Collection; import @COLLECTIONS@.Collection;
import @COLLECTIONS@.Set;
public class ClassAnalyzer public class ClassAnalyzer
implements Analyzer, Scope, Declarable, ClassDeclarer implements Analyzer, Scope, Declarable, ClassDeclarer
@ -184,7 +185,7 @@ public class ClassAnalyzer
return; return;
} }
if ((Decompiler.options & Decompiler.OPTION_INNER) != 0 if ((Options.options & Options.OPTION_INNER) != 0
&& innerInfos != null) { && innerInfos != null) {
/* Create inner classes */ /* Create inner classes */
Expression[] outerThis = new Expression[] { Expression[] outerThis = new Expression[] {
@ -263,7 +264,7 @@ public class ClassAnalyzer
// If output should be immediate, we delay analyzation to output. // If output should be immediate, we delay analyzation to output.
// Note that this may break anonymous classes, but the user // Note that this may break anonymous classes, but the user
// has been warned. // has been warned.
if ((Decompiler.options & Decompiler.OPTION_IMMEDIATE) != 0) if ((Options.options & Options.OPTION_IMMEDIATE) != 0)
return; return;
// Analyze fields // Analyze fields
@ -281,7 +282,7 @@ public class ClassAnalyzer
// If output should be immediate, we delay analyzation to output. // If output should be immediate, we delay analyzation to output.
// Note that this may break anonymous classes, but the user // Note that this may break anonymous classes, but the user
// has been warned. // has been warned.
if ((Decompiler.options & Decompiler.OPTION_IMMEDIATE) != 0) if ((Options.options & Options.OPTION_IMMEDIATE) != 0)
return; return;
// Now analyze the inner classes. // Now analyze the inner classes.
@ -296,7 +297,7 @@ public class ClassAnalyzer
} }
public void makeDeclaration() { public void makeDeclaration(Set done) {
if (constrAna != null) if (constrAna != null)
constrAna.transform(); constrAna.transform();
if (staticConstructor != null) { if (staticConstructor != null) {
@ -308,16 +309,17 @@ public class ClassAnalyzer
// If output should be immediate, we delay analyzation to output. // If output should be immediate, we delay analyzation to output.
// Note that this may break anonymous classes, but the user // Note that this may break anonymous classes, but the user
// has been warned. // has been warned.
if ((Decompiler.options & Decompiler.OPTION_IMMEDIATE) != 0) if ((Options.options & Options.OPTION_IMMEDIATE) != 0)
return; return;
for (int j=0; j < fields.length; j++) for (int j=0; j < fields.length; j++)
fields[j].makeDeclaration(); fields[j].makeDeclaration(done);
for (int j=0; j < inners.length; j++) for (int j=0; j < inners.length; j++)
inners[j].makeDeclaration(); inners[j].makeDeclaration(done);
for (int j=0; j < methods.length; j++) for (int j=0; j < methods.length; j++)
methods[j].makeDeclaration(); methods[j].makeDeclaration(done);
} }
public void dumpDeclaration(TabbedPrintWriter writer) throws IOException public void dumpDeclaration(TabbedPrintWriter writer) throws IOException
{ {
dumpSource(writer); dumpSource(writer);
@ -328,6 +330,9 @@ public class ClassAnalyzer
writer.pushScope(this); writer.pushScope(this);
boolean needFieldNewLine = false; boolean needFieldNewLine = false;
boolean needNewLine = false; boolean needNewLine = false;
Set declared = null;
if ((Options.options & Options.OPTION_IMMEDIATE) != 0)
declared = new VariableSet();
for (int i=0; i< fields.length; i++) { for (int i=0; i< fields.length; i++) {
if (blockInitializers[i] != null) { if (blockInitializers[i] != null) {
if (needNewLine) if (needNewLine)
@ -339,10 +344,10 @@ public class ClassAnalyzer
writer.closeBrace(); writer.closeBrace();
needFieldNewLine = needNewLine = true; needFieldNewLine = needNewLine = true;
} }
if ((Decompiler.options & Decompiler.OPTION_IMMEDIATE) != 0) { if ((Options.options & Options.OPTION_IMMEDIATE) != 0) {
// We now do the analyzation we skipped before. // We now do the analyzation we skipped before.
fields[i].analyze(); fields[i].analyze();
fields[i].makeDeclaration(); fields[i].makeDeclaration(declared);
} }
if (fields[i].skipWriting()) if (fields[i].skipWriting())
continue; continue;
@ -365,23 +370,23 @@ public class ClassAnalyzer
if (needNewLine) if (needNewLine)
writer.println(""); writer.println("");
if ((Decompiler.options & Decompiler.OPTION_IMMEDIATE) != 0) { if ((Options.options & Options.OPTION_IMMEDIATE) != 0) {
// We now do the analyzation we skipped before. // We now do the analyzation we skipped before.
inners[i].analyze(); inners[i].analyze();
inners[i].analyzeInnerClasses(); inners[i].analyzeInnerClasses();
inners[i].makeDeclaration(); inners[i].makeDeclaration(declared);
} }
inners[i].dumpSource(writer); inners[i].dumpSource(writer);
needNewLine = true; needNewLine = true;
} }
for (int i=0; i< methods.length; i++) { for (int i=0; i< methods.length; i++) {
if ((Decompiler.options & Decompiler.OPTION_IMMEDIATE) != 0) { if ((Options.options & Options.OPTION_IMMEDIATE) != 0) {
// We now do the analyzation we skipped before. // We now do the analyzation we skipped before.
if (!methods[i].isConstructor()) if (!methods[i].isConstructor())
methods[i].analyze(); methods[i].analyze();
methods[i].analyzeInnerClasses(); methods[i].analyzeInnerClasses();
methods[i].makeDeclaration(); methods[i].makeDeclaration(declared);
} }
if (methods[i].skipWriting()) if (methods[i].skipWriting())
@ -451,6 +456,7 @@ public class ClassAnalyzer
writer.closeBraceNoSpace(); writer.closeBraceNoSpace();
} else } else
writer.closeBrace(); writer.closeBrace();
clazz.dropInfo(clazz.KNOWNATTRIBS | clazz.UNKNOWNATTRIBS);
} }
public void dumpJavaFile(TabbedPrintWriter writer) throws IOException { public void dumpJavaFile(TabbedPrintWriter writer) throws IOException {
@ -459,7 +465,7 @@ public class ClassAnalyzer
initialize(); initialize();
analyze(); analyze();
analyzeInnerClasses(); analyzeInnerClasses();
makeDeclaration(); makeDeclaration(new VariableSet());
imports.dumpHeader(writer); imports.dumpHeader(writer);
dumpSource(writer); dumpSource(writer);

@ -29,6 +29,8 @@ import jode.expr.OuterLocalOperator;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.io.IOException; import java.io.IOException;
import @COLLECTIONS@.Set;
public class FieldAnalyzer implements Analyzer { public class FieldAnalyzer implements Analyzer {
ClassAnalyzer clazz; ClassAnalyzer clazz;
ImportHandler imports; ImportHandler imports;
@ -137,10 +139,12 @@ public class FieldAnalyzer implements Analyzer {
imports.useType(type); imports.useType(type);
} }
public void makeDeclaration() { public void makeDeclaration(Set done) {
if (constant != null) if (constant != null) {
constant.makeDeclaration(done);
constant = constant.simplify(); constant = constant.simplify();
} }
}
public boolean skipWriting() { public boolean skipWriting() {
return analyzedSynthetic; return analyzedSynthetic;

@ -21,7 +21,6 @@ package jode.decompiler;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Vector; import java.util.Vector;
import jode.GlobalOptions; import jode.GlobalOptions;
import jode.Decompiler;
import jode.type.Type; import jode.type.Type;
import jode.expr.Expression; import jode.expr.Expression;
import jode.expr.LocalVarOperator; import jode.expr.LocalVarOperator;
@ -221,7 +220,7 @@ public class LocalInfo implements Declarable {
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_TYPES) != 0) if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_TYPES) != 0)
GlobalOptions.err.println(getName()+" set type to getHint()"); GlobalOptions.err.println(getName()+" set type to getHint()");
setType(type.getHint()); setType(type.getHint());
if ((Decompiler.options & Decompiler.OPTION_PRETTY) != 0) { if ((Options.options & Options.OPTION_PRETTY) != 0) {
name = type.getDefaultName(); name = type.getDefaultName();
} else { } else {
name = type.getDefaultName() name = type.getDefaultName()

@ -18,8 +18,6 @@
*/ */
package jode.decompiler; package jode.decompiler;
import java.io.*;
import jode.Decompiler;
import jode.type.Type; import jode.type.Type;
import jode.bytecode.LocalVariableInfo; import jode.bytecode.LocalVariableInfo;

@ -0,0 +1,328 @@
/* Main Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.decompiler;
import jode.bytecode.ClassInfo;
import jode.bytecode.SearchPath;
import jode.GlobalOptions;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.zip.ZipOutputStream;
import java.util.zip.ZipEntry;
import gnu.getopt.LongOpt;
import gnu.getopt.Getopt;
public class Main extends Options {
private static final int OPTION_START=0x10000;
private static final int OPTION_END =0x20000;
private static final LongOpt[] longOptions = new LongOpt[] {
new LongOpt("cp", LongOpt.REQUIRED_ARGUMENT, null, 'c'),
new LongOpt("classpath", LongOpt.REQUIRED_ARGUMENT, null, 'c'),
new LongOpt("dest", LongOpt.REQUIRED_ARGUMENT, null, 'd'),
new LongOpt("help", LongOpt.NO_ARGUMENT, null, 'h'),
new LongOpt("version", LongOpt.NO_ARGUMENT, null, 'V'),
new LongOpt("verbose", LongOpt.OPTIONAL_ARGUMENT, null, 'v'),
new LongOpt("debug", LongOpt.OPTIONAL_ARGUMENT, null, 'D'),
new LongOpt("import", LongOpt.REQUIRED_ARGUMENT, null, 'i'),
new LongOpt("style", LongOpt.REQUIRED_ARGUMENT, null, 's'),
new LongOpt("lvt", LongOpt.OPTIONAL_ARGUMENT, null,
OPTION_START+0),
new LongOpt("inner", LongOpt.OPTIONAL_ARGUMENT, null,
OPTION_START+1),
new LongOpt("anonymous", LongOpt.OPTIONAL_ARGUMENT, null,
OPTION_START+2),
new LongOpt("push", LongOpt.OPTIONAL_ARGUMENT, null,
OPTION_START+3),
new LongOpt("pretty", LongOpt.OPTIONAL_ARGUMENT, null,
OPTION_START+4),
new LongOpt("decrypt", LongOpt.OPTIONAL_ARGUMENT, null,
OPTION_START+5),
new LongOpt("onetime", LongOpt.OPTIONAL_ARGUMENT, null,
OPTION_START+6),
new LongOpt("immediate", LongOpt.OPTIONAL_ARGUMENT, null,
OPTION_START+7),
new LongOpt("verify", LongOpt.OPTIONAL_ARGUMENT, null,
OPTION_START+8),
new LongOpt("contrafo", LongOpt.OPTIONAL_ARGUMENT, null,
OPTION_START+9)
};
public static void usage() {
PrintWriter err = GlobalOptions.err;
err.println("Version: " + GlobalOptions.version);
err.println("Usage: java jode.decompiler.Main [OPTIONS]... [CLASSES]...");
err.println(" -h, --help "+
"show this information.");
err.println(" -V, --version "+
"output version information and exit.");
err.println(" -v, --verbose "+
"be verbose (multiple times means more verbose).");
err.println(" -c, --classpath <path> "+
"search for classes in specified classpath.");
err.println(" "+
"The directories should be separated by ','.");
err.println(" -d, --dest <dir> "+
"write decompiled files to disk into directory destdir.");
err.println(" -s, --style {sun|gnu} "+
"specify indentation style");
err.println(" -i, --import <pkglimit>,<clslimit>");
err.println(" "+
"import classes used more than clslimit times");
err.println(" "+
"and packages with more then pkglimit used classes.");
err.println(" "+
"Limit 0 means, never import, default is 0,1.");
err.println("The following options can be turned on or off with `yes' or `no' argument.");
err.println(" --inner "+
"decompile inner classes (default).");
err.println(" --anonymous "+
"decompile anonymous classes (default).");
err.println(" --contrafo "+
"transform constructors of inner classes (default).");
err.println(" --lvt "+
"use the local variable table (default).");
err.println(" --pretty "+
"use `pretty' names for local variables.");
err.println(" --push "+
"allow PUSH instructions in output.");
err.println(" --decrypt "+
"decrypt encrypted strings (default).");
err.println(" --onetime "+
"remove locals, that are used only one time.");
err.println(" --immediate "+
"output source immediately (may produce buggy code).");
err.println(" --verify "+
"verify code before decompiling it.");
err.println("Debugging options, mainly used to debug this decompiler:");
err.println(" -D, --debug=... "+
"use --debug=help for more information.");
}
public static boolean handleOption(int option, int longind, String arg) {
if (arg == null)
options ^= 1 << option;
else if ("yes".startsWith(arg) || arg.equals("on"))
options |= 1 << option;
else if ("no".startsWith(arg) || arg.equals("off"))
options &= ~(1 << option);
else {
GlobalOptions.err.println
("jode.decompiler.Main: option --"+longOptions[longind].getName()
+" takes one of `yes', `no', `on', `off' as parameter");
return false;
}
return true;
}
public static void main(String[] params) {
if (params.length == 0) {
usage();
return;
}
String classPath = System.getProperty("java.class.path")
.replace(File.pathSeparatorChar, SearchPath.altPathSeparatorChar);
String destDir = null;
int importPackageLimit = ImportHandler.DEFAULT_PACKAGE_LIMIT;
int importClassLimit = ImportHandler.DEFAULT_CLASS_LIMIT;;
GlobalOptions.err.println(GlobalOptions.copyright);
boolean errorInParams = false;
Getopt g = new Getopt("jode.decompiler.Main", params, "hVvc:d:D:i:s:",
longOptions, true);
for (int opt = g.getopt(); opt != -1; opt = g.getopt()) {
switch(opt) {
case 0:
break;
case 'h':
usage();
errorInParams = true;
break;
case 'V':
GlobalOptions.err.println(GlobalOptions.version);
break;
case 'c':
classPath = g.getOptarg();
break;
case 'd':
destDir = g.getOptarg();
break;
case 'v': {
String arg = g.getOptarg();
if (arg == null)
GlobalOptions.verboseLevel++;
else {
try {
GlobalOptions.verboseLevel = Integer.parseInt(arg);
} catch (NumberFormatException ex) {
GlobalOptions.err.println
("jode.decompiler.Main: Argument `"
+arg+"' to --verbose must be numeric:");
errorInParams = true;
}
}
break;
}
case 'D': {
String arg = g.getOptarg();
if (arg == null)
arg = "help";
errorInParams |= !GlobalOptions.setDebugging(arg);
break;
}
case 's': {
String arg = g.getOptarg();
if ("sun".startsWith(arg))
outputStyle = SUN_STYLE;
else if ("gnu".startsWith(arg))
outputStyle = GNU_STYLE;
else {
GlobalOptions.err.println
("jode.decompiler.Main: Unknown style `"+arg+"'.");
errorInParams = true;
}
break;
}
case 'i': {
String arg = g.getOptarg();
int comma = arg.indexOf(',');
try {
int packLimit = Integer.parseInt(arg.substring(0, comma));
if (packLimit == 0)
packLimit = Integer.MAX_VALUE;
if (packLimit < 0)
throw new IllegalArgumentException();
int clazzLimit = Integer.parseInt(arg.substring(comma+1));
if (clazzLimit == 0)
clazzLimit = Integer.MAX_VALUE;
if (clazzLimit < 0)
throw new IllegalArgumentException();
importPackageLimit = packLimit;
importClassLimit = clazzLimit;
} catch (RuntimeException ex) {
GlobalOptions.err.println
("jode.decompiler.Main: Invalid argument for -i option.");
errorInParams = true;
}
break;
}
default:
if (opt >= OPTION_START && opt <= OPTION_END) {
errorInParams |= !handleOption(opt-OPTION_START,
g.getLongind(),
g.getOptarg());
} else
errorInParams = true;
break;
}
}
if (errorInParams)
return;
ClassInfo.setClassPath(classPath.toString());
ImportHandler imports = new ImportHandler(importPackageLimit,
importClassLimit);
ZipOutputStream destZip = null;
TabbedPrintWriter writer = null;
if (destDir == null)
writer = new TabbedPrintWriter(System.out, imports);
else if (destDir.toLowerCase().endsWith(".zip")
|| destDir.toLowerCase().endsWith(".jar")) {
try {
destZip = new ZipOutputStream(new FileOutputStream(destDir));
} catch (IOException ex) {
GlobalOptions.err.println("Can't open zip file "+destDir);
ex.printStackTrace(GlobalOptions.err);
return;
}
writer = new TabbedPrintWriter(new BufferedOutputStream(destZip),
imports, false);
}
for (int i= g.getOptind(); i< params.length; i++) {
try {
ClassInfo clazz;
try {
clazz = ClassInfo.forName(params[i]);
} catch (IllegalArgumentException ex) {
GlobalOptions.err.println
("`"+params[i]+"' is not a class name");
continue;
}
if (skipClass(clazz))
continue;
String filename =
params[i].replace('.', File.separatorChar)+".java";
if (destZip != null) {
writer.flush();
destZip.putNextEntry(new ZipEntry(filename));
} else if (destDir != null) {
File file = new File (destDir, filename);
File directory = new File(file.getParent());
if (!directory.exists() && !directory.mkdirs()) {
GlobalOptions.err.println
("Could not create directory "
+ directory.getPath() + ", check permissions.");
}
writer = new TabbedPrintWriter
(new BufferedOutputStream(new FileOutputStream(file)),
imports, false);
}
GlobalOptions.err.println(params[i]);
ClassAnalyzer clazzAna = new ClassAnalyzer(clazz, imports);
clazzAna.dumpJavaFile(writer);
if (destZip != null) {
writer.flush();
destZip.closeEntry();
} else if (destDir != null)
writer.close();
/* Now is a good time to clean up */
System.gc();
} catch (IOException ex) {
GlobalOptions.err.println
("Can't write source of "+params[i]+".");
GlobalOptions.err.println("Check the permissions.");
ex.printStackTrace(GlobalOptions.err);
}
}
if (destZip != null) {
try {
destZip.close();
} catch (IOException ex) {
GlobalOptions.err.println("Can't close Zipfile");
ex.printStackTrace(GlobalOptions.err);
}
}
}
}

@ -12,6 +12,7 @@ BUILD_CLASSPATH = $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB)
MY_JAVA_FILES = \ MY_JAVA_FILES = \
Analyzer.java \ Analyzer.java \
Applet.java \
ClassAnalyzer.java \ ClassAnalyzer.java \
ClassDeclarer.java \ ClassDeclarer.java \
DeadCodeAnalysis.java \ DeadCodeAnalysis.java \
@ -22,12 +23,15 @@ MY_JAVA_FILES = \
LocalVarEntry.java \ LocalVarEntry.java \
LocalVariableRangeList.java \ LocalVariableRangeList.java \
LocalVariableTable.java \ LocalVariableTable.java \
Main.java \
MethodAnalyzer.java \ MethodAnalyzer.java \
Opcodes.java \ Opcodes.java \
Options.java \
OuterValueListener.java \ OuterValueListener.java \
OuterValues.java \ OuterValues.java \
Scope.java \ Scope.java \
TabbedPrintWriter.java TabbedPrintWriter.java \
Window.java
noinst_DATA = $(MY_JAVA_FILES:.java=.class) noinst_DATA = $(MY_JAVA_FILES:.java=.class)
EXTRA_DIST = $(MY_JAVA_FILES) EXTRA_DIST = $(MY_JAVA_FILES)

@ -19,7 +19,6 @@
package jode.decompiler; package jode.decompiler;
import jode.AssertError; import jode.AssertError;
import jode.Decompiler;
import jode.GlobalOptions; import jode.GlobalOptions;
import jode.bytecode.BytecodeInfo; import jode.bytecode.BytecodeInfo;
import jode.bytecode.ClassInfo; import jode.bytecode.ClassInfo;
@ -57,6 +56,7 @@ import @COLLECTIONS@.Map;
import @COLLECTIONS@.Collection; import @COLLECTIONS@.Collection;
import @COLLECTIONS@.ArrayList; import @COLLECTIONS@.ArrayList;
import @COLLECTIONS@.Iterator; import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.Set;
/** /**
* A method analyzer is the main class for analyzation of methods. * A method analyzer is the main class for analyzation of methods.
@ -75,7 +75,7 @@ import @COLLECTIONS@.Iterator;
* <dd>This will determine when to declare variables. For constructors * <dd>This will determine when to declare variables. For constructors
* it will do special transformations like field initialization.</dd> * it will do special transformations like field initialization.</dd>
*/ */
public class MethodAnalyzer implements Analyzer, Scope, ClassDeclarer { public class MethodAnalyzer implements Scope, ClassDeclarer {
/** /**
* The import handler where we should register our types. * The import handler where we should register our types.
*/ */
@ -200,7 +200,7 @@ public class MethodAnalyzer implements Analyzer, Scope, ClassDeclarer {
if (minfo.getBytecode() != null) { if (minfo.getBytecode() != null) {
code = minfo.getBytecode(); code = minfo.getBytecode();
if ((Decompiler.options & Decompiler.OPTION_VERIFY) != 0) { if ((Options.options & Options.OPTION_VERIFY) != 0) {
CodeVerifier verifier CodeVerifier verifier
= new CodeVerifier(getClazz(), minfo, code); = new CodeVerifier(getClazz(), minfo, code);
try { try {
@ -211,7 +211,7 @@ public class MethodAnalyzer implements Analyzer, Scope, ClassDeclarer {
} }
} }
if ((Decompiler.options & Decompiler.OPTION_LVT) != 0) { if ((Options.options & Options.OPTION_LVT) != 0) {
LocalVariableInfo[] localvars = code.getLocalVariableTable(); LocalVariableInfo[] localvars = code.getLocalVariableTable();
if (localvars != null) if (localvars != null)
lvt = new LocalVariableTable(code.getMaxLocals(), lvt = new LocalVariableTable(code.getMaxLocals(),
@ -552,10 +552,10 @@ public class MethodAnalyzer implements Analyzer, Scope, ClassDeclarer {
excHandlers.analyze(); excHandlers.analyze();
methodHeader.analyze(); methodHeader.analyze();
if ((Decompiler.options & Decompiler.OPTION_PUSH) == 0 if ((Options.options & Options.OPTION_PUSH) == 0
&& methodHeader.mapStackToLocal()) && methodHeader.mapStackToLocal())
methodHeader.removePush(); methodHeader.removePush();
if ((Decompiler.options & Decompiler.OPTION_ONETIME) != 0) if ((Options.options & Options.OPTION_ONETIME) != 0)
methodHeader.removeOnetimeLocals(); methodHeader.removeOnetimeLocals();
methodHeader.mergeParams(param); methodHeader.mergeParams(param);
@ -621,29 +621,7 @@ public class MethodAnalyzer implements Analyzer, Scope, ClassDeclarer {
* the types and names of the local variables and where to declare them. * the types and names of the local variables and where to declare them.
* It will also determine where to declare method scoped local variables. * It will also determine where to declare method scoped local variables.
*/ */
public void makeDeclaration() { public void makeDeclaration(Set done) {
for (Enumeration enum = allLocals.elements();
enum.hasMoreElements(); ) {
LocalInfo li = (LocalInfo)enum.nextElement();
if (!li.isShadow())
imports.useType(li.getType());
}
for (int i=0; i < param.length; i++) {
param[i].guessName();
for (int j=0; j < i; j++) {
if (param[j].getName().equals(param[i].getName())) {
/* A name conflict happened. */
param[i].makeNameUnique();
break; /* j */
}
}
}
if (code != null) {
methodHeader.makeDeclaration(param);
methodHeader.simplify();
}
if (innerAnalyzers != null) { if (innerAnalyzers != null) {
for (Enumeration enum = innerAnalyzers.elements(); for (Enumeration enum = innerAnalyzers.elements();
enum.hasMoreElements(); ) { enum.hasMoreElements(); ) {
@ -659,10 +637,38 @@ public class MethodAnalyzer implements Analyzer, Scope, ClassDeclarer {
li.markFinal(); li.markFinal();
} }
} }
classAna.makeDeclaration();
} }
} }
} }
for (Enumeration enum = allLocals.elements();
enum.hasMoreElements(); ) {
LocalInfo li = (LocalInfo)enum.nextElement();
if (!li.isShadow())
imports.useType(li.getType());
}
for (int i=0; i < param.length; i++) {
param[i].guessName();
Iterator doneIter = done.iterator();
while (doneIter.hasNext()) {
Declarable previous = (Declarable) doneIter.next();
if (param[i].getName().equals(previous.getName())) {
/* A name conflict happened. */
param[i].makeNameUnique();
break;
}
}
done.add(param[i]);
}
if (code != null) {
methodHeader.makeDeclaration(done);
methodHeader.simplify();
}
for (int i=0; i < param.length; i++) {
done.remove(param[i]);
// remove the parameters, since we leave the scope
}
} }
/** /**
@ -677,8 +683,8 @@ public class MethodAnalyzer implements Analyzer, Scope, ClassDeclarer {
return true; return true;
if (synth.getKind() >= synth.ACCESSGETFIELD if (synth.getKind() >= synth.ACCESSGETFIELD
&& synth.getKind() <= synth.ACCESSCONSTRUCTOR && synth.getKind() <= synth.ACCESSCONSTRUCTOR
&& (Decompiler.options & Decompiler.OPTION_INNER) != 0 && (Options.options & Options.OPTION_INNER) != 0
&& (Decompiler.options & Decompiler.OPTION_ANON) != 0) && (Options.options & Options.OPTION_ANON) != 0)
return true; return true;
} }
@ -750,7 +756,7 @@ public class MethodAnalyzer implements Analyzer, Scope, ClassDeclarer {
int modifiedModifiers = minfo.getModifiers(); int modifiedModifiers = minfo.getModifiers();
if (isConstructor() && !isStatic() if (isConstructor() && !isStatic()
&& (Decompiler.options & Decompiler.OPTION_CONTRAFO) != 0 && (Options.options & Options.OPTION_CONTRAFO) != 0
&& classAnalyzer.outerValues != null) && classAnalyzer.outerValues != null)
skipParams = classAnalyzer.outerValues.getCount(); skipParams = classAnalyzer.outerValues.getCount();
@ -771,11 +777,6 @@ public class MethodAnalyzer implements Analyzer, Scope, ClassDeclarer {
writer.pushScope(this); writer.pushScope(this);
if (minfo.isSynthetic()
&& (classAnalyzer.getName() != null
|| !isConstructor()))
writer.print("/*synthetic*/ ");
/* /*
* JLS-1.0, section 9.4: * JLS-1.0, section 9.4:
* *
@ -793,15 +794,31 @@ public class MethodAnalyzer implements Analyzer, Scope, ClassDeclarer {
*/ */
if (classAnalyzer.getClazz().isInterface()) if (classAnalyzer.getClazz().isInterface())
modifiedModifiers &= ~Modifier.ABSTRACT; modifiedModifiers &= ~Modifier.ABSTRACT;
/* Don't ask me why, but jikes declares the static constructor
* as final.
*/
if (isConstructor() && isStatic())
modifiedModifiers &= ~Modifier.FINAL;
String delim ="";
if (minfo.isSynthetic()) {
writer.print("/*synthetic*/");
delim = " ";
}
String modif = Modifier.toString(modifiedModifiers); String modif = Modifier.toString(modifiedModifiers);
writer.print(delim + modif);
if (modif.length() > 0) if (modif.length() > 0)
writer.print(modif+" "); delim = " ";
if (isConstructor if (isConstructor
&& (isStatic() && (isStatic()
|| (classAnalyzer.getName() == null || (classAnalyzer.getName() == null
&& skipParams == methodType.getParameterTypes().length))) { && skipParams == methodType.getParameterTypes().length))) {
/* static block or unnamed constructor */ /* static block or unnamed constructor */
} else { } else {
writer.print(delim);
if (declareAsConstructor) if (declareAsConstructor)
writer.print(classAnalyzer.getName()); writer.print(classAnalyzer.getName());
else { else {

@ -0,0 +1,66 @@
/* Options Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.decompiler;
import jode.bytecode.ClassInfo;
import jode.bytecode.InnerClassInfo;
public class Options {
public static final int TAB_SIZE_MASK = 0x0f;
public static final int BRACE_AT_EOL = 0x10;
public static final int SUN_STYLE = 0x14;
public static final int GNU_STYLE = 0x02;
public static final int OPTION_LVT = 0x0001;
public static final int OPTION_INNER = 0x0002;
public static final int OPTION_ANON = 0x0004;
public static final int OPTION_PUSH = 0x0008;
public static final int OPTION_PRETTY = 0x0010;
public static final int OPTION_DECRYPT = 0x0020;
public static final int OPTION_ONETIME = 0x0040;
public static final int OPTION_IMMEDIATE = 0x0080;
public static final int OPTION_VERIFY = 0x0100;
public static final int OPTION_CONTRAFO = 0x0200;
public static int options =
OPTION_LVT | OPTION_INNER | OPTION_ANON |
OPTION_DECRYPT | OPTION_VERIFY | OPTION_CONTRAFO;
public static int outputStyle = SUN_STYLE;
public final static boolean doAnonymous() {
return (options & OPTION_ANON) != 0;
}
public final static boolean doInner() {
return (options & OPTION_INNER) != 0;
}
public static boolean skipClass(ClassInfo clazz) {
InnerClassInfo[] outers = clazz.getOuterClasses();
if (outers != null) {
if (outers[0].outer == null) {
return doAnonymous();
} else {
return doInner();
}
}
return false;
}
}

@ -20,7 +20,6 @@
package jode.decompiler; package jode.decompiler;
import java.io.*; import java.io.*;
import java.util.Stack; import java.util.Stack;
import jode.Decompiler;
import jode.GlobalOptions; import jode.GlobalOptions;
import jode.bytecode.ClassInfo; import jode.bytecode.ClassInfo;
import jode.bytecode.InnerClassInfo; import jode.bytecode.InnerClassInfo;
@ -39,7 +38,7 @@ public class TabbedPrintWriter {
boolean autoFlush) { boolean autoFlush) {
pw = new PrintWriter(os, autoFlush); pw = new PrintWriter(os, autoFlush);
this.imports = imports; this.imports = imports;
this.indentsize = (Decompiler.outputStyle & Decompiler.TAB_SIZE_MASK); this.indentsize = (Options.outputStyle & Options.TAB_SIZE_MASK);
atbol = true; atbol = true;
} }
@ -47,7 +46,7 @@ public class TabbedPrintWriter {
boolean autoFlush) { boolean autoFlush) {
pw = new PrintWriter(os, autoFlush); pw = new PrintWriter(os, autoFlush);
this.imports = imports; this.imports = imports;
this.indentsize = (Decompiler.outputStyle & Decompiler.TAB_SIZE_MASK); this.indentsize = (Options.outputStyle & Options.TAB_SIZE_MASK);
atbol = true; atbol = true;
} }
@ -129,7 +128,7 @@ public class TabbedPrintWriter {
* brace. It doesn't do a tab stop after opening the brace. * brace. It doesn't do a tab stop after opening the brace.
*/ */
public void openBrace() { public void openBrace() {
if ((Decompiler.outputStyle & Decompiler.BRACE_AT_EOL) != 0) if ((Options.outputStyle & Options.BRACE_AT_EOL) != 0)
if (atbol) if (atbol)
println("{"); println("{");
else else
@ -247,14 +246,14 @@ public class TabbedPrintWriter {
public String getClassString(ClassInfo clazz, int scopeType) { public String getClassString(ClassInfo clazz, int scopeType) {
String name = clazz.getName(); String name = clazz.getName();
if (name.indexOf('$') >= 0) { if (name.indexOf('$') >= 0) {
if ((Decompiler.options & Decompiler.OPTION_INNER) != 0) { if ((Options.options & Options.OPTION_INNER) != 0) {
String innerClassName String innerClassName
= getInnerClassString(clazz, scopeType); = getInnerClassString(clazz, scopeType);
if (innerClassName != null) if (innerClassName != null)
return innerClassName; return innerClassName;
} }
if ((Decompiler.options if ((Options.options
& Decompiler.OPTION_ANON) != 0) { & Options.OPTION_ANON) != 0) {
String innerClassName String innerClassName
= getAnonymousClassString(clazz, scopeType); = getAnonymousClassString(clazz, scopeType);
if (innerClassName != null) if (innerClassName != null)
@ -289,7 +288,7 @@ public class TabbedPrintWriter {
* brace. It doesn't do a tab stop after opening the brace. * brace. It doesn't do a tab stop after opening the brace.
*/ */
public void openBraceNoSpace() { public void openBraceNoSpace() {
if ((Decompiler.outputStyle & Decompiler.BRACE_AT_EOL) != 0) if ((Options.outputStyle & Options.BRACE_AT_EOL) != 0)
println("{"); println("{");
else { else {
if (!atbol) if (!atbol)
@ -301,7 +300,7 @@ public class TabbedPrintWriter {
} }
public void closeBraceContinue() { public void closeBraceContinue() {
if ((Decompiler.outputStyle & Decompiler.BRACE_AT_EOL) != 0) if ((Options.outputStyle & Options.BRACE_AT_EOL) != 0)
print("} "); print("} ");
else { else {
println("}"); println("}");
@ -311,7 +310,7 @@ public class TabbedPrintWriter {
} }
public void closeBraceNoSpace() { public void closeBraceNoSpace() {
if ((Decompiler.outputStyle & Decompiler.BRACE_AT_EOL) != 0) if ((Options.outputStyle & Options.BRACE_AT_EOL) != 0)
print("}"); print("}");
else { else {
println("}"); println("}");
@ -321,7 +320,7 @@ public class TabbedPrintWriter {
} }
public void closeBrace() { public void closeBrace() {
if ((Decompiler.outputStyle & Decompiler.BRACE_AT_EOL) != 0) if ((Options.outputStyle & Options.BRACE_AT_EOL) != 0)
println("}"); println("}");
else { else {
println("}"); println("}");

@ -0,0 +1,310 @@
/* Window Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.decompiler;
import java.applet.*;
import java.awt.*;
///#ifndef AWT10
import java.awt.event.*;
///#endif
import java.io.*;
import jode.bytecode.ClassInfo;
import jode.bytecode.SearchPath;
import jode.GlobalOptions;
public class Window
implements Runnable
///#ifndef AWT10
, ActionListener
///#endif
{
TextField classpathField, classField;
TextArea sourcecodeArea, errorArea;
Checkbox verboseCheck, prettyCheck;
Button startButton, saveButton;
String lastClassName;
Frame frame;
Thread decompileThread;
public Window(Container window) {
buildComponents(window);
}
private void buildComponents(Container window) {
if (window instanceof Frame)
frame = (Frame) window;
window.setFont(new Font("dialog", Font.PLAIN, 10));
classpathField = new TextField(50);
classField = new TextField(50);
sourcecodeArea = new TextArea(20, 80);
errorArea = new TextArea(3, 80);
verboseCheck = new Checkbox("verbose", false);
prettyCheck = new Checkbox("pretty", false);
startButton = new Button("start");
saveButton = new Button("save");
///#ifdef AWT10
/// saveButton.disable();
///#else
saveButton.setEnabled(false);
///#endif
sourcecodeArea.setEditable(false);
errorArea.setEditable(false);
Font monospaced = new Font("monospaced", Font.PLAIN, 10);
sourcecodeArea.setFont(monospaced);
errorArea.setFont(monospaced);
GridBagLayout gbl = new GridBagLayout();
window.setLayout(gbl);
GridBagConstraints labelConstr = new GridBagConstraints();
GridBagConstraints textConstr = new GridBagConstraints();
GridBagConstraints areaConstr = new GridBagConstraints();
GridBagConstraints checkConstr = new GridBagConstraints();
GridBagConstraints buttonConstr = new GridBagConstraints();
labelConstr.fill = GridBagConstraints.NONE;
textConstr.fill = GridBagConstraints.HORIZONTAL;
areaConstr.fill = GridBagConstraints.BOTH;
checkConstr.fill = GridBagConstraints.NONE;
buttonConstr.fill = GridBagConstraints.NONE;
labelConstr.anchor = GridBagConstraints.EAST;
textConstr.anchor = GridBagConstraints.CENTER;
checkConstr.anchor = GridBagConstraints.WEST;
buttonConstr.anchor = GridBagConstraints.CENTER;
labelConstr.anchor = GridBagConstraints.EAST;
textConstr.gridwidth = GridBagConstraints.REMAINDER;
textConstr.weightx = 1.0;
areaConstr.gridwidth = GridBagConstraints.REMAINDER;
areaConstr.weightx = 1.0;
areaConstr.weighty = 1.0;
///#ifdef AWT10
/// Label label = new Label("class path: ");
/// gbl.setConstraints(label, labelConstr);
/// window.add(label);
/// gbl.setConstraints(classpathField, textConstr);
/// window.add(classpathField);
/// label = new Label("class name: ");
/// gbl.setConstraints(label, labelConstr);
/// window.add(label);
/// gbl.setConstraints(classField, textConstr);
/// window.add(classField);
/// gbl.setConstraints(verboseCheck, checkConstr);
/// window.add(verboseCheck);
/// gbl.setConstraints(prettyCheck, checkConstr);
/// window.add(prettyCheck);
/// labelConstr.weightx = 1.0;
/// label = new Label();
/// gbl.setConstraints(label, labelConstr);
/// window.add(label);
/// gbl.setConstraints(startButton, buttonConstr);
/// window.add(startButton);
/// buttonConstr.gridwidth = GridBagConstraints.REMAINDER;
/// gbl.setConstraints(saveButton, buttonConstr);
/// window.add(saveButton);
/// gbl.setConstraints(sourcecodeArea, areaConstr);
/// window.add(sourcecodeArea);
/// areaConstr.gridheight = GridBagConstraints.REMAINDER;
/// areaConstr.weighty = 0.0;
/// gbl.setConstraints(errorArea, areaConstr);
/// window.add(errorArea);
///#else
window.add(new Label("class path: "), labelConstr);
window.add(classpathField, textConstr);
window.add(new Label("class name: "), labelConstr);
window.add(classField, textConstr);
window.add(verboseCheck, checkConstr);
window.add(prettyCheck, checkConstr);
labelConstr.weightx = 1.0;
window.add(new Label(), labelConstr);
window.add(startButton, buttonConstr);
buttonConstr.gridwidth = GridBagConstraints.REMAINDER;
window.add(saveButton, buttonConstr);
window.add(sourcecodeArea, areaConstr);
areaConstr.gridheight = GridBagConstraints.REMAINDER;
areaConstr.weighty = 0.0;
window.add(errorArea, areaConstr);
startButton.addActionListener(this);
saveButton.addActionListener(this);
///#endif
GlobalOptions.err = new PrintWriter(new AreaWriter(errorArea));
}
public void setClasspath(String cp) {
classpathField.setText(cp);
}
public void setClass(String cls) {
classField.setText(cls);
}
///#ifdef AWT10
/// public synchronized void action(Event e, Object target) {
///#else
public synchronized void actionPerformed(ActionEvent e) {
Object target = e.getSource();
///#endif
if (target == startButton) {
///#ifdef AWT10
/// startButton.disable();
///#else
startButton.setEnabled(false);
///#endif
decompileThread = new Thread(this);
sourcecodeArea.setText("Please wait, while decompiling...\n");
decompileThread.start();
} else if (target == saveButton) {
if (frame == null)
frame = new Frame(); //XXX
FileDialog fd = new FileDialog(frame,
"Save decompiled code",
FileDialog.SAVE);
fd.setFile(lastClassName.substring
(lastClassName.lastIndexOf('.')+1).concat(".java"));
fd.show();
String fileName = fd.getFile();
if (fileName == null)
return;
try {
File f = new File(new File(fd.getDirectory()), fileName);
FileWriter out = new FileWriter(f);
out.write(sourcecodeArea.getText());
out.close();
} catch (IOException ex) {
errorArea.setText("");
GlobalOptions.err.println("Couldn't write to file "
+ fileName + ": ");
ex.printStackTrace(GlobalOptions.err);
} catch (SecurityException ex) {
errorArea.setText("");
GlobalOptions.err.println("Couldn't write to file "
+ fileName + ": ");
ex.printStackTrace(GlobalOptions.err);
}
}
}
public class AreaWriter extends Writer {
boolean initialized = false;
private TextArea area;
public AreaWriter(TextArea a) {
area = a;
}
public void write(char[] b, int off, int len) throws IOException {
if (!initialized) {
area.setText("");
initialized = true;
}
///#ifdef AWT10
/// area.appendText(new String(b, off, len));
///#else
area.append(new String(b, off, len));
///#endif
}
public void flush() {
}
public void close() {
}
}
public void run() {
GlobalOptions.verboseLevel = verboseCheck.getState() ? 1 : 0;
if (prettyCheck.getState())
Options.options |= Options.OPTION_PRETTY;
else
Options.options &= ~Options.OPTION_PRETTY;
errorArea.setText("");
///#ifdef AWT10
/// saveButton.disable();
///#else
saveButton.setEnabled(false);
///#endif
lastClassName = classField.getText();
ClassInfo.setClassPath(classpathField.getText());
ImportHandler imports = new ImportHandler();
try {
ClassInfo clazz;
try {
clazz = ClassInfo.forName(lastClassName);
} catch (IllegalArgumentException ex) {
sourcecodeArea.setText
("`"+lastClassName+"' is not a class name\n"
+"You have to give a full qualified classname "
+"with '.' as package delimiter \n"
+"and without .class ending");
return;
}
TabbedPrintWriter writer =
new TabbedPrintWriter(new AreaWriter(sourcecodeArea), imports);
ClassAnalyzer clazzAna = new ClassAnalyzer(null, clazz, imports);
clazzAna.dumpJavaFile(writer);
///#ifdef AWT10
/// saveButton.enable();
///#else
saveButton.setEnabled(true);
///#endif
} catch (Throwable t) {
sourcecodeArea.setText("Didn't succeed.\n"
+"Check the below area for more info.");
t.printStackTrace();
} finally {
synchronized(this) {
decompileThread = null;
///#ifdef AWT10
/// startButton.enable();
///#else
startButton.setEnabled(true);
///#endif
}
}
}
public static void main(String argv[]) {
Frame frame = new Frame(GlobalOptions.copyright);
Window win = new Window(frame);
String cp = System.getProperty("java.class.path");
if (cp != null)
win.setClasspath(cp.replace(File.pathSeparatorChar,
SearchPath.altPathSeparatorChar));
String cls = win.getClass().getName();
win.setClass(cls);
///#ifndef AWT10
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
///#endif
frame.pack();
frame.show();
}
}
Loading…
Cancel
Save