Applied changes from the Jode-1.1 tree.

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1327 379699f6-c40d-0410-875b-85095c16579e
master
hoenicke 24 years ago
parent 9f97289a90
commit c30ac484c5
  1. 57
      jode/ChangeLog
  2. 5
      jode/THANKS
  3. 18
      jode/configure.in
  4. 2
      jode/jode/Makefile.am
  5. 2
      jode/jode/bytecode/ClassInfo.java
  6. 34
      jode/jode/bytecode/ClassPath.java
  7. 9
      jode/jode/decompiler/ClassAnalyzer.java
  8. 118
      jode/jode/decompiler/DeadCodeAnalysis.java
  9. 6
      jode/jode/decompiler/Decompiler.java
  10. 5
      jode/jode/decompiler/FieldAnalyzer.java
  11. 98
      jode/jode/decompiler/LocalInfo.java
  12. 183
      jode/jode/decompiler/Main.java
  13. 8
      jode/jode/decompiler/MethodAnalyzer.java
  14. 97
      jode/jode/decompiler/TabbedPrintWriter.java
  15. 18
      jode/jode/expr/Expression.java
  16. 4
      jode/jode/expr/IfThenElseOperator.java
  17. 53
      jode/jode/expr/InvokeOperator.java
  18. 11
      jode/jode/expr/PopOperator.java
  19. 1
      jode/jode/expr/UnaryOperator.java
  20. 3
      jode/jode/flow/TransformExceptionHandlers.java
  21. 4
      jode/jode/jvm/SyntheticAnalyzer.java
  22. 2
      jode/jode/obfuscator/ConstantRuntimeEnvironment.java
  23. 3
      jode/jode/obfuscator/modules/ConstantAnalyzer.java
  24. 2
      jode/jode/swingui/Main.java
  25. 11
      jode/jode/type/NullType.java

@ -0,0 +1,57 @@
2001-07-15 Jochen Hoenicke <jochen@gnu.org>
Applied patch from Java 1.1 tree:
* jode/expr/Expression.java.in (updateParentTypes): Call setType,
instead of merging the types. Other childs want to know about the
type change as well.
* jode/decompiler/LocalInfo.java (combineWith): Reorganized a bit,
but no changes.
* jode/expr/InvokeOperator.java.in (dumpExpression): Always print
the ThisOperator if a field is from a parent class of an outer
class is used. And always qualify the this operator if not
innermost.
2001-07-14 Jochen Hoenicke <jochen@gnu.org>
Applied patches from the Java 1.1 tree:
* jode/decompiler/TabbedPrintWriter.java: Better gnu style handling:
(openBraceClass) (closeBraceClass)
(openBraceNoIndent) (closeBraceNoIndent): new functions.
(closeBraceNoSpace): Removed.
* jode/decompiler/TabbedPrintWriter.java (GNU_SPACING): new constant.
(printOptionalSpace): Print space for GNU_SPACING.
* jode/decompiler/Options.java (setOptions): changed gnu style
to include GNU_SPACING.
* jode/decompiler/ClassAnalyzer.java.in (dumpSource): Use
open/closeBraceClass.
* jode/decompiler/MethodAnalyzer.java.in (dumpSource): Use
open/closeBraceNoIndent. Call printOptionalSpace.
* jode/decompiler/InvokeOperator.java.in (dumpExpression):
Call printOptionalSpace, use open/closeBraceClass for inner
classes.
* jode/decompiler/UnaryOperator.java (dumpExpression): Call
printOptionalSpace.
Added pascal style from Rolf Howarth <rolf@squarebox.co.uk>
* jode/decompiler/Decompiler.java (setOption): detect pascal option.
* jode/decompiler/TabbedPrintWriter.java (BRACE_FLUSH_LEFT):
new constant.
(openBrace, openBraceContinue, closeBrace, closeBraceNoSpace,
closeBraceContinue): handle flush left.
* jode/type/NullType.java (intersection): Removed, since the
version in ReferenceType is more correct. Before
tNull.isOfType(tRange(X,tNull)) returned false, which lead to
incorrect behaviour in InvokeOperator.needsCast.
* jode/decompiler/FieldAnalyzer.java.in (dumpSource): Removed the
"= null" hack for final fields; it was not correct, since the
field could be initialized in a constructor.
* jode/decompiler/TabbedPrintWriter.java (BreakPoint.endOp):
Simplified the code, copy options always from child.
* jode/expr/InvokeOperator.java (isGetClass): Allow the method to
be declared inside an outer class: We simply check if we can get
the method analyzer.
(simplify): handle unifyParam.
* jode/expr/PopOperator.java (getBreakPenalty): return penalty of
inner expression. (dumpExpression): Call dumpExpression of
subexpression immediately without priority.

