/* 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.obfuscator; import jode.bytecode.ClassInfo; import jode.bytecode.SearchPath; import jode.GlobalOptions; import java.util.Vector; import java.util.StringTokenizer; import java.lang.reflect.Modifier; import java.io.PrintWriter; import java.io.File; ///#ifdef JDK12 ///import java.util.Collection; ///import java.util.Arrays; ///import java.util.HashSet; ///#else import jode.util.Collection; import jode.util.Arrays; import jode.util.HashSet; ///#endif public class Main { public static boolean swapOrder = false; public static final int OPTION_STRONGOVERLOAD = 0x0001; public static final int OPTION_PRESERVESERIAL = 0x0002; public static int options = OPTION_PRESERVESERIAL; public static final String[] stripNames = { "unreach", "inner", "lvt", "lnt", "source" }; public static final int STRIP_UNREACH = 0x0001; public static final int STRIP_INNERINFO = 0x0002; public static final int STRIP_LVT = 0x0004; public static final int STRIP_LNT = 0x0008; public static final int STRIP_SOURCE = 0x0010; public static int stripping = 0x1; private static ClassBundle bundle; public static void usage() { PrintWriter err = GlobalOptions.err; err.println("usage: jode.Obfuscator flags* [class | package]*"); err.println("\t-v "+ "Verbose output (allowed multiple times)."); err.println("\t--nostrip "+ "Don't strip not needed methods"); err.println("\t--cp "+ "The class path; should contain classes.zip"); err.println("\t-d,--dest "+ "Destination directory for output classes"); err.println("Preserve options: "); err.println("\t--package "+ "Preserve all package members"); err.println("\t--protected "+ "Preserve all protected members"); err.println("\t--public "+ "Preserve all public members"); err.println("\t--preserve "+ "Preserve only the given name (allowed multiple times)"); err.println("\t--breakserial "+ "Allow the serialized form to change"); err.println("Obfuscating options: "); err.println("\t--rename={strong|weak|unique|none} "+ "Rename identifiers with given scheme"); err.println("\t--strip=... "+ "use --strip=help for more information."); err.println("\t--table "+ "Read (some) translation table from file"); err.println("\t--revtable "+ "Write reversed translation table to file"); err.println("\t--swaporder "+ "Swap the order of fields and methods."); err.println("\t--debug=... "+ "use --debug=help for more information."); } public static void usageStrip() { PrintWriter err = GlobalOptions.err; err.println("Strip options: --strip=flag1,flag2,..."); err.println("possible flags:"); err.println("\tunreach " + "strip all unreachable methods and classes."); err.println("\tinner " + "strip inner classes info."); err.println("\tlvt " + "strip local variable tables."); err.println("\tlnt " + "strip line number tables."); err.println("\tsource " + "strip the name of the source file."); err.println("\tinout " + "show T1/T2 in/out set analysis."); err.println("\tlvt " + "dump LocalVariableTable."); err.println("\tcheck " + "do time consuming sanity checks."); err.println("\tlocals " + "dump local merging information."); err.println("\tconstructors " + "dump constructor simplification."); err.println("\tinterpreter " + "debug execution of interpreter."); System.exit(0); } public static void setStripOptions(String stripString) { if (stripString.length() == 0 || stripString.equals("help")) usageStrip(); StringTokenizer st = new StringTokenizer(stripString, ","); next_token: while (st.hasMoreTokens()) { String token = st.nextToken().intern(); for (int i=0; i < stripNames.length; i++) { if (token == stripNames[i]) { stripping |= 1 << i; continue next_token; } } GlobalOptions.err.println("Illegal strip flag: "+token); usageStrip(); } } public static Renamer getRenamer(String option) { if (option.equals("strong")) return new StrongRenamer ("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); else if (option.equals("weak")) return new StrongRenamer ("abcdefghijklmnopqrstuvwxyz", "0123456789abcdefghijklmnopqrstuvwxyz"); else if (option.equals("unique")) { return new Renamer() { static int serialnr = 0; public String generateName(Identifier ident, String lastName) { return ("xxx" + serialnr++); } }; } else if (option.equals("none")) { return new Renamer() { public String generateName(Identifier ident, String lastName) { String name = ident.getName(); if (lastName == null) return name; int nr = 2; if (lastName.length() > name.length()) nr = 1 + Integer.parseInt (lastName.substring(name.length())); return name + nr; } }; } GlobalOptions.err.println("Incorrect value for --rename option: " + option); usage(); System.exit(0); return null; } public static ClassBundle getClassBundle() { return bundle; } public static CodeAnalyzer createCodeAnalyzer() { return new SimpleAnalyzer() /*XXX*/; } static CodeTransformer[] codeTransformers = { new LocalOptimizer(), new RemovePopAnalyzer() }; public static Collection getCodeTransformers() { return Arrays.asList(codeTransformers); } public static void main(String[] params) { int i; String sourcePath = System.getProperty("java.class.path") .replace(File.pathSeparatorChar, SearchPath.pathSeparatorChar); String destPath = "."; Collection preservedIdents = new HashSet(); ModifierMatcher preserveRule = ModifierMatcher.denyAll; Renamer renamer = null; String table = null; String toTable = null; for (i=0; i