001: package tide.exttools.proguard;
002:
003: import tide.project.*;
004: import tide.editor.*;
005: import javax.swing.*;
006: import java.awt.*;
007: import java.awt.event.*;
008: import javax.swing.border.*;
009: import java.util.*;
010: import java.io.*;
011: import snow.utils.*;
012: import snow.utils.storage.*;
013: import snow.utils.gui.*;
014:
015: /** Todo: start proguardUI if wanted...
016: * [May2007] 4.0b3 and b4 have errors. (Eric Lafortune is analysing...)
017: * and b5 and b6...
018: * ### also when -dontoptimize and -Xss2048k don't work
019: * Todo: look at yWorks obfuscator
020: *
021: * 3.10.1: works (without -optimize)
022: * 4.0: works with -Xss8192k and -dontoptimize
023: *
024: * todo: link refcard at docs/manual/refcard.html
025: * 4.1b1 works...
026: */
027: public class ProGuardSettingsDialog extends JDialog {
028: private final FileField csPath = new FileField("", false,
029: "Give the proguard jar path", JFileChooser.FILES_ONLY);
030: // the map alow later to recover stacktraces
031: private final FileField mapPath = new FileField("", true,
032: "Give the obfuscation map location",
033: JFileChooser.FILES_ONLY);
034: final private JButton viewOpts = new JButton(
035: "Arguments and classes to keep");
036: private boolean analyseAllNow = false;
037: final private JTextField vmOpts = new JTextField(20);
038:
039: final private JButton retraceBT = new JButton("retrace",
040: Icons.sharedWiz);
041:
042: final public static String defaultPGLocation = "c:/java/tools/proguard3.8/lib/proguard.jar";
043:
044: final public static String defaultPGVMOpts = "-Xmx1024m -Xss8192k";
045:
046: public boolean dialogWasAccepted = false;
047:
048: final private JCheckBox cbShrink = new JCheckBox("Shrink", true);
049: final private JCheckBox cbOptim = new JCheckBox("Optimize", false); // NOT STABLE !
050: final private JCheckBox cbObfusc = new JCheckBox("Obfuscate", true);
051:
052: public final static String DEFAULT_ARGS = "#-printseeds # show what is kept."
053: + "\r\n#-verbose # show a lot of internal details."
054: + "\r\n-useuniqueclassmembernames"
055: + "\r\n-dontskipnonpubliclibraryclasses" // solves the problem with ZipConstants and StringBuilder
056: + "\r\n#-overloadaggressively"
057: + "\r\n-defaultpackage ''"
058: + "\r\n-allowaccessmodification"
059:
060: + "\r\n\r\n# produces useful obfuscated stack traces"
061: + "\r\n-renamesourcefileattribute SourceFile"
062: + "\r\n-keepattributes SourceFile, LineNumberTable"
063:
064: + "\r\n\r\n# replace $mainclass with * to keep all classes with main methods, also classes that are not public."
065: + "\r\n-keepclasseswithmembers class $mainclass {"
066: + "\r\n public static void main(java.lang.String[]);\r\n}"
067:
068: + "\r\n\r\n# keep all native methods"
069: + "\r\n-keepclasseswithmembernames class * {"
070: + "\r\n native <methods>;\r\n}\r\n"
071:
072: + "\r\n# keep mbean classes completely (PUT HERE THE BASE PACKAGE OF YOUR MBEANS)"
073: + "\r\n#-keep class management.**"
074:
075: + "\r\n\r\n# keep database drivers"
076: + "\r\n-keep class * implements java.sql.Driver"
077:
078: + "\r\n\r\n# keep UI components"
079: + "\r\n-keep class * extends javax.swing.plaf.ComponentUI {"
080: + "\r\n public static javax.swing.plaf.ComponentUI createUI(javax.swing.JComponent);\r\n}"
081:
082: + "\r\n\r\n# keep enums special methods"
083: + "\r\n-keepclassmembers class * extends java.lang.Enum {"
084: + "\r\n public static **[] values();"
085: + "\r\n public static ** valueOf(java.lang.String);"
086: + "\r\n}"
087:
088: + "\r\n\r\n# keep serializable classes"
089: + "\r\n-keepclassmembers class * implements java.io.Serializable {"
090: + "\r\n static final long serialVersionUID;"
091: + "\r\n private void writeObject(java.io.ObjectOutputStream);"
092: + "\r\n private void readObject(java.io.ObjectInputStream);"
093: + "\r\n java.lang.Object writeReplace();"
094: + "\r\n java.lang.Object readResolve();" + "\r\n}";
095:
096: public final static String proGuardHomepage = "http://proguard.sourceforge.net/";
097:
098: public ProGuardSettingsDialog(final JFrame parent,
099: final ProjectSettings settings) {
100: super (parent, "Proguard shrinker / optimizer / obfuscator",
101: true);
102:
103: JComponent ta = GUIUtils
104: .createReadOnlyDescriptionArea("Proguard is an external tool, download it from "
105: + proGuardHomepage
106: + " and link it below."
107: + "\nProGuard is a free Java class file shrinker, optimizer, and obfuscator. It can detect and remove"
108: + "\nunused classes, fields, methods, and attributes. It can then optimize bytecode and remove"
109: + "\nunused instructions. Finally, it can rename the remaining classes, fields, and methods using short"
110: + "\nmeaningless names. The resulting jars are smaller and harder to reverse-engineer."
111: + "\n\nUSAGE: from the Project menu / create a project jar file (CTRL+J)."
112: + "\n\nCAUTION: If OverflowExceptions araises, you have to tune -Xss vm options and maybe disable the optimization.");
113: add(ta, BorderLayout.NORTH);
114:
115: JPanel inputPanel = new JPanel();
116: add(inputPanel, BorderLayout.CENTER);
117: GridLayout3 gl3 = new GridLayout3(2, inputPanel);
118:
119: JButton help = new JButton("Help", Icons.createHelpIcon(16,
120: true));
121: help.setMargin(new Insets(0, 2, 0, 2));
122: help.setFocusPainted(false);
123: gl3.addSeparator();
124: gl3.add(help);
125: gl3.addSeparator();
126: help.addActionListener(new ActionListener() {
127: public void actionPerformed(ActionEvent ae) {
128: if (csPath.getPath() != null) {
129: try {
130: File local = new File(csPath.getPath()
131: .getParentFile().getParentFile(),
132: "docs/index.html");
133: if (local.exists()) {
134: SysUtils.openBrowser("file://" + local);
135: } else {
136: System.out.println("No local pg help: "
137: + local);
138: SysUtils.openBrowser(proGuardHomepage);
139: }
140: } catch (Exception e) {
141:
142: }
143: }
144: }
145: });
146:
147: gl3.add("ProGuard jar");
148: gl3.add(csPath);
149: csPath.setPath(settings.getProperty("ProGuard_path",
150: defaultPGLocation));
151: if (MainEditorFrame.instance != null) {
152: csPath.offerRememberedGlobalCompletion(
153: MainEditorFrame.instance.globalProperties,
154: "knownProGuards");
155: }
156: csPath.setComponentWidth(350);
157: csPath.setAutoColorized();
158: csPath.allowedExtensions.add("jar");
159: csPath.fileTypeDescription = "ProGuard executable jar";
160:
161: gl3.add("Arguments");
162: viewOpts.setMargin(new Insets(0, 2, 0, 2));
163: viewOpts.setFocusPainted(false);
164: gl3.add(viewOpts);
165: viewOpts.addActionListener(new ActionListener() {
166: public void actionPerformed(ActionEvent ae) {
167: editArguments(settings);
168: }
169: });
170:
171: gl3.add("Map path");
172: gl3.add(mapPath);
173:
174: gl3.add("JVM Options");
175: gl3.add(vmOpts);
176:
177: vmOpts.setText(settings.getProperty("ProGuard_JVMOpts",
178: defaultPGVMOpts));
179:
180: File sh = settings.getSources_Home();
181: if (sh != null) {
182: File defMapFile = new File(settings.getSources_Home()
183: .getParentFile(), "dev/proguard.map");
184: mapPath.setPath(settings.getProperty("ProGuard_mappath", ""
185: + defMapFile.getAbsolutePath()));
186: }
187: mapPath.setComponentWidth(350);
188: mapPath.setAutoColorized();
189: mapPath.allowedExtensions.add("map");
190: mapPath.fileTypeDescription = "ProGuard obfuscation map";
191:
192: gl3.addTitleSeparator("Operations");
193:
194: cbShrink.setSelected(settings.getBooleanProperty(
195: "ProGuard_Shrink", true));
196: cbOptim.setSelected(settings.getBooleanProperty(
197: "ProGuard_Optimize", false)); // NOT STABLE !
198: cbObfusc.setSelected(settings.getBooleanProperty(
199: "ProGuard_Obfuscate", true));
200:
201: gl3.add(cbShrink);
202: gl3.addTF("discards all unused class members");
203: gl3.add(cbOptim);
204: gl3
205: .addTF("deeper remanipulations at bytecode level (may cause StackOverflow)");
206: gl3.add(cbObfusc);
207: gl3
208: .addTF("renames non entry points to make bytecode difficult to reverse engineer");
209:
210: gl3.addTitleSeparator("Retrace");
211:
212: gl3.add(retraceBT);
213: retraceBT.setFocusPainted(false);
214: retraceBT.setMargin(new Insets(0, 1, 0, 1));
215: gl3
216: .addTF("reconstitute a stacktrace from an obfuscated one, using the map above");
217: retraceBT.addActionListener(new ActionListener() {
218: public void actionPerformed(ActionEvent ae) {
219: retraceDialog();
220: }
221: });
222:
223: CloseControlPanel ccp = new CloseControlPanel(this , true, true,
224: "Ok");
225: add(ccp, BorderLayout.SOUTH);
226:
227: pack();
228: this .setLocationRelativeTo(parent);
229: this .setVisible(true); // MODAL => waits
230:
231: if (ccp.getWasCancelled())
232: return;
233:
234: dialogWasAccepted = true;
235:
236: // save settings
237: if (settings != null) {
238: settings.setProperty("ProGuard_path", csPath.getPathName());
239: settings.setProperty("ProGuard_mappath", mapPath
240: .getPathName());
241: settings.setBooleanProperty("ProGuard_Shrink", cbShrink
242: .isSelected());
243: settings.setBooleanProperty("ProGuard_Optimize", cbOptim
244: .isSelected());
245: settings.setBooleanProperty("ProGuard_Obfuscate", cbObfusc
246: .isSelected());
247: settings.setProperty("ProGuard_JVMOpts", vmOpts.getText());
248:
249: csPath.rememberPathForGlobalCompletion(
250: MainEditorFrame.instance.globalProperties,
251: "knownProGuards");
252: }
253: } // Constructor
254:
255: /** @return true if proguard jar is present.
256: Used to detect if a setup dialog should be shown when starting the tool (if not found).
257: */
258: public static boolean isConfigured() {
259: if (MainEditorFrame.instance == null)
260: return false;
261: ProjectSettings actualProject = MainEditorFrame.instance
262: .getActualProject();
263: return new File(actualProject.getProperty("ProGuard_path",
264: defaultPGLocation)).exists(); // cache to avoid filesystem access ?
265: }
266:
267: private void retraceDialog() {
268: JDialog optionsDialog = new JDialog(this ,
269: "Proguard retracing: paste your stacktrace below", true);
270: JTextPane tp = new JTextPane();
271: tp.setFont(MainEditorFrame.fixedWidthFontForProcesses);
272: optionsDialog.add(new JScrollPane(tp), BorderLayout.CENTER);
273: CloseControlPanel ccp = new CloseControlPanel(optionsDialog,
274: true, true, "Retrace");
275: optionsDialog.add(ccp, BorderLayout.SOUTH);
276: optionsDialog.setSize(500, 450);
277: optionsDialog.setLocationRelativeTo(viewOpts);
278: optionsDialog.setVisible(true);
279:
280: if (ccp.getWasCancelled())
281: return;
282: if (!ccp.getWasAccepted())
283: return;
284:
285: try {
286: Retracer.retrace(mapPath.getPath(), tp.getText());
287: } catch (Exception e) {
288: e.printStackTrace();
289: }
290: }
291:
292: void editArguments(final ProjectSettings settings) {
293: final JDialog d = new JDialog(this , "Proguard arguments", true);
294:
295: d
296: .add(
297: GUIUtils
298: .createReadOnlyDescriptionArea("Proguard settings can be customized here. Note that the libraries and in/out jars are automatically set."
299: + "\nPlease read the good Proguard manual and examples and ensure to keep the"
300: + "\nenums, annotations, mbeans, classes created with Class.forName(variable string), RMI, ComponenUIs, ..."
301: + "\n$mainclass will be replaced with the name of the project main class."),
302: BorderLayout.NORTH);
303:
304: JPanel centerPan = new JPanel(new BorderLayout(3, 3));
305: d.add(centerPan, BorderLayout.CENTER);
306:
307: final JTextPane tp = new JTextPane();
308: centerPan.add(new JScrollPane(tp), BorderLayout.CENTER);
309: tp.setText(settings.getProperty("ProGuard_Arguments",
310: DEFAULT_ARGS));
311: tp.setCaretPosition(0);
312: tp.setFont(MainEditorFrame.fixedWidthFontForProcesses);
313:
314: JPanel controlPan = new JPanel(new FlowLayout(FlowLayout.LEFT,
315: 3, 2));
316: centerPan.add(controlPan, BorderLayout.NORTH);
317: JButton resetToDef = GUIUtils
318: .niceMediumButton("Reset to default arguments text");
319: controlPan.add(resetToDef);
320: resetToDef.addActionListener(new ActionListener() {
321: public void actionPerformed(ActionEvent ae) {
322: // ask? no, if one press cancel below, it will keep the old text...
323: tp.setText(DEFAULT_ARGS);
324: tp.setCaretPosition(0);
325: }
326: });
327:
328: // Close panel
329: CloseControlPanel ccp = new CloseControlPanel(d, true, true,
330: "Ok");
331: d.add(ccp, BorderLayout.SOUTH);
332: d.setSize(600, 550);
333: d.setLocationRelativeTo(viewOpts);
334: d.setVisible(true);
335:
336: if (ccp.getWasCancelled())
337: return;
338: if (!ccp.getWasAccepted())
339: return;
340:
341: settings.setProperty("ProGuard_Arguments", tp.getText());
342: }
343:
344: /* test
345: public static void main(String[] aa)
346: {
347: JFrame f = new JFrame("Test");
348: f.setDefaultCloseOperation(f.EXIT_ON_CLOSE);
349: ProjectSettings props = new ProjectSettings();
350: new ProGuardSettingsDialog(f, props);
351: System.exit(0);
352: }*/
353:
354: }
|