Use gnu.getopt package to parse the options.

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1037 379699f6-c40d-0410-875b-85095c16579e
branch_1_1
jochen 26 years ago
parent aace74ecc2
commit efdfcbf7bc
  1. 296
      jode/jode/Decompiler.java

@ -25,6 +25,9 @@ import jode.bytecode.InnerClassInfo;
import jode.decompiler.*; import jode.decompiler.*;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import gnu.getopt.LongOpt;
import gnu.getopt.Getopt;
public class Decompiler { public class Decompiler {
public final static int TAB_SIZE_MASK = 0x0f; public final static int TAB_SIZE_MASK = 0x0f;
@ -47,10 +50,38 @@ public class Decompiler {
OPTION_LVT | OPTION_INNER | OPTION_ANON | OPTION_LVT | OPTION_INNER | OPTION_ANON |
OPTION_DECRYPT | OPTION_VERIFY | OPTION_CONTRAFO; OPTION_DECRYPT | OPTION_VERIFY | OPTION_CONTRAFO;
public static final String[] optionNames = { private static final int OPTION_START=100;
"lvt", "inner", "anonymous", "push", private static final int OPTION_END =200;
"pretty", "decrypt", "onetime", "immediate", private static final LongOpt[] longOptions = new LongOpt[] {
"verify", "contrafo" 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 int outputStyle = SUN_STYLE; public static int outputStyle = SUN_STYLE;
@ -58,52 +89,69 @@ public class Decompiler {
public static void usage() { public static void usage() {
PrintWriter err = GlobalOptions.err; PrintWriter err = GlobalOptions.err;
err.println("Version: " + GlobalOptions.version); err.println("Version: " + GlobalOptions.version);
err.print("use: jode [-v]" err.println("Usage: java jode.Decompiler [OPTIONS]... [CLASSES]...");
+"[--cp <classpath>][--dest <destdir>]" err.println(" -h, --help "+
+"[--import <pkglimit> <clslimit>]"); "show this information.");
for (int i=0; i < optionNames.length; i++) err.println(" -v, --verbose "+
err.print("[--[no]"+optionNames[i]+"]");
err.println("[--debug=...] class1 [class2 ...]");
err.println("\t-v "+
"be verbose (multiple times means more verbose)."); "be verbose (multiple times means more verbose).");
err.println("\t--cp <classpath> "+ err.println(" -c, --classpath <path> "+
"search for classes in specified classpath."); "search for classes in specified classpath.");
err.println("\t "+ err.println(" "+
"The paths should be separated by ','."); "The directories should be separated by ','.");
err.println("\t--dest <destdir> "+ err.println(" -d, --dest <dir> "+
"write decompiled files to disk into directory destdir."); "write decompiled files to disk into directory destdir.");
err.println("\t--style {sun|gnu}"+ err.println(" -s, --style {sun|gnu} "+
" specifies indentation style"); "specify indentation style");
err.println("\t--import <pkglimit> <clslimit>"); err.println(" -i, --import <pkglimit>,<clslimit>");
err.println("\t "+ err.println(" "+
"import classes used more than clslimit times"); "import classes used more than clslimit times");
err.println("\t "+ err.println(" "+
"and packages with more then pkglimit used classes"); "and packages with more then pkglimit used classes.");
err.println("\t--[no]inner "+ err.println(" "+
"[don't] decompile inner classes."); "Limit 0 means, never import, default is 0,1.");
err.println("\t--[no]anonymous "+
"[don't] decompile anonymous classes."); err.println("The following options can be turned on or off with `yes' or `no' argument.");
err.println("\t--[no]contrafo "+ err.println(" --inner "+
"[don't] transform constructors of inner classes."); "decompile inner classes (default).");
err.println("\t--[no]lvt "+ err.println(" --anonymous "+
"[don't] use the local variable table."); "decompile anonymous classes (default).");
err.println("\t--[no]pretty "+ err.println(" --contrafo "+
"[don't] use `pretty' names for local variables."); "transform constructors of inner classes (default).");
err.println("\t--[no]push "+ err.println(" --lvt "+
"[replace] PUSH instructions [with compilable code]."); "use the local variable table (default).");
err.println("\t--[no]decrypt "+ err.println(" --pretty "+
"[don't] try to decrypt encrypted strings."); "use `pretty' names for local variables.");
err.println("\t--[no]onetime "+ err.println(" --push "+
"[don't] remove locals, that are used only one time."); "allow PUSH instructions in output.");
err.println("\t--[no]immediate "+ err.println(" --decrypt "+
"[don't] output source immediately with wrong import."); "decrypt encrypted strings (default).");
err.println("\t--[no]verify "+ err.println(" --onetime "+
"[don't] verify code before decompiling it."); "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("Debugging options, mainly used to debug this decompiler:");
err.println("\t--debug=... "+ err.println(" -D, --debug=... "+
"use --debug=help for more information."); "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: option --"+longOptions[longind].getName()
+" takes one of `yes', `no', `on', `off' as parameter");
return false;
}
return true;
}
public static boolean skipClass(ClassInfo clazz) { public static boolean skipClass(ClassInfo clazz) {
InnerClassInfo[] outers = clazz.getOuterClasses(); InnerClassInfo[] outers = clazz.getOuterClasses();
if (outers != null) { if (outers != null) {
@ -117,99 +165,123 @@ public class Decompiler {
} }
public static void main(String[] params) { public static void main(String[] params) {
int i; if (params.length == 0) {
usage();
return;
}
String classPath = System.getProperty("java.class.path") String classPath = System.getProperty("java.class.path")
.replace(File.pathSeparatorChar, SearchPath.pathSeparatorChar); .replace(File.pathSeparatorChar, SearchPath.pathSeparatorChar);
File destDir = null; String destDir = null;
ZipOutputStream destZip = null;
int importPackageLimit = ImportHandler.DEFAULT_PACKAGE_LIMIT; int importPackageLimit = ImportHandler.DEFAULT_PACKAGE_LIMIT;
int importClassLimit = ImportHandler.DEFAULT_CLASS_LIMIT;; int importClassLimit = ImportHandler.DEFAULT_CLASS_LIMIT;;
GlobalOptions.err.println(GlobalOptions.copyright); GlobalOptions.err.println(GlobalOptions.copyright);
for (i=0; i<params.length && params[i].startsWith("-"); i++) {
if (params[i].equals("-v")) boolean errorInParams = false;
GlobalOptions.verboseLevel++; Getopt g = new Getopt("jode.Decompiler", params, "hVvc:d:D:i:s:",
else if (params[i].equals("--dest")) longOptions, true);
destDir = new File(params[++i]); for (int opt = g.getopt(); opt != -1; opt = g.getopt()) {
else if (params[i].startsWith("--debug")) { switch(opt) {
String flags; case 0:
if (params[i].startsWith("--debug=")) { break;
flags = params[i].substring(8); case 'h':
} else if (params[i].length() != 7) {
usage(); usage();
return; errorInParams = true;
} else { break;
flags = params[++i]; case 'V':
} GlobalOptions.err.println(GlobalOptions.version);
GlobalOptions.setDebugging(flags); break;
} else if (params[i].equals("--style")) { case 'c':
String style = params[++i]; classPath = g.getOptarg();
if (style.equals("sun")) break;
outputStyle = SUN_STYLE; case 'd':
else if (style.equals("gnu")) destDir = g.getOptarg();
outputStyle = GNU_STYLE; break;
case 'v': {
String arg = g.getOptarg();
if (arg == null)
GlobalOptions.verboseLevel++;
else { else {
GlobalOptions.err.println("Unknown style: "+style); try {
usage(); GlobalOptions.verboseLevel = Integer.parseInt(arg);
return; } catch (NumberFormatException ex) {
GlobalOptions.err.println
("jode.Decompiler: Argument `"
+arg+"' to --verbose must be numeric:");
errorInParams = true;
} }
} else if (params[i].equals("--import")) {
importPackageLimit = Integer.parseInt(params[++i]);
importClassLimit = Integer.parseInt(params[++i]);
} else if (params[i].equals("--cp")) {
classPath = params[++i];
} else if (params[i].equals("--")) {
i++;
break;
} else {
if (params[i].startsWith("--")) {
boolean negated = false;
String optionName = params[i].substring(2);
if (optionName.startsWith("no")) {
optionName = optionName.substring(2);
negated = true;
} }
int index = -1;
for (int j=0; j < optionNames.length; j++) {
if (optionNames[j].startsWith(optionName)) {
if (optionNames[j].equals(optionName)) {
index = j;
break; break;
} }
if (index == -1) { case 'D': {
index = j; String arg = g.getOptarg();
} else { if (arg == null)
index = -2; arg = "help";
errorInParams |= !GlobalOptions.setDebugging(arg);
break; 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: Unknown style `"+arg+"'.");
errorInParams = true;
} }
break;
} }
if (index >= 0) { case 'i': {
if (negated) String arg = g.getOptarg();
options &= ~(1<< index); int comma = arg.indexOf(',');
else try {
options |= 1 << index; int packLimit = Integer.parseInt(arg.substring(0, comma));
continue; 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: Invalid argument for -i option.");
errorInParams = true;
} }
break;
} }
if (!params[i].startsWith("-h") && !params[i].equals("--help")) default:
GlobalOptions.err.println("Unknown option: "+params[i]); if (opt >= OPTION_START && opt <= OPTION_END) {
usage(); errorInParams |= !handleOption(opt-OPTION_START,
return; g.getLongind(),
g.getOptarg());
} else
errorInParams = true;
break;
} }
} }
if (i == params.length) { if (errorInParams)
usage();
return; return;
} ClassInfo.setClassPath(classPath.toString());
ClassInfo.setClassPath(classPath);
ImportHandler imports = new ImportHandler(importPackageLimit, ImportHandler imports = new ImportHandler(importPackageLimit,
importClassLimit); importClassLimit);
ZipOutputStream destZip = null;
TabbedPrintWriter writer = null; TabbedPrintWriter writer = null;
if (destDir == null) if (destDir == null)
writer = new TabbedPrintWriter(System.out, imports); writer = new TabbedPrintWriter(System.out, imports);
else if (destDir.getName().endsWith(".zip")) { else if (destDir.toLowerCase().endsWith(".zip")
|| destDir.toLowerCase().endsWith(".jar")) {
try { try {
destZip = new ZipOutputStream(new FileOutputStream(destDir)); destZip = new ZipOutputStream(new FileOutputStream(destDir));
} catch (IOException ex) { } catch (IOException ex) {
@ -220,7 +292,7 @@ public class Decompiler {
writer = new TabbedPrintWriter(new BufferedOutputStream(destZip), writer = new TabbedPrintWriter(new BufferedOutputStream(destZip),
imports, false); imports, false);
} }
for (; i< params.length; i++) { for (int i= g.getOptind(); i< params.length; i++) {
try { try {
ClassInfo clazz; ClassInfo clazz;
try { try {
@ -238,7 +310,7 @@ public class Decompiler {
if (destZip != null) { if (destZip != null) {
writer.flush(); writer.flush();
destZip.putNextEntry(new ZipEntry(filename)); destZip.putNextEntry(new ZipEntry(filename));
} else if (destDir != null) { } else if (writer == null) {
File file = new File (destDir, filename); File file = new File (destDir, filename);
File directory = new File(file.getParent()); File directory = new File(file.getParent());
if (!directory.exists() && !directory.mkdirs()) { if (!directory.exists() && !directory.mkdirs()) {

Loading…
Cancel
Save