@ -0,0 +1,5 @@
Joe Bronkema <joseph.d.bronkema at lmco.com>
Rolf Howarth <rolf at squarebox.co.uk> for pascal indentaton style.
Erik Modén <Erik.Moden at emw.ericsson.se>
Martin Schmitz <m.schmitz at e-sign.com> for finding many bugs in the obfuscator.
zzzeek <classic at io.com>

@ -114,6 +114,13 @@ JODE_CHECK_CLASS(java.lang.Object, $CLASSLIB,
[ AC_MSG_RESULT(no)
AC_MSG_ERROR(Please specify location of core java class library) ])
AC_MSG_CHECKING(for java.lang.ref.WeakReference)
JODE_CHECK_CLASS(java.lang.ref.WeakReference, $CLASSLIB,
[ AC_MSG_RESULT(yes)
JCPPFLAGS="-DJDK12" ],
[ AC_MSG_RESULT(no)
JCPPFLAGS="-DJDK11" ])
AC_MSG_CHECKING(for collection classes)
JODE_CHECK_CLASS(java.util.Set, $CLASSPATH:$CLASSLIB,
[ COLLECTIONS="java.util"
@ -155,6 +162,8 @@ else
fi
AC_SUBST(SWINGUI)
JCPPFLAGS="$JCPPFLAGS -DCOLLECTIONS=$COLLECTIONS -DCOLLECTIONEXTRA=$COLLECTIONEXTRA -DJAVAX_SWING=$JAVAX_SWING"
AC_SUBST(CLASSPATH)
AC_SUBST(JAVAC)
AC_SUBST(JAR)
@ -176,4 +185,11 @@ bin/jode
bin/jode.bat
doc/Makefile
test/Makefile,
[chmod 755 bin/jode])
[chmod 755 bin/jode],
[for i in \$CONFIG_FILES; do
changequote(, )dnl
if [ \$i != \${i%.java} ]; then
changequote([, ])dnl
$PERL $srcdir/jcpp $JCPPFLAGS \$i
fi
done])

@ -1,6 +1,6 @@
## Input file for automake to generate the Makefile.in used by configure
SUBDIRS = util bytecode type jvm expr flow decompiler @SWINGUI@ # obfuscator
SUBDIRS = util bytecode type jvm expr flow decompiler @SWINGUI@ # obfuscator
JAVADEP = $(PERL) -w -s $(top_srcdir)/scripts/javaDependencies.pl \
-subdir=$(subdir) -dependdir=$(top_builddir) \

@ -736,7 +736,7 @@ public final class ClassInfo extends BinaryInfo implements Comparable {
int version = input.readUnsignedShort();
version |= input.readUnsignedShort() << 16;
if (version < (45 << 16 | 0)
|| version > (46 << 16 | 0))
|| version > (47 << 16 | 0))
throw new ClassFormatException("Wrong class version");
/* constant pool */

@ -151,6 +151,10 @@ public class ClassPath {
return false;
}
}
public String toString() {
return "reflection:";
}
}
private class LocalPath extends Path {
@ -212,6 +216,10 @@ public class ClassPath {
}
};
}
public String toString() {
return dir.getName();
}
}
private class ZipPath extends Path {
@ -351,6 +359,10 @@ public class ClassPath {
return direntries.elements();
return null;
}
public String toString() {
return file.getName();
}
}
private class URLPath extends Path {
@ -396,6 +408,10 @@ public class ClassPath {
clazz.read(input, howMuch);
return true;
}
public String toString() {
return base.toString();
}
}
private Path[] paths;
@ -435,8 +451,8 @@ public class ClassPath {
* @see #ClassPath(String[] paths)
*/
public ClassPath(String path, ClassPath fallback) {
this(path);
this.fallback = fallback;
initPath(tokenizeClassPath(path));
}
/**
@ -449,6 +465,10 @@ public class ClassPath {
* @see #ClassPath(String[] paths)
*/
public ClassPath(String path) {
initPath(tokenizeClassPath(path));
}
private String[] tokenizeClassPath(String path) {
// Calculate a good approximation (rounded upwards) of the tokens
// in this path.
int length = 1;
@ -505,7 +525,7 @@ public class ClassPath {
tokens[i] = path.substring(ptr, next);
ptr = next;
}
initPath(tokens);
return tokens;
}
private byte[] readURLZip(URLConnection conn) {
@ -826,4 +846,14 @@ public class ClassPath {
return fallback.loadClass(clazz, howMuch);
return false;
}
public String toString() {
StringBuffer sb = new StringBuffer("ClassPath[");
for (int i = 0; i < paths.length; i++) {
if (paths[i] != null)
sb.append(paths[i]).append(',');
}
sb.append(fallback).append(']');
return sb.toString();
}
}

@ -604,15 +604,12 @@ public class ClassAnalyzer
}
writer.println();
writer.openBrace();
writer.openBraceClass();
writer.tab();
dumpBlock(writer, pl, done, scale);
writer.untab();
if (parent instanceof MethodAnalyzer) {
/* This is a method scope class */
writer.closeBraceNoSpace();
} else
writer.closeBrace();
writer.closeBraceClass();
writer.println();
clazz.drop(clazz.DECLARATIONS);
}

