/* * Copyright (C) 2010-2016 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.debugger.flash.Debugger; import com.jpexs.debugger.flash.DebuggerCommands; import com.jpexs.debugger.flash.Variable; import com.jpexs.debugger.flash.VariableType; import com.jpexs.debugger.flash.messages.in.InCallFunction; 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.SwfOpenException; import com.jpexs.decompiler.flash.UrlResolver; import com.jpexs.decompiler.flash.Version; import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.configuration.SwfSpecificConfiguration; import com.jpexs.decompiler.flash.console.CommandLineArgumentParser; import com.jpexs.decompiler.flash.console.ContextMenuTools; import com.jpexs.decompiler.flash.exporters.modes.ExeExportMode; import com.jpexs.decompiler.flash.gui.debugger.DebugListener; import com.jpexs.decompiler.flash.gui.debugger.DebuggerTools; import com.jpexs.decompiler.flash.gui.pipes.FirstInstance; import com.jpexs.decompiler.flash.gui.proxy.ProxyFrame; import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.FontTag; import com.jpexs.decompiler.flash.tags.base.ImportTag; 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.BufferedOutputStream; 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.InetSocketAddress; import java.net.Proxy; import java.net.URL; import java.net.URLConnection; 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; import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.logging.ConsoleHandler; import java.util.logging.FileHandler; import java.util.logging.Formatter; import java.util.logging.Handler; 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; import org.pushingpixels.substance.api.SubstanceLookAndFeel; /** * Main executable class * * @author JPEXS */ public class Main { protected static ProxyFrame proxyFrame; private static List<SWFSourceInfo> sourceInfos = new ArrayList<>(); public static LoadingDialog loadingDialog; private static boolean working = false; private static TrayIcon trayIcon; private static MenuItem stopMenuItem; private static volatile MainFrame mainFrame; public static final int UPDATE_SYSTEM_MAJOR = 1; public static final int UPDATE_SYSTEM_MINOR = 3; private static LoadFromMemoryFrame loadFromMemoryFrame; private static LoadFromCacheFrame loadFromCacheFrame; private static final Logger logger = Logger.getLogger(Main.class.getName()); public static DebugLogDialog debugDialog; public static boolean shouldCloseWhenClosingLoadingDialog; private static Debugger flashDebugger; private static DebuggerHandler debugHandler = null; //private static int ip = 0; //private static String ipClass = null; private static Process runProcess; private static boolean runProcessDebug; private static boolean runProcessDebugPCode; private static boolean inited = false; private static File runTempFile; private static List<File> runTempFiles = new ArrayList<>(); public static void freeRun() { synchronized (Main.class) { if (runTempFile != null) { runTempFile.delete(); runTempFile = null; } for (File f : runTempFiles) { f.delete(); } runTempFiles.clear(); runProcess = null; } if (mainFrame != null && mainFrame.getPanel() != null) { mainFrame.getPanel().clearDebuggerColors(); } if (runProcessDebug) { Main.getDebugHandler().disconnect(); } } public static synchronized boolean isDebugPaused() { return runProcess != null && runProcessDebug && getDebugHandler().isPaused(); } public static synchronized boolean isDebugRunning() { return runProcess != null && runProcessDebug; } public static synchronized boolean isDebugPCode() { return runProcessDebugPCode; } public static synchronized boolean isDebugConnected() { return getDebugHandler().isConnected(); } public static synchronized boolean isRunning() { return runProcess != null && !runProcessDebug; } /** * FIXME! * * @param v */ public static synchronized void dumpBytes(Variable v) { InCallFunction icf; try { long objectId = 0l; if ((v.vType == VariableType.OBJECT || v.vType == VariableType.MOVIECLIP)) { objectId = (Long) v.value; } Object oldPos = getDebugHandler().getVariable(objectId, "position", true).parent.value; getDebugHandler().setVariable(objectId, "position", VariableType.NUMBER, 0); icf = getDebugHandler().callFunction(false, "readUTF", v, new ArrayList<>()); System.out.println("Result=" + icf.variables.get(0).value); getDebugHandler().setVariable(objectId, "position", VariableType.NUMBER, oldPos); } catch (DebuggerHandler.ActionScriptException ex) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); } } public static synchronized boolean addWatch(Variable v, long v_id, boolean watchRead, boolean watchWrite) { DebuggerCommands.Watch w = getDebugHandler().addWatch(v, v_id, watchRead, watchWrite); return w != null; } public static void runPlayer(String title, final String exePath, String file, String flashVars) { if (!new File(file).exists()) { return; } if (flashVars != null && !flashVars.isEmpty()) { file += "?" + flashVars; } final String ffile = file; CancellableWorker runWorker = new CancellableWorker() { @Override protected Object doInBackground() throws Exception { Process proc; try { proc = Runtime.getRuntime().exec(new String[]{exePath, ffile}); } catch (IOException ex) { logger.log(Level.SEVERE, null, ex); return null; } boolean isDebug; synchronized (Main.class) { runProcess = proc; isDebug = runProcessDebug; } if (isDebug) { mainFrame.getMenu().hilightPath("/debugging"); } mainFrame.getMenu().updateComponents(); try { if (proc != null) { proc.waitFor(); } } catch (InterruptedException ex) { if (proc != null) { try { proc.destroy(); } catch (Exception ex2) { //ignore } } } freeRun(); stopDebugger(); mainFrame.getMenu().updateComponents(); return null; } @Override protected void done() { Main.stopWork(); } @Override public void workerCancelled() { Main.stopWork(); synchronized (Main.class) { if (runProcess != null) { try { runProcess.destroy(); } catch (Exception ex) { } } } freeRun(); mainFrame.getMenu().updateComponents(); } }; mainFrame.getMenu().updateComponents(); Main.startWork(title + "...", runWorker); runWorker.execute(); } public static void stopRun() { synchronized (Main.class) { if (runProcess != null) { runProcess.destroy(); } } freeRun(); stopDebugger(); mainFrame.getMenu().updateComponents(); } private static interface SwfPreparation { public SWF prepare(SWF swf); } private static class SwfRunPrepare implements SwfPreparation { @Override public SWF prepare(SWF swf) { if (Configuration.autoOpenLoadedSWFs.get()) { if (!DebuggerTools.hasDebugger(swf)) { DebuggerTools.switchDebugger(swf); } DebuggerTools.injectDebugLoader(swf); } return swf; } } private static class SwfDebugPrepare extends SwfRunPrepare { private boolean doPCode; public SwfDebugPrepare(boolean doPCode) { this.doPCode = doPCode; } @Override public SWF prepare(SWF instrSWF) { instrSWF = super.prepare(instrSWF); try { File fTempFile = new File(instrSWF.getFile()); instrSWF.enableDebugging(true, new File("."), true, doPCode); FileOutputStream fos = new FileOutputStream(fTempFile); instrSWF.saveTo(fos); fos.close(); if (!instrSWF.isAS3()) { //Read again, because line file offsets changed with adding debug tags //TODO: handle somehow without rereading? instrSWF = null; try (FileInputStream fis = new FileInputStream(fTempFile)) { instrSWF = new SWF(fis, false, false); } catch (InterruptedException ex) { logger.log(Level.SEVERE, null, ex); } if (instrSWF != null) { String swfFileName = fTempFile.getAbsolutePath(); if (swfFileName.toLowerCase().endsWith(".swf")) { swfFileName = swfFileName.substring(0, swfFileName.length() - 4) + ".swd"; } else { swfFileName = swfFileName + ".swd"; } File swdFile = new File(swfFileName); if (doPCode) { instrSWF.generatePCodeSwdFile(swdFile, getPackBreakPoints(true)); } else { instrSWF.generateSwdFile(swdFile, getPackBreakPoints(true)); } } } } catch (IOException ex) { //ignore, return instrSWF } return instrSWF; } } private static void prepareSwf(SwfPreparation prep, File toPrepareFile, File origFile, List<File> tempFiles) throws IOException { SWF instrSWF = null; try (FileInputStream fis = new FileInputStream(toPrepareFile)) { instrSWF = new SWF(fis, toPrepareFile.getAbsolutePath(), origFile.getName(), false); } catch (InterruptedException ex) { logger.log(Level.SEVERE, null, ex); } if (instrSWF != null) { for (Tag t : instrSWF.getLocalTags()) { if (t instanceof ImportTag) { ImportTag it = (ImportTag) t; String url = it.getUrl(); File importedFile = new File(origFile.getParentFile(), url); if (importedFile.exists()) { File newTempFile = File.createTempFile("ffdec_run_import_", ".swf"); it.setUrl("./" + newTempFile.getName()); byte[] impData = Helper.readFile(importedFile.getAbsolutePath()); Helper.writeFile(newTempFile.getAbsolutePath(), impData); tempFiles.add(newTempFile); prepareSwf(prep, newTempFile, importedFile, tempFiles); } } } if (prep != null) { instrSWF = prep.prepare(instrSWF); } try (FileOutputStream fos = new FileOutputStream(toPrepareFile)) { instrSWF.saveTo(fos); } } } public static void run(SWF swf) { String flashVars = "";//key=val&key2=val2 String playerLocation = Configuration.playerLocation.get(); if (playerLocation.isEmpty() || (!new File(playerLocation).exists())) { View.showMessageDialog(null, AppStrings.translate("message.playerpath.notset"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE); advancedSettings("paths"); return; } if (swf == null) { return; } File tempFile; List<File> tempFiles = new ArrayList<>(); try { tempFile = File.createTempFile("ffdec_run_", ".swf"); try (FileOutputStream fos = new FileOutputStream(tempFile)) { swf.saveTo(fos); } prepareSwf(new SwfRunPrepare(), tempFile, new File(swf.getFile()), tempFiles); } catch (IOException ex) { return; } if (tempFile != null) { synchronized (Main.class) { runTempFile = tempFile; runTempFiles = tempFiles; runProcessDebug = false; } runPlayer(AppStrings.translate("work.running"), playerLocation, tempFile.getAbsolutePath(), flashVars); } } public static void runDebug(SWF swf, final boolean doPCode) { String flashVars = "";//key=val&key2=val2 String playerLocation = Configuration.playerDebugLocation.get(); if (playerLocation.isEmpty() || (!new File(playerLocation).exists())) { View.showMessageDialog(null, AppStrings.translate("message.playerpath.debug.notset"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE); Main.advancedSettings("paths"); return; } if (swf == null) { return; } File tempFile = null; try { tempFile = File.createTempFile("ffdec_debug_", ".swf"); } catch (Exception ex) { } if (tempFile != null) { final File fTempFile = tempFile; final List<File> tempFiles = new ArrayList<>(); CancellableWorker instrumentWorker = new CancellableWorker() { @Override protected Object doInBackground() throws Exception { try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(fTempFile))) { swf.saveTo(fos); } prepareSwf(new SwfDebugPrepare(doPCode), fTempFile, new File(swf.getFile()), tempFiles); return null; } @Override public void workerCancelled() { Main.stopWork(); } @Override protected void done() { synchronized (Main.class) { runTempFile = fTempFile; runProcessDebug = true; runProcessDebugPCode = doPCode; runTempFiles = tempFiles; } Main.stopWork(); Main.startDebugger(); runPlayer(AppStrings.translate("work.debugging.wait"), playerLocation, fTempFile.getAbsolutePath(), flashVars); } }; Main.startWork(AppStrings.translate("work.debugging.instrumenting"), instrumentWorker); instrumentWorker.execute(); } } /* public static void debuggerNotSuspended() { }*/ public static boolean isDebugging() { return isDebugRunning(); } public synchronized static int getIp(Object pack) { return getDebugHandler().getBreakIp(); } public synchronized static String getIpClass() { return getDebugHandler().getBreakScriptName(); } public static synchronized boolean isBreakPointValid(String scriptName, int line) { return !getDebugHandler().isBreakpointInvalid(scriptName, line); } public synchronized static void addBreakPoint(String scriptName, int line) { getDebugHandler().addBreakPoint(scriptName, line); } public synchronized static void removeBreakPoint(String scriptName, int line) { getDebugHandler().removeBreakPoint(scriptName, line); } public synchronized static boolean toggleBreakPoint(String scriptName, int line) { if (getDebugHandler().isBreakpointToAdd(scriptName, line) || getDebugHandler().isBreakpointConfirmed(scriptName, line) || getDebugHandler().isBreakpointInvalid(scriptName, line)) { getDebugHandler().removeBreakPoint(scriptName, line); return false; } else { getDebugHandler().addBreakPoint(scriptName, line); return true; } } public synchronized static Map<String, Set<Integer>> getPackBreakPoints(boolean validOnly) { return getDebugHandler().getAllBreakPoints(validOnly); } public synchronized static Set<Integer> getScriptBreakPoints(String pack, boolean onlyValid) { return getDebugHandler().getBreakPoints(pack, onlyValid); } public static DebuggerHandler getDebugHandler() { return debugHandler; } public static void ensureMainFrame() { if (mainFrame == null) { synchronized (Main.class) { if (mainFrame == null) { MainFrame frame; if (Configuration.useRibbonInterface.get()) { frame = new MainFrameRibbon(); } else { frame = new MainFrameClassic(); } frame.getPanel().setErrorState(ErrorLogFrame.getInstance().getErrorState()); mainFrame = frame; } } } } 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 setVariable(long parentId, String varName, int valueType, Object value) { getDebugHandler().setVariable(parentId, varName, valueType, value); } public static void setSubLimiter(boolean value) { if (value) { AVM2Code.toSourceLimit = Configuration.sublimiter.get(); } else { AVM2Code.toSourceLimit = -1; } } public synchronized static boolean isInited() { return inited; } public synchronized static void setSessionLoaded(boolean v) { inited = v; } public static boolean isWorking() { return working; } public static void startProxy(int port) { 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, CancellableWorker worker) { startWork(name, -1, worker); } public static void startWork(final String name, final int percent, final CancellableWorker worker) { working = true; View.execInEventDispatchLater(() -> { 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); loadingDialog.setPercent(percent); } if (CommandLineArgumentParser.isCommandLineMode()) { System.out.println(name); } }); } public static void stopWork() { working = false; View.execInEventDispatchLater(() -> { 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.bundle = bundle; result.name = new File(sourceInfo.getFileTitleOrName()).getName(); for (Entry<String, SeekableInputStream> streamEntry : bundle.getAll().entrySet()) { InputStream stream = streamEntry.getValue(); stream.reset(); CancellableWorker<SWF> worker = new CancellableWorker<SWF>() { @Override public SWF doInBackground() throws Exception { final CancellableWorker worker = this; SWF swf = new SWF(stream, null, streamEntry.getKey(), new ProgressListener() { @Override public void progress(int p) { startWork(AppStrings.translate("work.reading.swf"), p, worker); } }, Configuration.parallelSpeedUp.get()); return swf; } }; loadingDialog.setWroker(worker); worker.execute(); try { result.add(worker.get()); } catch (CancellationException ex) { logger.log(Level.WARNING, "Loading SWF {0} was cancelled.", streamEntry.getKey()); } } } else { InputStream fInputStream = inputStream; final String[] yesno = new String[]{AppStrings.translate("button.yes"), AppStrings.translate("button.no"), AppStrings.translate("button.yes.all"), AppStrings.translate("button.no.all")}; CancellableWorker<SWF> worker = new CancellableWorker<SWF>() { private boolean yestoall = false; private boolean notoall = false; private SWF open(InputStream is, String file, String fileTitle) throws IOException, InterruptedException { final CancellableWorker worker = this; SWF swf = new SWF(is, file, fileTitle, new ProgressListener() { @Override public void progress(int p) { startWork(AppStrings.translate("work.reading.swf"), p, worker); } }, Configuration.parallelSpeedUp.get(), false, true, new UrlResolver() { @Override public SWF resolveUrl(final String url) { int opt = -1; if (!(yestoall || notoall)) { opt = View.showOptionDialog(null, AppStrings.translate("message.imported.swf").replace("%url%", url), AppStrings.translate("message.warning"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, yesno, AppStrings.translate("button.yes")); if (opt == 2) { yestoall = true; } if (opt == 3) { notoall = true; } } if (yestoall) { opt = 0; // yes } else if (notoall) { opt = 1; // no } if (opt == 1) //no { return null; } if (url.startsWith("http://") || url.startsWith("https://")) { try { URL u = new URL(url); return open(u.openStream(), null, url); //? } catch (Exception ex) { //ignore } } else { File f = new File(new File(file).getParentFile(), url); if (f.exists()) { try { return open(new FileInputStream(f), f.getAbsolutePath(), f.getName()); } catch (Exception ex) { //ignore } } } Reference<SWF> ret = new Reference<>(null); View.execInEventDispatch(new Runnable() { @Override public void run() { while (JOptionPane.YES_OPTION == View.showConfirmDialog(null, AppStrings.translate("message.imported.swf.manually").replace("%url%", url), AppStrings.translate("error"), JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE)) { JFileChooser fc = new JFileChooser(); fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get())); FileFilter allSupportedFilter = new FileFilter() { private final String[] supportedExtensions = new String[]{".swf", ".gfx"}; @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 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); 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 selFile = Helper.fixDialogFile(fc.getSelectedFile()); try { ret.setVal(open(new FileInputStream(selFile), selFile.getAbsolutePath(), selFile.getName())); break; } catch (Exception ex) { //ignore; } } else { break; } } } }); return ret.getVal(); } }); return swf; } @Override public SWF doInBackground() throws Exception { return open(fInputStream, sourceInfo.getFile(), sourceInfo.getFileTitle()); } }; if (loadingDialog != null) { loadingDialog.setWroker(worker); } worker.execute(); try { result.add(worker.get()); } catch (CancellationException ex) { logger.log(Level.WARNING, "Loading SWF {0} was cancelled.", sourceInfo.getFileTitleOrName()); } } 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 handleExportingEvent(String type, int index, int count, Object data) { String text = AppStrings.translate("work.exporting"); if (type != null && type.length() > 0) { text += " " + type; } startWork(text + " " + index + "/" + count + " " + data, null); } @Override public void handleExportedEvent(String type, int index, int count, Object data) { String text = AppStrings.translate("work.exported"); if (type != null && type.length() > 0) { text += " " + type; } startWork(text + " " + index + "/" + count + " " + data, null); } @Override public void handleEvent(String event, Object data) { if (event.equals("exporting") || event.equals("exported")) { throw new Error("Event is not supported by this handler."); } if (event.equals("getVariables")) { startWork(AppStrings.translate("work.gettingvariables") + "..." + (String) data, null); } if (event.equals("deobfuscate")) { startWork(AppStrings.translate("work.deobfuscating") + "..." + (String) data, null); } if (event.equals("rename")) { startWork(AppStrings.translate("work.renaming") + "..." + (String) data, null); } } }); } return result; } public static void saveFile(SWF swf, String outfile) throws IOException { saveFile(swf, outfile, SaveFileMode.SAVE, null); } public static void saveFile(SWF swf, String outfile, SaveFileMode mode, ExeExportMode exeExportMode) throws IOException { if (mode == SaveFileMode.SAVEAS && !swf.swfList.isBundle()) { swf.setFile(outfile); swf.swfList.sourceInfo.setFile(outfile); } File outfileF = new File(outfile); File tmpFile = new File(outfile + ".tmp"); try (FileOutputStream fos = new FileOutputStream(tmpFile); BufferedOutputStream bos = new BufferedOutputStream(fos)) { if (mode == SaveFileMode.EXE) { switch (exeExportMode) { case WRAPPER: InputStream exeStream = View.class.getClassLoader().getResourceAsStream("com/jpexs/helpers/resource/Swf2Exe.bin"); Helper.copyStream(exeStream, bos); int width = swf.displayRect.Xmax - swf.displayRect.Xmin; int height = swf.displayRect.Ymax - swf.displayRect.Ymin; bos.write(width & 0xff); bos.write((width >> 8) & 0xff); bos.write((width >> 16) & 0xff); bos.write((width >> 24) & 0xff); bos.write(height & 0xff); bos.write((height >> 8) & 0xff); bos.write((height >> 16) & 0xff); bos.write((height >> 24) & 0xff); bos.write(Configuration.saveAsExeScaleMode.get()); break; case PROJECTOR_WIN: case PROJECTOR_MAC: case PROJECTOR_LINUX: File projectorFile = Configuration.getProjectorFile(exeExportMode); if (projectorFile == null) { String message = "Projector not found, please place it to " + Configuration.getProjectorPath(); logger.log(Level.SEVERE, message); throw new IOException(message); } Helper.copyStream(new FileInputStream(projectorFile), bos); bos.flush(); break; } } long pos = fos.getChannel().position(); swf.saveTo(bos); if (mode == SaveFileMode.EXE) { switch (exeExportMode) { case PROJECTOR_WIN: case PROJECTOR_MAC: case PROJECTOR_LINUX: bos.flush(); int swfSize = (int) (fos.getChannel().position() - pos); // write magic number bos.write(0x56); bos.write(0x34); bos.write(0x12); bos.write(0xfa); bos.write(swfSize & 0xff); bos.write((swfSize >> 8) & 0xff); bos.write((swfSize >> 16) & 0xff); bos.write((swfSize >> 24) & 0xff); } } } 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"); } } else { throw new IOException("Output not found"); } } private static class OpenFileWorker extends SwingWorker { private final SWFSourceInfo[] sourceInfos; private final Runnable executeAfterOpen; private final int[] reloadIndices; public OpenFileWorker(SWFSourceInfo sourceInfo) { this(sourceInfo, -1); } public OpenFileWorker(SWFSourceInfo sourceInfo, int reloadIndex) { this(sourceInfo, null, reloadIndex); } public OpenFileWorker(SWFSourceInfo sourceInfo, Runnable executeAfterOpen) { this(sourceInfo, executeAfterOpen, -1); } public OpenFileWorker(SWFSourceInfo sourceInfo, Runnable executeAfterOpen, int reloadIndex) { this.sourceInfos = new SWFSourceInfo[]{sourceInfo}; this.executeAfterOpen = executeAfterOpen; this.reloadIndices = new int[]{reloadIndex}; } public OpenFileWorker(SWFSourceInfo[] sourceInfos) { this(sourceInfos, null, null); } public OpenFileWorker(SWFSourceInfo[] sourceInfos, Runnable executeAfterOpen) { this(sourceInfos, executeAfterOpen, null); } public OpenFileWorker(SWFSourceInfo[] sourceInfos, Runnable executeAfterOpen, int[] reloadIndices) { this.sourceInfos = sourceInfos; this.executeAfterOpen = executeAfterOpen; int[] indices = new int[sourceInfos.length]; for (int i = 0; i < indices.length; i++) { indices[i] = -1; } this.reloadIndices = reloadIndices == null ? indices : reloadIndices; } @Override protected Object doInBackground() throws Exception { boolean first = true; SWF firstSWF = null; for (int index = 0; index < sourceInfos.length; index++) { SWFSourceInfo sourceInfo = sourceInfos[index]; SWFList swfs = null; try { Main.startWork(AppStrings.translate("work.reading.swf") + "...", null); try { swfs = parseSWF(sourceInfo); } catch (ExecutionException ex) { Throwable cause = ex.getCause(); if (cause instanceof SwfOpenException) { throw (SwfOpenException) cause; } throw ex; } } catch (OutOfMemoryError ex) { logger.log(Level.SEVERE, null, ex); View.showMessageDialog(null, "Cannot load SWF file. Out of memory."); continue; } catch (SwfOpenException ex) { logger.log(Level.SEVERE, null, ex); View.showMessageDialog(null, ex.getMessage()); continue; } catch (Exception ex) { logger.log(Level.SEVERE, null, ex); View.showMessageDialog(null, "Cannot load SWF file."); continue; } final SWFList swfs1 = swfs; final boolean first1 = first; first = false; if (firstSWF == null && swfs1.size() > 0) { firstSWF = swfs1.get(0); } final int findex = index; try { View.execInEventDispatch(() -> { Main.startWork(AppStrings.translate("work.creatingwindow") + "...", null); ensureMainFrame(); if (reloadIndices[findex] > -1) { mainFrame.getPanel().loadSwfAtPos(swfs1, reloadIndices[findex]); } else { mainFrame.getPanel().load(swfs1, first1); } }); } catch (Exception ex) { logger.log(Level.SEVERE, null, ex); } } loadingDialog.setVisible(false); shouldCloseWhenClosingLoadingDialog = false; final SWF fswf = firstSWF; View.execInEventDispatch(() -> { if (mainFrame != null) { mainFrame.setVisible(true); } Main.stopWork(); if (mainFrame != null && Configuration.gotoMainClassOnStartup.get()) { mainFrame.getPanel().gotoDocumentClass(fswf); } if (mainFrame != null && fswf != null) { SwfSpecificConfiguration swfConf = Configuration.getSwfSpecificConfiguration(fswf.getShortFileName()); if (swfConf != null) { String pathStr = swfConf.lastSelectedPath; mainFrame.getPanel().tagTree.setSelectionPathString(pathStr); } } if (executeAfterOpen != null) { executeAfterOpen.run(); } }); 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.dispose(); debugDialog = null; } if (loadingDialog != null) { synchronized (Main.class) { if (loadingDialog != null) { loadingDialog.setVisible(false); loadingDialog.dispose(); loadingDialog = null; } } } if (proxyFrame != null) { proxyFrame.setVisible(false); proxyFrame.dispose(); proxyFrame = null; } if (loadFromMemoryFrame != null) { loadFromMemoryFrame.setVisible(false); loadFromMemoryFrame.dispose(); loadFromMemoryFrame = null; } if (loadFromCacheFrame != null) { loadFromCacheFrame.setVisible(false); loadFromCacheFrame.dispose(); loadFromCacheFrame = null; } if (mainFrame != null) { mainFrame.setVisible(false); mainFrame.getPanel().closeAll(false); mainFrame.dispose(); mainFrame = null; } FontTag.reload(); Cache.clearAll(); initGui(); reloadSWFs(); } public static OpenFileResult openFile(String swfFile, String fileTitle) { return openFile(swfFile, fileTitle, null); } public static OpenFileResult openFile(String swfFile, String fileTitle, Runnable executeAfterOpen) { 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(); 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 sourceInfo, Runnable executeAfterOpen) { return openFile(new SWFSourceInfo[]{sourceInfo}, executeAfterOpen); } public static OpenFileResult openFile(SWFSourceInfo sourceInfo, Runnable executeAfterOpen, int reloadIndex) { return openFile(new SWFSourceInfo[]{sourceInfo}, executeAfterOpen, new int[]{reloadIndex}); } public static OpenFileResult openFile(SWFSourceInfo[] newSourceInfos) { return openFile(newSourceInfos, null); } public static OpenFileResult openFile(SWFSourceInfo[] newSourceInfos, Runnable executeAfterOpen) { return openFile(newSourceInfos, executeAfterOpen, null); } public static OpenFileResult openFile(SWFSourceInfo[] newSourceInfos, Runnable executeAfterOpen, int[] reloadIndices) { if (mainFrame != null && !Configuration.openMultipleFiles.get()) { sourceInfos.clear(); mainFrame.getPanel().closeAll(false); mainFrame.setVisible(false); Helper.freeMem(); reloadIndices = null; } loadingDialog.setVisible(true); for (int i = 0; i < newSourceInfos.length; i++) { SWFSourceInfo si = newSourceInfos[i]; String fileName = si.getFile(); if (fileName != null) { Configuration.addRecentFile(fileName); } } OpenFileWorker wrk = new OpenFileWorker(newSourceInfos, executeAfterOpen, reloadIndices); wrk.execute(); if (reloadIndices == null) { sourceInfos.addAll(Arrays.asList(newSourceInfos)); } else { for (int i = 0; i < reloadIndices.length; i++) { sourceInfos.set(reloadIndices[i], newSourceInfos[i]); } } return OpenFileResult.OK; } public static void closeFile(SWFList swf) { sourceInfos.remove(swf.sourceInfo); mainFrame.getPanel().close(swf); } public static void reloadFile(SWFList swf) { //mainFrame.getPanel().close(swf); openFile(swf.sourceInfo, null, sourceInfos.indexOf(swf.sourceInfo)); } public static boolean closeAll() { boolean closeResult = mainFrame.getPanel().closeAll(true); if (closeResult) { sourceInfos.clear(); } return closeResult; } 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.getFile() != null) { ext = Path.getExtension(swf.getFile()); } break; case EXE: ext = ".exe"; break; } 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"); } }; 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"); } }; ExeExportMode exeExportMode = null; if (mode == SaveFileMode.EXE) { exeExportMode = Configuration.exeExportMode.get(); if (exeExportMode == null) { exeExportMode = ExeExportMode.WRAPPER; } String filterDescription = null; switch (exeExportMode) { case WRAPPER: case PROJECTOR_WIN: ext = ".exe"; filterDescription = "filter.exe"; break; case PROJECTOR_MAC: ext = ".dmg"; filterDescription = "filter.dmg"; break; case PROJECTOR_LINUX: // linux projector is compressed with tar.gz // todo: decompress ext = ""; filterDescription = "filter.linuxExe"; break; } String fext = ext; String ffilterDescription = filterDescription; FileFilter exeFilter = new FileFilter() { @Override public boolean accept(File f) { return (f.getName().toLowerCase().endsWith(fext)) || (f.isDirectory()); } @Override public String getDescription() { return AppStrings.translate(ffilterDescription); } }; fc.setFileFilter(exeFilter); } else if (swf.gfx) { fc.addChoosableFileFilter(swfFilter); fc.setFileFilter(gfxFilter); } else { fc.setFileFilter(swfFilter); fc.addChoosableFileFilter(gfxFilter); } final String extension = ext; 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, exeExportMode); 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", ".iggy"}; @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 iggyFilter = new FileFilter() { @Override public boolean accept(File f) { return (f.getName().toLowerCase().endsWith(".iggy")) || (f.isDirectory()); } @Override public String getDescription() { return AppStrings.translate("filter.iggy"); } }; fc.addChoosableFileFilter(iggyFilter); 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 String md5(byte data[]) { try { java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5"); byte[] array = md.digest(data); StringBuilder sb = new StringBuilder(); for (int i = 0; i < array.length; ++i) { sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1, 3)); } return sb.toString(); } catch (java.security.NoSuchAlgorithmException e) { } return null; } private static void initGui() { if (GraphicsEnvironment.isHeadless()) { System.err.println("Error: Your system does not support Graphic User Interface"); exit(); } System.setProperty("sun.java2d.d3d", "false"); System.setProperty("sun.java2d.noddraw", "true"); if (Configuration.hwAcceleratedGraphics.get()) { System.setProperty("sun.java2d.opengl", Configuration._debugMode.get() ? "True" : "true"); } else { System.setProperty("sun.java2d.opengl", "false"); } initUiLang(); if (Configuration.useRibbonInterface.get()) { View.setLookAndFeel(); } else { try { UIManager.put(SubstanceLookAndFeel.COLORIZATION_FACTOR, null); UIManager.put("Tree.expandedIcon", null); UIManager.put("Tree.collapsedIcon", null); UIManager.put("ColorChooserUI", null); UIManager.put("ColorChooser.swatchesRecentSwatchSize", null); UIManager.put("ColorChooser.swatchesSwatchSize", null); UIManager.put("RibbonApplicationMenuPopupPanelUI", null); UIManager.put("RibbonApplicationMenuButtonUI", null); UIManager.put("ProgressBarUI", null); UIManager.put("TextField.background", null); UIManager.put("FormattedTextField.background", null); UIManager.put("CommandButtonUI", null); UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { logger.log(Level.SEVERE, null, ex); } } View.execInEventDispatch(() -> { ErrorLogFrame.createNewInstance(); autoCheckForUpdates(); offerAssociation(); loadingDialog = new LoadingDialog(); DebuggerTools.initDebugger().addMessageListener(new DebugListener() { @Override public void onMessage(String clientId, String msg) { } @Override public void onLoaderURL(String clientId, String url) { } @Override public void onLoaderBytes(String clientId, byte[] data) { String hash = md5(data); for (SWFList sl : Main.getMainFrame().getPanel().getSwfs()) { for (int s = 0; s < sl.size(); s++) { String t = sl.get(s).getFileTitle(); if (t == null) { t = ""; } if (t.endsWith(":" + hash)) { //this one is already opened return; } } } SWF swf = Main.getMainFrame().getPanel().getCurrentSwf(); String title = swf == null ? "?" : swf.getFileTitle(); title = title + ":" + hash; String tfile; try { tfile = tempFile(title); Helper.writeFile(tfile, data); openFile(new SWFSourceInfo(null, tfile, title)); } catch (IOException ex) { logger.log(Level.SEVERE, "Cannot create tempfile"); } } @Override public void onFinish(String clientId) { } }); try { flashDebugger = new Debugger(); debugHandler = new DebuggerHandler(); debugHandler.addBreakListener(new DebuggerHandler.BreakListener() { @Override public void doContinue() { mainFrame.getPanel().clearDebuggerColors(); } @Override public void breakAt(String scriptName, int line, final int classIndex, final int traitIndex, final int methodIndex) { View.execInEventDispatch(new Runnable() { @Override public void run() { mainFrame.getPanel().gotoScriptLine(getMainFrame().getPanel().getCurrentSwf(), scriptName, line, classIndex, traitIndex, methodIndex); } }); } }); debugHandler.addConnectionListener(new DebuggerHandler.ConnectionListener() { @Override public void connected() { Main.mainFrame.getMenu().updateComponents(); } @Override public void disconnected() { if (Main.mainFrame != null && Main.mainFrame.getPanel() != null) { Main.mainFrame.getPanel().refreshBreakPoints(); } } }); flashDebugger.addConnectionListener(debugHandler); } catch (IOException ex) { logger.log(Level.SEVERE, "eeex", ex); } }); } public static void startDebugger() { flashDebugger.startDebugger(); } public static void stopDebugger() { flashDebugger.stopDebugger(); } public static void showModeFrame() { 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 initUiLang() { if (GraphicsEnvironment.isHeadless()) { //No GUI in OS return; } 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")); } public static void initLang() { 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(); 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"); } }); if (delFiles != null) { for (File f : delFiles) { try { f.delete(); } catch (Exception ex) { //ignore } } } } /** * @param args the command line arguments * @throws IOException On error */ public static void main(String[] args) throws IOException { setSessionLoaded(false); clearTemp(); try { SWFDecompilerPlugin.loadPlugins(); } catch (Throwable ex) { logger.log(Level.SEVERE, "Failed to load plugins", ex); } 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(); checkLibraryVersion(); View.execInEventDispatch(() -> { if (Configuration.allowOnlyOneInstance.get() && FirstInstance.focus()) { //Try to focus first instance Main.exit(); } else { showModeFrame(); reloadLastSession(); } }); } else { checkLibraryVersion(); setSessionLoaded(true); String[] filesToOpen = CommandLineArgumentParser.parseArguments(args); if (filesToOpen != null && filesToOpen.length > 0) { View.execInEventDispatch(() -> { initGui(); shouldCloseWhenClosingLoadingDialog = true; if (Configuration.allowOnlyOneInstance.get() && FirstInstance.openFiles(Arrays.asList(filesToOpen))) { //Try to open in first instance Main.exit(); } else { for (String fileToOpen : filesToOpen) { openFile(fileToOpen, null); } } }); } } } private static void checkLibraryVersion() { if (!ApplicationInfo.version.equals("unknown") && !ApplicationInfo.libraryVersion.equals("unknown") && !Objects.equals(ApplicationInfo.version, ApplicationInfo.libraryVersion)) { logger.log(Level.WARNING, "Application version is different from library version. FFDec may not work properly."); } } private static void reloadLastSession() { boolean openingFiles = false; if (Configuration.saveSessionOnExit.get()) { String lastSession = Configuration.lastSessionFiles.get(); if (lastSession != null && lastSession.length() > 0) { String[] filesToOpen = lastSession.split(File.pathSeparator, -1); List<String> exfiles = new ArrayList<>(); List<String> extitles = new ArrayList<>(); String lastSessionTitles = Configuration.lastSessionFileTitles.get(); String[] fileTitles = new String[0]; if (lastSessionTitles != null && !lastSessionTitles.isEmpty()) { fileTitles = lastSessionTitles.split(File.pathSeparator, -1); } for (int i = 0; i < filesToOpen.length; i++) { if (new File(filesToOpen[i]).exists()) { exfiles.add(filesToOpen[i]); if (fileTitles.length > i) { extitles.add(fileTitles[i]); } else { extitles.add(null); } } } SWFSourceInfo[] sourceInfos = new SWFSourceInfo[exfiles.size()]; for (int i = 0; i < exfiles.size(); i++) { String extitle = extitles.get(i); sourceInfos[i] = new SWFSourceInfo(null, exfiles.get(i), extitle == null || extitle.isEmpty() ? null : extitle); } if (sourceInfos.length > 0) { openingFiles = true; openFile(sourceInfos, () -> { mainFrame.getPanel().tagTree.setSelectionPathString(Configuration.lastSessionSelection.get()); setSessionLoaded(true); }); } } } if (!openingFiles) { setSessionLoaded(true); } } public static String tempFile(String url) throws IOException { File f = new File(Configuration.getFFDecHome() + "saved" + File.separator); Path.createDirectorySafe(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 (mainFrame != null && mainFrame.getPanel() != null) { mainFrame.getPanel().unloadFlashPlayer(); mainFrame.dispose(); } if (fileTxt != null) { try { fileTxt.flush(); fileTxt.close(); } catch (Exception ex) { //ignore } } System.exit(0); } public static void about() { (new AboutDialog()).setVisible(true); } public static void advancedSettings() { advancedSettings(null); } public static void advancedSettings(String category) { (new AdvancedSettingsDialog(category)).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 = String.join(",", accepted); try { String proxyAddress = Configuration.updateProxyAddress.get(); URL url = new URL(ApplicationInfo.updateCheckUrl); URLConnection uc; if (proxyAddress != null && !proxyAddress.isEmpty()) { int port = 8080; if (proxyAddress.contains(":")) { String[] parts = proxyAddress.split(":"); port = Integer.parseInt(parts[1]); proxyAddress = parts[0]; } uc = url.openConnection(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyAddress, port))); } else { uc = url.openConnection(); } uc.setRequestProperty("X-Accept-Versions", acceptVersions); uc.setRequestProperty("X-Update-Major", "" + UPDATE_SYSTEM_MAJOR); uc.setRequestProperty("X-Update-Minor", "" + UPDATE_SYSTEM_MINOR); uc.setRequestProperty("User-Agent", ApplicationInfo.shortApplicationVerName); String currentLoc = Configuration.locale.get("en"); uc.setRequestProperty("Accept-Language", currentLoc + ("en".equals(currentLoc) ? "" : ", en;q=0.8")); uc.connect(); BufferedReader br = new BufferedReader(new InputStreamReader(uc.getInputStream())); String s; 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) { 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<>()); } List<String> chlist = ver.changes.get(changeType); chlist.add(change); } } } } if (!versions.isEmpty()) { View.execInEventDispatch(() -> { 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(""); FileHandler oldFileTxt = fileTxt; fileTxt = null; if (oldFileTxt != null) { logger.removeHandler(fileTxt); oldFileTxt.flush(); oldFileTxt.close(); } String fileName = null; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss"); try { fileName = Configuration.getFFDecHome() + "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) { //cannot get lock error if (ex.getMessage().contains("lock for")) { //remove all old log files and their .lck for (int i = 0; i <= 100; i++) { File flog = new File(fileName + (i == 0 ? "" : "." + i)); File flog_lock = new File(fileName + (i == 0 ? "" : "." + i) + ".lck"); flog.delete(); flog_lock.delete(); } try { fileTxt = new FileHandler(fileName); } catch (IOException | SecurityException ex1) { logger.log(Level.SEVERE, "Cannot initialize logging", ex); } } else { logger.log(Level.SEVERE, "Cannot initialize logging", ex); } } Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { logger.log(Level.SEVERE, "Uncaught exception in thread: " + t.getName(), e); if (e instanceof OutOfMemoryError || !Helper.is64BitJre() && Helper.is64BitOs()) { View.showMessageDialog(null, AppStrings.translate("message.warning.outOfMemory32BitJre"), AppStrings.translate("message.warning"), JOptionPane.WARNING_MESSAGE); } } }); Formatter formatterTxt = new LogFormatter(); if (fileTxt != null) { fileTxt.setFormatter(formatterTxt); logger.addHandler(fileTxt); } if (!GraphicsEnvironment.isHeadless() && ErrorLogFrame.hasInstance()) { 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); Handler[] handlers = logger.getHandlers(); for (int i = handlers.length - 1; i >= 0; i--) { logger.removeHandler(handlers[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"); } } }