mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-03 18:44:46 +00:00
1518 lines
65 KiB
Java
1518 lines
65 KiB
Java
/*
|
|
* Copyright (C) 2010-2015 JPEXS
|
|
*
|
|
* 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package com.jpexs.decompiler.flash.gui;
|
|
|
|
import com.jpexs.decompiler.flash.ApplicationInfo;
|
|
import com.jpexs.decompiler.flash.EventListener;
|
|
import com.jpexs.decompiler.flash.SWF;
|
|
import com.jpexs.decompiler.flash.SWFBundle;
|
|
import com.jpexs.decompiler.flash.SWFSourceInfo;
|
|
import com.jpexs.decompiler.flash.SearchMode;
|
|
import com.jpexs.decompiler.flash.Version;
|
|
import com.jpexs.decompiler.flash.abc.ABC;
|
|
import com.jpexs.decompiler.flash.abc.ClassPath;
|
|
import com.jpexs.decompiler.flash.abc.ScriptPack;
|
|
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
|
import com.jpexs.decompiler.flash.abc.types.Multiname;
|
|
import com.jpexs.decompiler.flash.abc.types.Namespace;
|
|
import com.jpexs.decompiler.flash.configuration.Configuration;
|
|
import com.jpexs.decompiler.flash.console.CommandLineArgumentParser;
|
|
import com.jpexs.decompiler.flash.console.ContextMenuTools;
|
|
import com.jpexs.decompiler.flash.gui.debugger.Debugger;
|
|
import com.jpexs.decompiler.flash.gui.proxy.ProxyFrame;
|
|
import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin;
|
|
import com.jpexs.decompiler.flash.helpers.collections.MyEntry;
|
|
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
|
|
import com.jpexs.decompiler.flash.tags.Tag;
|
|
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
|
import com.jpexs.decompiler.flash.treeitems.SWFList;
|
|
import com.jpexs.helpers.Cache;
|
|
import com.jpexs.helpers.CancellableWorker;
|
|
import com.jpexs.helpers.Helper;
|
|
import com.jpexs.helpers.Path;
|
|
import com.jpexs.helpers.ProgressListener;
|
|
import com.jpexs.helpers.Stopwatch;
|
|
import com.jpexs.helpers.streams.SeekableInputStream;
|
|
import com.sun.jna.Platform;
|
|
import com.sun.jna.platform.win32.Advapi32Util;
|
|
import com.sun.jna.platform.win32.Kernel32;
|
|
import com.sun.jna.platform.win32.WinReg;
|
|
import java.awt.AWTException;
|
|
import java.awt.Frame;
|
|
import java.awt.GraphicsEnvironment;
|
|
import java.awt.MenuItem;
|
|
import java.awt.PopupMenu;
|
|
import java.awt.SystemTray;
|
|
import java.awt.TrayIcon;
|
|
import java.awt.event.ActionEvent;
|
|
import java.awt.event.ActionListener;
|
|
import java.awt.event.MouseAdapter;
|
|
import java.awt.event.MouseEvent;
|
|
import java.io.BufferedInputStream;
|
|
import java.io.BufferedReader;
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.FileOutputStream;
|
|
import java.io.FilenameFilter;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.InputStreamReader;
|
|
import java.io.OutputStream;
|
|
import java.lang.reflect.Field;
|
|
import java.net.Socket;
|
|
import java.net.URLEncoder;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Calendar;
|
|
import java.util.Date;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
import java.util.Map.Entry;
|
|
import java.util.Random;
|
|
import java.util.logging.ConsoleHandler;
|
|
import java.util.logging.FileHandler;
|
|
import java.util.logging.Formatter;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
import java.util.logging.SimpleFormatter;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
import javax.swing.JFileChooser;
|
|
import javax.swing.JFrame;
|
|
import javax.swing.JOptionPane;
|
|
import javax.swing.SwingWorker;
|
|
import javax.swing.UIManager;
|
|
import javax.swing.UnsupportedLookAndFeelException;
|
|
import javax.swing.filechooser.FileFilter;
|
|
|
|
/**
|
|
* Main executable class
|
|
*
|
|
* @author JPEXS
|
|
*/
|
|
public class Main {
|
|
|
|
public static ProxyFrame proxyFrame;
|
|
private static List<SWFSourceInfo> sourceInfos = new ArrayList<>();
|
|
public static LoadingDialog loadingDialog;
|
|
public static ModeFrame modeFrame;
|
|
private static boolean working = false;
|
|
private static TrayIcon trayIcon;
|
|
private static MenuItem stopMenuItem;
|
|
private static MainFrame mainFrame;
|
|
public static final int UPDATE_SYSTEM_MAJOR = 1;
|
|
public static final int UPDATE_SYSTEM_MINOR = 2;
|
|
public static LoadFromMemoryFrame loadFromMemoryFrame;
|
|
public static LoadFromCacheFrame loadFromCacheFrame;
|
|
private static final Logger logger = Logger.getLogger(Main.class.getName());
|
|
private static Debugger debugger;
|
|
public static DebugLogDialog debugDialog;
|
|
public static final String DEBUGGER_PACKAGE = "com.jpexs.decompiler.flash.debugger";
|
|
|
|
private static ABCContainerTag getDebuggerABCTag(SWF swf) {
|
|
for (ABCContainerTag ac : swf.abcList) {
|
|
ABC a = ac.getABC();
|
|
for (MyEntry<ClassPath, ScriptPack> m : a.getScriptPacks()) {
|
|
if (isDebuggerClass(m.getKey().packageStr, null)) {
|
|
return ac;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private static String getDebuggerPackage(SWF swf) {
|
|
ABCContainerTag ac = getDebuggerABCTag(swf);
|
|
if (ac == null) {
|
|
return null;
|
|
}
|
|
ABC a = ac.getABC();
|
|
for (MyEntry<ClassPath, ScriptPack> m : a.getScriptPacks()) {
|
|
if (isDebuggerClass(m.getKey().packageStr, null)) {
|
|
return m.getKey().packageStr;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static boolean hasDebugger(SWF swf) {
|
|
return getDebuggerABCTag(swf) != null;
|
|
}
|
|
|
|
public static void ensureMainFrame() {
|
|
if (mainFrame == null) {
|
|
if (Configuration.useRibbonInterface.get()) {
|
|
mainFrame = new MainFrameRibbon();
|
|
} else {
|
|
mainFrame = new MainFrameClassic();
|
|
}
|
|
mainFrame.getPanel().setErrorState(ErrorLogFrame.getInstance().getErrorState());
|
|
}
|
|
}
|
|
|
|
public static MainFrame getMainFrame() {
|
|
return mainFrame;
|
|
}
|
|
|
|
public static void loadFromCache() {
|
|
if (loadFromCacheFrame == null) {
|
|
loadFromCacheFrame = new LoadFromCacheFrame();
|
|
}
|
|
loadFromCacheFrame.setVisible(true);
|
|
}
|
|
|
|
public static void loadFromMemory() {
|
|
if (loadFromMemoryFrame == null) {
|
|
loadFromMemoryFrame = new LoadFromMemoryFrame(mainFrame);
|
|
}
|
|
loadFromMemoryFrame.setVisible(true);
|
|
}
|
|
|
|
public static void setSubLimiter(boolean value) {
|
|
if (value) {
|
|
AVM2Code.toSourceLimit = Configuration.sublimiter.get();
|
|
} else {
|
|
AVM2Code.toSourceLimit = -1;
|
|
}
|
|
}
|
|
|
|
public static boolean isWorking() {
|
|
return working;
|
|
}
|
|
|
|
public static void startProxy(int port) {
|
|
View.execInEventDispatch(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
if (proxyFrame == null) {
|
|
proxyFrame = new ProxyFrame(mainFrame);
|
|
}
|
|
}
|
|
});
|
|
proxyFrame.setPort(port);
|
|
addTrayIcon();
|
|
switchProxy();
|
|
}
|
|
|
|
public static void showProxy() {
|
|
if (proxyFrame == null) {
|
|
proxyFrame = new ProxyFrame(mainFrame);
|
|
}
|
|
proxyFrame.setVisible(true);
|
|
proxyFrame.setState(Frame.NORMAL);
|
|
}
|
|
|
|
public static void startWork(String name) {
|
|
startWork(name, -1, null);
|
|
}
|
|
|
|
public static void startWork(String name, int percent) {
|
|
startWork(name, percent, null);
|
|
}
|
|
|
|
public static void startWork(String name, CancellableWorker worker) {
|
|
startWork(name, -1, worker);
|
|
}
|
|
|
|
public static void startWork(final String name, final int percent, final CancellableWorker worker) {
|
|
working = true;
|
|
View.execInEventDispatchLater(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
if (mainFrame != null) {
|
|
mainFrame.getPanel().setWorkStatus(name, worker);
|
|
if (percent == -1) {
|
|
mainFrame.getPanel().hidePercent();
|
|
} else {
|
|
mainFrame.getPanel().setPercent(percent);
|
|
}
|
|
}
|
|
if (loadingDialog != null) {
|
|
loadingDialog.setDetail(name);
|
|
if (percent == -1) {
|
|
loadingDialog.hidePercent();
|
|
} else {
|
|
loadingDialog.setPercent(percent);
|
|
}
|
|
}
|
|
if (CommandLineArgumentParser.isCommandLineMode()) {
|
|
System.out.println(name);
|
|
}
|
|
}
|
|
});
|
|
|
|
}
|
|
|
|
public static void stopWork() {
|
|
working = false;
|
|
View.execInEventDispatchLater(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
if (mainFrame != null) {
|
|
mainFrame.getPanel().setWorkStatus("", null);
|
|
}
|
|
if (loadingDialog != null) {
|
|
loadingDialog.setDetail("");
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public static SWFList parseSWF(SWFSourceInfo sourceInfo) throws Exception {
|
|
SWFList result = new SWFList();
|
|
|
|
InputStream inputStream = sourceInfo.getInputStream();
|
|
SWFBundle bundle = null;
|
|
FileInputStream fis = null;
|
|
if (inputStream == null) {
|
|
inputStream = new BufferedInputStream(fis = new FileInputStream(sourceInfo.getFile()));
|
|
bundle = sourceInfo.getBundle(false, SearchMode.ALL);
|
|
logger.log(Level.INFO, "Load file: {0}", sourceInfo.getFile());
|
|
} else if (inputStream instanceof SeekableInputStream
|
|
|| inputStream instanceof BufferedInputStream) {
|
|
try {
|
|
inputStream.reset();
|
|
} catch (IOException ex) {
|
|
logger.log(Level.SEVERE, null, ex);
|
|
}
|
|
logger.log(Level.INFO, "Load stream: {0}", sourceInfo.getFileTitle());
|
|
}
|
|
|
|
Stopwatch sw = Stopwatch.startNew();
|
|
if (bundle != null) {
|
|
result.isBundle = true;
|
|
result.bundleClass = bundle.getClass();
|
|
result.name = new File(sourceInfo.getFileTitleOrName()).getName();
|
|
for (Entry<String, SeekableInputStream> streamEntry : bundle.getAll().entrySet()) {
|
|
InputStream stream = streamEntry.getValue();
|
|
stream.reset();
|
|
SWF swf = new SWF(stream, new ProgressListener() {
|
|
@Override
|
|
public void progress(int p) {
|
|
startWork(AppStrings.translate("work.reading.swf"), p);
|
|
}
|
|
}, Configuration.parallelSpeedUp.get());
|
|
swf.fileTitle = streamEntry.getKey();
|
|
swf.readOnly = true;
|
|
result.add(swf);
|
|
}
|
|
} else {
|
|
SWF swf = new SWF(inputStream, new ProgressListener() {
|
|
@Override
|
|
public void progress(int p) {
|
|
startWork(AppStrings.translate("work.reading.swf"), p);
|
|
}
|
|
}, Configuration.parallelSpeedUp.get());
|
|
swf.file = sourceInfo.getFile();
|
|
swf.fileTitle = sourceInfo.getFileTitle();
|
|
result.add(swf);
|
|
}
|
|
|
|
if (fis != null) {
|
|
logger.log(Level.INFO, "File loaded in {0} seconds.", (sw.getElapsedMilliseconds() / 1000));
|
|
fis.close();
|
|
} else {
|
|
logger.log(Level.INFO, "Stream loaded in {0} seconds.", (sw.getElapsedMilliseconds() / 1000));
|
|
}
|
|
|
|
result.sourceInfo = sourceInfo;
|
|
for (SWF swf : result) {
|
|
logger.log(Level.INFO, "");
|
|
logger.log(Level.INFO, "== File information ==");
|
|
logger.log(Level.INFO, "Size: {0}", Helper.formatFileSize(swf.fileSize));
|
|
logger.log(Level.INFO, "Flash version: {0}", swf.version);
|
|
int width = (int) ((swf.displayRect.Xmax - swf.displayRect.Xmin) / SWF.unitDivisor);
|
|
int height = (int) ((swf.displayRect.Ymax - swf.displayRect.Ymin) / SWF.unitDivisor);
|
|
logger.log(Level.INFO, "Width: {0}", width);
|
|
logger.log(Level.INFO, "Height: {0}", height);
|
|
|
|
swf.swfList = result;
|
|
swf.addEventListener(new EventListener() {
|
|
@Override
|
|
public void handleEvent(String event, Object data) {
|
|
if (event.equals("exporting")) {
|
|
startWork((String) data);
|
|
}
|
|
if (event.equals("getVariables")) {
|
|
startWork(AppStrings.translate("work.gettingvariables") + "..." + (String) data);
|
|
}
|
|
if (event.equals("deobfuscate")) {
|
|
startWork(AppStrings.translate("work.deobfuscating") + "..." + (String) data);
|
|
}
|
|
if (event.equals("rename")) {
|
|
startWork(AppStrings.translate("work.renaming") + "..." + (String) data);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public static void saveFile(SWF swf, String outfile) throws IOException {
|
|
saveFile(swf, outfile, SaveFileMode.SAVE);
|
|
}
|
|
|
|
public static void saveFile(SWF swf, String outfile, SaveFileMode mode) throws IOException {
|
|
if (mode == SaveFileMode.SAVEAS && !swf.swfList.isBundle) {
|
|
swf.file = outfile;
|
|
swf.fileTitle = null;
|
|
swf.swfList.sourceInfo.setFile(outfile);
|
|
}
|
|
File outfileF = new File(outfile);
|
|
File tmpFile = new File(outfile + ".tmp");
|
|
FileOutputStream fos = new FileOutputStream(tmpFile);
|
|
if (mode == SaveFileMode.EXE) {
|
|
InputStream exeStream = View.class.getClassLoader().getResourceAsStream("com/jpexs/helpers/resource/Swf2Exe.bin");
|
|
byte[] buffer = new byte[4096];
|
|
int bytesRead;
|
|
while ((bytesRead = exeStream.read(buffer)) != -1) {
|
|
fos.write(buffer, 0, bytesRead);
|
|
}
|
|
int width = swf.displayRect.Xmax - swf.displayRect.Xmin;
|
|
int height = swf.displayRect.Ymax - swf.displayRect.Ymin;
|
|
fos.write(width & 0xff);
|
|
fos.write((width >> 8) & 0xff);
|
|
fos.write((width >> 16) & 0xff);
|
|
fos.write((width >> 24) & 0xff);
|
|
fos.write(height & 0xff);
|
|
fos.write((height >> 8) & 0xff);
|
|
fos.write((height >> 16) & 0xff);
|
|
fos.write((height >> 24) & 0xff);
|
|
fos.write(Configuration.saveAsExeScaleMode.get());
|
|
}
|
|
swf.saveTo(fos);
|
|
if (tmpFile.exists()) {
|
|
if (tmpFile.length() > 0) {
|
|
outfileF.delete();
|
|
if (!tmpFile.renameTo(outfileF)) {
|
|
tmpFile.delete();
|
|
throw new IOException("Cannot access " + outfile);
|
|
}
|
|
} else {
|
|
throw new IOException("Output is empty");
|
|
}
|
|
}
|
|
}
|
|
|
|
private static class OpenFileWorker extends SwingWorker {
|
|
|
|
private final SWFSourceInfo[] sourceInfos;
|
|
|
|
public OpenFileWorker(SWFSourceInfo sourceInfo) {
|
|
this.sourceInfos = new SWFSourceInfo[]{sourceInfo};
|
|
}
|
|
|
|
public OpenFileWorker(SWFSourceInfo[] sourceInfos) {
|
|
this.sourceInfos = sourceInfos;
|
|
}
|
|
|
|
@Override
|
|
protected Object doInBackground() throws Exception {
|
|
boolean first = true;
|
|
SWF firstSWF = null;
|
|
for (final SWFSourceInfo sourceInfo : sourceInfos) {
|
|
SWFList swfs = null;
|
|
try {
|
|
Main.startWork(AppStrings.translate("work.reading.swf") + "...");
|
|
swfs = parseSWF(sourceInfo);
|
|
} catch (OutOfMemoryError ex) {
|
|
logger.log(Level.SEVERE, null, ex);
|
|
View.showMessageDialog(null, "Cannot load SWF file. Out of memory.");
|
|
} catch (Exception ex) {
|
|
logger.log(Level.SEVERE, null, ex);
|
|
View.showMessageDialog(null, "Cannot load SWF file.");
|
|
}
|
|
|
|
final SWFList swfs1 = swfs;
|
|
final boolean first1 = first;
|
|
first = false;
|
|
if (firstSWF == null) {
|
|
firstSWF = swfs1.get(0);
|
|
}
|
|
try {
|
|
Main.startWork(AppStrings.translate("work.creatingwindow") + "...");
|
|
View.execInEventDispatch(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
ensureMainFrame();
|
|
mainFrame.getPanel().load(swfs1, first1);
|
|
}
|
|
});
|
|
|
|
} catch (Exception ex) {
|
|
logger.log(Level.SEVERE, null, ex);
|
|
}
|
|
}
|
|
|
|
loadingDialog.setVisible(false);
|
|
final SWF fswf = firstSWF;
|
|
View.execInEventDispatch(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
if (mainFrame != null) {
|
|
mainFrame.setVisible(true);
|
|
}
|
|
Main.stopWork();
|
|
if (mainFrame != null && Configuration.gotoMainClassOnStartup.get()) {
|
|
mainFrame.getPanel().gotoDocumentClass(fswf);
|
|
}
|
|
}
|
|
});
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public static boolean reloadSWFs() {
|
|
CancellableWorker.cancelBackgroundThreads();
|
|
if (Main.sourceInfos.isEmpty()) {
|
|
Helper.freeMem();
|
|
showModeFrame();
|
|
return true;
|
|
} else {
|
|
SWFSourceInfo[] sourceInfosCopy = new SWFSourceInfo[sourceInfos.size()];
|
|
sourceInfos.toArray(sourceInfosCopy);
|
|
sourceInfos.clear();
|
|
openFile(sourceInfosCopy);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public static void reloadApp() {
|
|
if (debugDialog != null) {
|
|
debugDialog.setVisible(false);
|
|
debugDialog = null;
|
|
}
|
|
if (loadingDialog != null) {
|
|
loadingDialog.setVisible(false);
|
|
loadingDialog = null;
|
|
}
|
|
if (proxyFrame != null) {
|
|
proxyFrame.setVisible(false);
|
|
proxyFrame = null;
|
|
}
|
|
if (loadFromMemoryFrame != null) {
|
|
loadFromMemoryFrame.setVisible(false);
|
|
loadFromMemoryFrame = null;
|
|
}
|
|
if (loadFromCacheFrame != null) {
|
|
loadFromCacheFrame.setVisible(false);
|
|
loadFromCacheFrame = null;
|
|
}
|
|
if (mainFrame != null) {
|
|
mainFrame.setVisible(false);
|
|
mainFrame.getPanel().closeAll();
|
|
mainFrame = null;
|
|
}
|
|
FontTag.reload();
|
|
Cache.clearAll();
|
|
initGui();
|
|
reloadSWFs();
|
|
}
|
|
|
|
public static OpenFileResult openFile(String swfFile, String fileTitle) {
|
|
try {
|
|
File file = new File(swfFile);
|
|
if (!file.exists()) {
|
|
View.showMessageDialog(null, AppStrings.translate("open.error.fileNotFound"), AppStrings.translate("open.error"), JOptionPane.ERROR_MESSAGE);
|
|
return OpenFileResult.NOT_FOUND;
|
|
}
|
|
swfFile = file.getCanonicalPath();
|
|
Configuration.addRecentFile(swfFile);
|
|
SWFSourceInfo sourceInfo = new SWFSourceInfo(null, swfFile, fileTitle);
|
|
OpenFileResult openResult = openFile(sourceInfo);
|
|
return openResult;
|
|
} catch (IOException ex) {
|
|
View.showMessageDialog(null, AppStrings.translate("open.error.cannotOpen"), AppStrings.translate("open.error"), JOptionPane.ERROR_MESSAGE);
|
|
return OpenFileResult.ERROR;
|
|
}
|
|
}
|
|
|
|
public static OpenFileResult openFile(SWFSourceInfo sourceInfo) {
|
|
return openFile(new SWFSourceInfo[]{sourceInfo});
|
|
}
|
|
|
|
public static OpenFileResult openFile(SWFSourceInfo[] newSourceInfos) {
|
|
if (mainFrame != null && !Configuration.openMultipleFiles.get()) {
|
|
sourceInfos.clear();
|
|
mainFrame.getPanel().closeAll();
|
|
mainFrame.setVisible(false);
|
|
Helper.freeMem();
|
|
}
|
|
|
|
View.execInEventDispatch(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
if (Main.loadingDialog == null || Main.loadingDialog.getOwner() == null) {
|
|
Main.loadingDialog = new LoadingDialog(mainFrame == null ? null : mainFrame.getWindow());
|
|
}
|
|
}
|
|
});
|
|
|
|
Main.loadingDialog.setVisible(true);
|
|
OpenFileWorker wrk = new OpenFileWorker(newSourceInfos);
|
|
wrk.execute();
|
|
sourceInfos.addAll(Arrays.asList(newSourceInfos));
|
|
return OpenFileResult.OK;
|
|
}
|
|
|
|
public static void closeFile(SWFList swf) {
|
|
sourceInfos.remove(swf.sourceInfo);
|
|
mainFrame.getPanel().close(swf);
|
|
}
|
|
|
|
public static void closeAll() {
|
|
sourceInfos.clear();
|
|
mainFrame.getPanel().closeAll();
|
|
}
|
|
|
|
public static boolean saveFileDialog(SWF swf, final SaveFileMode mode) {
|
|
JFileChooser fc = new JFileChooser();
|
|
fc.setCurrentDirectory(new File(Configuration.lastSaveDir.get()));
|
|
String ext = ".swf";
|
|
switch (mode) {
|
|
case SAVE:
|
|
case SAVEAS:
|
|
if (swf.file != null) {
|
|
ext = Path.getExtension(swf.file);
|
|
}
|
|
break;
|
|
case EXE:
|
|
ext = ".exe";
|
|
break;
|
|
}
|
|
final String extension = ext;
|
|
FileFilter swfFilter = new FileFilter() {
|
|
@Override
|
|
public boolean accept(File f) {
|
|
return (f.getName().toLowerCase().endsWith(".swf")) || (f.isDirectory());
|
|
}
|
|
|
|
@Override
|
|
public String getDescription() {
|
|
return AppStrings.translate("filter.swf");
|
|
}
|
|
};
|
|
if (!swf.gfx) {
|
|
fc.setFileFilter(swfFilter);
|
|
} else {
|
|
fc.addChoosableFileFilter(swfFilter);
|
|
}
|
|
FileFilter gfxFilter = new FileFilter() {
|
|
@Override
|
|
public boolean accept(File f) {
|
|
return (f.getName().toLowerCase().endsWith(".gfx")) || (f.isDirectory());
|
|
}
|
|
|
|
@Override
|
|
public String getDescription() {
|
|
return AppStrings.translate("filter.gfx");
|
|
}
|
|
};
|
|
if (mode == SaveFileMode.SAVE || mode == SaveFileMode.SAVEAS) {
|
|
if (swf.gfx) {
|
|
fc.setFileFilter(gfxFilter);
|
|
} else {
|
|
fc.addChoosableFileFilter(gfxFilter);
|
|
}
|
|
}
|
|
fc.setAcceptAllFileFilterUsed(false);
|
|
JFrame f = new JFrame();
|
|
View.setWindowIcon(f);
|
|
if (fc.showSaveDialog(f) == JFileChooser.APPROVE_OPTION) {
|
|
File file = Helper.fixDialogFile(fc.getSelectedFile());
|
|
FileFilter selFilter = fc.getFileFilter();
|
|
try {
|
|
String fileName = file.getAbsolutePath();
|
|
if (selFilter == swfFilter) {
|
|
if (!fileName.toLowerCase().endsWith(extension)) {
|
|
fileName += extension;
|
|
}
|
|
swf.gfx = false;
|
|
}
|
|
if (selFilter == gfxFilter) {
|
|
if (!fileName.toLowerCase().endsWith(".gfx")) {
|
|
fileName += ".gfx";
|
|
}
|
|
swf.gfx = true;
|
|
}
|
|
Main.saveFile(swf, fileName, mode);
|
|
Configuration.lastSaveDir.set(file.getParentFile().getAbsolutePath());
|
|
return true;
|
|
} catch (IOException ex) {
|
|
View.showMessageDialog(null, AppStrings.translate("error.file.write"));
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static boolean openFileDialog() {
|
|
JFileChooser fc = new JFileChooser();
|
|
if (Configuration.openMultipleFiles.get()) {
|
|
fc.setMultiSelectionEnabled(true);
|
|
}
|
|
fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get()));
|
|
FileFilter allSupportedFilter = new FileFilter() {
|
|
private final String[] supportedExtensions = new String[]{".swf", ".gfx", ".swc", ".zip"};
|
|
|
|
@Override
|
|
public boolean accept(File f) {
|
|
String name = f.getName().toLowerCase();
|
|
for (String ext : supportedExtensions) {
|
|
if (name.endsWith(ext)) {
|
|
return true;
|
|
}
|
|
}
|
|
return f.isDirectory();
|
|
}
|
|
|
|
@Override
|
|
public String getDescription() {
|
|
String exts = Helper.joinStrings(supportedExtensions, "*%s", "; ");
|
|
return AppStrings.translate("filter.supported") + " (" + exts + ")";
|
|
}
|
|
};
|
|
fc.setFileFilter(allSupportedFilter);
|
|
FileFilter swfFilter = new FileFilter() {
|
|
@Override
|
|
public boolean accept(File f) {
|
|
return (f.getName().toLowerCase().endsWith(".swf")) || (f.isDirectory());
|
|
}
|
|
|
|
@Override
|
|
public String getDescription() {
|
|
return AppStrings.translate("filter.swf");
|
|
}
|
|
};
|
|
fc.addChoosableFileFilter(swfFilter);
|
|
|
|
FileFilter swcFilter = new FileFilter() {
|
|
@Override
|
|
public boolean accept(File f) {
|
|
return (f.getName().toLowerCase().endsWith(".swc")) || (f.isDirectory());
|
|
}
|
|
|
|
@Override
|
|
public String getDescription() {
|
|
return AppStrings.translate("filter.swc");
|
|
}
|
|
};
|
|
fc.addChoosableFileFilter(swcFilter);
|
|
|
|
FileFilter gfxFilter = new FileFilter() {
|
|
@Override
|
|
public boolean accept(File f) {
|
|
return (f.getName().toLowerCase().endsWith(".gfx")) || (f.isDirectory());
|
|
}
|
|
|
|
@Override
|
|
public String getDescription() {
|
|
return AppStrings.translate("filter.gfx");
|
|
}
|
|
};
|
|
fc.addChoosableFileFilter(gfxFilter);
|
|
|
|
FileFilter zipFilter = new FileFilter() {
|
|
@Override
|
|
public boolean accept(File f) {
|
|
return (f.getName().toLowerCase().endsWith(".zip")) || (f.isDirectory());
|
|
}
|
|
|
|
@Override
|
|
public String getDescription() {
|
|
return AppStrings.translate("filter.zip");
|
|
}
|
|
};
|
|
fc.addChoosableFileFilter(zipFilter);
|
|
|
|
FileFilter binaryFilter = new FileFilter() {
|
|
@Override
|
|
public boolean accept(File f) {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public String getDescription() {
|
|
return AppStrings.translate("filter.binary");
|
|
}
|
|
};
|
|
fc.addChoosableFileFilter(binaryFilter);
|
|
|
|
fc.setAcceptAllFileFilterUsed(false);
|
|
JFrame f = new JFrame();
|
|
View.setWindowIcon(f);
|
|
int returnVal = fc.showOpenDialog(f);
|
|
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
|
Configuration.lastOpenDir.set(Helper.fixDialogFile(fc.getSelectedFile()).getParentFile().getAbsolutePath());
|
|
File[] selFiles = fc.getSelectedFiles();
|
|
for (File file : selFiles) {
|
|
File selfile = Helper.fixDialogFile(file);
|
|
Main.openFile(selfile.getAbsolutePath(), null);
|
|
}
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static void displayErrorFrame() {
|
|
ErrorLogFrame.getInstance().setVisible(true);
|
|
}
|
|
|
|
private static void initGui() {
|
|
if (GraphicsEnvironment.isHeadless()) {
|
|
System.err.println("Error: Your system does not support Graphic User Interface");
|
|
exit();
|
|
}
|
|
if (Configuration.useRibbonInterface.get()) {
|
|
View.setLookAndFeel();
|
|
} else {
|
|
try {
|
|
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
|
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
|
|
logger.log(Level.SEVERE, null, ex);
|
|
}
|
|
}
|
|
autoCheckForUpdates();
|
|
offerAssociation();
|
|
}
|
|
|
|
public static void showModeFrame() {
|
|
View.execInEventDispatch(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
ensureMainFrame();
|
|
mainFrame.setVisible(true);
|
|
}
|
|
});
|
|
|
|
}
|
|
|
|
private static void offerAssociation() {
|
|
boolean offered = Configuration.offeredAssociation.get();
|
|
if (!offered) {
|
|
if (Platform.isWindows()) {
|
|
if ((!ContextMenuTools.isAddedToContextMenu()) && View.showConfirmDialog(null, "Do you want to add FFDec to context menu of SWF files?\n(Can be changed later from main menu)", "Context menu", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
|
|
ContextMenuTools.addToContextMenu(true, false);
|
|
}
|
|
}
|
|
}
|
|
Configuration.offeredAssociation.set(true);
|
|
}
|
|
|
|
public static void initLang() {
|
|
if (GraphicsEnvironment.isHeadless()) { //No GUI in OS
|
|
return;
|
|
}
|
|
if (!Configuration.locale.hasValue()) {
|
|
if (Platform.isWindows()) {
|
|
//Load from Installer
|
|
String uninstKey = "{E618D276-6596-41F4-8A98-447D442A77DB}_is1";
|
|
uninstKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + uninstKey;
|
|
try {
|
|
if (Advapi32Util.registryKeyExists(WinReg.HKEY_LOCAL_MACHINE, uninstKey)) {
|
|
if (Advapi32Util.registryValueExists(WinReg.HKEY_LOCAL_MACHINE, uninstKey, "NSIS: Language")) {
|
|
String installedLoc = Advapi32Util.registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE, uninstKey, "NSIS: Language");
|
|
int lcid = Integer.parseInt(installedLoc);
|
|
char buf[] = new char[9];
|
|
int cnt = Kernel32.INSTANCE.GetLocaleInfo(lcid, Kernel32.LOCALE_SISO639LANGNAME, buf, 9);
|
|
String langCode = new String(buf, 0, cnt).trim().toLowerCase();
|
|
|
|
cnt = Kernel32.INSTANCE.GetLocaleInfo(lcid, Kernel32.LOCALE_SISO3166CTRYNAME, buf, 9);
|
|
String countryCode = new String(buf, 0, cnt).trim().toLowerCase();
|
|
|
|
List<String> langs = Arrays.asList(SelectLanguageDialog.getAvailableLanguages());
|
|
for (int i = 0; i < langs.size(); i++) {
|
|
langs.set(i, langs.get(i).toLowerCase());
|
|
}
|
|
|
|
String selectedLang = null;
|
|
|
|
if (langs.contains(langCode + "-" + countryCode)) {
|
|
selectedLang = SelectLanguageDialog.getAvailableLanguages()[langs.indexOf(langCode + "-" + countryCode)];
|
|
} else if (langs.contains(langCode)) {
|
|
selectedLang = SelectLanguageDialog.getAvailableLanguages()[langs.indexOf(langCode)];
|
|
}
|
|
if (selectedLang != null) {
|
|
Configuration.locale.set(selectedLang);
|
|
}
|
|
}
|
|
}
|
|
} catch (Exception ex) {
|
|
//ignore
|
|
}
|
|
}
|
|
}
|
|
Locale.setDefault(Locale.forLanguageTag(Configuration.locale.get()));
|
|
AppStrings.updateLanguage();
|
|
ErrorLogFrame.createNewInstance();
|
|
|
|
try {
|
|
Class<?> cl = Class.forName("org.pushingpixels.substance.api.SubstanceLookAndFeel");
|
|
Field field = cl.getDeclaredField("LABEL_BUNDLE");
|
|
field.setAccessible(true);
|
|
field.set(null, null);
|
|
} catch (Throwable ex) {
|
|
logger.log(Level.SEVERE, null, ex);
|
|
}
|
|
|
|
UIManager.put("OptionPane.okButtonText", AppStrings.translate("button.ok"));
|
|
UIManager.put("OptionPane.yesButtonText", AppStrings.translate("button.yes"));
|
|
UIManager.put("OptionPane.noButtonText", AppStrings.translate("button.no"));
|
|
UIManager.put("OptionPane.cancelButtonText", AppStrings.translate("button.cancel"));
|
|
UIManager.put("OptionPane.messageDialogTitle", AppStrings.translate("dialog.message.title"));
|
|
UIManager.put("OptionPane.titleText", AppStrings.translate("dialog.select.title"));
|
|
|
|
UIManager.put("FileChooser.acceptAllFileFilterText", AppStrings.translate("FileChooser.acceptAllFileFilterText"));
|
|
UIManager.put("FileChooser.lookInLabelText", AppStrings.translate("FileChooser.lookInLabelText"));
|
|
UIManager.put("FileChooser.cancelButtonText", AppStrings.translate("button.cancel"));
|
|
UIManager.put("FileChooser.cancelButtonToolTipText", AppStrings.translate("button.cancel"));
|
|
UIManager.put("FileChooser.openButtonText", AppStrings.translate("FileChooser.openButtonText"));
|
|
UIManager.put("FileChooser.openButtonToolTipText", AppStrings.translate("FileChooser.openButtonToolTipText"));
|
|
UIManager.put("FileChooser.filesOfTypeLabelText", AppStrings.translate("FileChooser.filesOfTypeLabelText"));
|
|
UIManager.put("FileChooser.fileNameLabelText", AppStrings.translate("FileChooser.fileNameLabelText"));
|
|
UIManager.put("FileChooser.listViewButtonToolTipText", AppStrings.translate("FileChooser.listViewButtonToolTipText"));
|
|
UIManager.put("FileChooser.listViewButtonAccessibleName", AppStrings.translate("FileChooser.listViewButtonAccessibleName"));
|
|
UIManager.put("FileChooser.detailsViewButtonToolTipText", AppStrings.translate("FileChooser.detailsViewButtonToolTipText"));
|
|
UIManager.put("FileChooser.detailsViewButtonAccessibleName", AppStrings.translate("FileChooser.detailsViewButtonAccessibleName"));
|
|
UIManager.put("FileChooser.upFolderToolTipText", AppStrings.translate("FileChooser.upFolderToolTipText"));
|
|
UIManager.put("FileChooser.upFolderAccessibleName", AppStrings.translate("FileChooser.upFolderAccessibleName"));
|
|
UIManager.put("FileChooser.homeFolderToolTipText", AppStrings.translate("FileChooser.homeFolderToolTipText"));
|
|
UIManager.put("FileChooser.homeFolderAccessibleName", AppStrings.translate("FileChooser.homeFolderAccessibleName"));
|
|
UIManager.put("FileChooser.fileNameHeaderText", AppStrings.translate("FileChooser.fileNameHeaderText"));
|
|
UIManager.put("FileChooser.fileSizeHeaderText", AppStrings.translate("FileChooser.fileSizeHeaderText"));
|
|
UIManager.put("FileChooser.fileTypeHeaderText", AppStrings.translate("FileChooser.fileTypeHeaderText"));
|
|
UIManager.put("FileChooser.fileDateHeaderText", AppStrings.translate("FileChooser.fileDateHeaderText"));
|
|
UIManager.put("FileChooser.fileAttrHeaderText", AppStrings.translate("FileChooser.fileAttrHeaderText"));
|
|
UIManager.put("FileChooser.openDialogTitleText", AppStrings.translate("FileChooser.openDialogTitleText"));
|
|
UIManager.put("FileChooser.directoryDescriptionText", AppStrings.translate("FileChooser.directoryDescriptionText"));
|
|
UIManager.put("FileChooser.directoryOpenButtonText", AppStrings.translate("FileChooser.directoryOpenButtonText"));
|
|
UIManager.put("FileChooser.directoryOpenButtonToolTipText", AppStrings.translate("FileChooser.directoryOpenButtonToolTipText"));
|
|
UIManager.put("FileChooser.fileDescriptionText", AppStrings.translate("FileChooser.fileDescriptionText"));
|
|
UIManager.put("FileChooser.fileNameLabelText", AppStrings.translate("FileChooser.fileNameLabelText"));
|
|
UIManager.put("FileChooser.helpButtonText", AppStrings.translate("FileChooser.helpButtonText"));
|
|
UIManager.put("FileChooser.helpButtonToolTipText", AppStrings.translate("FileChooser.helpButtonToolTipText"));
|
|
UIManager.put("FileChooser.newFolderAccessibleName", AppStrings.translate("FileChooser.newFolderAccessibleName"));
|
|
UIManager.put("FileChooser.newFolderErrorText", AppStrings.translate("FileChooser.newFolderErrorText"));
|
|
UIManager.put("FileChooser.newFolderToolTipText", AppStrings.translate("FileChooser.newFolderToolTipText"));
|
|
UIManager.put("FileChooser.other.newFolder", AppStrings.translate("FileChooser.other.newFolder"));
|
|
UIManager.put("FileChooser.other.newFolder.subsequent", AppStrings.translate("FileChooser.other.newFolder.subsequent"));
|
|
UIManager.put("FileChooser.win32.newFolder", AppStrings.translate("FileChooser.win32.newFolder"));
|
|
UIManager.put("FileChooser.win32.newFolder.subsequent", AppStrings.translate("FileChooser.win32.newFolder.subsequent"));
|
|
UIManager.put("FileChooser.saveButtonText", AppStrings.translate("FileChooser.saveButtonText"));
|
|
UIManager.put("FileChooser.saveButtonToolTipText", AppStrings.translate("FileChooser.saveButtonToolTipText"));
|
|
UIManager.put("FileChooser.saveDialogTitleText", AppStrings.translate("FileChooser.saveDialogTitleText"));
|
|
UIManager.put("FileChooser.saveInLabelText", AppStrings.translate("FileChooser.saveInLabelText"));
|
|
UIManager.put("FileChooser.updateButtonText", AppStrings.translate("FileChooser.updateButtonText"));
|
|
UIManager.put("FileChooser.updateButtonToolTipText", AppStrings.translate("FileChooser.updateButtonToolTipText"));
|
|
|
|
UIManager.put("FileChooser.detailsViewActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.detailsViewActionLabel.textAndMnemonic"));
|
|
UIManager.put("FileChooser.detailsViewButtonToolTip.textAndMnemonic", AppStrings.translate("FileChooser.detailsViewButtonToolTip.textAndMnemonic"));
|
|
UIManager.put("FileChooser.fileAttrHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileAttrHeader.textAndMnemonic"));
|
|
UIManager.put("FileChooser.fileDateHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileDateHeader.textAndMnemonic"));
|
|
UIManager.put("FileChooser.fileNameHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileNameHeader.textAndMnemonic"));
|
|
UIManager.put("FileChooser.fileNameLabel.textAndMnemonic", AppStrings.translate("FileChooser.fileNameLabel.textAndMnemonic"));
|
|
UIManager.put("FileChooser.fileSizeHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileSizeHeader.textAndMnemonic"));
|
|
UIManager.put("FileChooser.fileTypeHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileTypeHeader.textAndMnemonic"));
|
|
UIManager.put("FileChooser.filesOfTypeLabel.textAndMnemonic", AppStrings.translate("FileChooser.filesOfTypeLabel.textAndMnemonic"));
|
|
UIManager.put("FileChooser.folderNameLabel.textAndMnemonic", AppStrings.translate("FileChooser.folderNameLabel.textAndMnemonic"));
|
|
UIManager.put("FileChooser.homeFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.homeFolderToolTip.textAndMnemonic"));
|
|
UIManager.put("FileChooser.listViewActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.listViewActionLabel.textAndMnemonic"));
|
|
UIManager.put("FileChooser.listViewButtonToolTip.textAndMnemonic", AppStrings.translate("FileChooser.listViewButtonToolTip.textAndMnemonic"));
|
|
UIManager.put("FileChooser.lookInLabel.textAndMnemonic", AppStrings.translate("FileChooser.lookInLabel.textAndMnemonic"));
|
|
UIManager.put("FileChooser.newFolderActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.newFolderActionLabel.textAndMnemonic"));
|
|
UIManager.put("FileChooser.newFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.newFolderToolTip.textAndMnemonic"));
|
|
UIManager.put("FileChooser.refreshActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.refreshActionLabel.textAndMnemonic"));
|
|
UIManager.put("FileChooser.saveInLabel.textAndMnemonic", AppStrings.translate("FileChooser.saveInLabel.textAndMnemonic"));
|
|
UIManager.put("FileChooser.upFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.upFolderToolTip.textAndMnemonic"));
|
|
UIManager.put("FileChooser.viewMenuButtonAccessibleName", AppStrings.translate("FileChooser.viewMenuButtonAccessibleName"));
|
|
UIManager.put("FileChooser.viewMenuButtonToolTipText", AppStrings.translate("FileChooser.viewMenuButtonToolTipText"));
|
|
UIManager.put("FileChooser.viewMenuLabel.textAndMnemonic", AppStrings.translate("FileChooser.viewMenuLabel.textAndMnemonic"));
|
|
UIManager.put("FileChooser.newFolderActionLabelText", AppStrings.translate("FileChooser.newFolderActionLabelText"));
|
|
UIManager.put("FileChooser.listViewActionLabelText", AppStrings.translate("FileChooser.listViewActionLabelText"));
|
|
UIManager.put("FileChooser.detailsViewActionLabelText", AppStrings.translate("FileChooser.detailsViewActionLabelText"));
|
|
UIManager.put("FileChooser.refreshActionLabelText", AppStrings.translate("FileChooser.refreshActionLabelText"));
|
|
UIManager.put("FileChooser.sortMenuLabelText", AppStrings.translate("FileChooser.sortMenuLabelText"));
|
|
UIManager.put("FileChooser.viewMenuLabelText", AppStrings.translate("FileChooser.viewMenuLabelText"));
|
|
UIManager.put("FileChooser.fileSizeKiloBytes", AppStrings.translate("FileChooser.fileSizeKiloBytes"));
|
|
UIManager.put("FileChooser.fileSizeMegaBytes", AppStrings.translate("FileChooser.fileSizeMegaBytes"));
|
|
UIManager.put("FileChooser.fileSizeGigaBytes", AppStrings.translate("FileChooser.fileSizeGigaBytes"));
|
|
UIManager.put("FileChooser.folderNameLabelText", AppStrings.translate("FileChooser.folderNameLabelText"));
|
|
|
|
UIManager.put("ColorChooser.okText", AppStrings.translate("ColorChooser.okText"));
|
|
UIManager.put("ColorChooser.cancelText", AppStrings.translate("ColorChooser.cancelText"));
|
|
UIManager.put("ColorChooser.resetText", AppStrings.translate("ColorChooser.resetText"));
|
|
UIManager.put("ColorChooser.previewText", AppStrings.translate("ColorChooser.previewText"));
|
|
UIManager.put("ColorChooser.swatchesNameText", AppStrings.translate("ColorChooser.swatchesNameText"));
|
|
UIManager.put("ColorChooser.swatchesRecentText", AppStrings.translate("ColorChooser.swatchesRecentText"));
|
|
UIManager.put("ColorChooser.sampleText", AppStrings.translate("ColorChooser.sampleText"));
|
|
|
|
Helper.decompilationErrorAdd = AppStrings.translate(Configuration.autoDeobfuscate.get() ? "deobfuscation.comment.failed" : "deobfuscation.comment.tryenable");
|
|
}
|
|
|
|
/**
|
|
* Clear old FFDec/JavactiveX temp files
|
|
*/
|
|
private static void clearTemp() {
|
|
String tempDirPath = System.getProperty("java.io.tmpdir");
|
|
if (tempDirPath == null) {
|
|
return;
|
|
}
|
|
File tempDir = new File(tempDirPath);
|
|
if (!tempDir.exists()) {
|
|
return;
|
|
}
|
|
File delFiles[] = tempDir.listFiles(new FilenameFilter() {
|
|
|
|
@Override
|
|
public boolean accept(File dir, String name) {
|
|
return name.matches("ffdec_cache.*\\.tmp") || name.matches("javactivex_.*\\.exe") || name.matches("temp[0-9]+\\.swf") || name.matches("ffdec_view_.*\\.swf");
|
|
}
|
|
});
|
|
for (File f : delFiles) {
|
|
try {
|
|
f.delete();
|
|
} catch (Exception ex) {
|
|
//ignore
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param args the command line arguments
|
|
* @throws IOException
|
|
*/
|
|
public static void main(String[] args) throws IOException {
|
|
|
|
clearTemp();
|
|
String pluginPath = Configuration.pluginPath.get();
|
|
if (pluginPath != null && !pluginPath.isEmpty()) {
|
|
try {
|
|
SWFDecompilerPlugin.loadPlugin(pluginPath);
|
|
} catch (Throwable e) {
|
|
View.showMessageDialog(null, "Failed to load plugin: " + pluginPath);
|
|
}
|
|
}
|
|
|
|
AppStrings.setResourceClass(MainFrame.class);
|
|
initLogging(Configuration.debugMode.get());
|
|
initLang();
|
|
|
|
if (Configuration.cacheOnDisk.get()) {
|
|
Cache.setStorageType(Cache.STORAGE_FILES);
|
|
} else {
|
|
Cache.setStorageType(Cache.STORAGE_MEMORY);
|
|
}
|
|
|
|
if (args.length == 0) {
|
|
initGui();
|
|
showModeFrame();
|
|
} else {
|
|
String fileToOpen = CommandLineArgumentParser.parseArguments(args);
|
|
if (fileToOpen != null) {
|
|
initGui();
|
|
openFile(fileToOpen, null);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static String tempFile(String url) throws IOException {
|
|
File f = new File(Configuration.getFFDecHome() + "saved" + File.separator);
|
|
if (!f.exists()) {
|
|
if (!f.mkdirs()) {
|
|
if (!f.exists()) {
|
|
throw new IOException("cannot create directory " + f);
|
|
}
|
|
}
|
|
}
|
|
return Configuration.getFFDecHome() + "saved" + File.separator + "asdec_" + Integer.toHexString(url.hashCode()) + ".tmp";
|
|
|
|
}
|
|
|
|
public static void removeTrayIcon() {
|
|
if (SystemTray.isSupported()) {
|
|
SystemTray tray = SystemTray.getSystemTray();
|
|
if (trayIcon != null) {
|
|
tray.remove(trayIcon);
|
|
trayIcon = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void switchProxy() {
|
|
proxyFrame.switchState();
|
|
if (stopMenuItem != null) {
|
|
if (proxyFrame.isRunning()) {
|
|
stopMenuItem.setLabel(AppStrings.translate("proxy.stop"));
|
|
} else {
|
|
stopMenuItem.setLabel(AppStrings.translate("proxy.start"));
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void addTrayIcon() {
|
|
if (trayIcon != null) {
|
|
return;
|
|
}
|
|
if (SystemTray.isSupported()) {
|
|
SystemTray tray = SystemTray.getSystemTray();
|
|
trayIcon = new TrayIcon(View.loadImage("proxy16"), ApplicationInfo.VENDOR + " " + ApplicationInfo.SHORT_APPLICATION_NAME + " " + AppStrings.translate("proxy"));
|
|
trayIcon.setImageAutoSize(true);
|
|
PopupMenu trayPopup = new PopupMenu();
|
|
|
|
ActionListener trayListener = new ActionListener() {
|
|
/**
|
|
* Invoked when an action occurs.
|
|
*/
|
|
@Override
|
|
public void actionPerformed(ActionEvent e) {
|
|
if (e.getActionCommand().equals("EXIT")) {
|
|
Main.exit();
|
|
}
|
|
if (e.getActionCommand().equals("SHOW")) {
|
|
Main.showProxy();
|
|
}
|
|
if (e.getActionCommand().equals("SWITCH")) {
|
|
Main.switchProxy();
|
|
}
|
|
}
|
|
};
|
|
|
|
MenuItem showMenuItem = new MenuItem(AppStrings.translate("proxy.show"));
|
|
showMenuItem.setActionCommand("SHOW");
|
|
showMenuItem.addActionListener(trayListener);
|
|
trayPopup.add(showMenuItem);
|
|
stopMenuItem = new MenuItem(AppStrings.translate("proxy.start"));
|
|
stopMenuItem.setActionCommand("SWITCH");
|
|
stopMenuItem.addActionListener(trayListener);
|
|
trayPopup.add(stopMenuItem);
|
|
trayPopup.addSeparator();
|
|
MenuItem exitMenuItem = new MenuItem(AppStrings.translate("exit"));
|
|
exitMenuItem.setActionCommand("EXIT");
|
|
exitMenuItem.addActionListener(trayListener);
|
|
trayPopup.add(exitMenuItem);
|
|
|
|
trayIcon.setPopupMenu(trayPopup);
|
|
trayIcon.addMouseListener(new MouseAdapter() {
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public void mouseClicked(MouseEvent e) {
|
|
if (e.getButton() == MouseEvent.BUTTON1) {
|
|
Main.showProxy();
|
|
}
|
|
}
|
|
});
|
|
try {
|
|
tray.add(trayIcon);
|
|
} catch (AWTException ex) {
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void exit() {
|
|
Configuration.saveConfig();
|
|
/*if (proxyFrame != null && Main.proxyFrame.isVisible()) {
|
|
return;
|
|
}
|
|
if (loadFromMemoryFrame != null && Main.loadFromMemoryFrame.isVisible()) {
|
|
return;
|
|
}
|
|
if (loadFromCacheFrame != null && loadFromCacheFrame.isVisible()) {
|
|
return;
|
|
}*/
|
|
if (mainFrame != null && mainFrame.getPanel() != null) {
|
|
mainFrame.getPanel().unloadFlashPlayer();
|
|
}
|
|
System.exit(0);
|
|
}
|
|
|
|
public static void about() {
|
|
(new AboutDialog()).setVisible(true);
|
|
}
|
|
|
|
public static void advancedSettings() {
|
|
(new AdvancedSettingsDialog()).setVisible(true);
|
|
}
|
|
|
|
private static boolean isDebuggerClass(String tested, String cls) {
|
|
if (tested == null) {
|
|
return false;
|
|
}
|
|
if (cls == null) {
|
|
cls = "";
|
|
} else {
|
|
cls = "\\." + Pattern.quote(cls);
|
|
}
|
|
return tested.matches(Pattern.quote(DEBUGGER_PACKAGE) + "(\\.pkg[a-f0-9]+)?" + cls);
|
|
}
|
|
|
|
private static String byteArrayToHex(byte[] a) {
|
|
StringBuilder sb = new StringBuilder(a.length * 2);
|
|
for (byte b : a) {
|
|
sb.append(String.format("%02x", b & 0xff));
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
public static void replaceTraceCalls(String fname) {
|
|
SWF swf = getMainFrame().getPanel().getCurrentSwf();
|
|
if (hasDebugger(swf)) {
|
|
String debuggerPkg = getDebuggerPackage(swf);
|
|
//change trace to fname
|
|
for (ABCContainerTag ct : swf.abcList) {
|
|
ABC a = ct.getABC();
|
|
for (int i = 1; i < a.constants.constant_multiname.size(); i++) {
|
|
Multiname m = a.constants.constant_multiname.get(i);
|
|
if ("trace".equals(m.getNameWithNamespace(a.constants, true))) {
|
|
m.namespace_index = a.constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE, a.constants.getStringId(debuggerPkg, true)), 0, true);
|
|
m.name_index = a.constants.getStringId(fname, true);
|
|
((Tag) ct).setModified(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void switchDebugger() {
|
|
int port = Configuration.debuggerPort.get();
|
|
SWF swf = getMainFrame().getPanel().getCurrentSwf();
|
|
ABCContainerTag found = getDebuggerABCTag(swf);
|
|
if (found != null) {
|
|
swf.tags.remove((Tag) found);
|
|
swf.abcList.remove(found);
|
|
|
|
//Change all debugger calls to normal trace
|
|
for (ABCContainerTag ct : swf.abcList) {
|
|
ABC a = ct.getABC();
|
|
for (int i = 1; i < a.constants.constant_multiname.size(); i++) {
|
|
Multiname m = a.constants.constant_multiname.get(i);
|
|
if (isDebuggerClass(m.getNameWithNamespace(a.constants, true), "debugTrace")
|
|
|| isDebuggerClass(m.getNameWithNamespace(a.constants, true), "debugAlert")
|
|
|| isDebuggerClass(m.getNameWithNamespace(a.constants, true), "debugSocket")
|
|
|| isDebuggerClass(m.getNameWithNamespace(a.constants, true), "debugConsole")) {
|
|
m.name_index = a.constants.getStringId("trace", true);
|
|
m.namespace_index = a.constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE, a.constants.getStringId("", true)), 0, true);
|
|
((Tag) ct).setModified(true);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
Random rnd = new Random();
|
|
byte rb[] = new byte[16];
|
|
rnd.nextBytes(rb);
|
|
String rhex = byteArrayToHex(rb);
|
|
try {
|
|
//load debug swf
|
|
SWF debugSWF = new SWF(Main.class.getClassLoader().getResourceAsStream("com/jpexs/decompiler/flash/gui/debugger/debug.swf"), false);
|
|
|
|
ABCContainerTag firstAbc = swf.abcList.get(0);
|
|
String newdebuggerpkg = DEBUGGER_PACKAGE;
|
|
|
|
if (Configuration.randomDebuggerPackage.get()) {
|
|
newdebuggerpkg += ".pkg" + rhex;
|
|
}
|
|
|
|
//add debug ABC tags to main SWF
|
|
for (ABCContainerTag ds : debugSWF.abcList) {
|
|
ABC a = ds.getABC();
|
|
//Append random hex to Debugger package name
|
|
for (int i = 1; i < a.constants.constant_namespace.size(); i++) {
|
|
if (a.constants.constant_namespace.get(i).hasName(DEBUGGER_PACKAGE, a.constants)) {
|
|
a.constants.constant_namespace.get(i).name_index = a.constants.getStringId(newdebuggerpkg, true);
|
|
}
|
|
}
|
|
//Set debugger port to actually set port
|
|
for (int i = 0; i < a.constants.constant_int.size(); i++) {
|
|
if (a.constants.constant_int.get(i) == 123456L) {
|
|
a.constants.constant_int.set(i, (long) port);
|
|
}
|
|
}
|
|
//Add to target SWF
|
|
((Tag) ds).setSwf(swf);
|
|
swf.tags.add(swf.tags.indexOf(firstAbc), (Tag) ds);
|
|
swf.abcList.add(swf.abcList.indexOf(firstAbc), ds);
|
|
((Tag) ds).setModified(true);
|
|
}
|
|
|
|
} catch (Exception ex) {
|
|
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Error while attaching debugger", ex);
|
|
//ignore
|
|
}
|
|
|
|
}
|
|
initDebugger();
|
|
}
|
|
|
|
private static void initDebugger() {
|
|
if (debugger == null) {
|
|
debugger = new Debugger(Configuration.debuggerPort.get());
|
|
debugger.start();
|
|
}
|
|
}
|
|
|
|
public static void debuggerShowLog() {
|
|
initDebugger();
|
|
if (debugDialog == null) {
|
|
debugDialog = new DebugLogDialog(debugger);
|
|
}
|
|
debugDialog.setVisible(true);
|
|
}
|
|
|
|
public static void autoCheckForUpdates() {
|
|
if (Configuration.checkForUpdatesAuto.get()) {
|
|
Calendar lastUpdatesCheckDate = Configuration.lastUpdatesCheckDate.get();
|
|
if ((lastUpdatesCheckDate == null) || (lastUpdatesCheckDate.getTime().getTime() < Calendar.getInstance().getTime().getTime() - Configuration.checkForUpdatesDelay.get())) {
|
|
new SwingWorker() {
|
|
@Override
|
|
protected Object doInBackground() throws Exception {
|
|
checkForUpdates();
|
|
return null;
|
|
}
|
|
}.execute();
|
|
}
|
|
}
|
|
}
|
|
|
|
public static boolean checkForUpdates() {
|
|
String currentVersion = ApplicationInfo.version;
|
|
if (currentVersion.equals("unknown")) {
|
|
// sometimes during development the version information is not available
|
|
return false;
|
|
}
|
|
|
|
List<String> accepted = new ArrayList<>();
|
|
if (Configuration.checkForUpdatesStable.get()) {
|
|
accepted.add("stable");
|
|
}
|
|
if (Configuration.checkForUpdatesNightly.get()) {
|
|
accepted.add("nightly");
|
|
}
|
|
|
|
if (accepted.isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
String acceptVersions = "";
|
|
for (String a : accepted) {
|
|
if (!acceptVersions.isEmpty()) {
|
|
acceptVersions += ",";
|
|
}
|
|
acceptVersions += a;
|
|
}
|
|
try {
|
|
Socket sock = new Socket("www.free-decompiler.com", 80);
|
|
OutputStream os = sock.getOutputStream();
|
|
String currentLoc = Configuration.locale.get("en");
|
|
os.write(("GET /flash/update.html?action=check¤tVersion=" + URLEncoder.encode(currentVersion, "UTF-8")
|
|
+ "¤tRevision=" + URLEncoder.encode(ApplicationInfo.revision, "UTF-8")
|
|
+ "¤tVersionMajor=" + URLEncoder.encode("" + ApplicationInfo.version_major, "UTF-8")
|
|
+ "¤tVersionMinor=" + URLEncoder.encode("" + ApplicationInfo.version_minor, "UTF-8")
|
|
+ "¤tVersionRelease=" + URLEncoder.encode("" + ApplicationInfo.version_release, "UTF-8")
|
|
+ "¤tVersionBuild=" + URLEncoder.encode("" + ApplicationInfo.version_build, "UTF-8")
|
|
+ "¤tNightly=" + (ApplicationInfo.nightly ? "1" : "0") + " HTTP/1.1\r\n"
|
|
+ "Host: www.free-decompiler.com\r\n"
|
|
+ "X-Accept-Versions: " + acceptVersions + "\r\n"
|
|
+ "X-Update-Major: " + UPDATE_SYSTEM_MAJOR + "\r\n"
|
|
+ "X-Update-Minor: " + UPDATE_SYSTEM_MINOR + "\r\n"
|
|
+ "User-Agent: " + ApplicationInfo.shortApplicationVerName + "\r\n"
|
|
+ "Accept-Language: " + currentLoc + ("en".equals(currentLoc) ? "" : ", en;q=0.8") + "\r\n"
|
|
+ "Connection: close\r\n"
|
|
+ "\r\n").getBytes());
|
|
BufferedReader br = new BufferedReader(new InputStreamReader(sock.getInputStream()));
|
|
String s;
|
|
boolean start = false;
|
|
final java.util.List<Version> versions = new ArrayList<>();
|
|
String header = "";
|
|
Pattern headerPat = Pattern.compile("\\[([a-zA-Z0-9]+)\\]");
|
|
int updateMajor;
|
|
int updateMinor;
|
|
Version ver = null;
|
|
while ((s = br.readLine()) != null) {
|
|
if (start) {
|
|
Matcher m = headerPat.matcher(s);
|
|
if (m.matches()) {
|
|
header = m.group(1);
|
|
if (header.equals("version")) {
|
|
ver = new Version();
|
|
versions.add(ver);
|
|
}
|
|
if (header.equals("noversion")) {
|
|
break;
|
|
}
|
|
} else {
|
|
if (s.contains("=")) {
|
|
String key = s.substring(0, s.indexOf('='));
|
|
String val = s.substring(s.indexOf('=') + 1);
|
|
if ("updateSystem".equals(header)) {
|
|
if (key.equals("majorVersion")) {
|
|
updateMajor = Integer.parseInt(val);
|
|
if (updateMajor > UPDATE_SYSTEM_MAJOR) {
|
|
break;
|
|
}
|
|
}
|
|
if (key.equals("minorVersion")) {
|
|
updateMinor = Integer.parseInt(val);
|
|
}
|
|
}
|
|
if ("version".equals(header) && (ver != null)) {
|
|
if (key.equals("versionId")) {
|
|
ver.versionId = Integer.parseInt(val);
|
|
}
|
|
if (key.equals("versionName")) {
|
|
ver.versionName = val;
|
|
}
|
|
if (key.equals("nightly")) {
|
|
ver.nightly = val.equals("true");
|
|
}
|
|
if (key.equals("revision")) {
|
|
ver.revision = val;
|
|
}
|
|
if (key.equals("build")) {
|
|
ver.build = Integer.parseInt(val);
|
|
}
|
|
if (key.equals("major")) {
|
|
ver.major = Integer.parseInt(val);
|
|
}
|
|
if (key.equals("minor")) {
|
|
ver.minor = Integer.parseInt(val);
|
|
}
|
|
if (key.equals("release")) {
|
|
ver.release = Integer.parseInt(val);
|
|
}
|
|
if (key.equals("longVersionName")) {
|
|
ver.longVersionName = val;
|
|
}
|
|
if (key.equals("releaseDate")) {
|
|
ver.releaseDate = val;
|
|
}
|
|
if (key.equals("appName")) {
|
|
ver.appName = val;
|
|
}
|
|
if (key.equals("appFullName")) {
|
|
ver.appFullName = val;
|
|
}
|
|
if (key.equals("updateLink")) {
|
|
ver.updateLink = val;
|
|
}
|
|
if (key.equals("change[]")) {
|
|
String changeType = val.substring(0, val.indexOf('|'));
|
|
String change = val.substring(val.indexOf('|') + 1);
|
|
if (!ver.changes.containsKey(changeType)) {
|
|
ver.changes.put(changeType, new ArrayList<String>());
|
|
}
|
|
List<String> chlist = ver.changes.get(changeType);
|
|
chlist.add(change);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (s.isEmpty()) {
|
|
start = true;
|
|
}
|
|
}
|
|
|
|
if (!versions.isEmpty()) {
|
|
View.execInEventDispatch(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
NewVersionDialog newVersionDialog = new NewVersionDialog(versions);
|
|
newVersionDialog.setVisible(true);
|
|
Configuration.lastUpdatesCheckDate.set(Calendar.getInstance());
|
|
}
|
|
});
|
|
|
|
return true;
|
|
}
|
|
} catch (IOException | NumberFormatException ex) {
|
|
return false;
|
|
}
|
|
Configuration.lastUpdatesCheckDate.set(Calendar.getInstance());
|
|
return false;
|
|
}
|
|
private static FileHandler fileTxt;
|
|
|
|
public static void clearLogFile() {
|
|
Logger logger = Logger.getLogger("");
|
|
if (fileTxt != null) {
|
|
fileTxt.flush();
|
|
fileTxt.close();
|
|
logger.removeHandler(fileTxt);
|
|
}
|
|
|
|
String fileName;
|
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss");
|
|
|
|
try {
|
|
fileName = Configuration.getFFDecHome() + File.separator + "logs" + File.separator;
|
|
if (Configuration.useDetailedLogging.get()) {
|
|
fileName += "log-" + sdf.format(new Date()) + ".txt";
|
|
} else {
|
|
fileName += "log.txt";
|
|
}
|
|
File f = new File(fileName).getParentFile();
|
|
if (!f.exists()) {
|
|
f.mkdir();
|
|
}
|
|
fileTxt = new FileHandler(fileName);
|
|
} catch (IOException | SecurityException ex) {
|
|
logger.log(Level.SEVERE, null, ex);
|
|
}
|
|
|
|
Formatter formatterTxt = new LogFormatter();
|
|
fileTxt.setFormatter(formatterTxt);
|
|
logger.addHandler(fileTxt);
|
|
|
|
if (!GraphicsEnvironment.isHeadless()) {
|
|
ErrorLogFrame.getInstance().clearErrorState();
|
|
}
|
|
|
|
sdf = new SimpleDateFormat("yyyy-MM-dd");
|
|
logger.log(Level.INFO, "Date: {0}", sdf.format(new Date()));
|
|
logger.log(Level.INFO, ApplicationInfo.applicationVerName);
|
|
logger.log(Level.INFO, "{0} {1} {2}", new Object[]{
|
|
System.getProperty("os.name"), System.getProperty("os.version"), System.getProperty("os.arch")});
|
|
logger.log(Level.INFO, "{0} {1} {2}", new Object[]{
|
|
System.getProperty("java.version"), System.getProperty("java.vendor"), System.getProperty("os.arch")});
|
|
}
|
|
|
|
public static void initLogging(boolean debug) {
|
|
try {
|
|
Logger logger = Logger.getLogger("");
|
|
logger.setLevel(Configuration.logLevel);
|
|
|
|
int handlerCount = logger.getHandlers().length;
|
|
for (int i = handlerCount - 1; i >= 0; i--) {
|
|
logger.removeHandler(logger.getHandlers()[i]);
|
|
}
|
|
ConsoleHandler conHan = new ConsoleHandler();
|
|
conHan.setLevel(debug ? Level.CONFIG : Level.WARNING);
|
|
SimpleFormatter formatterTxt = new SimpleFormatter();
|
|
conHan.setFormatter(formatterTxt);
|
|
logger.addHandler(conHan);
|
|
clearLogFile();
|
|
|
|
} catch (Exception ex) {
|
|
throw new RuntimeException("Problems with creating the log files");
|
|
}
|
|
}
|
|
}
|