@ -1,118 +0,0 @@
/* DeadCodeAnalysis 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 jode.bytecode.BytecodeInfo;
import jode.bytecode.Instruction;
import jode.bytecode.Handler;
///#def COLLECTIONS java.util
import java.util.Iterator;
///#enddef
public class DeadCodeAnalysis {
private final static String REACHABLE = "R";
private final static String REACHCHANGED = "C";
private static void propagateReachability(BytecodeInfo code) {
boolean changed;
do {
changed = false;
for (Iterator iter = code.getInstructions().iterator();
iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next();
if (instr.getTmpInfo() == REACHCHANGED) {
changed = true;
instr.setTmpInfo(REACHABLE);
Instruction[] succs = instr.getSuccs();
if (succs != null)
for (int i=0; i< succs.length; i++)
if (succs[i].getTmpInfo() == null)
succs[i].setTmpInfo(REACHCHANGED);
if (!instr.doesAlwaysJump()
&& instr.getNextByAddr() != null)
if (instr.getNextByAddr().getTmpInfo() == null)
instr.getNextByAddr().setTmpInfo(REACHCHANGED);
/*XXX code after jsr reachable iff ret is reachable...*/
if (instr.getOpcode() == Opcodes.opc_jsr)
if (instr.getNextByAddr().getTmpInfo() == null)
instr.getNextByAddr().setTmpInfo(REACHCHANGED);
}
}
} while (changed);
}
public static void removeDeadCode(BytecodeInfo code) {
((Instruction) code.getInstructions().get(0)).setTmpInfo(REACHCHANGED);
propagateReachability(code);
Handler[] handlers = code.getExceptionHandlers();
boolean changed;
do {
changed = false;
for (int i=0; i < handlers.length; i++) {
if (handlers[i].catcher.getTmpInfo() == null) {
/* check if the try block is somewhere reachable
* and mark the catcher as reachable then.
*/
for (Instruction instr = handlers[i].start;
instr != null; instr = instr.getNextByAddr()) {
if (instr.getTmpInfo() != null) {
handlers[i].catcher.setTmpInfo(REACHCHANGED);
propagateReachability(code);
changed = true;
break;
}
if (instr == handlers[i].end)
break;
}
}
}
} while (changed);
for (int i=0; i< handlers.length; i++) {
/* A handler is not reachable iff the catcher is not reachable */
if (handlers[i].catcher.getTmpInfo() == null) {
/* This is very seldom, so we can make it slow */
Handler[] newHandlers = new Handler[handlers.length - 1];
System.arraycopy(handlers, 0, newHandlers, 0, i);
System.arraycopy(handlers, i+1, newHandlers, i,
handlers.length - (i+1));
handlers = newHandlers;
code.setExceptionHandlers(newHandlers);
i--;
} else {
/* This works! */
while (handlers[i].start.getTmpInfo() == null)
handlers[i].start = handlers[i].start.getNextByAddr();
while (handlers[i].end.getTmpInfo() == null)
handlers[i].end = handlers[i].end.getPrevByAddr();
}
}
/* Now remove the dead code and clean up tmpInfo */
for (Iterator i = code.getInstructions().iterator(); i.hasNext(); ) {
Instruction instr = (Instruction) i.next();
if (instr.getTmpInfo() != null)
instr.setTmpInfo(null);
else
i.remove();
}
}
}

