From 9ce95e120a3f958c25201eb91b2ee157f12fbc65 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 30 Jan 2000 16:44:03 +0000 Subject: [PATCH] New Decompiler/ProgressListener interface bug fix in blockInitializers (now uses StructuredBlocks) Makefile optimized git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1217 379699f6-c40d-0410-875b-85095c16579e --- jode/jode/decompiler/Applet.java | 3 +- jode/jode/decompiler/ClassAnalyzer.java.in | 185 +++++++++++++++---- jode/jode/decompiler/Decompiler.java | 193 ++++++++++++++++++++ jode/jode/decompiler/Makefile.am | 6 +- jode/jode/decompiler/MethodAnalyzer.java.in | 85 ++++++--- jode/jode/decompiler/Options.java | 2 +- jode/jode/decompiler/ProgressListener.java | 44 +++++ jode/jode/decompiler/Window.java | 40 ++-- 8 files changed, 475 insertions(+), 83 deletions(-) create mode 100644 jode/jode/decompiler/Decompiler.java create mode 100644 jode/jode/decompiler/ProgressListener.java diff --git a/jode/jode/decompiler/Applet.java b/jode/jode/decompiler/Applet.java index 545d6ae..c758b3d 100644 --- a/jode/jode/decompiler/Applet.java +++ b/jode/jode/decompiler/Applet.java @@ -32,10 +32,9 @@ public class Applet extends java.applet.Applet { public void init() { String cp = getParameter("classpath"); if (cp != null) - jodeWin.setClasspath(cp); + jodeWin.setClassPath(cp); String cls = getParameter("class"); if (cls != null) jodeWin.setClass(cls); } } - diff --git a/jode/jode/decompiler/ClassAnalyzer.java.in b/jode/jode/decompiler/ClassAnalyzer.java.in index f83c730..ce89427 100644 --- a/jode/jode/decompiler/ClassAnalyzer.java.in +++ b/jode/jode/decompiler/ClassAnalyzer.java.in @@ -30,8 +30,7 @@ import jode.expr.Expression; import jode.expr.ThisOperator; import jode.flow.TransformConstructors; import jode.flow.StructuredBlock; -import jode.flow.FlowBlock; -import jode.flow.VariableSet; +import jode.util.SimpleSet; import java.lang.reflect.Modifier; import java.util.NoSuchElementException; @@ -43,14 +42,26 @@ import @COLLECTIONS@.Collection; import @COLLECTIONS@.Set; public class ClassAnalyzer - implements Analyzer, Scope, Declarable, ClassDeclarer + implements Scope, Declarable, ClassDeclarer { ImportHandler imports; ClassInfo clazz; ClassDeclarer parent; + ProgressListener progressListener; + + /** + * The complexity for initi#alizing a class. + */ + private static double INITIALIZE_COMPLEXITY = 0.03; + /** + * The minimal visible complexity. + */ + private static double STEP_COMPLEXITY = 0.03; + double methodComplexity = 0.0; + double innerComplexity = 0.0; String name; - FlowBlock[] blockInitializers; + StructuredBlock[] blockInitializers; FieldAnalyzer[] fields; MethodAnalyzer[] methods; ClassAnalyzer[] inners; @@ -169,8 +180,8 @@ public class ClassAnalyzer public void addBlockInitializer(int index, StructuredBlock initializer) { if (blockInitializers[index] == null) - blockInitializers[index] = new FlowBlock(null, 0); - blockInitializers[index].appendBlock(initializer, 0); + blockInitializers[index] = initializer; + blockInitializers[index].appendBlock(initializer); } public void initialize() { @@ -206,7 +217,7 @@ public class ClassAnalyzer fields = new FieldAnalyzer[finfos.length]; methods = new MethodAnalyzer[minfos.length]; - blockInitializers = new FlowBlock[finfos.length+1]; + blockInitializers = new StructuredBlock[finfos.length+1]; for (int j=0; j < finfos.length; j++) fields[j] = new FieldAnalyzer(this, finfos[j], imports); @@ -221,6 +232,7 @@ public class ClassAnalyzer else constrVector.addElement(methods[j]); } + methodComplexity += methods[j].getComplexity(); } constructors = new MethodAnalyzer[constrVector.size()]; @@ -229,12 +241,25 @@ public class ClassAnalyzer // initialize the inner classes. for (int j=0; j < inners.length; j++) { inners[j].initialize(); + innerComplexity += inners[j].getComplexity(); } } - public void analyze() { + /** + * Gets the complexity of this class. Must be called after it has + * been initialized. This is used for a nice progress bar. + */ + public double getComplexity() { + return (methodComplexity + innerComplexity); + } + + public void analyze(ProgressListener pl, double done, double scale) { if (GlobalOptions.verboseLevel > 0) - GlobalOptions.err.println("Class " + clazz.getName()); + GlobalOptions.err.println("Class " + name); + double subScale = scale / methodComplexity; + if (pl != null) + pl.updateProgress(done, name); + imports.useClass(clazz); if (clazz.getSuperclass() != null) imports.useClass(clazz.getSuperclass()); @@ -254,12 +279,37 @@ public class ClassAnalyzer constrAna = null; if (constructors.length > 0) { for (int j=0; j< constructors.length; j++) - constructors[j].analyze(); + { + if (pl != null) { + double constrCompl = constructors[j].getComplexity() + * subScale; + if (constrCompl > STEP_COMPLEXITY) + constructors[j].analyze(pl, done, constrCompl); + else { + pl.updateProgress(done, name); + constructors[j].analyze(null, 0.0, 0.0); + } + done += constrCompl; + } else + constructors[j].analyze(null, 0.0, 0.0); + } constrAna = new TransformConstructors(this, false, constructors); constrAna.removeSynthInitializers(); } - if (staticConstructor != null) - staticConstructor.analyze(); + if (staticConstructor != null) { + if (pl != null) { + double constrCompl + = staticConstructor.getComplexity() * subScale; + if (constrCompl > STEP_COMPLEXITY) + staticConstructor.analyze(pl, done, constrCompl); + else { + pl.updateProgress(done, name); + staticConstructor.analyze(null, 0.0, 0.0); + } + done += constrCompl; + } else + staticConstructor.analyze(null, 0.0, 0.0); + } // If output should be immediate, we delay analyzation to output. // Note that this may break anonymous classes, but the user @@ -274,11 +324,24 @@ public class ClassAnalyzer // Now analyze remaining methods. for (int j=0; j < methods.length; j++) { if (!methods[j].isConstructor()) - methods[j].analyze(); + if (pl != null) { + double methodCompl = methods[j].getComplexity() + * subScale; + if (methodCompl > STEP_COMPLEXITY) + methods[j].analyze(pl, done, methodCompl); + else { + pl.updateProgress(done, methods[j].getName()); + methods[j].analyze(null, 0.0, 0.0); + } + done += methodCompl; + } else + methods[j].analyze(null, 0.0, 0.0); } } - public void analyzeInnerClasses() { + public void analyzeInnerClasses(ProgressListener pl, + double done, double scale) { + double subScale = scale / innerComplexity; // If output should be immediate, we delay analyzation to output. // Note that this may break anonymous classes, but the user // has been warned. @@ -287,8 +350,23 @@ public class ClassAnalyzer // Now analyze the inner classes. for (int j=0; j < inners.length; j++) { - inners[j].analyze(); - inners[j].analyzeInnerClasses(); + if (pl != null) { + double innerCompl = inners[j].getComplexity() * subScale; + if (innerCompl > STEP_COMPLEXITY) { + double innerscale = subScale * inners[j].methodComplexity; + inners[j].analyze(pl, done, innerscale); + inners[j].analyzeInnerClasses(null, done + innerscale, + innerCompl - innerscale); + } else { + pl.updateProgress(done, inners[j].name); + inners[j].analyze(null, 0.0, 0.0); + inners[j].analyzeInnerClasses(null, 0.0, 0.0); + } + done += innerCompl; + } else { + inners[j].analyze(null, 0.0, 0.0); + inners[j].analyzeInnerClasses(null, 0.0, 0.0); + } } // Now analyze the method scoped classes. @@ -325,14 +403,23 @@ public class ClassAnalyzer dumpSource(writer); } - public void dumpBlock(TabbedPrintWriter writer) throws IOException + public void dumpBlock(TabbedPrintWriter writer) + throws IOException { + dumpBlock(writer, null, 0.0, 0.0); + } + + public void dumpBlock(TabbedPrintWriter writer, + ProgressListener pl, double done, double scale) + throws IOException + { + double subScale = scale / getComplexity(); writer.pushScope(this); boolean needFieldNewLine = false; boolean needNewLine = false; Set declared = null; if ((Options.options & Options.OPTION_IMMEDIATE) != 0) - declared = new VariableSet(); + declared = new SimpleSet(); for (int i=0; i< fields.length; i++) { if (blockInitializers[i] != null) { if (needNewLine) @@ -372,19 +459,29 @@ public class ClassAnalyzer if ((Options.options & Options.OPTION_IMMEDIATE) != 0) { // We now do the analyzation we skipped before. - inners[i].analyze(); - inners[i].analyzeInnerClasses(); + inners[i].analyze(null, 0.0, 0.0); + inners[i].analyzeInnerClasses(null, 0.0, 0.0); inners[i].makeDeclaration(declared); } - inners[i].dumpSource(writer); + if (pl != null) { + double innerCompl = inners[i].getComplexity() * subScale; + if (innerCompl > STEP_COMPLEXITY) + inners[i].dumpSource(writer, pl, done, innerCompl); + else { + pl.updateProgress(done, name); + inners[i].dumpSource(writer); + } + done += innerCompl; + } else + inners[i].dumpSource(writer); needNewLine = true; } for (int i=0; i< methods.length; i++) { if ((Options.options & Options.OPTION_IMMEDIATE) != 0) { // We now do the analyzation we skipped before. if (!methods[i].isConstructor()) - methods[i].analyze(); + methods[i].analyze(null, 0.0, 0.0); methods[i].analyzeInnerClasses(); methods[i].makeDeclaration(declared); } @@ -393,13 +490,28 @@ public class ClassAnalyzer continue; if (needNewLine) writer.println(""); - methods[i].dumpSource(writer); + + if (pl != null) { + double methodCompl = methods[i].getComplexity() * subScale; + pl.updateProgress(done, methods[i].getName()); + methods[i].dumpSource(writer); + done += methodCompl; + } else + methods[i].dumpSource(writer); needNewLine = true; } writer.popScope(); } - public void dumpSource(TabbedPrintWriter writer) throws IOException + public void dumpSource(TabbedPrintWriter writer) + throws IOException + { + dumpSource(writer, null, 0.0, 0.0); + } + + public void dumpSource(TabbedPrintWriter writer, + ProgressListener pl, double done, double scale) + throws IOException { if (fields == null) { /* This means that the class could not be loaded. @@ -449,7 +561,7 @@ public class ClassAnalyzer writer.openBrace(); writer.tab(); - dumpBlock(writer); + dumpBlock(writer, pl, done, scale); writer.untab(); if (parent instanceof MethodAnalyzer) { /* This is a method scope class */ @@ -459,16 +571,27 @@ public class ClassAnalyzer clazz.dropInfo(clazz.KNOWNATTRIBS | clazz.UNKNOWNATTRIBS); } - public void dumpJavaFile(TabbedPrintWriter writer) throws IOException { + public void dumpJavaFile(TabbedPrintWriter writer) + throws IOException { + dumpJavaFile(writer, null); + } + + public void dumpJavaFile(TabbedPrintWriter writer, ProgressListener pl) + throws IOException { imports.init(clazz.getName()); LocalInfo.init(); initialize(); - analyze(); - analyzeInnerClasses(); - makeDeclaration(new VariableSet()); - + double done = 0.05; + double scale = (0.75) * methodComplexity + / (methodComplexity + innerComplexity); + analyze(pl, INITIALIZE_COMPLEXITY, scale); + done += scale; + analyzeInnerClasses(pl, done, 0.8 - done); + makeDeclaration(new SimpleSet()); imports.dumpHeader(writer); - dumpSource(writer); + dumpSource(writer, pl, 0.8, 0.2); + if (pl != null) + pl.updateProgress(1.0, name); } public boolean isScopeOf(Object obj, int scopeType) { diff --git a/jode/jode/decompiler/Decompiler.java b/jode/jode/decompiler/Decompiler.java new file mode 100644 index 0000000..937cc33 --- /dev/null +++ b/jode/jode/decompiler/Decompiler.java @@ -0,0 +1,193 @@ +/* Decompiler Copyright (C) 2000 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.GlobalOptions; +import jode.bytecode.SearchPath; +import jode.bytecode.ClassInfo; +import java.io.File; +import java.io.PrintWriter; +import java.io.Writer; +import java.io.BufferedWriter; + +/** + * This is the interface that other java classes may use to decompile + * classes. Feel free to use it in your own GNU GPL'ed project. + * Please tell me about your project.
+ * + * Note that the GNU GPL doesn't allow you to use this interface in + * commercial programs. + * + * @author Jochen Hoenicke + * @version 1.0 + */ +public class Decompiler { + private SearchPath searchPath = null; + private int importPackageLimit = ImportHandler.DEFAULT_PACKAGE_LIMIT; + private int importClassLimit = ImportHandler.DEFAULT_CLASS_LIMIT; + + /** + * We need a different pathSeparatorChar, since ':' (used for most + * UNIX System) is used a protocol separator in URLs. + * + * We currently allow both pathSeparatorChar and + * altPathSeparatorChar and decide if it is a protocol separator + * by context. + */ + public static final char altPathSeparatorChar + = SearchPath.altPathSeparatorChar; + + /** + * Create a new decompiler. + */ + public Decompiler() { + } + + /** + * Sets the class path. Should be called once before decompile is + * called, otherwise the system class path is used. + * @param classpath A comma separated classpath. + * @exception NullPointerException if classpath is null. + * @see #setClassPath(String[]) + */ + public void setClassPath(String classpath) { + searchPath = new SearchPath(classpath); + } + + /** + * Set the class path. Should be called once before decompile is + * called, otherwise the system class path is used. + * @param classpath a non empty array of jar files and directories; + * URLs are allowed, too. + * @exception NullPointerException if classpath is null. + * @exception IndexOutOfBoundsException if classpath array is empty. + * @see #setClassPath(String) + */ + public void setClassPath(String[] classpath) { + StringBuffer sb = new StringBuffer(classpath[0]); + for (int i = 1; i < classpath.length; i++) + sb.append(altPathSeparatorChar).append(classpath[i]); + searchPath = new SearchPath(sb.toString()); + } + + private static final String[] optionStrings = { + "lvt", "inner", "anonymous", "push", "pretty", "decrypt", + "onetime", "immediate", "verify", "contrafo" + }; + + /** + * Set an option. + * @param option the option (pretty, style, decrypt, verify, etc.) + * @param value ("1"/"0" for on/off, "sun"/"gnu" for style) + * @exception IllegalArgumentException if option or value is invalid. + */ + public void setOption(String option, String value) { + if (option.equals("style")) { + if (value.equals("gnu")) + Options.outputStyle = Options.GNU_STYLE; + else if (value.equals("sun")) + Options.outputStyle = Options.SUN_STYLE; + else + throw new IllegalArgumentException("Invalid style "+value); + return; + } + if (option.equals("import")) { + int comma = value.indexOf(','); + int packLimit = Integer.parseInt(value.substring(0, comma)); + if (packLimit == 0) + packLimit = Integer.MAX_VALUE; + int clazzLimit = Integer.parseInt(value.substring(comma+1)); + if (clazzLimit == 0) + clazzLimit = Integer.MAX_VALUE; + if (clazzLimit < 0 || packLimit < 0) + throw new IllegalArgumentException + ("Option import doesn't allow negative parameters"); + importPackageLimit = packLimit; + importClassLimit = clazzLimit; + return; + } + if (option.equals("verbose")) { + GlobalOptions.verboseLevel = Integer.parseInt(value); + return; + } + for (int i=0; i < optionStrings.length; i++) { + if (option.equals(optionStrings[i])) { + if (value.equals("0") + || value.equals("off") + || value.equals("no")) + Options.options &= ~(1 << i); + else if (value.equals("1") + || value.equals("on") + || value.equals("yes")) + Options.options &= ~(1 << i); + else + throw new IllegalArgumentException("Illegal value for "+ + option); + return; + } + } + throw new IllegalArgumentException("Illegal option: "+option); + } + + + /** + * Set the stream where copyright and warnings/errors are printed + * to. + * @param errorStream the error stream. Note that this is a + * PrintWriter, not a PrintStream (which are deprecated since 1.1). + */ + public void setErr(PrintWriter errorStream) { + GlobalOptions.err = errorStream; + } + + /** + * Decompile a class. + * @param className full-qualified classname, dot separated, e.g. + * "java.lang.Object" + * @param writer The stream where the decompiled code should be + * written. Hint: Use a BufferedWriter for good performance. + * @param progress A progress listener (see below). Null if you + * don't need information about progress. + * @exception IllegalArgumentException if className isn't correct. + * @exception jode.jvm.VerifyException The code + * isn't valid or a dependent class, needed for type + * guessing, couldn't be found. + * @exception IOException if writer throws an exception. + * @exception RuntimeException If jode has a bug ;-) + */ + public void decompile(String className, Writer writer, + ProgressListener progress) + throws java.io.IOException { + if (searchPath == null) { + String classPath = System.getProperty("java.class.path") + .replace(File.pathSeparatorChar, altPathSeparatorChar); + searchPath = new SearchPath(classPath); + } + + ClassInfo.setClassPath(searchPath); + ClassInfo clazz = ClassInfo.forName(className); + ImportHandler imports = new ImportHandler(importPackageLimit, + importClassLimit); + TabbedPrintWriter tabbedWriter = + new TabbedPrintWriter(writer, imports, false); + ClassAnalyzer clazzAna = new ClassAnalyzer(null, clazz, imports); + clazzAna.dumpJavaFile(tabbedWriter, progress); + writer.flush(); + } +} diff --git a/jode/jode/decompiler/Makefile.am b/jode/jode/decompiler/Makefile.am index be2ae92..a67e4ce 100644 --- a/jode/jode/decompiler/Makefile.am +++ b/jode/jode/decompiler/Makefile.am @@ -8,7 +8,7 @@ JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\ CLASSPATH = @CLASSPATH@ CLASSLIB = @CLASSLIB@ SUBSTCP = @SUBSTCP@ -BUILD_CLASSPATH = $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB) +FULL_CLASSPATH := $(shell $(SUBSTCP) $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB)) MY_JAVA_FILES = \ Analyzer.java \ @@ -17,6 +17,7 @@ MY_JAVA_FILES = \ ClassDeclarer.java \ DeadCodeAnalysis.java \ Declarable.java \ + Decompiler.java \ FieldAnalyzer.java \ ImportHandler.java \ LocalInfo.java \ @@ -29,6 +30,7 @@ MY_JAVA_FILES = \ Options.java \ OuterValueListener.java \ OuterValues.java \ + ProgressListener.java \ Scope.java \ TabbedPrintWriter.java \ Window.java @@ -39,7 +41,7 @@ EXTRA_DIST = $(MY_JAVA_FILES) @QUOTE@-include Makefile.dep %.class: %.java - $(JAVAC) -classpath `$(SUBSTCP) $(BUILD_CLASSPATH):$(CLASSLIB)` -d $(top_builddir) $< + $(JAVAC) -classpath $(FULL_CLASSPATH) -d $(top_builddir) $< Makefile.dep: $(MY_JAVA_FILES:.java=.class) $(JAVADEP) $^ diff --git a/jode/jode/decompiler/MethodAnalyzer.java.in b/jode/jode/decompiler/MethodAnalyzer.java.in index b13a8ca..0092891 100644 --- a/jode/jode/decompiler/MethodAnalyzer.java.in +++ b/jode/jode/decompiler/MethodAnalyzer.java.in @@ -76,6 +76,10 @@ import @COLLECTIONS@.Set; * it will do special transformations like field initialization. */ public class MethodAnalyzer implements Scope, ClassDeclarer { + /** + * The minimal visible complexity. + */ + private static double STEP_COMPLEXITY = 0.01; /** * The import handler where we should register our types. */ @@ -199,24 +203,6 @@ public class MethodAnalyzer implements Scope, ClassDeclarer { if (minfo.getBytecode() != null) { code = minfo.getBytecode(); - - if ((Options.options & Options.OPTION_VERIFY) != 0) { - CodeVerifier verifier - = new CodeVerifier(getClazz(), minfo, code); - try { - verifier.verify(); - } catch (VerifyException ex) { - ex.printStackTrace(GlobalOptions.err); - throw new jode.AssertError("Verification error"); - } - } - - if ((Options.options & Options.OPTION_LVT) != 0) { - LocalVariableInfo[] localvars = code.getLocalVariableTable(); - if (localvars != null) - lvt = new LocalVariableTable(code.getMaxLocals(), - localvars); - } } String[] excattr = minfo.getExceptions(); if (excattr == null) { @@ -440,14 +426,32 @@ public class MethodAnalyzer implements Scope, ClassDeclarer { return li; } + /** + * Gets the complexity of this class. Must be called after it has + * been initialized. This is used for a nice progress bar. + */ + public double getComplexity() { + if (code == null) + return 0.0; + else + return code.getInstructions().size(); + } + /** * Analyzes the code of this method. This creates the * flow blocks (including methodHeader) and analyzes them. */ - private void analyzeCode() + private void analyzeCode(ProgressListener pl, double done, double scale) { + int instrsPerStep = Integer.MAX_VALUE; if (GlobalOptions.verboseLevel > 0) GlobalOptions.err.print(methodName+": "); + + if (pl != null) { + instrsPerStep = (int) ((code.getInstructions().size() + * STEP_COMPLEXITY) / (scale * 0.9)); + } + /* The adjacent analyzation relies on this */ DeadCodeAnalysis.removeDeadCode(code); Handler[] handlers = code.getExceptionHandlers(); @@ -487,6 +491,7 @@ public class MethodAnalyzer implements Scope, ClassDeclarer { * second has no predecessors. */ int mark = 1000; + int count = 0; FlowBlock lastBlock = null; boolean lastSequential = false; for (Iterator i = code.getInstructions().iterator(); @@ -500,6 +505,12 @@ public class MethodAnalyzer implements Scope, ClassDeclarer { GlobalOptions.err.print('.'); mark += 1000; } + if (++count >= instrsPerStep) { + done += count * scale / code.getInstructions().size(); + pl.updateProgress(done, methodName); + count = 0; + } + if (lastSequential && instr.getTmpInfo() == null /* Only merge with previous block, if this is sequential, @@ -562,15 +573,41 @@ public class MethodAnalyzer implements Scope, ClassDeclarer { if (GlobalOptions.verboseLevel > 0) GlobalOptions.err.println(""); + if (pl != null) { + done += 0.1 * scale; + pl.updateProgress(done, methodName); + } } /** * This is the first pass of the analyzation. It will analyze the * code of this method, but not the method scoped classes. */ - public void analyze() + public void analyze(ProgressListener pl, double done, double scale) throws ClassFormatError { + if (pl != null) + pl.updateProgress(done, methodName); + if (code != null) { + if ((Options.options & Options.OPTION_VERIFY) != 0) { + CodeVerifier verifier + = new CodeVerifier(getClazz(), minfo, code); + try { + verifier.verify(); + } catch (VerifyException ex) { + ex.printStackTrace(GlobalOptions.err); + throw new jode.AssertError("Verification error"); + } + } + + if ((Options.options & Options.OPTION_LVT) != 0) { + LocalVariableInfo[] localvars = code.getLocalVariableTable(); + if (localvars != null) + lvt = new LocalVariableTable(code.getMaxLocals(), + localvars); + } + } + Type[] paramTypes = getType().getParameterTypes(); int paramCount = (isStatic() ? 0 : 1) + paramTypes.length; param = new LocalInfo[paramCount]; @@ -598,14 +635,14 @@ public class MethodAnalyzer implements Scope, ClassDeclarer { imports.useType(methodType.getReturnType()); if (code != null) - analyzeCode(); + analyzeCode(pl, done, scale); } /** * This is the second pass of the analyzation. It will analyze * the method scoped classes. */ - public void analyzeInnerClasses() + public void analyzeInnerClasses() throws ClassFormatError { int serialnr = 0; @@ -984,8 +1021,8 @@ public class MethodAnalyzer implements Scope, ClassDeclarer { outerValueArray); addClassAnalyzer(anonAnalyzer); anonAnalyzer.initialize(); - anonAnalyzer.analyze(); - anonAnalyzer.analyzeInnerClasses(); + anonAnalyzer.analyze(null, 0.0, 0.0); + anonAnalyzer.analyzeInnerClasses(null, 0.0, 0.0); } else { /* * Get the previously created outerValues and diff --git a/jode/jode/decompiler/Options.java b/jode/jode/decompiler/Options.java index e7f0661..a083181 100644 --- a/jode/jode/decompiler/Options.java +++ b/jode/jode/decompiler/Options.java @@ -39,7 +39,7 @@ public class Options { public static final int OPTION_CONTRAFO = 0x0200; public static int options = - OPTION_LVT | OPTION_INNER | OPTION_ANON | + OPTION_LVT | OPTION_INNER | OPTION_ANON | OPTION_PRETTY | OPTION_DECRYPT | OPTION_VERIFY | OPTION_CONTRAFO; public static int outputStyle = SUN_STYLE; diff --git a/jode/jode/decompiler/ProgressListener.java b/jode/jode/decompiler/ProgressListener.java new file mode 100644 index 0000000..c1f08f1 --- /dev/null +++ b/jode/jode/decompiler/ProgressListener.java @@ -0,0 +1,44 @@ +/* ProgressListener Copyright (C) 2000 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.GlobalOptions; +import jode.bytecode.SearchPath; +import jode.bytecode.ClassInfo; +import java.io.File; +import java.io.PrintWriter; +import java.io.Writer; +import java.io.BufferedWriter; + +/** + * This interface is used by jode to tell about its progress. You + * supply an instance of this interface to the + * {@link Decompiler.decompile} method.
+ * + * @author Jochen Hoenicke + * @version 1.0 */ +public interface ProgressListener { + /** + * Gets called when jode makes some progress. + * @param progress A number between 0.0 and 1.0 + * @param detail + * The name of the currently decompiled method or class. + */ + public void updateProgress(double progress, String detail); +} diff --git a/jode/jode/decompiler/Window.java b/jode/jode/decompiler/Window.java index 6002253..3478633 100644 --- a/jode/jode/decompiler/Window.java +++ b/jode/jode/decompiler/Window.java @@ -24,8 +24,6 @@ import java.awt.*; import java.awt.event.*; ///#endif import java.io.*; -import jode.bytecode.ClassInfo; -import jode.bytecode.SearchPath; import jode.GlobalOptions; public class Window @@ -42,6 +40,8 @@ public class Window String lastClassName; Frame frame; + PrintWriter errStream; + Decompiler decompiler = new Decompiler(); Thread decompileThread; public Window(Container window) { @@ -147,10 +147,11 @@ public class Window startButton.addActionListener(this); saveButton.addActionListener(this); ///#endif - GlobalOptions.err = new PrintWriter(new AreaWriter(errorArea)); + errStream = new PrintWriter(new AreaWriter(errorArea)); + decompiler.setErr(errStream); } - public void setClasspath(String cp) { + public void setClassPath(String cp) { classpathField.setText(cp); } public void setClass(String cls) { @@ -192,14 +193,14 @@ public class Window out.close(); } catch (IOException ex) { errorArea.setText(""); - GlobalOptions.err.println("Couldn't write to file " + errStream.println("Couldn't write to file " + fileName + ": "); - ex.printStackTrace(GlobalOptions.err); + ex.printStackTrace(errStream); } catch (SecurityException ex) { errorArea.setText(""); - GlobalOptions.err.println("Couldn't write to file " + errStream.println("Couldn't write to file " + fileName + ": "); - ex.printStackTrace(GlobalOptions.err); + ex.printStackTrace(errStream); } } } @@ -232,11 +233,11 @@ public class Window } public void run() { - GlobalOptions.verboseLevel = verboseCheck.getState() ? 1 : 0; + decompiler.setOption("verbose", verboseCheck.getState() ? "1" : "0"); if (prettyCheck.getState()) - Options.options |= Options.OPTION_PRETTY; + decompiler.setOption("pretty", "0"); else - Options.options &= ~Options.OPTION_PRETTY; + decompiler.setOption("pretty", "1"); errorArea.setText(""); ///#ifdef AWT10 /// saveButton.disable(); @@ -245,12 +246,11 @@ public class Window ///#endif lastClassName = classField.getText(); - ClassInfo.setClassPath(classpathField.getText()); - ImportHandler imports = new ImportHandler(); + decompiler.setClassPath(classpathField.getText()); try { - ClassInfo clazz; + Writer writer = new AreaWriter(sourcecodeArea); try { - clazz = ClassInfo.forName(lastClassName); + decompiler.decompile(lastClassName, writer, null); } catch (IllegalArgumentException ex) { sourcecodeArea.setText ("`"+lastClassName+"' is not a class name\n" @@ -259,12 +259,6 @@ public class Window +"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 @@ -292,8 +286,8 @@ public class Window String cp = System.getProperty("java.class.path"); if (cp != null) - win.setClasspath(cp.replace(File.pathSeparatorChar, - SearchPath.altPathSeparatorChar)); + win.setClassPath(cp.replace(File.pathSeparatorChar, + Decompiler.altPathSeparatorChar)); String cls = win.getClass().getName(); win.setClass(cls);