@ -116,11 +116,15 @@ public class Decompiler {
public void setOption(String option, String value) {
if (option.equals("style")) {
if (value.equals("gnu")) {
outputStyle = 0;
outputStyle = TabbedPrintWriter.GNU_SPACING
| TabbedPrintWriter.INDENT_BRACES;
indentSize = 2;
} else if (value.equals("sun")) {
outputStyle = TabbedPrintWriter.BRACE_AT_EOL;
indentSize = 4;
} else if (value.equals("pascal")) {
outputStyle = 0;
indentSize = 4;
} else
throw new IllegalArgumentException("Invalid style "+value);
return;

@ -189,11 +189,6 @@ public class FieldAnalyzer implements Analyzer {
writer.breakOp();
writer.print(" = ");
constant.dumpExpression(writer.IMPL_PAREN, writer);
} else if ((modifiers & (Modifier.STATIC | Modifier.FINAL))
== (Modifier.STATIC | Modifier.FINAL)) {
/* Static final fields must always be initialized */
writer.breakOp();
writer.print(" = null;");
}
writer.endOp();
writer.println(";");

@ -126,56 +126,58 @@ public class LocalInfo implements Declarable {
* If this is called with ourself nothing will happen.
* @param li the local info that we want to shadow.
*/
public void combineWith(LocalInfo li) {
li = li.getLocalInfo();
if (shadow != null) {
getLocalInfo().combineWith(li);
} else {
if (this != li) {
shadow = li;
if (!nameIsGenerated)
shadow.name = name;
if (constExpr != null) {
if (shadow.constExpr != null)
throw new jode.AssertError
("local has multiple constExpr");
shadow.constExpr = constExpr;
}
public void combineWith(LocalInfo shadow) {
if (this.shadow != null) {
getLocalInfo().combineWith(shadow);
return;
}
// GlobalOptions.err.println("combining "+name+"("+type+") and "
// +shadow.name+"("+shadow.type+")");
shadow.setType(type);
boolean needTypeUpdate = !li.type.equals(type);
java.util.Enumeration enum = operators.elements();
while (enum.hasMoreElements()) {
LocalVarOperator lvo =
(LocalVarOperator) enum.nextElement();
if (needTypeUpdate) {
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_TYPES) != 0)
GlobalOptions.err.println("updating " + lvo);
lvo.updateType();
}
shadow.operators.addElement(lvo);
}
enum = hints.elements();
while (enum.hasMoreElements()) {
Object hint = enum.nextElement();
if (!shadow.hints.contains(hint))
shadow.hints.addElement(hint);
}
shadow = shadow.getLocalInfo();
if (this == shadow)
return;
this.shadow = shadow;
if (!nameIsGenerated)
shadow.name = name;
if (constExpr != null) {
if (shadow.constExpr != null)
throw new jode.AssertError
("local has multiple constExpr");
shadow.constExpr = constExpr;
}
/* Clear unused fields, to allow garbage collection.
*/
type = null;
name = null;
operators = null;
}
}
// GlobalOptions.err.println("combining "+name+"("+type+") and "
// +shadow.name+"("+shadow.type+")");
shadow.setType(type);
boolean needTypeUpdate = !shadow.type.equals(type);
java.util.Enumeration enum = operators.elements();
while (enum.hasMoreElements()) {
LocalVarOperator lvo =
(LocalVarOperator) enum.nextElement();
if (needTypeUpdate) {
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_TYPES) != 0)
GlobalOptions.err.println("updating " + lvo);
lvo.updateType();
}
shadow.operators.addElement(lvo);
}
enum = hints.elements();
while (enum.hasMoreElements()) {
Object hint = enum.nextElement();
if (!shadow.hints.contains(hint))
shadow.hints.addElement(hint);
}
/* Clear unused fields, to allow garbage collection.
*/
type = null;
name = null;
operators = null;
}
/**

@ -29,7 +29,9 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.zip.ZipOutputStream;
import java.util.zip.ZipFile;
import java.util.zip.ZipEntry;
import java.util.Enumeration;
import gnu.getopt.LongOpt;
import gnu.getopt.Getopt;
@ -48,6 +50,7 @@ public class Main extends Options {
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,
@ -73,7 +76,10 @@ public class Main extends Options {
public static void usage() {
PrintWriter err = GlobalOptions.err;
err.println("Version: " + GlobalOptions.version);
err.println("Usage: java jode.decompiler.Main [OPTIONS]... [CLASSES]...");
err.println("Usage: java jode.decompiler.Main [OPTION]* {CLASS|JAR}*");
err.println("Give a fully qualified CLASS name, e.g. jode.decompiler.Main, if you want to");
err.println("decompile a single class, or a JAR file containing many classes.");
err.println("OPTION is any of these:");
err.println(" -h, --help "+
"show this information.");
err.println(" -V, --version "+
@ -86,6 +92,15 @@ public class Main extends Options {
"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.");
}
public static boolean handleOption(int option, int longind, String arg) {
@ -104,6 +119,67 @@ public class Main extends Options {
return true;
}
public static void decompileClass(String className, ClassPath classPath,
String classPathStr,
ZipOutputStream destZip, String destDir,
TabbedPrintWriter writer,
ImportHandler imports) {
try {
ClassInfo clazz;
try {
clazz = classPath.getClassInfo(className);
} catch (IllegalArgumentException ex) {
GlobalOptions.err.println
("`"+className+"' is not a class name");
return;
}
if (skipClass(clazz))
return;
String filename =
className.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(className);
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 (FileNotFoundException ex) {
GlobalOptions.err.println
("Can't read "+ex.getMessage()+".");
GlobalOptions.err.println
("Check the class path ("+classPathStr+
") and check that you use the java class name.");
} catch (IOException ex) {
GlobalOptions.err.println
("Can't write source of "+className+".");
GlobalOptions.err.println("Check the permissions.");
ex.printStackTrace(GlobalOptions.err);
}
}
public static void main(String[] params) {
if (params.length == 0) {
usage();
@ -111,12 +187,21 @@ public class Main extends Options {
}
ClassPath classPath;
String classPathStr = System.getProperty("java.class.path")
.replace(File.pathSeparatorChar, ClassPath.altPathSeparatorChar);
String bootClassPath = System.getProperty("sun.boot.class.path");
if (bootClassPath != null)
classPathStr = classPathStr + ClassPath.altPathSeparatorChar
+ bootClassPath.replace(File.pathSeparatorChar,
ClassPath.altPathSeparatorChar);
String destDir = null;
int importPackageLimit = ImportHandler.DEFAULT_PACKAGE_LIMIT;
int importClassLimit = ImportHandler.DEFAULT_CLASS_LIMIT;;
int outputStyle = TabbedPrintWriter.BRACE_AT_EOL;
int indentSize = 4;
GlobalOptions.err.println(GlobalOptions.copyright);
@ -163,6 +248,25 @@ public class Main extends Options {
errorInParams |= !GlobalOptions.setDebugging(arg);
break;
}
case 's': {
String arg = g.getOptarg();
if (arg.equals("gnu")) {
outputStyle = TabbedPrintWriter.GNU_SPACING
| TabbedPrintWriter.INDENT_BRACES;
indentSize = 2;
} else if (arg.equals("sun")) {
outputStyle = TabbedPrintWriter.BRACE_AT_EOL;
indentSize = 4;
} else if (arg.equals("pascal")) {
outputStyle = 0;
indentSize = 4;
} else {
GlobalOptions.err.println
("jode.decompiler.Main: Unknown style `"+arg+"'.");
errorInParams = true;
}
break;
}
case 'i': {
String arg = g.getOptarg();
int comma = arg.indexOf(',');
@ -208,7 +312,8 @@ public class Main extends Options {
ZipOutputStream destZip = null;
TabbedPrintWriter writer = null;
if (destDir == null)
writer = new TabbedPrintWriter(System.out, imports);
writer = new TabbedPrintWriter(System.out, imports, true,
outputStyle, indentSize, 0, 79);
else if (destDir.toLowerCase().endsWith(".zip")
|| destDir.toLowerCase().endsWith(".jar")) {
try {
@ -219,61 +324,37 @@ public class Main extends Options {
return;
}
writer = new TabbedPrintWriter(new BufferedOutputStream(destZip),
imports, false);
imports, false,
outputStyle, indentSize, 0, 79);
}
for (int i= g.getOptind(); i< params.length; i++) {
try {
ClassInfo clazz;
try {
clazz = classPath.getClassInfo(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.");
if ((params[i].endsWith(".jar") || params[i].endsWith(".zip"))
&& new File(params[i]).isFile()) {
/* The user obviously wants to decompile a jar/zip file.
* Lets do him a pleasure and allow this.
*/
ClassPath zipClassPath
= new ClassPath(params[i], classPath);
Enumeration enum = new ZipFile(params[i]).entries();
while (enum.hasMoreElements()) {
String entry
= ((ZipEntry) enum.nextElement()).getName();
if (entry.endsWith(".class")) {
entry = entry.substring(0, entry.length() - 6)
.replace('/', '.');
decompileClass(entry, zipClassPath, classPathStr,
destZip, destDir,
writer, imports);
}
}
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 (FileNotFoundException ex) {
GlobalOptions.err.println
("Can't read "+ex.getMessage()+".");
GlobalOptions.err.println
("Check the class path ("+classPathStr+
") and check that you use the java class name.");
} else
decompileClass(params[i], classPath, classPathStr,
destZip, destDir,
writer, imports);
} catch (IOException ex) {
GlobalOptions.err.println
("Can't write source of "+params[i]+".");
GlobalOptions.err.println("Check the permissions.");
("Can't read zip file " + params[i] + ".");
ex.printStackTrace(GlobalOptions.err);
}
}

@ -833,6 +833,7 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
writer.print(" " + methodName);
}
writer.breakOp();
writer.printOptionalSpace();
writer.print("(");
writer.startOp(writer.EXPL_PAREN, 0);
int offset = skipParams + (isStatic() ? 0 : 1);
@ -862,11 +863,11 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
}
writer.endOp();
if (bb != null) {
writer.openBrace();
writer.openBraceNoIndent();
writer.tab();
methodHeader.dumpSource(writer);
writer.untab();
writer.closeBrace();
writer.closeBraceNoIndent();
} else
writer.println(";");
writer.popScope();
@ -975,8 +976,7 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
expr).getSubExpressions()[0];
if (expr instanceof ThisOperator) {
outerValueArray[j] =
new ThisOperator(((ThisOperator)
expr).getClassInfo());
new ThisOperator(((ThisOperator) expr).getClassInfo());
continue;
}
LocalInfo li = null;

@ -40,7 +40,9 @@ public class TabbedPrintWriter {
private ImportHandler imports;
private Stack scopes = new Stack();
public static final int BRACE_AT_EOL = 0x10;
public static final int BRACE_AT_EOL = 0x10;
public static final int INDENT_BRACES = 0x20;
public static final int GNU_SPACING = 0x40;
/**
* This string contains a few tab characters followed by tabWidth - 1
@ -132,6 +134,7 @@ public class TabbedPrintWriter {
* our child, if possible.
*/
BreakPoint child = (BreakPoint) childBPs.elementAt(0);
options = child.options;
startPos = child.startPos;
options = child.options;
endPos = child.endPos;
@ -728,69 +731,91 @@ public class TabbedPrintWriter {
return type.toString();
}
public void printOptionalSpace() {
if ((style & GNU_SPACING) != 0)
print(" ");
}
/**
* Print a opening brace with the current indentation style.
* Called at the end of the line of the instance that opens the
* brace. It doesn't do a tab stop after opening the brace.
*/
public void openBrace() {
if ((style & BRACE_AT_EOL) != 0) {
print(currentLine.length() > 0 ? " {" : "{");
boolean bracePrinted = false;
if (currentLine.length() > 0) {
if ((style & BRACE_AT_EOL) != 0) {
print(" {");
bracePrinted = true;
}
println();
} else {
if (currentLine.length() > 0)
println();
if (currentIndent > 0)
tab();
println("{");
}
if ((style & INDENT_BRACES) != 0 && currentIndent > 0)
tab();
if (!bracePrinted)
println("{");
}
public void openBraceClass() {
openBraceNoIndent();
}
/**
* Print a opening brace with the current indentation style.
* Called at the end the line of a method declaration.
*/
public void openBraceNoIndent() {
if (currentLine.length() > 0) {
if ((style & BRACE_AT_EOL) != 0)
print(" ");
else
println();
}
println("{");
}
/**
* Print an opening brace with the current indentation style.
* Called at the end of the line of the instance that opens the
* brace. It doesn't do a tab stop after opening the brace.
*/
public void openBraceNoSpace() {
if ((style & BRACE_AT_EOL) != 0)
println("{");
else {
if (currentLine.length() > 0)
println();
if (currentIndent > 0)
tab();
println("{");
boolean bracePrinted = false;
if (currentLine.length() > 0) {
if ((style & BRACE_AT_EOL) != 0) {
print("{");
bracePrinted = true;
}
println();
}
if ((style & INDENT_BRACES) != 0 && currentIndent > 0)
tab();
if (!bracePrinted)
println("{");
}
public void closeBraceContinue() {
if ((style & BRACE_AT_EOL) != 0)
print("} ");
else {
else
println("}");
if (currentIndent > 0)
untab();
}
if ((style & INDENT_BRACES) != 0 && currentIndent > 0)
untab();
}
public void closeBraceNoSpace() {
if ((style & BRACE_AT_EOL) != 0)
print("}");
else {
println("}");
if (currentIndent > 0)
untab();
}
public void closeBraceClass() {
print("}");
}
public void closeBrace() {
if ((style & BRACE_AT_EOL) != 0)
println("}");
else {
println("}");
if (currentIndent > 0)
untab();
}
println("}");
if ((style & INDENT_BRACES) != 0 && currentIndent > 0)
untab();
}
public void closeBraceNoIndent() {
println("}");
}
public void flush() {

@ -55,23 +55,7 @@ public abstract class Expression {
}
public void updateParentType(Type otherType) {
Type newType = otherType.intersection(type);
if (type.equals(newType))
return;
if (newType == Type.tError) {
if (otherType == Type.tError) {
// Don't propagate type errors.
return;
}
GlobalOptions.err.println("updateParentType: Type error in "
+this+": merging "+getType()
+" and "+otherType);
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_TYPES) != 0)
Thread.dumpStack();
}
type = newType;
setType(otherType);
if (parent != null)
parent.updateType();
}

@ -40,9 +40,9 @@ public class IfThenElseOperator extends Operator {
}
public void updateType() {
Type subType = Type.tSuperType(subExpressions[1].getType())
Type commonType = Type.tSuperType(subExpressions[1].getType())
.intersection(Type.tSuperType(subExpressions[2].getType()));
updateParentType(subType);
updateParentType(commonType);
}
public Expression simplify() {

@ -242,7 +242,7 @@ public final class InvokeOperator extends Operator
}
/**
* Makes a non void expression out of this store instruction.
* Makes a non void expression, in case this is a constructor.
*/
public void makeNonVoid() {
if (type != Type.tVoid)
@ -417,12 +417,12 @@ public final class InvokeOperator extends Operator
* @return true if this is the magic class$ method, false otherwise.
*/
public boolean isGetClass() {
if (isThis()) {
SyntheticAnalyzer synth = getMethodAnalyzer().getSynthetic();
if (synth != null && synth.getKind() == SyntheticAnalyzer.GETCLASS)
return true;
}
return false;
MethodAnalyzer mana = getMethodAnalyzer();
if (mana == null)
return false;
SyntheticAnalyzer synth = getMethodAnalyzer().getSynthetic();
return (synth != null
&& synth.getKind() == SyntheticAnalyzer.GETCLASS);
}
class Environment extends SimpleRuntimeEnvironment {
@ -712,9 +712,10 @@ public final class InvokeOperator extends Operator
}
for (int p = offset; p < paramTypes.length; p++) {
if (!paramTypes[p]
.isOfType(Type.tSubType(otherParamTypes[p-offset])))
.isOfType(Type.tSubType(otherParamTypes[p-offset]))){
/* No conflict here */
continue next_method;
}
}
/* There is a conflict that can be resolved by a cast. */
return true;
@ -1100,30 +1101,19 @@ public final class InvokeOperator extends Operator
ThisOperator thisOp = (ThisOperator) subExpressions[0];
Scope scope = writer.getScope(thisOp.getClassInfo(),
Scope.CLASSSCOPE);
if (writer.conflicts(methodName, scope, Scope.METHODNAME)) {
if (writer.conflicts(methodName, scope, Scope.METHODNAME)
|| (/* This field is inherited from the parent of
* an outer class, or it is inherited from the
* parent of this class and there is a conflicting
* field in some outer class.
*/
getMethodAnalyzer() == null
&& (!isThis() ||
writer.conflicts(methodName, null,
Scope.NOSUPERMETHODNAME)))) {
thisOp.dumpExpression(writer, 950);
writer.breakOp();
writer.print(".");
} else if (/* This is a inherited field conflicting
* with a field name in some outer class.
*/
getMethodAnalyzer() == null
&& writer.conflicts(methodName, null,
Scope.NOSUPERMETHODNAME)) {
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer();
while (ana.getParent() instanceof ClassAnalyzer
&& ana != scope)
ana = (ClassAnalyzer) ana.getParent();
if (ana == scope) {
// For a simple outer class we can say this
writer.print("this");
} else {
// For a class that owns a method that owns
// us, we have to give the full class name
thisOp.dumpExpression(writer, 950);
}
writer.breakOp();
writer.print(".");
}
} else {
if (needsCast(0, paramTypes)){
@ -1150,6 +1140,7 @@ public final class InvokeOperator extends Operator
* We still need to check for casts though.
*/
writer.breakOp();
writer.printOptionalSpace();
writer.print("(");
writer.startOp(writer.EXPL_PAREN, 0);
boolean first = true;
@ -1183,11 +1174,11 @@ public final class InvokeOperator extends Operator
*/
if (anonymousNew) {
Object state = writer.saveOps();
writer.openBrace();
writer.openBraceClass();
writer.tab();
clazzAna.dumpBlock(writer);
writer.untab();
writer.closeBraceNoSpace();
writer.closeBraceClass();
writer.restoreOps(state);
}
}

@ -41,8 +41,17 @@ public class PopOperator extends Operator {
public void updateType() {
}
public int getBreakPenalty() {
if (subExpressions[0] instanceof Operator)
return ((Operator) subExpressions[0]).getBreakPenalty();
return 0;
}
public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
subExpressions[0].dumpExpression(writer, 0);
/* Don't give a priority; we can't allow parents around
* a statement.
*/
subExpressions[0].dumpExpression(writer);
}
}

@ -57,6 +57,7 @@ public class UnaryOperator extends Operator {
public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
writer.print(getOperatorString());
writer.printOptionalSpace();
subExpressions[0].dumpExpression(writer, 700);
}
}

@ -772,9 +772,6 @@ public class TransformExceptionHandlers {
if (subRoutine != null) {
while (subRoutine.analyze(tryFlow.getNextBlockNr(), end));
System.err.println("Finally: "+subRoutine+
" Try: "+tryFlow+
" preds: "+subRoutine.predecessors);
/* Now check if the subroutine is correct and has only the
* catchFlow as predecessor.

@ -52,7 +52,7 @@ public class SyntheticAnalyzer implements Opcodes {
int kind = UNKNOWN;
int unifyParam;
int unifyParam = -1;
Reference reference;
ClassInfo classInfo;
MethodInfo method;
@ -334,7 +334,7 @@ public class SyntheticAnalyzer implements Opcodes {
params++;
slot++;
}
if (instr.getOpcode() == opc_invokespecial) {
if (params > 0 && instr.getOpcode() == opc_invokespecial) {
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)

@ -231,7 +231,7 @@ public class ConstantRuntimeEnvironment extends SimpleRuntimeEnvironment {
if (fi != null && !fi.isNotConstant()) {
Object result = fi.getConstant();
if (result == null)
result = getDefaultValue(ref.getType());
result = TypeSignature.getDefaultValue(ref.getType());
return result;
}
throw new InterpreterException("Field " + ref + " not constant");

@ -1839,8 +1839,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
Handler[] newHandlers = new Handler[newHandlerCtr];
System.arraycopy(blocks, 0, newBlocks, 0, newBlockCtr);
System.arraycopy(handlers, 0, newHandlers, 0, newHandlerCtr);
bb.setBlocks(newBlocks, newStartBlock);
bb.setExceptionHandlers(newHandlers);
bb.setBlocks(newBlocks, newStartBlock, newHandlers);
}
}
}

@ -104,9 +104,11 @@ public class Main
classTree.addTreeSelectionListener(this);
JScrollPane spClassTree = new JScrollPane(classTree);
sourcecodeArea = new JTextArea(20, 80);
sourcecodeArea.setEditable(false);
sourcecodeArea.setFont(monospaced);
JScrollPane spText = new JScrollPane(sourcecodeArea);
errorArea = new JTextArea(3, 80);
errorArea.setEditable(false);
errorArea.setFont(monospaced);
JScrollPane spError = new JScrollPane(errorArea);

@ -83,15 +83,4 @@ public class NullType extends ReferenceType {
public Type findCommonClassTypes(Stack otherTypes) {
throw new UnsupportedOperationException();
}
/**
* Intersect this type with another type and return the new type.
* @param type the other type.
* @return the intersection, or tError, if a type conflict happens.
*/
public Type intersection(Type type) {
if (type == this)
return type;
return tError;
}
}

Loading…
Cancel
Save