From 550327f82e6639fe00ea489526299491e3a0b739 Mon Sep 17 00:00:00 2001 From: "honfika@gmail.com" Date: Sun, 17 May 2015 00:16:39 +0200 Subject: [PATCH] using less memory when playing sounds --- .../src/com/jpexs/decompiler/flash/SWF.java | 16 + .../flash/configuration/Configuration.java | 1598 ++++++------ .../flash/exporters/SoundExporter.java | 335 +-- .../flash/tags/DefineBitsJPEG2Tag.java | 6 +- .../flash/tags/DefineBitsJPEG3Tag.java | 11 +- .../flash/tags/DefineBitsJPEG4Tag.java | 11 +- .../flash/tags/DefineBitsLossless2Tag.java | 6 +- .../flash/tags/DefineBitsLosslessTag.java | 6 +- .../decompiler/flash/tags/DefineBitsTag.java | 6 +- .../decompiler/flash/tags/DefineSoundTag.java | 8 +- .../decompiler/flash/tags/DoActionTag.java | 2 +- .../flash/tags/DoInitActionTag.java | 2 +- .../flash/tags/SoundStreamHead2Tag.java | 9 +- .../flash/tags/SoundStreamHeadTag.java | 9 +- .../com/jpexs/decompiler/flash/tags/Tag.java | 2 +- .../decompiler/flash/tags/base/SoundTag.java | 12 +- .../flash/types/BUTTONCONDACTION.java | 680 +++--- .../flash/types/CLIPACTIONRECORD.java | 586 ++--- .../src/com/jpexs/helpers/ByteArrayRange.java | 4 + .../flash/gui/FolderPreviewPanel.java | 691 +++--- .../decompiler/flash/gui/ImagePanel.java | 2138 +++++++++-------- .../jpexs/decompiler/flash/gui/MainPanel.java | 4 +- .../decompiler/flash/gui/PreviewPanel.java | 6 +- .../decompiler/flash/gui/SoundTagPlayer.java | 657 ++--- .../locales/AdvancedSettingsDialog.properties | 707 +++--- .../AdvancedSettingsDialog_hu.properties | 707 +++--- .../flash/gui/player/FlashPlayerPanel.java | 4 - .../flash/gui/player/MediaDisplay.java | 139 +- 28 files changed, 4226 insertions(+), 4136 deletions(-) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java index 2f7ee5f41..8f94ed169 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -103,6 +103,7 @@ import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; import com.jpexs.decompiler.flash.tags.base.RemoveTag; import com.jpexs.decompiler.flash.tags.base.RenderContext; import com.jpexs.decompiler.flash.tags.base.ShapeTag; +import com.jpexs.decompiler.flash.tags.base.SoundTag; import com.jpexs.decompiler.flash.tags.base.TextTag; import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.decompiler.flash.timeline.AS2Package; @@ -290,6 +291,9 @@ public final class SWF implements SWFContainerItem, Timelined { @Internal private Cache frameCache = Cache.getInstance(false, false, "frame"); + @Internal + private Cache soundCache = Cache.getInstance(false, false, "sound"); + @Internal private final Cache as2Cache = Cache.getInstance(true, false, "as2"); @@ -336,6 +340,7 @@ public final class SWF implements SWFContainerItem, Timelined { as2Cache.clear(); as3Cache.clear(); frameCache.clear(); + soundCache.clear(); timeline = null; clearDumpInfo(dumpInfo); @@ -2075,12 +2080,23 @@ public final class SWF implements SWFContainerItem, Timelined { return null; } + public byte[] getFromCache(SoundTag soundTag) { + if (soundCache.contains(soundTag)) { + return soundCache.get(soundTag); + } + return null; + } + public void putToCache(String key, SerializableImage img) { if (Configuration.useFrameCache.get()) { frameCache.put(key, img); } } + public void putToCache(SoundTag soundTag, byte[] data) { + soundCache.put(soundTag, data); + } + public void clearImageCache() { frameCache.clear(); DefineSpriteTag.clearCache(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java index a919b75a1..cffdeca97 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java @@ -1,797 +1,801 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.configuration; - -import com.jpexs.decompiler.flash.ApplicationInfo; -import com.jpexs.decompiler.flash.helpers.CodeFormatting; -import com.jpexs.decompiler.flash.importers.TextImportResizeTextBoundsMode; -import com.jpexs.helpers.Helper; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.lang.reflect.ParameterizedType; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.swing.JOptionPane; - -public class Configuration { - - private static final String CONFIG_NAME = "config.bin"; - - private static final File unspecifiedFile = new File("unspecified"); - - private static File directory = unspecifiedFile; - - public static final Level logLevel; - - @ConfigurationDefaultBoolean(true) - @ConfigurationCategory("ui") - public static final ConfigurationItem openMultipleFiles = null; - - @ConfigurationDefaultBoolean(true) - @ConfigurationCategory("script") - public static final ConfigurationItem decompile = null; - - @ConfigurationDefaultBoolean(true) - @ConfigurationCategory("decompilation") - public static final ConfigurationItem parallelSpeedUp = null; - - @ConfigurationDefaultInt(20) - @ConfigurationCategory("decompilation") - public static final ConfigurationItem parallelThreadCount = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("script") - public static final ConfigurationItem autoDeobfuscate = null; - - @ConfigurationDefaultInt(1) - @ConfigurationCategory("script") - public static final ConfigurationItem deobfuscationMode = null; - - @ConfigurationDefaultBoolean(true) - @ConfigurationCategory("decompilation") - public static final ConfigurationItem cacheOnDisk = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("display") - public static final ConfigurationItem internalFlashViewer = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("display") - public static final ConfigurationItem dumpView = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("display") - public static final ConfigurationItem useHexColorFormat = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("display") - public static final ConfigurationItem showOldTextDuringTextEditing = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("ui") - public static final ConfigurationItem gotoMainClassOnStartup = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("script") - public static final ConfigurationItem autoRenameIdentifiers = null; - - @ConfigurationDefaultBoolean(false) - public static final ConfigurationItem offeredAssociation = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("script") - public static final ConfigurationItem decimalAddress = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("script") - public static final ConfigurationItem showAllAddresses = null; - - @ConfigurationDefaultBoolean(true) - @ConfigurationCategory("display") - public static final ConfigurationItem useFrameCache = null; - - @ConfigurationDefaultBoolean(true) - @ConfigurationCategory("ui") - public static final ConfigurationItem useRibbonInterface = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("export") - public static final ConfigurationItem openFolderAfterFlaExport = null; - - @ConfigurationCategory("export") - public static final ConfigurationItem overrideTextExportFileName = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("debug") - public static final ConfigurationItem useDetailedLogging = null; - - /** - * Debug mode = throwing an error when comparing original file and - * recompiled - */ - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("debug") - public static final ConfigurationItem debugMode = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("debug") - public static final ConfigurationItem showDebugMenu = null; - - /** - * Turn off resolving constants in ActionScript 2 - */ - @ConfigurationDefaultBoolean(true) - @ConfigurationCategory("script") - public static final ConfigurationItem resolveConstants = null; - - /** - * Limit of code subs (for obfuscated code) - */ - @ConfigurationDefaultInt(500) - @ConfigurationCategory("limit") - public static final ConfigurationItem sublimiter = null; - - /** - * Total export timeout in seconds - */ - @ConfigurationDefaultInt(30 * 60) - @ConfigurationCategory("limit") - public static final ConfigurationItem exportTimeout = null; - - /** - * Decompilation timeout in seconds for a single file - */ - @ConfigurationDefaultInt(5 * 60) - @ConfigurationCategory("limit") - public static final ConfigurationItem decompilationTimeoutFile = null; - - /** - * Using parameter names in decompiling may cause problems because official - * programs like Flash CS 5.5 inserts wrong parameter names indices - */ - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("script") - public static final ConfigurationItem paramNamesEnable = null; - - @ConfigurationDefaultBoolean(true) - @ConfigurationCategory("ui") - public static final ConfigurationItem displayFileName = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("debug") - public static final ConfigurationItem debugCopy = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("debug") - public static final ConfigurationItem dumpTags = null; - - @ConfigurationDefaultBoolean(true) - @ConfigurationCategory("debug") - public static final ConfigurationItem setFFDecVersionInExportedFont = null; - - @ConfigurationDefaultInt(60) - @ConfigurationCategory("limit") - public static final ConfigurationItem decompilationTimeoutSingleMethod = null; - - @ConfigurationDefaultInt(1) - public static final ConfigurationItem lastRenameType = null; - - @ConfigurationDefaultString(".") - public static final ConfigurationItem lastSaveDir = null; - - @ConfigurationDefaultString(".") - public static final ConfigurationItem lastOpenDir = null; - - @ConfigurationDefaultString(".") - public static final ConfigurationItem lastExportDir = null; - - @ConfigurationDefaultString("en") - @ConfigurationCategory("ui") - public static final ConfigurationItem locale = null; - - @ConfigurationDefaultString("_loc%d_") - @ConfigurationCategory("script") - public static final ConfigurationItem registerNameFormat = null; - - @ConfigurationDefaultInt(15) - public static final ConfigurationItem maxRecentFileCount = null; - - public static final ConfigurationItem recentFiles = null; - - public static final ConfigurationItem fontPairing = null; - - public static final ConfigurationItem lastUpdatesCheckDate = null; - - @ConfigurationDefaultInt(1000) - @ConfigurationName("gui.window.width") - public static final ConfigurationItem guiWindowWidth = null; - - @ConfigurationDefaultInt(700) - @ConfigurationName("gui.window.height") - public static final ConfigurationItem guiWindowHeight = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationName("gui.window.maximized.horizontal") - public static final ConfigurationItem guiWindowMaximizedHorizontal = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationName("gui.window.maximized.vertical") - public static final ConfigurationItem guiWindowMaximizedVertical = null; - - @ConfigurationDefaultDouble(0.5) - @ConfigurationName("gui.avm2.splitPane.dividerLocationPercent") - public static final ConfigurationItem guiAvm2SplitPaneDividerLocationPercent = null; - - @ConfigurationDefaultDouble(0.5) - @ConfigurationName("gui.actionSplitPane.dividerLocationPercent") - public static final ConfigurationItem guiActionSplitPaneDividerLocationPercent = null; - - @ConfigurationDefaultDouble(0.5) - @ConfigurationName("gui.previewSplitPane.dividerLocationPercent") - public static final ConfigurationItem guiPreviewSplitPaneDividerLocationPercent = null; - - @ConfigurationDefaultDouble(0.3333333333) - @ConfigurationName("gui.splitPane1.dividerLocationPercent") - public static final ConfigurationItem guiSplitPane1DividerLocationPercent = null; - - @ConfigurationDefaultDouble(0.6) - @ConfigurationName("gui.splitPane2.dividerLocationPercent") - public static final ConfigurationItem guiSplitPane2DividerLocationPercent = null; - - @ConfigurationDefaultDouble(0.5) - @ConfigurationName("gui.timeLineSplitPane.dividerLocationPercent") - public static final ConfigurationItem guiTimeLineSplitPaneDividerLocationPercent = null; - - @ConfigurationDefaultString("com.jpexs.decompiler.flash.gui.OceanicSkin") - @ConfigurationName("gui.skin") - @ConfigurationCategory("ui") - public static final ConfigurationItem guiSkin = null; - - @ConfigurationDefaultInt(3) - @ConfigurationCategory("export") - public static final ConfigurationItem saveAsExeScaleMode = null; - - @ConfigurationDefaultInt(1024 * 1024/*1MiB*/) - @ConfigurationCategory("limit") - public static final ConfigurationItem syntaxHighlightLimit = null; - - public static final ConfigurationItem guiFontPreviewSampleText = null; - - @ConfigurationName("gui.fontPreviewWindow.width") - public static final ConfigurationItem guiFontPreviewWidth = null; - - @ConfigurationName("gui.fontPreviewWindow.height") - public static final ConfigurationItem guiFontPreviewHeight = null; - - @ConfigurationName("gui.fontPreviewWindow.posX") - public static final ConfigurationItem guiFontPreviewPosX = null; - - @ConfigurationName("gui.fontPreviewWindow.posY") - public static final ConfigurationItem guiFontPreviewPosY = null; - - @ConfigurationDefaultInt(3) - @ConfigurationName("formatting.indent.size") - @ConfigurationCategory("format") - public static final ConfigurationItem indentSize = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationName("formatting.indent.useTabs") - @ConfigurationCategory("format") - public static final ConfigurationItem indentUseTabs = null; - - @ConfigurationDefaultBoolean(true) - @ConfigurationCategory("format") - public static final ConfigurationItem beginBlockOnNewLine = null; - - @ConfigurationDefaultInt(1000 * 60 * 60 * 24) - @ConfigurationCategory("update") - @ConfigurationName("check.updates.delay") - public static final ConfigurationItem checkForUpdatesDelay = null; - - @ConfigurationDefaultBoolean(true) - @ConfigurationCategory("update") - @ConfigurationName("check.updates.stable") - public static final ConfigurationItem checkForUpdatesStable = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("update") - @ConfigurationName("check.updates.nightly") - public static final ConfigurationItem checkForUpdatesNightly = null; - - @ConfigurationDefaultBoolean(true) - @ConfigurationCategory("update") - @ConfigurationName("check.updates.enabled") - public static final ConfigurationItem checkForUpdatesAuto = null; - - @ConfigurationCategory("update") - public static final ConfigurationItem updateProxyAddress = null; - - @ConfigurationDefaultString("") - @ConfigurationName("export.formats") - public static final ConfigurationItem lastSelectedExportFormats = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("export") - public static final ConfigurationItem textExportSingleFile = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("export") - public static final ConfigurationItem scriptExportSingleFile = null; - - @ConfigurationDefaultString("--- SEPARATOR ---") - @ConfigurationCategory("export") - public static final ConfigurationItem textExportSingleFileSeparator = null; - - @ConfigurationDefaultString("--- RECORDSEPARATOR ---") - @ConfigurationCategory("export") - public static final ConfigurationItem textExportSingleFileRecordSeparator = null; - - @ConfigurationCategory("import") - public static final ConfigurationItem textImportResizeTextBoundsMode = null; - - @ConfigurationDefaultBoolean(true) - @ConfigurationName("warning.experimental.as12edit") - @ConfigurationCategory("script") - public static final ConfigurationItem warningExperimentalAS12Edit = null; - - @ConfigurationDefaultBoolean(true) - @ConfigurationName("warning.experimental.as3edit") - @ConfigurationCategory("script") - public static final ConfigurationItem warningExperimentalAS3Edit = null; - - @ConfigurationDefaultBoolean(true) - @ConfigurationCategory("script") - public static final ConfigurationItem showCodeSavedMessage = null; - - @ConfigurationDefaultBoolean(true) - @ConfigurationCategory("script") - public static final ConfigurationItem showTraitSavedMessage = null; - - @ConfigurationDefaultBoolean(true) - @ConfigurationCategory("export") - public static final ConfigurationItem packJavaScripts = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("export") - public static final ConfigurationItem textExportExportFontFace = null; - - @ConfigurationDefaultInt(128) - public static final ConfigurationItem lzmaFastBytes = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("debug") - public static final ConfigurationItem showMethodBodyId = null; - - @ConfigurationDefaultDouble(1.0) - @ConfigurationName("export.zoom") - public static final ConfigurationItem lastSelectedExportZoom = null; - - public static final ConfigurationItem pluginPath = null; - - @ConfigurationDefaultInt(55556) - @ConfigurationCategory("script") - public static final ConfigurationItem debuggerPort = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("script") - public static final ConfigurationItem randomDebuggerPackage = null; - - @ConfigurationDefaultBoolean(true) - public static final ConfigurationItem displayDebuggerInfo = null; - - @ConfigurationDefaultString("debugConsole") - public static final ConfigurationItem lastDebuggerReplaceFunction = null; - - @ConfigurationDefaultBoolean(true) - @ConfigurationCategory("script") - public static final ConfigurationItem getLocalNamesFromDebugInfo = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("ui") - public static final ConfigurationItem tagTreeShowEmptyFolders = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("ui") - public static final ConfigurationItem autoLoadEmbeddedSwfs = null; - - @ConfigurationDefaultBoolean(true) - @ConfigurationCategory("ui") - public static final ConfigurationItem showCloseConfirmation = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("ui") - public static final ConfigurationItem editorMode = null; - - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("ui") - public static final ConfigurationItem autoSaveTagModifications = null; - - @ConfigurationDefaultBoolean(true) - @ConfigurationCategory("ui") - public static final ConfigurationItem saveSessionOnExit = null; - - public static final ConfigurationItem lastSessionData = null; - - @ConfigurationDefaultBoolean(true) - @ConfigurationCategory("ui") - public static final ConfigurationItem loopMedia = null; - - @ConfigurationDefaultBoolean(true) - @ConfigurationCategory("ui") - public static final ConfigurationItem allowOnlyOneInstance = null; - - private enum OSId { - - WINDOWS, OSX, UNIX - } - - private static OSId getOSId() { - PrivilegedAction doGetOSName = new PrivilegedAction() { - @Override - public String run() { - return System.getProperty("os.name"); - } - }; - OSId id = OSId.UNIX; - String osName = AccessController.doPrivileged(doGetOSName); - if (osName != null) { - if (osName.toLowerCase().startsWith("mac os x")) { - id = OSId.OSX; - } else if (osName.contains("Windows")) { - id = OSId.WINDOWS; - } - } - return id; - } - - public static String getFFDecHome() { - if (directory == unspecifiedFile) { - directory = null; - String userHome = null; - try { - userHome = System.getProperty("user.home"); - } catch (SecurityException ignore) { - } - if (userHome != null) { - String applicationId = ApplicationInfo.SHORT_APPLICATION_NAME; - OSId osId = getOSId(); - if (osId == OSId.WINDOWS) { - File appDataDir = null; - try { - String appDataEV = System.getenv("APPDATA"); - if ((appDataEV != null) && (appDataEV.length() > 0)) { - appDataDir = new File(appDataEV); - } - } catch (SecurityException ignore) { - } - String vendorId = ApplicationInfo.VENDOR; - if ((appDataDir != null) && appDataDir.isDirectory()) { - // ${APPDATA}\{vendorId}\${applicationId} - String path = vendorId + "\\" + applicationId + "\\"; - directory = new File(appDataDir, path); - } else { - // ${userHome}\Application Data\${vendorId}\${applicationId} - String path = "Application Data\\" + vendorId + "\\" + applicationId + "\\"; - directory = new File(userHome, path); - } - } else if (osId == OSId.OSX) { - // ${userHome}/Library/Application Support/${applicationId} - String path = "Library/Application Support/" + applicationId + "/"; - directory = new File(userHome, path); - } else { - // ${userHome}/.${applicationId}/ - String path = "." + applicationId + "/"; - directory = new File(userHome, path); - } - } else { - //no home, then use application directory - directory = new File("."); - } - } - if (!directory.exists()) { - if (!directory.mkdirs()) { - if (!directory.exists()) { - directory = new File("."); //fallback to current directory - } - } - } - String ret = directory.getAbsolutePath(); - if (!ret.endsWith(File.separator)) { - ret += File.separator; - } - return ret; - } - - public static List getRecentFiles() { - String files = recentFiles.get(); - if (files == null || files.isEmpty()) { - return new ArrayList<>(); - } - return Arrays.asList(files.split("::")); - } - - public static void addRecentFile(String path) { - List recentFilesArray = new ArrayList<>(getRecentFiles()); - int idx = recentFilesArray.indexOf(path); - if (idx != -1) { - recentFilesArray.remove(idx); - } - recentFilesArray.add(path); - while (recentFilesArray.size() > maxRecentFileCount.get()) { - recentFilesArray.remove(0); - } - recentFiles.set(Helper.joinStrings(recentFilesArray, "::")); - } - - public static void removeRecentFile(String path) { - List recentFilesArray = new ArrayList<>(getRecentFiles()); - int idx = recentFilesArray.indexOf(path); - if (idx != -1) { - recentFilesArray.remove(idx); - } - recentFiles.set(Helper.joinStrings(recentFilesArray, "::")); - } - - public static Map getFontToNameMap() { - String fonts = fontPairing.get(); - if (fonts == null) { - return new HashMap<>(); - } - - Map result = new HashMap<>(); - for (String pair : fonts.split("::")) { - if (!pair.isEmpty()) { - String[] splittedPair = pair.split("="); - result.put(splittedPair[0], splittedPair[1]); - } - } - return result; - } - - public static void addFontPair(String fileName, int fontId, String fontName, String installedName) { - String key = fileName + "_" + fontId + "_" + fontName; - Map fontPairs = getFontToNameMap(); - fontPairs.put(key, installedName); - fontPairs.put(fontName, installedName); - - StringBuilder sb = new StringBuilder(); - int i = 0; - for (Entry pair : fontPairs.entrySet()) { - if (i != 0) { - sb.append("::"); - } - sb.append(pair.getKey()).append("=").append(pair.getValue()); - i++; - } - fontPairing.set(sb.toString()); - } - - private static String getConfigFile() throws IOException { - return getFFDecHome() + CONFIG_NAME; - } - - private static HashMap loadFromFile(String file) { - try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) { - - @SuppressWarnings("unchecked") - HashMap cfg = (HashMap) ois.readObject(); - return cfg; - } catch (ClassNotFoundException | IOException ex) { - // ignore - } - - return new HashMap<>(); - } - - private static void saveToFile(String file) { - HashMap config = new HashMap<>(); - for (Entry entry : getConfigurationFields().entrySet()) { - try { - String name = entry.getKey(); - Field field = entry.getValue(); - ConfigurationItem item = (ConfigurationItem) field.get(null); - if (item.hasValue) { - config.put(name, item.get()); - } - } catch (IllegalArgumentException | IllegalAccessException ex) { - Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex); - } - } - try (ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) { - oos.writeObject(config); - } catch (IOException ex) { - //TODO: move this to GUI - JOptionPane.showMessageDialog(null, "Cannot save configuration.", "Error", JOptionPane.ERROR_MESSAGE); - Logger.getLogger(Configuration.class.getName()).severe("Configuration directory is read only."); - } - } - - public static void saveConfig() { - try { - saveToFile(getConfigFile()); - } catch (IOException ex) { - // ignore - } - } - - static { - setConfigurationFields(); - if (useDetailedLogging.get()) { - logLevel = Level.FINEST; - } else if (debugMode.get()) { - logLevel = Level.INFO; - } else { - logLevel = Level.WARNING; - } - int processorCount = Runtime.getRuntime().availableProcessors(); - if (parallelThreadCount.get() > processorCount) { - parallelThreadCount.set(processorCount); - } - - if (lastUpdatesCheckDate.get() == null) { - GregorianCalendar mingc = new GregorianCalendar(); - mingc.setTime(new Date(Long.MIN_VALUE)); - lastUpdatesCheckDate.set(mingc); - } - } - - @SuppressWarnings("unchecked") - public static void setConfigurationFields() { - try { - HashMap config = loadFromFile(getConfigFile()); - for (Entry entry : getConfigurationFields().entrySet()) { - String name = entry.getKey(); - Field field = entry.getValue(); - // remove final modifier from field - Field modifiersField = field.getClass().getDeclaredField("modifiers"); - modifiersField.setAccessible(true); - modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); - - Object defaultValue = getDefaultValue(field); - Object value = null; - if (config.containsKey(name)) { - value = config.get(name); - - Class type = (Class) (((ParameterizedType) (field.getGenericType())).getActualTypeArguments()[0]); - if (value != null && !type.isAssignableFrom(value.getClass())) { - System.out.println("Configuration item has a wrong type: " + name + " expected: " + type.getSimpleName() + " actual: " + value.getClass().getSimpleName()); - value = null; - } - } - - if (value != null) { - field.set(null, new ConfigurationItem(name, defaultValue, value)); - } else { - field.set(null, new ConfigurationItem(name, defaultValue)); - } - } - } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException ex) { - // Reflection exceptions. This should never happen - throw new Error(ex.getMessage()); - } catch (IOException ex) { - Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex); - } - } - - public static Object getDefaultValue(Field field) { - Object defaultValue = null; - ConfigurationDefaultBoolean aBool = field.getAnnotation(ConfigurationDefaultBoolean.class); - if (aBool != null) { - defaultValue = aBool.value(); - } - ConfigurationDefaultInt aInt = field.getAnnotation(ConfigurationDefaultInt.class); - if (aInt != null) { - defaultValue = aInt.value(); - } - ConfigurationDefaultString aString = field.getAnnotation(ConfigurationDefaultString.class); - if (aString != null) { - defaultValue = aString.value(); - } - ConfigurationDefaultDouble aDouble = field.getAnnotation(ConfigurationDefaultDouble.class); - if (aDouble != null) { - defaultValue = aDouble.value(); - } - return defaultValue; - } - - public static Map getConfigurationFields() { - Field[] fields = Configuration.class.getFields(); - Map result = new HashMap<>(); - for (Field field : fields) { - if (ConfigurationItem.class.isAssignableFrom(field.getType())) { - ConfigurationName annotation = field.getAnnotation(ConfigurationName.class); - String name = annotation == null ? field.getName() : annotation.value(); - result.put(name, field); - } - } - return result; - } - - public static CodeFormatting getCodeFormatting() { - CodeFormatting ret = new CodeFormatting(); - String indentString = ""; - for (int i = 0; i < indentSize.get(); i++) { - indentString += indentUseTabs.get() ? "\t" : " "; - } - ret.indentString = indentString; - ret.beginBlockOnNewLine = beginBlockOnNewLine.get(); - return ret; - } - - public static int getParallelThreadCount() { - int count = parallelThreadCount.get(); - if (count < 2) { - count = 2; - } - - return count; - } - - public static File getFlashLibPath() { - String home = getFFDecHome(); - File libsdir = new File(home + "flashlib"); - if (!libsdir.exists()) { - libsdir.mkdirs(); - } - return libsdir; - } - - public static File getPlayerSWC() { - File libsdir = getFlashLibPath(); - if (libsdir != null && libsdir.exists()) { - File[] libs = libsdir.listFiles(new FilenameFilter() { - - @Override - public boolean accept(File dir, String name) { - return name.toLowerCase().startsWith("playerglobal"); - } - }); - List libnames = new ArrayList<>(); - for (File f : libs) { - libnames.add(f.getName()); - } - Collections.sort(libnames); - if (!libnames.isEmpty()) { - return new File(libsdir.getAbsolutePath() + File.separator + libnames.get(libnames.size() - 1)); - } else { - return null; - } - } - - return null; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.configuration; + +import com.jpexs.decompiler.flash.ApplicationInfo; +import com.jpexs.decompiler.flash.helpers.CodeFormatting; +import com.jpexs.decompiler.flash.importers.TextImportResizeTextBoundsMode; +import com.jpexs.helpers.Helper; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JOptionPane; + +public class Configuration { + + private static final String CONFIG_NAME = "config.bin"; + + private static final File unspecifiedFile = new File("unspecified"); + + private static File directory = unspecifiedFile; + + public static final Level logLevel; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("ui") + public static final ConfigurationItem openMultipleFiles = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("script") + public static final ConfigurationItem decompile = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("decompilation") + public static final ConfigurationItem parallelSpeedUp = null; + + @ConfigurationDefaultInt(20) + @ConfigurationCategory("decompilation") + public static final ConfigurationItem parallelThreadCount = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("script") + public static final ConfigurationItem autoDeobfuscate = null; + + @ConfigurationDefaultInt(1) + @ConfigurationCategory("script") + public static final ConfigurationItem deobfuscationMode = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("") + public static final ConfigurationItem cacheOnDisk = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("") + public static final ConfigurationItem cacheImages = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("display") + public static final ConfigurationItem internalFlashViewer = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("display") + public static final ConfigurationItem dumpView = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("display") + public static final ConfigurationItem useHexColorFormat = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("display") + public static final ConfigurationItem showOldTextDuringTextEditing = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("ui") + public static final ConfigurationItem gotoMainClassOnStartup = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("script") + public static final ConfigurationItem autoRenameIdentifiers = null; + + @ConfigurationDefaultBoolean(false) + public static final ConfigurationItem offeredAssociation = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("script") + public static final ConfigurationItem decimalAddress = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("script") + public static final ConfigurationItem showAllAddresses = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("display") + public static final ConfigurationItem useFrameCache = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("ui") + public static final ConfigurationItem useRibbonInterface = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("export") + public static final ConfigurationItem openFolderAfterFlaExport = null; + + @ConfigurationCategory("export") + public static final ConfigurationItem overrideTextExportFileName = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("debug") + public static final ConfigurationItem useDetailedLogging = null; + + /** + * Debug mode = throwing an error when comparing original file and + * recompiled + */ + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("debug") + public static final ConfigurationItem debugMode = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("debug") + public static final ConfigurationItem showDebugMenu = null; + + /** + * Turn off resolving constants in ActionScript 2 + */ + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("script") + public static final ConfigurationItem resolveConstants = null; + + /** + * Limit of code subs (for obfuscated code) + */ + @ConfigurationDefaultInt(500) + @ConfigurationCategory("limit") + public static final ConfigurationItem sublimiter = null; + + /** + * Total export timeout in seconds + */ + @ConfigurationDefaultInt(30 * 60) + @ConfigurationCategory("limit") + public static final ConfigurationItem exportTimeout = null; + + /** + * Decompilation timeout in seconds for a single file + */ + @ConfigurationDefaultInt(5 * 60) + @ConfigurationCategory("limit") + public static final ConfigurationItem decompilationTimeoutFile = null; + + /** + * Using parameter names in decompiling may cause problems because official + * programs like Flash CS 5.5 inserts wrong parameter names indices + */ + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("script") + public static final ConfigurationItem paramNamesEnable = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("ui") + public static final ConfigurationItem displayFileName = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("debug") + public static final ConfigurationItem debugCopy = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("debug") + public static final ConfigurationItem dumpTags = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("debug") + public static final ConfigurationItem setFFDecVersionInExportedFont = null; + + @ConfigurationDefaultInt(60) + @ConfigurationCategory("limit") + public static final ConfigurationItem decompilationTimeoutSingleMethod = null; + + @ConfigurationDefaultInt(1) + public static final ConfigurationItem lastRenameType = null; + + @ConfigurationDefaultString(".") + public static final ConfigurationItem lastSaveDir = null; + + @ConfigurationDefaultString(".") + public static final ConfigurationItem lastOpenDir = null; + + @ConfigurationDefaultString(".") + public static final ConfigurationItem lastExportDir = null; + + @ConfigurationDefaultString("en") + @ConfigurationCategory("ui") + public static final ConfigurationItem locale = null; + + @ConfigurationDefaultString("_loc%d_") + @ConfigurationCategory("script") + public static final ConfigurationItem registerNameFormat = null; + + @ConfigurationDefaultInt(15) + public static final ConfigurationItem maxRecentFileCount = null; + + public static final ConfigurationItem recentFiles = null; + + public static final ConfigurationItem fontPairing = null; + + public static final ConfigurationItem lastUpdatesCheckDate = null; + + @ConfigurationDefaultInt(1000) + @ConfigurationName("gui.window.width") + public static final ConfigurationItem guiWindowWidth = null; + + @ConfigurationDefaultInt(700) + @ConfigurationName("gui.window.height") + public static final ConfigurationItem guiWindowHeight = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationName("gui.window.maximized.horizontal") + public static final ConfigurationItem guiWindowMaximizedHorizontal = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationName("gui.window.maximized.vertical") + public static final ConfigurationItem guiWindowMaximizedVertical = null; + + @ConfigurationDefaultDouble(0.5) + @ConfigurationName("gui.avm2.splitPane.dividerLocationPercent") + public static final ConfigurationItem guiAvm2SplitPaneDividerLocationPercent = null; + + @ConfigurationDefaultDouble(0.5) + @ConfigurationName("gui.actionSplitPane.dividerLocationPercent") + public static final ConfigurationItem guiActionSplitPaneDividerLocationPercent = null; + + @ConfigurationDefaultDouble(0.5) + @ConfigurationName("gui.previewSplitPane.dividerLocationPercent") + public static final ConfigurationItem guiPreviewSplitPaneDividerLocationPercent = null; + + @ConfigurationDefaultDouble(0.3333333333) + @ConfigurationName("gui.splitPane1.dividerLocationPercent") + public static final ConfigurationItem guiSplitPane1DividerLocationPercent = null; + + @ConfigurationDefaultDouble(0.6) + @ConfigurationName("gui.splitPane2.dividerLocationPercent") + public static final ConfigurationItem guiSplitPane2DividerLocationPercent = null; + + @ConfigurationDefaultDouble(0.5) + @ConfigurationName("gui.timeLineSplitPane.dividerLocationPercent") + public static final ConfigurationItem guiTimeLineSplitPaneDividerLocationPercent = null; + + @ConfigurationDefaultString("com.jpexs.decompiler.flash.gui.OceanicSkin") + @ConfigurationName("gui.skin") + @ConfigurationCategory("ui") + public static final ConfigurationItem guiSkin = null; + + @ConfigurationDefaultInt(3) + @ConfigurationCategory("export") + public static final ConfigurationItem saveAsExeScaleMode = null; + + @ConfigurationDefaultInt(1024 * 1024/*1MiB*/) + @ConfigurationCategory("limit") + public static final ConfigurationItem syntaxHighlightLimit = null; + + public static final ConfigurationItem guiFontPreviewSampleText = null; + + @ConfigurationName("gui.fontPreviewWindow.width") + public static final ConfigurationItem guiFontPreviewWidth = null; + + @ConfigurationName("gui.fontPreviewWindow.height") + public static final ConfigurationItem guiFontPreviewHeight = null; + + @ConfigurationName("gui.fontPreviewWindow.posX") + public static final ConfigurationItem guiFontPreviewPosX = null; + + @ConfigurationName("gui.fontPreviewWindow.posY") + public static final ConfigurationItem guiFontPreviewPosY = null; + + @ConfigurationDefaultInt(3) + @ConfigurationName("formatting.indent.size") + @ConfigurationCategory("format") + public static final ConfigurationItem indentSize = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationName("formatting.indent.useTabs") + @ConfigurationCategory("format") + public static final ConfigurationItem indentUseTabs = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("format") + public static final ConfigurationItem beginBlockOnNewLine = null; + + @ConfigurationDefaultInt(1000 * 60 * 60 * 24) + @ConfigurationCategory("update") + @ConfigurationName("check.updates.delay") + public static final ConfigurationItem checkForUpdatesDelay = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("update") + @ConfigurationName("check.updates.stable") + public static final ConfigurationItem checkForUpdatesStable = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("update") + @ConfigurationName("check.updates.nightly") + public static final ConfigurationItem checkForUpdatesNightly = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("update") + @ConfigurationName("check.updates.enabled") + public static final ConfigurationItem checkForUpdatesAuto = null; + + @ConfigurationCategory("update") + public static final ConfigurationItem updateProxyAddress = null; + + @ConfigurationDefaultString("") + @ConfigurationName("export.formats") + public static final ConfigurationItem lastSelectedExportFormats = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("export") + public static final ConfigurationItem textExportSingleFile = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("export") + public static final ConfigurationItem scriptExportSingleFile = null; + + @ConfigurationDefaultString("--- SEPARATOR ---") + @ConfigurationCategory("export") + public static final ConfigurationItem textExportSingleFileSeparator = null; + + @ConfigurationDefaultString("--- RECORDSEPARATOR ---") + @ConfigurationCategory("export") + public static final ConfigurationItem textExportSingleFileRecordSeparator = null; + + @ConfigurationCategory("import") + public static final ConfigurationItem textImportResizeTextBoundsMode = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationName("warning.experimental.as12edit") + @ConfigurationCategory("script") + public static final ConfigurationItem warningExperimentalAS12Edit = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationName("warning.experimental.as3edit") + @ConfigurationCategory("script") + public static final ConfigurationItem warningExperimentalAS3Edit = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("script") + public static final ConfigurationItem showCodeSavedMessage = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("script") + public static final ConfigurationItem showTraitSavedMessage = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("export") + public static final ConfigurationItem packJavaScripts = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("export") + public static final ConfigurationItem textExportExportFontFace = null; + + @ConfigurationDefaultInt(128) + public static final ConfigurationItem lzmaFastBytes = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("debug") + public static final ConfigurationItem showMethodBodyId = null; + + @ConfigurationDefaultDouble(1.0) + @ConfigurationName("export.zoom") + public static final ConfigurationItem lastSelectedExportZoom = null; + + public static final ConfigurationItem pluginPath = null; + + @ConfigurationDefaultInt(55556) + @ConfigurationCategory("script") + public static final ConfigurationItem debuggerPort = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("script") + public static final ConfigurationItem randomDebuggerPackage = null; + + @ConfigurationDefaultBoolean(true) + public static final ConfigurationItem displayDebuggerInfo = null; + + @ConfigurationDefaultString("debugConsole") + public static final ConfigurationItem lastDebuggerReplaceFunction = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("script") + public static final ConfigurationItem getLocalNamesFromDebugInfo = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("ui") + public static final ConfigurationItem tagTreeShowEmptyFolders = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("ui") + public static final ConfigurationItem autoLoadEmbeddedSwfs = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("ui") + public static final ConfigurationItem showCloseConfirmation = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("ui") + public static final ConfigurationItem editorMode = null; + + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("ui") + public static final ConfigurationItem autoSaveTagModifications = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("ui") + public static final ConfigurationItem saveSessionOnExit = null; + + public static final ConfigurationItem lastSessionData = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("ui") + public static final ConfigurationItem loopMedia = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("ui") + public static final ConfigurationItem allowOnlyOneInstance = null; + + private enum OSId { + + WINDOWS, OSX, UNIX + } + + private static OSId getOSId() { + PrivilegedAction doGetOSName = new PrivilegedAction() { + @Override + public String run() { + return System.getProperty("os.name"); + } + }; + OSId id = OSId.UNIX; + String osName = AccessController.doPrivileged(doGetOSName); + if (osName != null) { + if (osName.toLowerCase().startsWith("mac os x")) { + id = OSId.OSX; + } else if (osName.contains("Windows")) { + id = OSId.WINDOWS; + } + } + return id; + } + + public static String getFFDecHome() { + if (directory == unspecifiedFile) { + directory = null; + String userHome = null; + try { + userHome = System.getProperty("user.home"); + } catch (SecurityException ignore) { + } + if (userHome != null) { + String applicationId = ApplicationInfo.SHORT_APPLICATION_NAME; + OSId osId = getOSId(); + if (osId == OSId.WINDOWS) { + File appDataDir = null; + try { + String appDataEV = System.getenv("APPDATA"); + if ((appDataEV != null) && (appDataEV.length() > 0)) { + appDataDir = new File(appDataEV); + } + } catch (SecurityException ignore) { + } + String vendorId = ApplicationInfo.VENDOR; + if ((appDataDir != null) && appDataDir.isDirectory()) { + // ${APPDATA}\{vendorId}\${applicationId} + String path = vendorId + "\\" + applicationId + "\\"; + directory = new File(appDataDir, path); + } else { + // ${userHome}\Application Data\${vendorId}\${applicationId} + String path = "Application Data\\" + vendorId + "\\" + applicationId + "\\"; + directory = new File(userHome, path); + } + } else if (osId == OSId.OSX) { + // ${userHome}/Library/Application Support/${applicationId} + String path = "Library/Application Support/" + applicationId + "/"; + directory = new File(userHome, path); + } else { + // ${userHome}/.${applicationId}/ + String path = "." + applicationId + "/"; + directory = new File(userHome, path); + } + } else { + //no home, then use application directory + directory = new File("."); + } + } + if (!directory.exists()) { + if (!directory.mkdirs()) { + if (!directory.exists()) { + directory = new File("."); //fallback to current directory + } + } + } + String ret = directory.getAbsolutePath(); + if (!ret.endsWith(File.separator)) { + ret += File.separator; + } + return ret; + } + + public static List getRecentFiles() { + String files = recentFiles.get(); + if (files == null || files.isEmpty()) { + return new ArrayList<>(); + } + return Arrays.asList(files.split("::")); + } + + public static void addRecentFile(String path) { + List recentFilesArray = new ArrayList<>(getRecentFiles()); + int idx = recentFilesArray.indexOf(path); + if (idx != -1) { + recentFilesArray.remove(idx); + } + recentFilesArray.add(path); + while (recentFilesArray.size() > maxRecentFileCount.get()) { + recentFilesArray.remove(0); + } + recentFiles.set(Helper.joinStrings(recentFilesArray, "::")); + } + + public static void removeRecentFile(String path) { + List recentFilesArray = new ArrayList<>(getRecentFiles()); + int idx = recentFilesArray.indexOf(path); + if (idx != -1) { + recentFilesArray.remove(idx); + } + recentFiles.set(Helper.joinStrings(recentFilesArray, "::")); + } + + public static Map getFontToNameMap() { + String fonts = fontPairing.get(); + if (fonts == null) { + return new HashMap<>(); + } + + Map result = new HashMap<>(); + for (String pair : fonts.split("::")) { + if (!pair.isEmpty()) { + String[] splittedPair = pair.split("="); + result.put(splittedPair[0], splittedPair[1]); + } + } + return result; + } + + public static void addFontPair(String fileName, int fontId, String fontName, String installedName) { + String key = fileName + "_" + fontId + "_" + fontName; + Map fontPairs = getFontToNameMap(); + fontPairs.put(key, installedName); + fontPairs.put(fontName, installedName); + + StringBuilder sb = new StringBuilder(); + int i = 0; + for (Entry pair : fontPairs.entrySet()) { + if (i != 0) { + sb.append("::"); + } + sb.append(pair.getKey()).append("=").append(pair.getValue()); + i++; + } + fontPairing.set(sb.toString()); + } + + private static String getConfigFile() throws IOException { + return getFFDecHome() + CONFIG_NAME; + } + + private static HashMap loadFromFile(String file) { + try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) { + + @SuppressWarnings("unchecked") + HashMap cfg = (HashMap) ois.readObject(); + return cfg; + } catch (ClassNotFoundException | IOException ex) { + // ignore + } + + return new HashMap<>(); + } + + private static void saveToFile(String file) { + HashMap config = new HashMap<>(); + for (Entry entry : getConfigurationFields().entrySet()) { + try { + String name = entry.getKey(); + Field field = entry.getValue(); + ConfigurationItem item = (ConfigurationItem) field.get(null); + if (item.hasValue) { + config.put(name, item.get()); + } + } catch (IllegalArgumentException | IllegalAccessException ex) { + Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex); + } + } + try (ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) { + oos.writeObject(config); + } catch (IOException ex) { + //TODO: move this to GUI + JOptionPane.showMessageDialog(null, "Cannot save configuration.", "Error", JOptionPane.ERROR_MESSAGE); + Logger.getLogger(Configuration.class.getName()).severe("Configuration directory is read only."); + } + } + + public static void saveConfig() { + try { + saveToFile(getConfigFile()); + } catch (IOException ex) { + // ignore + } + } + + static { + setConfigurationFields(); + if (useDetailedLogging.get()) { + logLevel = Level.FINEST; + } else if (debugMode.get()) { + logLevel = Level.INFO; + } else { + logLevel = Level.WARNING; + } + int processorCount = Runtime.getRuntime().availableProcessors(); + if (parallelThreadCount.get() > processorCount) { + parallelThreadCount.set(processorCount); + } + + if (lastUpdatesCheckDate.get() == null) { + GregorianCalendar mingc = new GregorianCalendar(); + mingc.setTime(new Date(Long.MIN_VALUE)); + lastUpdatesCheckDate.set(mingc); + } + } + + @SuppressWarnings("unchecked") + public static void setConfigurationFields() { + try { + HashMap config = loadFromFile(getConfigFile()); + for (Entry entry : getConfigurationFields().entrySet()) { + String name = entry.getKey(); + Field field = entry.getValue(); + // remove final modifier from field + Field modifiersField = field.getClass().getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + + Object defaultValue = getDefaultValue(field); + Object value = null; + if (config.containsKey(name)) { + value = config.get(name); + + Class type = (Class) (((ParameterizedType) (field.getGenericType())).getActualTypeArguments()[0]); + if (value != null && !type.isAssignableFrom(value.getClass())) { + System.out.println("Configuration item has a wrong type: " + name + " expected: " + type.getSimpleName() + " actual: " + value.getClass().getSimpleName()); + value = null; + } + } + + if (value != null) { + field.set(null, new ConfigurationItem(name, defaultValue, value)); + } else { + field.set(null, new ConfigurationItem(name, defaultValue)); + } + } + } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException ex) { + // Reflection exceptions. This should never happen + throw new Error(ex.getMessage()); + } catch (IOException ex) { + Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex); + } + } + + public static Object getDefaultValue(Field field) { + Object defaultValue = null; + ConfigurationDefaultBoolean aBool = field.getAnnotation(ConfigurationDefaultBoolean.class); + if (aBool != null) { + defaultValue = aBool.value(); + } + ConfigurationDefaultInt aInt = field.getAnnotation(ConfigurationDefaultInt.class); + if (aInt != null) { + defaultValue = aInt.value(); + } + ConfigurationDefaultString aString = field.getAnnotation(ConfigurationDefaultString.class); + if (aString != null) { + defaultValue = aString.value(); + } + ConfigurationDefaultDouble aDouble = field.getAnnotation(ConfigurationDefaultDouble.class); + if (aDouble != null) { + defaultValue = aDouble.value(); + } + return defaultValue; + } + + public static Map getConfigurationFields() { + Field[] fields = Configuration.class.getFields(); + Map result = new HashMap<>(); + for (Field field : fields) { + if (ConfigurationItem.class.isAssignableFrom(field.getType())) { + ConfigurationName annotation = field.getAnnotation(ConfigurationName.class); + String name = annotation == null ? field.getName() : annotation.value(); + result.put(name, field); + } + } + return result; + } + + public static CodeFormatting getCodeFormatting() { + CodeFormatting ret = new CodeFormatting(); + String indentString = ""; + for (int i = 0; i < indentSize.get(); i++) { + indentString += indentUseTabs.get() ? "\t" : " "; + } + ret.indentString = indentString; + ret.beginBlockOnNewLine = beginBlockOnNewLine.get(); + return ret; + } + + public static int getParallelThreadCount() { + int count = parallelThreadCount.get(); + if (count < 2) { + count = 2; + } + + return count; + } + + public static File getFlashLibPath() { + String home = getFFDecHome(); + File libsdir = new File(home + "flashlib"); + if (!libsdir.exists()) { + libsdir.mkdirs(); + } + return libsdir; + } + + public static File getPlayerSWC() { + File libsdir = getFlashLibPath(); + if (libsdir != null && libsdir.exists()) { + File[] libs = libsdir.listFiles(new FilenameFilter() { + + @Override + public boolean accept(File dir, String name) { + return name.toLowerCase().startsWith("playerglobal"); + } + }); + List libnames = new ArrayList<>(); + for (File f : libs) { + libnames.add(f.getName()); + } + Collections.sort(libnames); + if (!libnames.isEmpty()) { + return new File(libsdir.getAbsolutePath() + File.separator + libnames.get(libnames.size() - 1)); + } else { + return null; + } + } + + return null; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/SoundExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/SoundExporter.java index 970f1aab4..a9c81cc03 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/SoundExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/SoundExporter.java @@ -1,167 +1,168 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.exporters; - -import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; -import com.jpexs.decompiler.flash.EventListener; -import com.jpexs.decompiler.flash.RetryTask; -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.exporters.modes.SoundExportMode; -import com.jpexs.decompiler.flash.exporters.settings.SoundExportSettings; -import com.jpexs.decompiler.flash.flv.AUDIODATA; -import com.jpexs.decompiler.flash.flv.FLVOutputStream; -import com.jpexs.decompiler.flash.flv.FLVTAG; -import com.jpexs.decompiler.flash.tags.DefineSoundTag; -import com.jpexs.decompiler.flash.tags.SoundStreamBlockTag; -import com.jpexs.decompiler.flash.tags.Tag; -import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag; -import com.jpexs.decompiler.flash.tags.base.SoundTag; -import com.jpexs.decompiler.flash.types.sound.SoundFormat; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.Path; -import java.io.BufferedOutputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class SoundExporter { - - public List exportSounds(AbortRetryIgnoreHandler handler, String outdir, List tags, final SoundExportSettings settings, EventListener evl) throws IOException { - List ret = new ArrayList<>(); - if (tags.isEmpty()) { - return ret; - } - - File foutdir = new File(outdir); - Path.createDirectorySafe(foutdir); - - int count = 0; - for (Tag t : tags) { - if (t instanceof SoundTag) { - count++; - } - } - - if (count == 0) { - return ret; - } - - int currentIndex = 1; - for (Tag t : tags) { - if (t instanceof SoundTag) { - if (evl != null) { - evl.handleExportingEvent("sound", currentIndex, count, t.getName()); - } - - final SoundTag st = (SoundTag) t; - - String ext = "wav"; - SoundFormat fmt = st.getSoundFormat(); - switch (fmt.getNativeExportFormat()) { - case SoundFormat.EXPORT_MP3: - if (settings.mode.hasMP3()) { - ext = "mp3"; - } - break; - case SoundFormat.EXPORT_FLV: - if (settings.mode.hasFlv()) { - ext = "flv"; - } - break; - } - if (settings.mode == SoundExportMode.FLV) { - ext = "flv"; - } - - final File file = new File(outdir + File.separator + Helper.makeFileName(st.getCharacterExportFileName()) + "." + ext); - new RetryTask(() -> { - try (OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) { - exportSound(os, st, settings.mode); - } - }, handler).run(); - - ret.add(file); - - if (evl != null) { - evl.handleExportedEvent("sound", currentIndex, count, t.getName()); - } - - currentIndex++; - } - } - return ret; - } - - public byte[] exportSound(SoundTag t, SoundExportMode mode) throws IOException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - exportSound(baos, t, mode); - return baos.toByteArray(); - } - - public void exportSound(OutputStream fos, SoundTag st, SoundExportMode mode) throws IOException { - SoundFormat fmt = st.getSoundFormat(); - int nativeFormat = fmt.getNativeExportFormat(); - - if (nativeFormat == SoundFormat.EXPORT_MP3 && mode.hasMP3()) { - List datas = st.getRawSoundData(); - for (byte[] data : datas) { - fos.write(data); - } - } else if ((nativeFormat == SoundFormat.EXPORT_FLV && mode.hasFlv()) || mode == SoundExportMode.FLV) { - if (st instanceof DefineSoundTag) { - FLVOutputStream flv = new FLVOutputStream(fos); - flv.writeHeader(true, false); - List datas = st.getRawSoundData(); - for (byte[] data : datas) { - flv.writeTag(new FLVTAG(0, new AUDIODATA(st.getSoundFormatId(), st.getSoundRate(), st.getSoundSize(), st.getSoundType(), data))); - } - } else if (st instanceof SoundStreamHeadTypeTag) { - SoundStreamHeadTypeTag sh = (SoundStreamHeadTypeTag) st; - FLVOutputStream flv = new FLVOutputStream(fos); - flv.writeHeader(true, false); - List blocks = sh.getBlocks(); - - int ms = (int) (1000.0f / ((float) ((Tag) st).getSwf().frameRate)); - for (int b = 0; b < blocks.size(); b++) { - byte[] data = blocks.get(b).streamSoundData.getRangeData(); - if (st.getSoundFormatId() == 2) { //MP3 - data = Arrays.copyOfRange(data, 4, data.length); - } - flv.writeTag(new FLVTAG(ms * b, new AUDIODATA(st.getSoundFormatId(), st.getSoundRate(), st.getSoundSize(), st.getSoundType(), data))); - } - } - } else { - List soundData = st.getRawSoundData(); - SWF swf = ((Tag) st).getSwf(); - List siss = new ArrayList<>(); - for (byte[] data : soundData) { - siss.add(new SWFInputStream(swf, data)); - } - fmt.createWav(siss, fos); - } - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.exporters; + +import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; +import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.RetryTask; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.exporters.modes.SoundExportMode; +import com.jpexs.decompiler.flash.exporters.settings.SoundExportSettings; +import com.jpexs.decompiler.flash.flv.AUDIODATA; +import com.jpexs.decompiler.flash.flv.FLVOutputStream; +import com.jpexs.decompiler.flash.flv.FLVTAG; +import com.jpexs.decompiler.flash.tags.DefineSoundTag; +import com.jpexs.decompiler.flash.tags.SoundStreamBlockTag; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag; +import com.jpexs.decompiler.flash.tags.base.SoundTag; +import com.jpexs.decompiler.flash.types.sound.SoundFormat; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.Path; +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class SoundExporter { + + public List exportSounds(AbortRetryIgnoreHandler handler, String outdir, List tags, final SoundExportSettings settings, EventListener evl) throws IOException { + List ret = new ArrayList<>(); + if (tags.isEmpty()) { + return ret; + } + + File foutdir = new File(outdir); + Path.createDirectorySafe(foutdir); + + int count = 0; + for (Tag t : tags) { + if (t instanceof SoundTag) { + count++; + } + } + + if (count == 0) { + return ret; + } + + int currentIndex = 1; + for (Tag t : tags) { + if (t instanceof SoundTag) { + if (evl != null) { + evl.handleExportingEvent("sound", currentIndex, count, t.getName()); + } + + final SoundTag st = (SoundTag) t; + + String ext = "wav"; + SoundFormat fmt = st.getSoundFormat(); + switch (fmt.getNativeExportFormat()) { + case SoundFormat.EXPORT_MP3: + if (settings.mode.hasMP3()) { + ext = "mp3"; + } + break; + case SoundFormat.EXPORT_FLV: + if (settings.mode.hasFlv()) { + ext = "flv"; + } + break; + } + if (settings.mode == SoundExportMode.FLV) { + ext = "flv"; + } + + final File file = new File(outdir + File.separator + Helper.makeFileName(st.getCharacterExportFileName()) + "." + ext); + new RetryTask(() -> { + try (OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) { + exportSound(os, st, settings.mode); + } + }, handler).run(); + + ret.add(file); + + if (evl != null) { + evl.handleExportedEvent("sound", currentIndex, count, t.getName()); + } + + currentIndex++; + } + } + return ret; + } + + public byte[] exportSound(SoundTag t, SoundExportMode mode) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + exportSound(baos, t, mode); + return baos.toByteArray(); + } + + public void exportSound(OutputStream fos, SoundTag st, SoundExportMode mode) throws IOException { + SoundFormat fmt = st.getSoundFormat(); + int nativeFormat = fmt.getNativeExportFormat(); + + if (nativeFormat == SoundFormat.EXPORT_MP3 && mode.hasMP3()) { + List datas = st.getRawSoundData(); + for (ByteArrayRange data : datas) { + fos.write(data.getRangeData()); + } + } else if ((nativeFormat == SoundFormat.EXPORT_FLV && mode.hasFlv()) || mode == SoundExportMode.FLV) { + if (st instanceof DefineSoundTag) { + FLVOutputStream flv = new FLVOutputStream(fos); + flv.writeHeader(true, false); + List datas = st.getRawSoundData(); + for (ByteArrayRange data : datas) { + flv.writeTag(new FLVTAG(0, new AUDIODATA(st.getSoundFormatId(), st.getSoundRate(), st.getSoundSize(), st.getSoundType(), data.getRangeData()))); + } + } else if (st instanceof SoundStreamHeadTypeTag) { + SoundStreamHeadTypeTag sh = (SoundStreamHeadTypeTag) st; + FLVOutputStream flv = new FLVOutputStream(fos); + flv.writeHeader(true, false); + List blocks = sh.getBlocks(); + + int ms = (int) (1000.0f / ((float) ((Tag) st).getSwf().frameRate)); + for (int b = 0; b < blocks.size(); b++) { + byte[] data = blocks.get(b).streamSoundData.getRangeData(); + if (st.getSoundFormatId() == 2) { //MP3 + data = Arrays.copyOfRange(data, 4, data.length); + } + flv.writeTag(new FLVTAG(ms * b, new AUDIODATA(st.getSoundFormatId(), st.getSoundRate(), st.getSoundSize(), st.getSoundType(), data))); + } + } + } else { + List soundData = st.getRawSoundData(); + SWF swf = ((Tag) st).getSwf(); + List siss = new ArrayList<>(); + for (ByteArrayRange data : soundData) { + siss.add(new SWFInputStream(swf, data.getRangeData())); + } + fmt.createWav(siss, fos); + } + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG2Tag.java index 661b35d7c..409ac02fc 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG2Tag.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.tags; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.helpers.ImageHelper; import com.jpexs.decompiler.flash.tags.base.AloneTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; @@ -116,7 +117,10 @@ public class DefineBitsJPEG2Tag extends ImageTag implements AloneTag { } SerializableImage ret = new SerializableImage(image); - cachedImage = ret; + if (Configuration.cacheImages.get()) { + cachedImage = ret; + } + return ret; } catch (IOException ex) { Logger.getLogger(DefineBitsJPEG2Tag.class.getName()).log(Level.SEVERE, "Failed to get image", ex); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG3Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG3Tag.java index c8d5d8477..7ce6edc6d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG3Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG3Tag.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.tags; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.helpers.ImageHelper; import com.jpexs.decompiler.flash.tags.base.AloneTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; @@ -178,7 +179,10 @@ public class DefineBitsJPEG3Tag extends ImageTag implements AloneTag { SerializableImage img = new SerializableImage(image); if (bitmapAlphaData.getLength() == 0) { - cachedImage = img; + if (Configuration.cacheImages.get()) { + cachedImage = img; + } + return img; } @@ -189,7 +193,10 @@ public class DefineBitsJPEG3Tag extends ImageTag implements AloneTag { pixels[i] = multiplyAlpha((pixels[i] & 0xffffff) | (a << 24)); } - cachedImage = img; + if (Configuration.cacheImages.get()) { + cachedImage = img; + } + return img; } catch (IOException ex) { Logger.getLogger(DefineBitsJPEG3Tag.class.getName()).log(Level.SEVERE, "Failed to get image", ex); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG4Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG4Tag.java index 6c0ccc7b2..b163dbd7a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG4Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG4Tag.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.tags; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.helpers.ImageHelper; import com.jpexs.decompiler.flash.tags.base.AloneTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; @@ -182,7 +183,10 @@ public class DefineBitsJPEG4Tag extends ImageTag implements AloneTag { SerializableImage img = new SerializableImage(image); if (bitmapAlphaData.getLength() == 0) { - cachedImage = img; + if (Configuration.cacheImages.get()) { + cachedImage = img; + } + return img; } @@ -193,7 +197,10 @@ public class DefineBitsJPEG4Tag extends ImageTag implements AloneTag { pixels[i] = multiplyAlpha((pixels[i] & 0xffffff) | (a << 24)); } - cachedImage = img; + if (Configuration.cacheImages.get()) { + cachedImage = img; + } + return img; } catch (IOException ex) { Logger.getLogger(DefineBitsJPEG4Tag.class.getName()).log(Level.SEVERE, "Failed to get image", ex); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java index 663ff8885..8506ac6b1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.tags; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.helpers.ImageHelper; import com.jpexs.decompiler.flash.tags.base.AloneTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; @@ -268,7 +269,10 @@ public class DefineBitsLossless2Tag extends ImageTag implements AloneTag { } } - cachedImage = bi; + if (Configuration.cacheImages.get()) { + cachedImage = bi; + } + return bi; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java index c6830b256..367d7d6f3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.tags; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.helpers.ImageHelper; import com.jpexs.decompiler.flash.tags.base.AloneTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; @@ -239,7 +240,10 @@ public class DefineBitsLosslessTag extends ImageTag implements AloneTag { } SerializableImage bi = new SerializableImage(bitmapWidth, bitmapHeight, SerializableImage.TYPE_INT_RGB, pixels); - cachedImage = bi; + if (Configuration.cacheImages.get()) { + cachedImage = bi; + } + return bi; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsTag.java index 06f5c10f5..fcfcd0980 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsTag.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.tags; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.helpers.ImageHelper; import com.jpexs.decompiler.flash.tags.base.ImageTag; import com.jpexs.decompiler.flash.tags.enums.ImageFormat; @@ -128,7 +129,10 @@ public class DefineBitsTag extends ImageTag implements TagChangedListener { } SerializableImage ret = new SerializableImage(image); - cachedImage = ret; + if (Configuration.cacheImages.get()) { + cachedImage = ret; + } + return ret; } catch (IOException ex) { Logger.getLogger(DefineBitsTag.class.getName()).log(Level.SEVERE, "Failed to get image", ex); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java index 61f49485d..c10608e47 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java @@ -330,14 +330,14 @@ public class DefineSoundTag extends CharacterTag implements SoundTag { } @Override - public List getRawSoundData() { - List ret = new ArrayList<>(); + public List getRawSoundData() { + List ret = new ArrayList<>(); if (soundFormat == SoundFormat.FORMAT_MP3) { - ret.add(soundData.getRangeData(2, soundData.getLength() - 2)); + ret.add(soundData.getSubRange(2, soundData.getLength() - 2)); return ret; } - ret.add(soundData.getRangeData()); + ret.add(soundData); return ret; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java index d71570a0b..b3e70807f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java @@ -150,7 +150,7 @@ public class DoActionTag extends Tag implements ASMSource { @Override public void setActions(List actions) { byte[] bytes = Action.actionsToBytes(actions, true, swf.version); - actionBytes = new ByteArrayRange(bytes, 0, bytes.length); + actionBytes = new ByteArrayRange(bytes); } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java index 26f16bd5a..901fb9c29 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java @@ -158,7 +158,7 @@ public class DoInitActionTag extends Tag implements CharacterIdTag, ASMSource { @Override public void setActions(List actions) { byte[] bytes = Action.actionsToBytes(actions, true, swf.version); - actionBytes = new ByteArrayRange(bytes, 0, bytes.length); + actionBytes = new ByteArrayRange(bytes); } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java index 1a99488e9..02ca2861f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java @@ -221,14 +221,15 @@ public class SoundStreamHead2Tag extends Tag implements SoundStreamHeadTypeTag { } @Override - public List getRawSoundData() { - List ret = new ArrayList<>(); + public List getRawSoundData() { + List ret = new ArrayList<>(); List blocks = getBlocks(); for (SoundStreamBlockTag block : blocks) { + ByteArrayRange data = block.streamSoundData; if (streamSoundCompression == SoundFormat.FORMAT_MP3) { - ret.add(block.streamSoundData.getRangeData(4, block.streamSoundData.getLength() - 4)); + ret.add(data.getSubRange(4, data.getLength() - 4)); } else { - ret.add(block.streamSoundData.getRangeData()); + ret.add(data); } } return ret; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java index b5196791f..bfd9b9488 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java @@ -244,14 +244,15 @@ public class SoundStreamHeadTag extends Tag implements SoundStreamHeadTypeTag { } @Override - public List getRawSoundData() { - List ret = new ArrayList<>(); + public List getRawSoundData() { + List ret = new ArrayList<>(); List blocks = getBlocks(); for (SoundStreamBlockTag block : blocks) { + ByteArrayRange data = block.streamSoundData; if (streamSoundCompression == SoundFormat.FORMAT_MP3) { - ret.add(block.streamSoundData.getRangeData(4, block.streamSoundData.getLength() - 4)); + ret.add(data.getSubRange(4, data.getLength() - 4)); } else { - ret.add(block.streamSoundData.getRangeData()); + ret.add(data); } } return ret; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java index 4384ddfa2..6e8c81b1a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java @@ -521,7 +521,7 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { byte[] tagData = new byte[data.length + headerData.length]; System.arraycopy(headerData, 0, tagData, 0, headerData.length); System.arraycopy(data, 0, tagData, headerData.length, data.length); - originalRange = new ByteArrayRange(tagData, 0, tagData.length); + originalRange = new ByteArrayRange(tagData); } public boolean isModified() { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/SoundTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/SoundTag.java index 783cd0b51..d8f22152f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/SoundTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/SoundTag.java @@ -1,22 +1,24 @@ /* * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.tags.base; import com.jpexs.decompiler.flash.treeitems.TreeItem; import com.jpexs.decompiler.flash.types.sound.SoundFormat; +import com.jpexs.helpers.ByteArrayRange; import java.io.InputStream; import java.util.List; @@ -36,7 +38,7 @@ public interface SoundTag extends TreeItem { public boolean getSoundType(); - public List getRawSoundData(); + public List getRawSoundData(); public int getSoundFormatId(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java index 5ed4a7e13..64f9f99d5 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java @@ -1,340 +1,340 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.types; - -import com.jpexs.decompiler.flash.DisassemblyListener; -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.action.Action; -import com.jpexs.decompiler.flash.action.ActionList; -import com.jpexs.decompiler.flash.action.ActionListReader; -import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; -import com.jpexs.decompiler.flash.helpers.GraphTextWriter; -import com.jpexs.decompiler.flash.tags.Tag; -import com.jpexs.decompiler.flash.tags.base.ASMSource; -import com.jpexs.decompiler.flash.types.annotations.Conditional; -import com.jpexs.decompiler.flash.types.annotations.Internal; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.Helper; -import java.io.IOException; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Actions to execute at particular button events - * - * @author JPEXS - */ -public class BUTTONCONDACTION implements ASMSource, Serializable { - - private final SWF swf; - - private final Tag tag; - - @Override - public SWF getSwf() { - return swf; - } - - // Constructor for Generic tag editor. TODO:Handle this somehow better - public BUTTONCONDACTION() { - swf = null; - tag = null; - } - - public BUTTONCONDACTION(SWF swf, SWFInputStream sis, Tag tag) throws IOException { - this.swf = swf; - this.tag = tag; - int condActionSize = sis.readUI16("condActionSize"); - isLast = condActionSize <= 0; - condIdleToOverDown = sis.readUB(1, "condIdleToOverDown") == 1; - condOutDownToIdle = sis.readUB(1, "condOutDownToIdle") == 1; - condOutDownToOverDown = sis.readUB(1, "condOutDownToOverDown") == 1; - condOverDownToOutDown = sis.readUB(1, "condOverDownToOutDown") == 1; - condOverDownToOverUp = sis.readUB(1, "condOverDownToOverUp") == 1; - condOverUpToOverDown = sis.readUB(1, "condOverUpToOverDown") == 1; - condOverUpToIddle = sis.readUB(1, "condOverUpToIddle") == 1; - condIdleToOverUp = sis.readUB(1, "condIdleToOverUp") == 1; - condKeyPress = (int) sis.readUB(7, "condKeyPress"); - condOverDownToIdle = sis.readUB(1, "condOverDownToIdle") == 1; - actionBytes = sis.readByteRangeEx(condActionSize <= 0 ? sis.available() : condActionSize - 4, "actionBytes"); - } - - /** - * Is this BUTTONCONDACTION last in the list? - */ - @Internal - public boolean isLast; - - /** - * Idle to OverDown - */ - public boolean condIdleToOverDown; - - /** - * OutDown to Idle - */ - public boolean condOutDownToIdle; - - /** - * OutDown to OverDown - */ - public boolean condOutDownToOverDown; - - /** - * OverDown to OutDown - */ - public boolean condOverDownToOutDown; - - /** - * OverDown to OverUp - */ - public boolean condOverDownToOverUp; - - /** - * OverUp to OverDown - */ - public boolean condOverUpToOverDown; - - /** - * OverUp to Idle - */ - public boolean condOverUpToIddle; - - /** - * Idle to OverUp - */ - public boolean condIdleToOverUp; - - /** - * @since SWF 4 key code - */ - @SWFType(value = BasicType.UB, count = 7) - @Conditional(minSwfVersion = 4) - public int condKeyPress; - - /** - * OverDown to Idle - */ - public boolean condOverDownToIdle; - - /** - * Actions to perform - */ - //public List actions; - /** - * Actions to perform in byte array - */ - @Internal - public ByteArrayRange actionBytes; - - /** - * Sets actions associated with this object - * - * @param actions Action list - */ - /*public void setActions(List actions) { - this.actions = actions; - }*/ - /** - * Returns a string representation of the object - * - * @return a string representation of the object. - */ - @Override - public String toString() { - return "BUTTONCONDACTION"; - } - - /** - * Converts actions to ASM source - * - * @param exportMode PCode or hex? - * @param writer - * @param actions - * @return ASM source - * @throws java.lang.InterruptedException - */ - @Override - public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException { - if (actions == null) { - actions = getActions(); - } - return Action.actionsToString(listeners, 0, actions, swf.version, exportMode, writer); - } - - /** - * Whether or not this object contains ASM source - * - * @return True when contains - */ - @Override - public boolean containsSource() { - return true; - } - - /** - * Returns actions associated with this object - * - * @return List of actions - * @throws java.lang.InterruptedException - */ - @Override - public ActionList getActions() throws InterruptedException { - try { - int prevLength = actionBytes.getPos(); - SWFInputStream rri = new SWFInputStream(swf, actionBytes.getArray()); - if (prevLength != 0) { - rri.seek(prevLength); - } - - ActionList list = ActionListReader.readActionListTimeout(listeners, rri, swf.version, prevLength, prevLength + actionBytes.getLength(), toString()/*FIXME?*/); - return list; - - } catch (InterruptedException ex) { - throw ex; - } catch (Exception ex) { - Logger.getLogger(BUTTONCONDACTION.class.getName()).log(Level.SEVERE, null, ex); - return new ActionList(); - } - } - - @Override - public void setActions(List actions) { - byte[] bytes = Action.actionsToBytes(actions, true, swf.version); - actionBytes = new ByteArrayRange(bytes, 0, bytes.length); - } - - @Override - public byte[] getActionBytes() { - return actionBytes.getRangeData(); - } - - @Override - public void setActionBytes(byte[] actionBytes) { - this.actionBytes = new ByteArrayRange(actionBytes); - } - - @Override - public void setModified() { - if (tag != null) { - tag.setModified(true); - } - } - - @Override - public boolean isModified() { - if (tag != null) { - return tag.isModified(); - } - return false; - } - - @Override - public GraphTextWriter getActionBytesAsHex(GraphTextWriter writer) { - return Helper.byteArrayToHexWithHeader(writer, actionBytes.getRangeData()); - } - - List listeners = new ArrayList<>(); - - @Override - public void addDisassemblyListener(DisassemblyListener listener) { - listeners.add(listener); - } - - @Override - public void removeDisassemblyListener(DisassemblyListener listener) { - listeners.remove(listener); - } - - private String getHeader(boolean asFilename) { - List events = new ArrayList<>(); - if (condOverUpToOverDown) { - events.add("press"); - } - if (condOverDownToOverUp) { - events.add("release"); - } - if (condOutDownToIdle) { - events.add("releaseOutside"); - } - if (condIdleToOverUp) { - events.add("rollOver"); - } - if (condOverUpToIddle) { - events.add("rollOut"); - } - if (condOverDownToOutDown) { - events.add("dragOut"); - } - if (condOutDownToOverDown) { - events.add("dragOver"); - } - if (condKeyPress > 0) { - if (asFilename) { - events.add("keyPress " + Helper.makeFileName(CLIPACTIONRECORD.keyToString(condKeyPress).replace("<", "").replace(">", "")) + ""); - } else { - events.add("keyPress \"" + CLIPACTIONRECORD.keyToString(condKeyPress) + "\""); - } - } - String onStr = ""; - for (int i = 0; i < events.size(); i++) { - if (i > 0) { - onStr += ", "; - } - onStr += events.get(i); - } - return "on(" + onStr + ")"; - } - - @Override - public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) { - writer.appendNoHilight(getHeader(false)); - writer.appendNoHilight("{").newLine(); - return writer.indent(); - } - - @Override - public GraphTextWriter getActionSourceSuffix(GraphTextWriter writer) { - writer.unindent(); - return writer.appendNoHilight("}").newLine(); - } - - @Override - public int getPrefixLineCount() { - return 1; - } - - @Override - public String removePrefixAndSuffix(String source) { - return Helper.unindentRows(1, 1, source); - } - - @Override - public String getExportFileName() { - return getHeader(true); - } - - @Override - public Tag getSourceTag() { - return tag; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.types; + +import com.jpexs.decompiler.flash.DisassemblyListener; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.action.Action; +import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.flash.action.ActionListReader; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.ASMSource; +import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.Internal; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.Helper; +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Actions to execute at particular button events + * + * @author JPEXS + */ +public class BUTTONCONDACTION implements ASMSource, Serializable { + + private final SWF swf; + + private final Tag tag; + + @Override + public SWF getSwf() { + return swf; + } + + // Constructor for Generic tag editor. TODO:Handle this somehow better + public BUTTONCONDACTION() { + swf = null; + tag = null; + } + + public BUTTONCONDACTION(SWF swf, SWFInputStream sis, Tag tag) throws IOException { + this.swf = swf; + this.tag = tag; + int condActionSize = sis.readUI16("condActionSize"); + isLast = condActionSize <= 0; + condIdleToOverDown = sis.readUB(1, "condIdleToOverDown") == 1; + condOutDownToIdle = sis.readUB(1, "condOutDownToIdle") == 1; + condOutDownToOverDown = sis.readUB(1, "condOutDownToOverDown") == 1; + condOverDownToOutDown = sis.readUB(1, "condOverDownToOutDown") == 1; + condOverDownToOverUp = sis.readUB(1, "condOverDownToOverUp") == 1; + condOverUpToOverDown = sis.readUB(1, "condOverUpToOverDown") == 1; + condOverUpToIddle = sis.readUB(1, "condOverUpToIddle") == 1; + condIdleToOverUp = sis.readUB(1, "condIdleToOverUp") == 1; + condKeyPress = (int) sis.readUB(7, "condKeyPress"); + condOverDownToIdle = sis.readUB(1, "condOverDownToIdle") == 1; + actionBytes = sis.readByteRangeEx(condActionSize <= 0 ? sis.available() : condActionSize - 4, "actionBytes"); + } + + /** + * Is this BUTTONCONDACTION last in the list? + */ + @Internal + public boolean isLast; + + /** + * Idle to OverDown + */ + public boolean condIdleToOverDown; + + /** + * OutDown to Idle + */ + public boolean condOutDownToIdle; + + /** + * OutDown to OverDown + */ + public boolean condOutDownToOverDown; + + /** + * OverDown to OutDown + */ + public boolean condOverDownToOutDown; + + /** + * OverDown to OverUp + */ + public boolean condOverDownToOverUp; + + /** + * OverUp to OverDown + */ + public boolean condOverUpToOverDown; + + /** + * OverUp to Idle + */ + public boolean condOverUpToIddle; + + /** + * Idle to OverUp + */ + public boolean condIdleToOverUp; + + /** + * @since SWF 4 key code + */ + @SWFType(value = BasicType.UB, count = 7) + @Conditional(minSwfVersion = 4) + public int condKeyPress; + + /** + * OverDown to Idle + */ + public boolean condOverDownToIdle; + + /** + * Actions to perform + */ + //public List actions; + /** + * Actions to perform in byte array + */ + @Internal + public ByteArrayRange actionBytes; + + /** + * Sets actions associated with this object + * + * @param actions Action list + */ + /*public void setActions(List actions) { + this.actions = actions; + }*/ + /** + * Returns a string representation of the object + * + * @return a string representation of the object. + */ + @Override + public String toString() { + return "BUTTONCONDACTION"; + } + + /** + * Converts actions to ASM source + * + * @param exportMode PCode or hex? + * @param writer + * @param actions + * @return ASM source + * @throws java.lang.InterruptedException + */ + @Override + public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException { + if (actions == null) { + actions = getActions(); + } + return Action.actionsToString(listeners, 0, actions, swf.version, exportMode, writer); + } + + /** + * Whether or not this object contains ASM source + * + * @return True when contains + */ + @Override + public boolean containsSource() { + return true; + } + + /** + * Returns actions associated with this object + * + * @return List of actions + * @throws java.lang.InterruptedException + */ + @Override + public ActionList getActions() throws InterruptedException { + try { + int prevLength = actionBytes.getPos(); + SWFInputStream rri = new SWFInputStream(swf, actionBytes.getArray()); + if (prevLength != 0) { + rri.seek(prevLength); + } + + ActionList list = ActionListReader.readActionListTimeout(listeners, rri, swf.version, prevLength, prevLength + actionBytes.getLength(), toString()/*FIXME?*/); + return list; + + } catch (InterruptedException ex) { + throw ex; + } catch (Exception ex) { + Logger.getLogger(BUTTONCONDACTION.class.getName()).log(Level.SEVERE, null, ex); + return new ActionList(); + } + } + + @Override + public void setActions(List actions) { + byte[] bytes = Action.actionsToBytes(actions, true, swf.version); + actionBytes = new ByteArrayRange(bytes); + } + + @Override + public byte[] getActionBytes() { + return actionBytes.getRangeData(); + } + + @Override + public void setActionBytes(byte[] actionBytes) { + this.actionBytes = new ByteArrayRange(actionBytes); + } + + @Override + public void setModified() { + if (tag != null) { + tag.setModified(true); + } + } + + @Override + public boolean isModified() { + if (tag != null) { + return tag.isModified(); + } + return false; + } + + @Override + public GraphTextWriter getActionBytesAsHex(GraphTextWriter writer) { + return Helper.byteArrayToHexWithHeader(writer, actionBytes.getRangeData()); + } + + List listeners = new ArrayList<>(); + + @Override + public void addDisassemblyListener(DisassemblyListener listener) { + listeners.add(listener); + } + + @Override + public void removeDisassemblyListener(DisassemblyListener listener) { + listeners.remove(listener); + } + + private String getHeader(boolean asFilename) { + List events = new ArrayList<>(); + if (condOverUpToOverDown) { + events.add("press"); + } + if (condOverDownToOverUp) { + events.add("release"); + } + if (condOutDownToIdle) { + events.add("releaseOutside"); + } + if (condIdleToOverUp) { + events.add("rollOver"); + } + if (condOverUpToIddle) { + events.add("rollOut"); + } + if (condOverDownToOutDown) { + events.add("dragOut"); + } + if (condOutDownToOverDown) { + events.add("dragOver"); + } + if (condKeyPress > 0) { + if (asFilename) { + events.add("keyPress " + Helper.makeFileName(CLIPACTIONRECORD.keyToString(condKeyPress).replace("<", "").replace(">", "")) + ""); + } else { + events.add("keyPress \"" + CLIPACTIONRECORD.keyToString(condKeyPress) + "\""); + } + } + String onStr = ""; + for (int i = 0; i < events.size(); i++) { + if (i > 0) { + onStr += ", "; + } + onStr += events.get(i); + } + return "on(" + onStr + ")"; + } + + @Override + public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) { + writer.appendNoHilight(getHeader(false)); + writer.appendNoHilight("{").newLine(); + return writer.indent(); + } + + @Override + public GraphTextWriter getActionSourceSuffix(GraphTextWriter writer) { + writer.unindent(); + return writer.appendNoHilight("}").newLine(); + } + + @Override + public int getPrefixLineCount() { + return 1; + } + + @Override + public String removePrefixAndSuffix(String source) { + return Helper.unindentRows(1, 1, source); + } + + @Override + public String getExportFileName() { + return getHeader(true); + } + + @Override + public Tag getSourceTag() { + return tag; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java index f9bf4437b..3bc0bb086 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java @@ -1,293 +1,293 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.types; - -import com.jpexs.decompiler.flash.DisassemblyListener; -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.action.Action; -import com.jpexs.decompiler.flash.action.ActionList; -import com.jpexs.decompiler.flash.action.ActionListReader; -import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; -import com.jpexs.decompiler.flash.helpers.GraphTextWriter; -import com.jpexs.decompiler.flash.tags.Tag; -import com.jpexs.decompiler.flash.tags.base.ASMSource; -import com.jpexs.decompiler.flash.types.annotations.Conditional; -import com.jpexs.decompiler.flash.types.annotations.Internal; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.Helper; -import java.io.IOException; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Event handler - * - * @author JPEXS - */ -public class CLIPACTIONRECORD implements ASMSource, Serializable { - - public static String keyToString(int key) { - if ((key < CLIPACTIONRECORD.KEYNAMES.length) && (key > 0) && (CLIPACTIONRECORD.KEYNAMES[key] != null)) { - return CLIPACTIONRECORD.KEYNAMES[key]; - } else { - return "" + (char) key; - } - } - - public static final String[] KEYNAMES = { - null, - "", - "", - "", - "", - "", - "", - null, - "", - null, - null, - null, - null, - "", - "", - "", - "", - "", - "", - "", - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - "" - }; - - @Internal - private final SWF swf; - - @Internal - private final Tag tag; - - // Constructor for Generic tag editor. TODO:Handle this somehow better - public CLIPACTIONRECORD() { - swf = null; - tag = null; - eventFlags = new CLIPEVENTFLAGS(); - actionBytes = ByteArrayRange.EMPTY; - } - - public CLIPACTIONRECORD(SWF swf, SWFInputStream sis, Tag tag) throws IOException { - this.swf = swf; - this.tag = tag; - eventFlags = sis.readCLIPEVENTFLAGS("eventFlags"); - if (eventFlags.isClear()) { - return; - } - long actionRecordSize = sis.readUI32("actionRecordSize"); - if (eventFlags.clipEventKeyPress) { - keyCode = sis.readUI8("keyCode"); - actionRecordSize--; - } - actionBytes = sis.readByteRangeEx(actionRecordSize, "actionBytes"); - } - - @Override - public SWF getSwf() { - return swf; - } - - /** - * Events to which this handler applies - */ - public CLIPEVENTFLAGS eventFlags; - - /** - * If EventFlags contain ClipEventKeyPress: Key code to trap - */ - @Conditional("eventFlags.clipEventKeyPress") - public int keyCode; - - /** - * Actions to perform - */ - //public List actions; - @Internal - public ByteArrayRange actionBytes; - - /** - * Returns a string representation of the object - * - * @return a string representation of the object. - */ - @Override - public String toString() { - return eventFlags.getHeader(keyCode, false); - } - - /** - * Returns header with events converted to string - * - * @return String representation of events - */ - public String getHeader() { - String ret; - ret = eventFlags.toString(); - if (eventFlags.clipEventKeyPress) { - ret = ret.replace("keyPress", "keyPress<" + keyCode + ">"); - } - return ret; - } - - /** - * Converts actions to ASM source - * - * @param exportMode PCode or hex? - * @param writer - * @param actions - * @return ASM source - * @throws java.lang.InterruptedException - */ - @Override - public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException { - if (actions == null) { - actions = getActions(); - } - return Action.actionsToString(listeners, 0, actions, swf.version, exportMode, writer); - } - - /** - * Whether or not this object contains ASM source - * - * @return True when contains - */ - @Override - public boolean containsSource() { - return true; - } - - @Override - public ActionList getActions() throws InterruptedException { - try { - int prevLength = actionBytes.getPos(); - SWFInputStream rri = new SWFInputStream(swf, actionBytes.getArray()); - if (prevLength != 0) { - rri.seek(prevLength); - } - - ActionList list = ActionListReader.readActionListTimeout(listeners, rri, swf.version, prevLength, prevLength + actionBytes.getLength(), toString()/*FIXME?*/); - return list; - } catch (InterruptedException ex) { - throw ex; - } catch (Exception ex) { - Logger.getLogger(CLIPACTIONRECORD.class.getName()).log(Level.SEVERE, null, ex); - return new ActionList(); - } - } - - @Override - public void setActions(List actions) { - byte[] bytes = Action.actionsToBytes(actions, true, swf.version); - actionBytes = new ByteArrayRange(bytes, 0, bytes.length); - } - - @Override - public byte[] getActionBytes() { - return actionBytes.getRangeData(); - } - - @Override - public void setActionBytes(byte[] actionBytes) { - this.actionBytes = new ByteArrayRange(actionBytes); - } - - @Override - public void setModified() { - if (tag != null) { - tag.setModified(true); - } - } - - @Override - public boolean isModified() { - if (tag != null) { - return tag.isModified(); - } - return false; - } - - @Override - public GraphTextWriter getActionBytesAsHex(GraphTextWriter writer) { - return Helper.byteArrayToHexWithHeader(writer, actionBytes.getRangeData()); - } - - List listeners = new ArrayList<>(); - - @Override - public void addDisassemblyListener(DisassemblyListener listener) { - listeners.add(listener); - } - - @Override - public void removeDisassemblyListener(DisassemblyListener listener) { - listeners.remove(listener); - } - - @Override - public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) { - writer.appendNoHilight(eventFlags.getHeader(keyCode, false)); - writer.appendNoHilight("{").newLine(); - return writer.indent(); - } - - @Override - public GraphTextWriter getActionSourceSuffix(GraphTextWriter writer) { - writer.unindent(); - return writer.appendNoHilight("}").newLine(); - } - - @Override - public int getPrefixLineCount() { - return 1; - } - - @Override - public String removePrefixAndSuffix(String source) { - return Helper.unindentRows(1, 1, source); - } - - @Override - public String getExportFileName() { - return eventFlags.getHeader(keyCode, true); - } - - @Override - public Tag getSourceTag() { - return tag; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.types; + +import com.jpexs.decompiler.flash.DisassemblyListener; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.action.Action; +import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.flash.action.ActionListReader; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.ASMSource; +import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.Internal; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.Helper; +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Event handler + * + * @author JPEXS + */ +public class CLIPACTIONRECORD implements ASMSource, Serializable { + + public static String keyToString(int key) { + if ((key < CLIPACTIONRECORD.KEYNAMES.length) && (key > 0) && (CLIPACTIONRECORD.KEYNAMES[key] != null)) { + return CLIPACTIONRECORD.KEYNAMES[key]; + } else { + return "" + (char) key; + } + } + + public static final String[] KEYNAMES = { + null, + "", + "", + "", + "", + "", + "", + null, + "", + null, + null, + null, + null, + "", + "", + "", + "", + "", + "", + "", + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + "" + }; + + @Internal + private final SWF swf; + + @Internal + private final Tag tag; + + // Constructor for Generic tag editor. TODO:Handle this somehow better + public CLIPACTIONRECORD() { + swf = null; + tag = null; + eventFlags = new CLIPEVENTFLAGS(); + actionBytes = ByteArrayRange.EMPTY; + } + + public CLIPACTIONRECORD(SWF swf, SWFInputStream sis, Tag tag) throws IOException { + this.swf = swf; + this.tag = tag; + eventFlags = sis.readCLIPEVENTFLAGS("eventFlags"); + if (eventFlags.isClear()) { + return; + } + long actionRecordSize = sis.readUI32("actionRecordSize"); + if (eventFlags.clipEventKeyPress) { + keyCode = sis.readUI8("keyCode"); + actionRecordSize--; + } + actionBytes = sis.readByteRangeEx(actionRecordSize, "actionBytes"); + } + + @Override + public SWF getSwf() { + return swf; + } + + /** + * Events to which this handler applies + */ + public CLIPEVENTFLAGS eventFlags; + + /** + * If EventFlags contain ClipEventKeyPress: Key code to trap + */ + @Conditional("eventFlags.clipEventKeyPress") + public int keyCode; + + /** + * Actions to perform + */ + //public List actions; + @Internal + public ByteArrayRange actionBytes; + + /** + * Returns a string representation of the object + * + * @return a string representation of the object. + */ + @Override + public String toString() { + return eventFlags.getHeader(keyCode, false); + } + + /** + * Returns header with events converted to string + * + * @return String representation of events + */ + public String getHeader() { + String ret; + ret = eventFlags.toString(); + if (eventFlags.clipEventKeyPress) { + ret = ret.replace("keyPress", "keyPress<" + keyCode + ">"); + } + return ret; + } + + /** + * Converts actions to ASM source + * + * @param exportMode PCode or hex? + * @param writer + * @param actions + * @return ASM source + * @throws java.lang.InterruptedException + */ + @Override + public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException { + if (actions == null) { + actions = getActions(); + } + return Action.actionsToString(listeners, 0, actions, swf.version, exportMode, writer); + } + + /** + * Whether or not this object contains ASM source + * + * @return True when contains + */ + @Override + public boolean containsSource() { + return true; + } + + @Override + public ActionList getActions() throws InterruptedException { + try { + int prevLength = actionBytes.getPos(); + SWFInputStream rri = new SWFInputStream(swf, actionBytes.getArray()); + if (prevLength != 0) { + rri.seek(prevLength); + } + + ActionList list = ActionListReader.readActionListTimeout(listeners, rri, swf.version, prevLength, prevLength + actionBytes.getLength(), toString()/*FIXME?*/); + return list; + } catch (InterruptedException ex) { + throw ex; + } catch (Exception ex) { + Logger.getLogger(CLIPACTIONRECORD.class.getName()).log(Level.SEVERE, null, ex); + return new ActionList(); + } + } + + @Override + public void setActions(List actions) { + byte[] bytes = Action.actionsToBytes(actions, true, swf.version); + actionBytes = new ByteArrayRange(bytes); + } + + @Override + public byte[] getActionBytes() { + return actionBytes.getRangeData(); + } + + @Override + public void setActionBytes(byte[] actionBytes) { + this.actionBytes = new ByteArrayRange(actionBytes); + } + + @Override + public void setModified() { + if (tag != null) { + tag.setModified(true); + } + } + + @Override + public boolean isModified() { + if (tag != null) { + return tag.isModified(); + } + return false; + } + + @Override + public GraphTextWriter getActionBytesAsHex(GraphTextWriter writer) { + return Helper.byteArrayToHexWithHeader(writer, actionBytes.getRangeData()); + } + + List listeners = new ArrayList<>(); + + @Override + public void addDisassemblyListener(DisassemblyListener listener) { + listeners.add(listener); + } + + @Override + public void removeDisassemblyListener(DisassemblyListener listener) { + listeners.remove(listener); + } + + @Override + public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) { + writer.appendNoHilight(eventFlags.getHeader(keyCode, false)); + writer.appendNoHilight("{").newLine(); + return writer.indent(); + } + + @Override + public GraphTextWriter getActionSourceSuffix(GraphTextWriter writer) { + writer.unindent(); + return writer.appendNoHilight("}").newLine(); + } + + @Override + public int getPrefixLineCount() { + return 1; + } + + @Override + public String removePrefixAndSuffix(String source) { + return Helper.unindentRows(1, 1, source); + } + + @Override + public String getExportFileName() { + return eventFlags.getHeader(keyCode, true); + } + + @Override + public Tag getSourceTag() { + return tag; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/helpers/ByteArrayRange.java b/libsrc/ffdec_lib/src/com/jpexs/helpers/ByteArrayRange.java index 7ef4ed965..9168ba7ae 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/helpers/ByteArrayRange.java +++ b/libsrc/ffdec_lib/src/com/jpexs/helpers/ByteArrayRange.java @@ -79,4 +79,8 @@ public class ByteArrayRange { System.arraycopy(array, this.pos + pos, data, 0, length); return data; } + + public ByteArrayRange getSubRange(int pos, int length) { + return new ByteArrayRange(array, this.pos + pos, length); + } } diff --git a/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java b/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java index 1528f37e8..32f1faca7 100644 --- a/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java @@ -1,344 +1,347 @@ -/* - * 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 . - */ -package com.jpexs.decompiler.flash.gui; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.tags.Tag; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; -import com.jpexs.decompiler.flash.tags.base.DrawableTag; -import com.jpexs.decompiler.flash.tags.base.ImageTag; -import com.jpexs.decompiler.flash.tags.base.RenderContext; -import com.jpexs.decompiler.flash.timeline.Frame; -import com.jpexs.decompiler.flash.treeitems.TreeItem; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.helpers.Cache; -import com.jpexs.helpers.SerializableImage; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.geom.AffineTransform; -import java.awt.image.BufferedImage; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import javax.swing.JLabel; -import javax.swing.JPanel; -import org.pushingpixels.substance.api.ColorSchemeAssociationKind; -import org.pushingpixels.substance.api.ComponentState; -import org.pushingpixels.substance.api.DecorationAreaType; -import org.pushingpixels.substance.api.SubstanceLookAndFeel; - -/** - * - * @author JPEXS - */ -public class FolderPreviewPanel extends JPanel { - - private static ExecutorService executor; - - private List items; - - private int selectedIndex = -1; - - private boolean repaintQueued; - - private int lastWidth; - - private int lastHeight; - - public Map selectedItems = new HashMap<>(); - - private Cache cachedPreviews; - - private static final int PREVIEW_SIZE = 150; - - private static final int BORDER_SIZE = 5; - - private static final int LABEL_HEIGHT = 20; - - private static final int CELL_HEIGHT = 2 * BORDER_SIZE + PREVIEW_SIZE + LABEL_HEIGHT; - - private static final int CELL_WIDTH = 2 * BORDER_SIZE + PREVIEW_SIZE; - - private static final SerializableImage noImage = new SerializableImage(PREVIEW_SIZE, PREVIEW_SIZE, BufferedImage.TYPE_INT_ARGB); - - static { - noImage.fillTransparent(); - executor = Executors.newFixedThreadPool(Configuration.parallelSpeedUp.get() ? Configuration.getParallelThreadCount() : 1); - } - - public FolderPreviewPanel(final MainPanel mainPanel, List items) { - this.items = items; - cachedPreviews = Cache.getInstance(false, false, "preview"); - - addMouseListener(new MouseAdapter() { - - @Override - public void mouseClicked(MouseEvent e) { - if (e.getClickCount() > 1) { - if (selectedIndex > -1) { - mainPanel.setTagTreeSelectedNode(FolderPreviewPanel.this.items.get(selectedIndex)); - } - } - } - - @Override - public void mousePressed(MouseEvent e) { - int width = getWidth(); - - int cols = width / CELL_WIDTH; - int rows = (int) Math.ceil(FolderPreviewPanel.this.items.size() / (float) cols); - int x = e.getX() / CELL_WIDTH; - int y = e.getY() / CELL_HEIGHT; - int index = y * cols + x; - if (index >= FolderPreviewPanel.this.items.size()) { - return; - } - - if (e.getButton() == MouseEvent.BUTTON1 || selectedItems.isEmpty()) { - if (!e.isControlDown()) { - selectedItems.clear(); - } - int oldSelectedIndex = selectedIndex; - selectedIndex = index; - - if (e.isShiftDown() && oldSelectedIndex > -1) { - int minindex = Math.min(selectedIndex, oldSelectedIndex); - int maxindex = Math.max(selectedIndex, oldSelectedIndex); - for (int i = minindex; i <= maxindex; i++) { - selectedItems.put(i, FolderPreviewPanel.this.items.get(i)); - } - selectedIndex = oldSelectedIndex; - } else { - TreeItem ti = FolderPreviewPanel.this.items.get(index); - if (!selectedItems.containsKey(selectedIndex)) { - selectedItems.put(selectedIndex, ti); - } else { - selectedItems.remove(selectedIndex); - selectedIndex = -1; - } - } - } - - if (e.getButton() == MouseEvent.BUTTON3) { - mainPanel.tagTree.contextPopupMenu.update(new ArrayList<>(selectedItems.values())); - mainPanel.tagTree.contextPopupMenu.show(FolderPreviewPanel.this, e.getX(), e.getY()); - } - repaint(); - } - - }); - } - - public synchronized void setItems(List items) { - this.items = items; - executor.shutdownNow(); - executor = Executors.newFixedThreadPool(Configuration.parallelSpeedUp.get() ? Configuration.getParallelThreadCount() : 1); - cachedPreviews.clear(); - revalidate(); - repaint(); - selectedItems.clear(); - selectedIndex = -1; - } - - @Override - public Dimension getPreferredSize() { - int width = getParent().getSize().width - 20; - int cols = width / CELL_WIDTH; - int rows = (int) Math.ceil(items.size() / (float) cols); - int height = rows * CELL_HEIGHT; - return (new Dimension(width, height)); - } - - @Override - public void paint(Graphics g) { - super.paint(g); - repaintQueued = false; - Rectangle r = getVisibleRect(); - int width = getWidth(); - - int cols = width / CELL_WIDTH; - int rows = (int) Math.ceil(items.size() / (float) cols); - int height = rows * CELL_HEIGHT; - - int start_y = r.y / CELL_HEIGHT; - JLabel l = new JLabel(); - Font f = l.getFont().deriveFont(AffineTransform.getScaleInstance(0.8, 0.8)); - int finish_y = (int) Math.ceil((r.y + r.height) / (float) CELL_HEIGHT); - Color color = SubstanceLookAndFeel.getCurrentSkin().getColorScheme(DecorationAreaType.GENERAL, ColorSchemeAssociationKind.FILL, ComponentState.ENABLED).getBackgroundFillColor(); - Color selectedColor = SubstanceLookAndFeel.getCurrentSkin().getColorScheme(DecorationAreaType.GENERAL, ColorSchemeAssociationKind.FILL, ComponentState.ROLLOVER_SELECTED).getBackgroundFillColor(); - Color borderColor = SubstanceLookAndFeel.getCurrentSkin().getColorScheme(DecorationAreaType.GENERAL, ColorSchemeAssociationKind.BORDER, ComponentState.ROLLOVER_SELECTED).getUltraDarkColor(); - Color textColor = SubstanceLookAndFeel.getCurrentSkin().getColorScheme(DecorationAreaType.GENERAL, ColorSchemeAssociationKind.FILL, ComponentState.ROLLOVER_SELECTED).getForegroundColor(); - - //g.setColor(SubstanceLookAndFeel.getCurrentSkin().getColorScheme(DecorationAreaType.GENERAL, ColorSchemeAssociationKind.FILL, ComponentState.ENABLED)); - for (int y = start_y; y <= finish_y; y++) { - for (int x = 0; x < cols; x++) { - int index = y * cols + x; - if (index < items.size()) { - - g.setColor(color); - if (selectedItems.containsKey(index)) { - g.setColor(selectedColor); - } - g.fillRect(x * CELL_WIDTH, y * CELL_HEIGHT, CELL_WIDTH, CELL_HEIGHT); - if (cachedPreviews.contains(index)) { - SerializableImage sImg = cachedPreviews.get(index); - if (sImg != null) { - BufferedImage img = cachedPreviews.get(index).getBufferedImage(); - g.drawImage(img, x * CELL_WIDTH + BORDER_SIZE + PREVIEW_SIZE / 2 - img.getWidth() / 2, y * CELL_HEIGHT + BORDER_SIZE + PREVIEW_SIZE / 2 - img.getHeight() / 2, null); - } - } else { - cachedPreviews.put(index, noImage); - renderImageTask(index, items.get(index)); - } - String s; - TreeItem treeItem = items.get(index); - if (treeItem instanceof Tag) { - s = ((Tag) treeItem).getTagName(); - if (treeItem instanceof CharacterTag) { - s = s + " (" + ((CharacterTag) treeItem).getCharacterId() + ")"; - } - } else { - s = treeItem.toString(); - } - g.setFont(f); - g.setColor(borderColor); - g.drawLine(x * CELL_WIDTH, y * CELL_HEIGHT + BORDER_SIZE + PREVIEW_SIZE, x * CELL_WIDTH + CELL_WIDTH, y * CELL_HEIGHT + BORDER_SIZE + PREVIEW_SIZE); - g.drawRect(x * CELL_WIDTH, y * CELL_HEIGHT, CELL_WIDTH, CELL_HEIGHT); - g.setColor(textColor); - g.drawString(s, x * CELL_WIDTH + BORDER_SIZE, y * CELL_HEIGHT + BORDER_SIZE + PREVIEW_SIZE + LABEL_HEIGHT); - - } - } - } - - if (lastWidth != width || lastHeight != height) { - lastWidth = width; - lastHeight = height; - setSize(new Dimension(width, height)); - } - } - - private synchronized void renderImageTask(final int index, final TreeItem treeItem) { - executor.submit(new Callable() { - - @Override - public Void call() throws Exception { - cachedPreviews.put(index, renderImage(treeItem.getSwf(), treeItem)); - if (!repaintQueued) { - repaintQueued = true; - View.execInEventDispatchLater(() -> { - repaint(); - }); - } - return null; - } - }); - } - - private SerializableImage renderImage(SWF swf, TreeItem treeItem) { - - int width = 0; - int height = 0; - SerializableImage imgSrc = null; - Matrix m = new Matrix(); - if (treeItem instanceof Frame) { - Frame fn = (Frame) treeItem; - RECT rect = swf.displayRect; - double zoom = 1.0; - if (rect.getWidth() > 0) { - double ratio = (PREVIEW_SIZE - 1) * SWF.unitDivisor / (rect.getWidth()); - if (ratio < zoom) { - zoom = ratio; - } - } - if (rect.getHeight() > 0) { - double ratio = (PREVIEW_SIZE - 1) * SWF.unitDivisor / (rect.getHeight()); - if (ratio < zoom) { - zoom = ratio; - } - } - imgSrc = SWF.frameToImageGet(swf.getTimeline(), fn.frame, 0, null, 0, rect, new Matrix(), new ColorTransform(), null, true, zoom); - width = imgSrc.getWidth(); - height = imgSrc.getHeight(); - } else if (treeItem instanceof ImageTag) { - imgSrc = ((ImageTag) treeItem).getImage(); - width = imgSrc.getWidth(); - height = imgSrc.getHeight(); - } else if (treeItem instanceof BoundedTag) { - BoundedTag boundedTag = (BoundedTag) treeItem; - RECT rect = boundedTag.getRect(); - width = (int) (rect.getWidth() / SWF.unitDivisor) + 1; - height = (int) (rect.getHeight() / SWF.unitDivisor) + 1; - m.translate(-rect.Xmin, -rect.Ymin); - } - - int w1 = width; - int h1 = height; - int w2 = PREVIEW_SIZE; - int h2 = PREVIEW_SIZE; - - int w; - int h = h1 * w2 / w1; - if (h > h2) { - w = w1 * h2 / h1; - } else { - w = w2; - } - - double scale = (double) w / (double) w1; - if (w1 <= w2 && h1 <= h2) { - if (imgSrc != null) { - return imgSrc; - } - - scale = 1; - } - - m = m.preConcatenate(Matrix.getScaleInstance(scale)); - width = (int) (scale * width); - height = (int) (scale * height); - if (width == 0 || height == 0) { - return null; - } - - SerializableImage image = new SerializableImage(width, height, SerializableImage.TYPE_INT_ARGB); - image.fillTransparent(); - if (imgSrc == null) { - DrawableTag drawable = (DrawableTag) treeItem; - drawable.toImage(0, 0, 0, new RenderContext(), image, m, new ColorTransform()); - } else { - Graphics2D g = (Graphics2D) image.getGraphics(); - g.setTransform(m.toTransform()); - g.drawImage(imgSrc.getBufferedImage(), 0, 0, null); - } - return image; - } -} +/* + * 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 . + */ +package com.jpexs.decompiler.flash.gui; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.BoundedTag; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.tags.base.DrawableTag; +import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.base.RenderContext; +import com.jpexs.decompiler.flash.timeline.Frame; +import com.jpexs.decompiler.flash.treeitems.TreeItem; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.helpers.Cache; +import com.jpexs.helpers.SerializableImage; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import javax.swing.JLabel; +import javax.swing.JPanel; +import org.pushingpixels.substance.api.ColorSchemeAssociationKind; +import org.pushingpixels.substance.api.ComponentState; +import org.pushingpixels.substance.api.DecorationAreaType; +import org.pushingpixels.substance.api.SubstanceLookAndFeel; + +/** + * + * @author JPEXS + */ +public class FolderPreviewPanel extends JPanel { + + private static ExecutorService executor; + + private List items; + + private int selectedIndex = -1; + + private boolean repaintQueued; + + private int lastWidth; + + private int lastHeight; + + public Map selectedItems = new HashMap<>(); + + private Cache cachedPreviews; + + private static final int PREVIEW_SIZE = 150; + + private static final int BORDER_SIZE = 5; + + private static final int LABEL_HEIGHT = 20; + + private static final int CELL_HEIGHT = 2 * BORDER_SIZE + PREVIEW_SIZE + LABEL_HEIGHT; + + private static final int CELL_WIDTH = 2 * BORDER_SIZE + PREVIEW_SIZE; + + private static final SerializableImage noImage = new SerializableImage(PREVIEW_SIZE, PREVIEW_SIZE, BufferedImage.TYPE_INT_ARGB); + + static { + noImage.fillTransparent(); + executor = Executors.newFixedThreadPool(Configuration.parallelSpeedUp.get() ? Configuration.getParallelThreadCount() : 1); + } + + public FolderPreviewPanel(final MainPanel mainPanel, List items) { + this.items = items; + cachedPreviews = Cache.getInstance(false, false, "preview"); + + addMouseListener(new MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() > 1) { + if (selectedIndex > -1) { + mainPanel.setTagTreeSelectedNode(FolderPreviewPanel.this.items.get(selectedIndex)); + } + } + } + + @Override + public void mousePressed(MouseEvent e) { + int width = getWidth(); + + int cols = width / CELL_WIDTH; + int rows = (int) Math.ceil(FolderPreviewPanel.this.items.size() / (float) cols); + int x = e.getX() / CELL_WIDTH; + int y = e.getY() / CELL_HEIGHT; + int index = y * cols + x; + if (index >= FolderPreviewPanel.this.items.size()) { + return; + } + + if (e.getButton() == MouseEvent.BUTTON1 || selectedItems.isEmpty()) { + if (!e.isControlDown()) { + selectedItems.clear(); + } + int oldSelectedIndex = selectedIndex; + selectedIndex = index; + + if (e.isShiftDown() && oldSelectedIndex > -1) { + int minindex = Math.min(selectedIndex, oldSelectedIndex); + int maxindex = Math.max(selectedIndex, oldSelectedIndex); + for (int i = minindex; i <= maxindex; i++) { + selectedItems.put(i, FolderPreviewPanel.this.items.get(i)); + } + selectedIndex = oldSelectedIndex; + } else { + TreeItem ti = FolderPreviewPanel.this.items.get(index); + if (!selectedItems.containsKey(selectedIndex)) { + selectedItems.put(selectedIndex, ti); + } else { + selectedItems.remove(selectedIndex); + selectedIndex = -1; + } + } + } + + if (e.getButton() == MouseEvent.BUTTON3) { + mainPanel.tagTree.contextPopupMenu.update(new ArrayList<>(selectedItems.values())); + mainPanel.tagTree.contextPopupMenu.show(FolderPreviewPanel.this, e.getX(), e.getY()); + } + repaint(); + } + + }); + } + + public synchronized void setItems(List items) { + this.items = items; + executor.shutdownNow(); + executor = Executors.newFixedThreadPool(Configuration.parallelSpeedUp.get() ? Configuration.getParallelThreadCount() : 1); + cachedPreviews.clear(); + revalidate(); + repaint(); + selectedItems.clear(); + selectedIndex = -1; + } + + public void clear() { + items = new ArrayList<>(); + executor.shutdownNow(); + cachedPreviews.clear(); + selectedItems.clear(); + selectedIndex = -1; + } + + @Override + public Dimension getPreferredSize() { + int width = getParent().getSize().width - 20; + int cols = width / CELL_WIDTH; + int rows = (int) Math.ceil(items.size() / (float) cols); + int height = rows * CELL_HEIGHT; + return (new Dimension(width, height)); + } + + @Override + public void paint(Graphics g) { + super.paint(g); + repaintQueued = false; + Rectangle r = getVisibleRect(); + int width = getWidth(); + + int cols = width / CELL_WIDTH; + int rows = (int) Math.ceil(items.size() / (float) cols); + int height = rows * CELL_HEIGHT; + + int start_y = r.y / CELL_HEIGHT; + JLabel l = new JLabel(); + Font f = l.getFont().deriveFont(AffineTransform.getScaleInstance(0.8, 0.8)); + int finish_y = (int) Math.ceil((r.y + r.height) / (float) CELL_HEIGHT); + Color color = SubstanceLookAndFeel.getCurrentSkin().getColorScheme(DecorationAreaType.GENERAL, ColorSchemeAssociationKind.FILL, ComponentState.ENABLED).getBackgroundFillColor(); + Color selectedColor = SubstanceLookAndFeel.getCurrentSkin().getColorScheme(DecorationAreaType.GENERAL, ColorSchemeAssociationKind.FILL, ComponentState.ROLLOVER_SELECTED).getBackgroundFillColor(); + Color borderColor = SubstanceLookAndFeel.getCurrentSkin().getColorScheme(DecorationAreaType.GENERAL, ColorSchemeAssociationKind.BORDER, ComponentState.ROLLOVER_SELECTED).getUltraDarkColor(); + Color textColor = SubstanceLookAndFeel.getCurrentSkin().getColorScheme(DecorationAreaType.GENERAL, ColorSchemeAssociationKind.FILL, ComponentState.ROLLOVER_SELECTED).getForegroundColor(); + + //g.setColor(SubstanceLookAndFeel.getCurrentSkin().getColorScheme(DecorationAreaType.GENERAL, ColorSchemeAssociationKind.FILL, ComponentState.ENABLED)); + for (int y = start_y; y <= finish_y; y++) { + for (int x = 0; x < cols; x++) { + int index = y * cols + x; + if (index < items.size()) { + + g.setColor(color); + if (selectedItems.containsKey(index)) { + g.setColor(selectedColor); + } + g.fillRect(x * CELL_WIDTH, y * CELL_HEIGHT, CELL_WIDTH, CELL_HEIGHT); + if (cachedPreviews.contains(index)) { + SerializableImage sImg = cachedPreviews.get(index); + if (sImg != null) { + BufferedImage img = cachedPreviews.get(index).getBufferedImage(); + g.drawImage(img, x * CELL_WIDTH + BORDER_SIZE + PREVIEW_SIZE / 2 - img.getWidth() / 2, y * CELL_HEIGHT + BORDER_SIZE + PREVIEW_SIZE / 2 - img.getHeight() / 2, null); + } + } else { + cachedPreviews.put(index, noImage); + renderImageTask(index, items.get(index)); + } + String s; + TreeItem treeItem = items.get(index); + if (treeItem instanceof Tag) { + s = ((Tag) treeItem).getTagName(); + if (treeItem instanceof CharacterTag) { + s = s + " (" + ((CharacterTag) treeItem).getCharacterId() + ")"; + } + } else { + s = treeItem.toString(); + } + g.setFont(f); + g.setColor(borderColor); + g.drawLine(x * CELL_WIDTH, y * CELL_HEIGHT + BORDER_SIZE + PREVIEW_SIZE, x * CELL_WIDTH + CELL_WIDTH, y * CELL_HEIGHT + BORDER_SIZE + PREVIEW_SIZE); + g.drawRect(x * CELL_WIDTH, y * CELL_HEIGHT, CELL_WIDTH, CELL_HEIGHT); + g.setColor(textColor); + g.drawString(s, x * CELL_WIDTH + BORDER_SIZE, y * CELL_HEIGHT + BORDER_SIZE + PREVIEW_SIZE + LABEL_HEIGHT); + + } + } + } + + if (lastWidth != width || lastHeight != height) { + lastWidth = width; + lastHeight = height; + setSize(new Dimension(width, height)); + } + } + + private synchronized void renderImageTask(final int index, final TreeItem treeItem) { + executor.submit(() -> { + cachedPreviews.put(index, renderImage(treeItem.getSwf(), treeItem)); + if (!repaintQueued) { + repaintQueued = true; + View.execInEventDispatchLater(() -> { + repaint(); + }); + } + return null; + }); + } + + private SerializableImage renderImage(SWF swf, TreeItem treeItem) { + + int width = 0; + int height = 0; + SerializableImage imgSrc = null; + Matrix m = new Matrix(); + if (treeItem instanceof Frame) { + Frame fn = (Frame) treeItem; + RECT rect = swf.displayRect; + double zoom = 1.0; + if (rect.getWidth() > 0) { + double ratio = (PREVIEW_SIZE - 1) * SWF.unitDivisor / (rect.getWidth()); + if (ratio < zoom) { + zoom = ratio; + } + } + if (rect.getHeight() > 0) { + double ratio = (PREVIEW_SIZE - 1) * SWF.unitDivisor / (rect.getHeight()); + if (ratio < zoom) { + zoom = ratio; + } + } + imgSrc = SWF.frameToImageGet(swf.getTimeline(), fn.frame, 0, null, 0, rect, new Matrix(), new ColorTransform(), null, true, zoom); + width = imgSrc.getWidth(); + height = imgSrc.getHeight(); + } else if (treeItem instanceof ImageTag) { + imgSrc = ((ImageTag) treeItem).getImage(); + width = imgSrc.getWidth(); + height = imgSrc.getHeight(); + } else if (treeItem instanceof BoundedTag) { + BoundedTag boundedTag = (BoundedTag) treeItem; + RECT rect = boundedTag.getRect(); + width = (int) (rect.getWidth() / SWF.unitDivisor) + 1; + height = (int) (rect.getHeight() / SWF.unitDivisor) + 1; + m.translate(-rect.Xmin, -rect.Ymin); + } + + int w1 = width; + int h1 = height; + int w2 = PREVIEW_SIZE; + int h2 = PREVIEW_SIZE; + + int w; + int h = h1 * w2 / w1; + if (h > h2) { + w = w1 * h2 / h1; + } else { + w = w2; + } + + double scale = (double) w / (double) w1; + if (w1 <= w2 && h1 <= h2) { + if (imgSrc != null) { + return imgSrc; + } + + scale = 1; + } + + m = m.preConcatenate(Matrix.getScaleInstance(scale)); + width = (int) (scale * width); + height = (int) (scale * height); + if (width == 0 || height == 0) { + return null; + } + + SerializableImage image = new SerializableImage(width, height, SerializableImage.TYPE_INT_ARGB); + image.fillTransparent(); + if (imgSrc == null) { + DrawableTag drawable = (DrawableTag) treeItem; + drawable.toImage(0, 0, 0, new RenderContext(), image, m, new ColorTransform()); + } else { + Graphics2D g = (Graphics2D) image.getGraphics(); + g.setTransform(m.toTransform()); + g.drawImage(imgSrc.getBufferedImage(), 0, 0, null); + } + return image; + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java index ddf3e107c..43b31100e 100644 --- a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java @@ -1,1065 +1,1073 @@ -/* - * 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 . - */ -package com.jpexs.decompiler.flash.gui; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.gui.player.MediaDisplay; -import com.jpexs.decompiler.flash.gui.player.MediaDisplayListener; -import com.jpexs.decompiler.flash.gui.player.Zoom; -import com.jpexs.decompiler.flash.tags.DefineButtonSoundTag; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; -import com.jpexs.decompiler.flash.tags.base.ButtonTag; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; -import com.jpexs.decompiler.flash.tags.base.DrawableTag; -import com.jpexs.decompiler.flash.tags.base.RenderContext; -import com.jpexs.decompiler.flash.tags.base.SoundTag; -import com.jpexs.decompiler.flash.tags.base.TextTag; -import com.jpexs.decompiler.flash.timeline.DepthState; -import com.jpexs.decompiler.flash.timeline.Timeline; -import com.jpexs.decompiler.flash.timeline.Timelined; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.ConstantColorColorTransform; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; -import com.jpexs.helpers.SerializableImage; -import java.awt.AlphaComposite; -import java.awt.BasicStroke; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Cursor; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.event.MouseMotionAdapter; -import java.awt.event.MouseMotionListener; -import java.awt.geom.AffineTransform; -import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.imageio.ImageIO; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.UnsupportedAudioFileException; -import javax.swing.JLabel; -import javax.swing.JPanel; - -public final class ImagePanel extends JPanel implements MediaDisplay { - - private final List listeners = new ArrayList<>(); - - private Timelined timelined; - - private boolean stillFrame = false; - - private Timer timer; - - private int frame = -1; - - private boolean loop; - - private boolean zoomAvailable = false; - - private SWF swf; - - private boolean loaded; - - private int mouseButton; - - private final JLabel debugLabel = new JLabel("-"); - - private DepthState stateUnderCursor = null; - - private MouseEvent lastMouseEvent = null; - - private final List soundPlayers = new ArrayList<>(); - - private final IconPanel iconPanel; - - private int time = 0; - - private int selectedDepth = -1; - - private Zoom zoom = new Zoom(); - - private final Object delayObject = new Object(); - - private boolean drawReady; - - private final int drawWaitLimit = 50; // ms - - private TextTag textTag; - - private TextTag newTextTag; - - public synchronized void selectDepth(int depth) { - if (depth != selectedDepth) { - this.selectedDepth = depth; - } - - hideMouseSelection(); - } - - public void fireMediaDisplayStateChanged() { - for (MediaDisplayListener l : listeners) { - l.mediaDisplayStateChanged(this); - } - } - - @Override - public void addEventListener(MediaDisplayListener listener) { - listeners.add(listener); - } - - @Override - public void removeEventListener(MediaDisplayListener listener) { - listeners.remove(listener); - } - - private class IconPanel extends JPanel { - - private SerializableImage img; - - private Rectangle rect = null; - - private List dss; - - private List outlines; - - public BufferedImage getLastImage() { - return img.getBufferedImage(); - } - - public synchronized void setOutlines(List dss, List outlines) { - this.outlines = outlines; - this.dss = dss; - } - - public void setImg(SerializableImage img) { - this.img = img; - calcRect(); - repaint(); - } - - public synchronized List getObjectsUnderPoint(Point p) { - List ret = new ArrayList<>(); - for (int i = 0; i < outlines.size(); i++) { - if (outlines.get(i).contains(p)) { - ret.add(dss.get(i)); - } - } - return ret; - } - - public Rectangle getRect() { - return rect; - } - - public Point toImagePoint(Point p) { - if (img == null) { - return null; - } - return new Point((p.x - rect.x) * img.getWidth() / rect.width, (p.y - rect.y) * img.getHeight() / rect.height); - } - - private void calcRect() { - if (img != null) { - int w1 = img.getWidth(); - int h1 = img.getHeight(); - - int w2 = getWidth(); - int h2 = getHeight(); - - int w; - int h; - if (w1 <= w2 && h1 <= h2) { - w = w1; - h = h1; - } else { - - h = h1 * w2 / w1; - if (h > h2) { - w = w1 * h2 / h1; - h = h2; - } else { - w = w2; - } - } - - rect = new Rectangle(getWidth() / 2 - w / 2, getHeight() / 2 - h / 2, w, h); - } else { - rect = null; - } - } - - @Override - protected void paintComponent(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - g2d.setPaint(View.transparentPaint); - g2d.fill(new Rectangle(0, 0, getWidth(), getHeight())); - g2d.setComposite(AlphaComposite.SrcOver); - g2d.setPaint(View.getSwfBackgroundColor()); - g2d.fill(new Rectangle(0, 0, getWidth(), getHeight())); - if (img != null) { - calcRect(); - g2d.setComposite(AlphaComposite.SrcOver); - g2d.drawImage(img.getBufferedImage(), rect.x, rect.y, rect.x + rect.width, rect.y + rect.height, 0, 0, img.getWidth(), img.getHeight(), null); - } - - } - } - - @Override - public void setBackground(Color bg) { - if (iconPanel != null) { - iconPanel.setBackground(bg); - } - super.setBackground(bg); - } - - @Override - public synchronized void addMouseListener(MouseListener l) { - iconPanel.addMouseListener(l); - } - - @Override - public synchronized void removeMouseListener(MouseListener l) { - iconPanel.removeMouseListener(l); - } - - @Override - public synchronized void addMouseMotionListener(MouseMotionListener l) { - iconPanel.addMouseMotionListener(l); - } - - @Override - public synchronized void removeMouseMotionListener(MouseMotionListener l) { - iconPanel.removeMouseMotionListener(l); - } - - private void updatePos(Timelined timelined, MouseEvent lastMouseEvent, Timer thisTimer) { - boolean handCursor = false; - DepthState newStateUnderCursor = null; - if (timelined != null) { - - Timeline tim = ((Timelined) timelined).getTimeline(); - BoundedTag bounded = (BoundedTag) timelined; - RECT rect = bounded.getRect(); - int width = rect.getWidth(); - double scale = 1.0; - /*if (width > swf.displayRect.getWidth()) { - scale = (double) swf.displayRect.getWidth() / (double) width; - }*/ - Matrix m = new Matrix(); - m.translate(-rect.Xmin, -rect.Ymin); - m.scale(scale); - - Point p = lastMouseEvent == null ? null : lastMouseEvent.getPoint(); - List objs = new ArrayList<>(); - String ret = ""; - - synchronized (ImagePanel.class) { - if (timer == thisTimer) { - p = p == null ? null : iconPanel.toImagePoint(p); - if (p != null) { - int x = p.x; - int y = p.y; - objs = iconPanel.getObjectsUnderPoint(p); - - ret += " [" + x + "," + y + "] : "; - } - } - } - - boolean first = true; - for (int i = 0; i < objs.size(); i++) { - DepthState ds = objs.get(i); - if (!first) { - ret += ", "; - } - first = false; - CharacterTag c = tim.swf.getCharacter(ds.characterId); - if (c instanceof ButtonTag) { - newStateUnderCursor = ds; - handCursor = true; - } - ret += c.toString(); - if (timelined instanceof ButtonTag) { - handCursor = true; - } - } - if (first) { - ret += " - "; - } - - synchronized (ImagePanel.class) { - if (timer == thisTimer) { - debugLabel.setText(ret); - - if (handCursor) { - iconPanel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - } else { - iconPanel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } - if (newStateUnderCursor != stateUnderCursor) { - stateUnderCursor = newStateUnderCursor; - } - } - } - } - } - - private void showSelectedName() { - if (selectedDepth > -1 && frame > -1) { - DepthState ds = timelined.getTimeline().getFrame(frame).layers.get(selectedDepth); - if (ds != null) { - CharacterTag cht = timelined.getTimeline().swf.getCharacter(ds.characterId); - if (cht != null) { - debugLabel.setText(cht.getName()); - } - } - } - } - - public void hideMouseSelection() { - if (selectedDepth > -1) { - showSelectedName(); - } else { - debugLabel.setText(" - "); - } - } - - public ImagePanel() { - super(new BorderLayout()); - //iconPanel.setHorizontalAlignment(JLabel.CENTER); - setOpaque(true); - setBackground(View.getDefaultBackgroundColor()); - - loop = true; - iconPanel = new IconPanel(); - //labelPan.add(label, new GridBagConstraints()); - add(iconPanel, BorderLayout.CENTER); - add(debugLabel, BorderLayout.NORTH); - iconPanel.addMouseListener(new MouseAdapter() { - - @Override - public void mouseEntered(MouseEvent e) { - synchronized (ImagePanel.class) { - lastMouseEvent = e; - redraw(); - } - } - - @Override - public void mouseExited(MouseEvent e) { - synchronized (ImagePanel.class) { - stateUnderCursor = null; - lastMouseEvent = null; - hideMouseSelection(); - redraw(); - } - } - - @Override - public void mousePressed(MouseEvent e) { - synchronized (ImagePanel.class) { - mouseButton = e.getButton(); - lastMouseEvent = e; - redraw(); - if (stateUnderCursor != null) { - ButtonTag b = (ButtonTag) swf.getCharacter(stateUnderCursor.characterId); - DefineButtonSoundTag sounds = b.getSounds(); - if (sounds != null && sounds.buttonSoundChar2 != 0) { //OverUpToOverDown - playSound((SoundTag) swf.getCharacter(sounds.buttonSoundChar2), timer); - } - } - } - } - - @Override - public void mouseReleased(MouseEvent e) { - synchronized (ImagePanel.class) { - mouseButton = 0; - lastMouseEvent = e; - redraw(); - if (stateUnderCursor != null) { - ButtonTag b = (ButtonTag) swf.getCharacter(stateUnderCursor.characterId); - DefineButtonSoundTag sounds = b.getSounds(); - if (sounds != null && sounds.buttonSoundChar3 != 0) { //OverDownToOverUp - playSound((SoundTag) swf.getCharacter(sounds.buttonSoundChar3), timer); - } - } - } - } - - }); - iconPanel.addMouseMotionListener(new MouseMotionAdapter() { - @Override - public void mouseMoved(MouseEvent e) { - synchronized (ImagePanel.class) { - lastMouseEvent = e; - redraw(); - DepthState lastUnderCur = stateUnderCursor; - if (stateUnderCursor != null) { - if (lastUnderCur == null || lastUnderCur.instanceId != stateUnderCursor.instanceId) { - // New mouse entered - ButtonTag b = (ButtonTag) swf.getCharacter(stateUnderCursor.characterId); - DefineButtonSoundTag sounds = b.getSounds(); - if (sounds != null && sounds.buttonSoundChar1 != 0) { //IddleToOverUp - playSound((SoundTag) swf.getCharacter(sounds.buttonSoundChar1), timer); - } - } - } - if (lastUnderCur != null) { - if (stateUnderCursor == null || stateUnderCursor.instanceId != lastUnderCur.instanceId) { - // Old mouse leave - ButtonTag b = (ButtonTag) swf.getCharacter(lastUnderCur.characterId); - DefineButtonSoundTag sounds = b.getSounds(); - if (sounds != null && sounds.buttonSoundChar0 != 0) { //OverUpToIddle - playSound((SoundTag) swf.getCharacter(sounds.buttonSoundChar0), timer); - } - } - } - } - } - - @Override - public void mouseDragged(MouseEvent e) { - synchronized (ImagePanel.class) { - lastMouseEvent = e; - redraw(); - } - } - - }); - } - - private synchronized void redraw() { - if (timer == null && timelined != null) { - startTimer(timelined.getTimeline(), false); - } - } - - @Override - public synchronized void zoom(Zoom zoom) { - boolean modified = this.zoom.value != zoom.value || this.zoom.fit != zoom.fit; - if (modified) { - this.zoom = zoom; - redraw(); - if (textTag != null) { - setText(textTag, newTextTag); - } - - fireMediaDisplayStateChanged(); - } - } - - @Override - public synchronized BufferedImage printScreen() { - return iconPanel.getLastImage(); - } - - @Override - public synchronized double getZoomToFit() { - if (timelined instanceof BoundedTag) { - RECT bounds = ((BoundedTag) timelined).getRect(); - double w1 = bounds.getWidth() / SWF.unitDivisor; - double h1 = bounds.getHeight() / SWF.unitDivisor; - - double w2 = getWidth(); - double h2 = getHeight(); - - double w; - double h; - h = h1 * w2 / w1; - if (h > h2) { - w = w1 * h2 / h1; - } else { - w = w2; - } - - if (w1 <= Double.MIN_NORMAL) { - return 1.0; - } - - return (double) w / (double) w1; - } - - return 1; - } - - public void setImage(byte[] data) { - try { - setImage(new SerializableImage(ImageIO.read(new ByteArrayInputStream(data)))); - } catch (IOException ex) { - Logger.getLogger(ImagePanel.class.getName()).log(Level.SEVERE, null, ex); - } - } - - @Override - public synchronized boolean zoomAvailable() { - return zoomAvailable; - } - - public void setTimelined(final Timelined drawable, final SWF swf, int frame) { - synchronized (ImagePanel.class) { - stopInternal(); - if (drawable instanceof ButtonTag) { - frame = ButtonTag.FRAME_UP; - } - - this.timelined = drawable; - this.swf = swf; - zoomAvailable = true; - timer = null; - if (frame > -1) { - this.frame = frame; - this.stillFrame = true; - } else { - this.frame = 0; - this.stillFrame = false; - } - - loaded = true; - - if (drawable.getTimeline().getFrameCount() == 0) { - clearImagePanel(); - return; - } - - time = 0; - drawReady = false; - redraw(); - play(); - } - - synchronized (delayObject) { - try { - delayObject.wait(drawWaitLimit); - } catch (InterruptedException ex) { - Logger.getLogger(ImagePanel.class.getName()).log(Level.SEVERE, null, ex); - } - } - - synchronized (ImagePanel.class) { - if (!drawReady) { - clearImagePanel(); - } - } - - fireMediaDisplayStateChanged(); - } - - public synchronized void setImage(SerializableImage image) { - setBackground(View.getSwfBackgroundColor()); - clear(); - - timelined = null; - loaded = true; - stillFrame = true; - zoomAvailable = false; - iconPanel.setImg(image); - iconPanel.setOutlines(new ArrayList<>(), new ArrayList<>()); - drawReady = true; - - fireMediaDisplayStateChanged(); - } - - public synchronized void setText(TextTag textTag, TextTag newTextTag) { - setBackground(View.getSwfBackgroundColor()); - clear(); - - timelined = null; - loaded = true; - stillFrame = true; - zoomAvailable = true; - - this.textTag = textTag; - this.newTextTag = newTextTag; - - double zoomDouble = zoom.fit ? getZoomToFit() : zoom.value; - - RECT rect = textTag.getRect(); - int width = (int) (rect.getWidth() * zoomDouble); - int height = (int) (rect.getHeight() * zoomDouble); - SerializableImage image = new SerializableImage((int) (width / SWF.unitDivisor) + 1, - (int) (height / SWF.unitDivisor) + 1, SerializableImage.TYPE_INT_ARGB); - image.fillTransparent(); - Matrix m = new Matrix(); - m.translate(-rect.Xmin * zoomDouble, -rect.Ymin * zoomDouble); - m.scale(zoomDouble); - textTag.toImage(0, 0, 0, new RenderContext(), image, m, new ConstantColorColorTransform(0xFFC0C0C0)); - - if (newTextTag != null) { - newTextTag.toImage(0, 0, 0, new RenderContext(), image, m, new ConstantColorColorTransform(0xFF000000)); - } - - iconPanel.setImg(image); - iconPanel.setOutlines(new ArrayList<>(), new ArrayList<>()); - drawReady = true; - - fireMediaDisplayStateChanged(); - } - - private synchronized void clearImagePanel() { - iconPanel.setImg(null); - iconPanel.setOutlines(new ArrayList<>(), new ArrayList<>()); - } - - @Override - public synchronized int getCurrentFrame() { - return frame; - } - - @Override - public synchronized int getTotalFrames() { - if (timelined == null) { - return 0; - } - if (stillFrame) { - return 0; - } - return timelined.getTimeline().getFrameCount(); - } - - @Override - public void pause() { - stopInternal(); - redraw(); - } - - @Override - public void stop() { - stopInternal(); - rewind(); - redraw(); - } - - private void stopAllSounds() { - for (int i = soundPlayers.size() - 1; i >= 0; i--) { - SoundTagPlayer pl = soundPlayers.get(i); - pl.pause(); - } - soundPlayers.clear(); - } - - private void clear() { - if (timer != null) { - timer.cancel(); - timer = null; - fireMediaDisplayStateChanged(); - } - - textTag = null; - newTextTag = null; - } - - private void nextFrame(Timer thisTimer) { - drawFrame(thisTimer); - synchronized (ImagePanel.class) { - if (timelined != null && timer == thisTimer) { - int frameCount = timelined.getTimeline().getFrameCount(); - - if (!stillFrame && frame == frameCount - 1 && !loop) { - stopInternal(); - return; - } - - int newframe; - if (frameCount > 0) { - newframe = (frame + 1) % frameCount; - } else { - newframe = frame; - } - - if (stillFrame) { - newframe = frame; - } - if (newframe != frame) { - if (newframe == 0) { - stopAllSounds(); - } - frame = newframe; - time = 0; - } else { - time++; - } - } - } - - fireMediaDisplayStateChanged(); - } - - private static SerializableImage getFrame(SWF swf, int frame, int time, Timelined drawable, DepthState stateUnderCursor, int mouseButton, int selectedDepth, double zoom) { - Timeline timeline = drawable.getTimeline(); - String key = "drawable_" + frame + "_" + drawable.hashCode() + "_" + mouseButton + "_depth" + selectedDepth + "_" + (stateUnderCursor == null ? "out" : stateUnderCursor.hashCode()) + "_" + zoom + "_" + timeline.fontFrameNum; - SerializableImage img = swf.getFromCache(key); - if (img == null) { - boolean shouldCache = timeline.isSingleFrame(frame); - if (drawable instanceof BoundedTag) { - BoundedTag bounded = (BoundedTag) drawable; - RECT rect = bounded.getRect(); - - int width = (int) (rect.getWidth() * zoom); - int height = (int) (rect.getHeight() * zoom); - SerializableImage image = new SerializableImage((int) Math.ceil(width / SWF.unitDivisor), - (int) Math.ceil(height / SWF.unitDivisor), SerializableImage.TYPE_INT_ARGB); - image.fillTransparent(); - Matrix m = new Matrix(); - m.translate(-rect.Xmin * zoom, -rect.Ymin * zoom); - m.scale(zoom); - RenderContext renderContext = new RenderContext(); - renderContext.stateUnderCursor = stateUnderCursor; - renderContext.mouseButton = mouseButton; - timeline.toImage(frame, time, frame, renderContext, image, m, new ColorTransform()); - - Graphics2D gg = (Graphics2D) image.getGraphics(); - gg.setStroke(new BasicStroke(3)); - gg.setPaint(Color.green); - gg.setTransform(AffineTransform.getTranslateInstance(0, 0)); - List dss = new ArrayList<>(); - List os = new ArrayList<>(); - DepthState ds = null; - if (timeline.getFrameCount() > frame) { - ds = timeline.getFrame(frame).layers.get(selectedDepth); - } - - if (ds != null) { - CharacterTag cht = swf.getCharacter(ds.characterId); - if (cht != null) { - if (cht instanceof DrawableTag) { - DrawableTag dt = (DrawableTag) cht; - Shape outline = dt.getOutline(0, ds.time, ds.ratio, renderContext, new Matrix(ds.matrix)); - Rectangle bounds = outline.getBounds(); - bounds.x *= zoom; - bounds.y *= zoom; - bounds.width *= zoom; - bounds.height *= zoom; - bounds.x /= 20; - bounds.y /= 20; - bounds.width /= 20; - bounds.height /= 20; - bounds.x -= rect.Xmin / 20; - bounds.y -= rect.Ymin / 20; - gg.setStroke(new BasicStroke(2.0f, - BasicStroke.CAP_BUTT, - BasicStroke.JOIN_MITER, - 10.0f, new float[]{10.0f}, 0.0f)); - gg.setPaint(Color.red); - gg.draw(bounds); - } - } - } - - img = image; - } - - if (shouldCache) { - swf.putToCache(key, img); - } - } - return img; - } - - private void drawFrame(Timer thisTimer) { - Timelined timelined; - MouseEvent lastMouseEvent; - int frame; - int time; - DepthState stateUnderCursor; - int mouseButton; - int selectedDepth; - Zoom zoom; - SWF swf; - - synchronized (ImagePanel.class) { - timelined = this.timelined; - lastMouseEvent = this.lastMouseEvent; - } - - synchronized (ImagePanel.class) { - frame = this.frame; - time = this.time; - stateUnderCursor = this.stateUnderCursor; - mouseButton = this.mouseButton; - selectedDepth = this.selectedDepth; - zoom = this.zoom; - swf = this.swf; - } - - if (timelined == null) { - return; - } - - SerializableImage img; - try { - Timeline timeline = timelined.getTimeline(); - if (frame >= timeline.getFrameCount()) { - return; - } - - double zoomDouble = zoom.fit ? getZoomToFit() : zoom.value; - getOutlines(timelined, frame, time, zoomDouble, stateUnderCursor, mouseButton, thisTimer); - updatePos(timelined, lastMouseEvent, thisTimer); - - Matrix mat = new Matrix(); - mat.translateX = swf.displayRect.Xmin; - mat.translateY = swf.displayRect.Ymin; - - img = getFrame(swf, frame, time, timelined, stateUnderCursor, mouseButton, selectedDepth, zoomDouble); - - List sounds = new ArrayList<>(); - List soundClasses = new ArrayList<>(); - timeline.getSounds(frame, time, stateUnderCursor, mouseButton, sounds, soundClasses); - for (int cid : swf.getCharacters().keySet()) { - CharacterTag c = swf.getCharacter(cid); - for (String cls : soundClasses) { - if (cls.equals(c.getClassName())) { - sounds.add(cid); - } - } - } - - for (int sndId : sounds) { - CharacterTag c = swf.getCharacter(sndId); - if (c instanceof SoundTag) { - SoundTag st = (SoundTag) c; - playSound(st, thisTimer); - } - } - } catch (Throwable ex) { - // swf was closed during the rendering probably - return; - } - - synchronized (ImagePanel.class) { - if (timer == thisTimer) { - iconPanel.setImg(img); - drawReady = true; - synchronized (delayObject) { - delayObject.notify(); - } - } - } - } - - private void playSound(SoundTag st, Timer thisTimer) { - final SoundTagPlayer sp; - try { - sp = new SoundTagPlayer(st, 1, false); - sp.addEventListener(new MediaDisplayListener() { - - @Override - public void mediaDisplayStateChanged(MediaDisplay source) { - } - - @Override - public void playingFinished(MediaDisplay source) { - synchronized (ImagePanel.class) { - soundPlayers.remove(sp); - } - } - }); - - synchronized (ImagePanel.class) { - if (timer != null && timer == thisTimer) { - soundPlayers.add(sp); - sp.play(); - } - } - } catch (LineUnavailableException | IOException | UnsupportedAudioFileException ex) { - Logger.getLogger(ImagePanel.class.getName()).log(Level.SEVERE, "Error during playing sound", ex); - } - } - - private List getOutlines(Timelined timelined, int frame, int time, double zoom, DepthState stateUnderCursor, int mouseButton, Timer thisTimer) { - List objs = new ArrayList<>(); - List outlines = new ArrayList<>(); - Matrix m = new Matrix(); - Timeline timeline = timelined.getTimeline(); - RECT rect = timeline.displayRect; - m.translate(-rect.Xmin * zoom, -rect.Ymin * zoom); - m.scale(zoom); - - timeline.getObjectsOutlines(frame, time, frame, stateUnderCursor, mouseButton, m, objs, outlines); - for (int i = 0; i < outlines.size(); i++) { - outlines.set(i, SHAPERECORD.twipToPixelShape(outlines.get(i))); - } - - synchronized (ImagePanel.class) { - if (timer == thisTimer) { - iconPanel.setOutlines(objs, outlines); - } - } - - return outlines; - } - - public synchronized void clearAll() { - stopInternal(); - clearImagePanel(); - timelined = null; - swf = null; - - fireMediaDisplayStateChanged(); - } - - private synchronized void stopInternal() { - clear(); - stopAllSounds(); - } - - @Override - public synchronized void play() { - stopInternal(); - if (timelined != null) { - Timeline timeline = timelined.getTimeline(); - if (!stillFrame && frame == timeline.getFrameCount() - 1) { - frame = 0; - } - - startTimer(timeline, true); - } - } - - private void startTimer(Timeline timeline, boolean playing) { - - int frameRate = timeline.frameRate; - int msPerFrame = frameRate == 0 ? 1000 : 1000 / frameRate; - final boolean singleFrame = !playing || (timeline.getRealFrameCount() <= 1 && timeline.isSingleFrame()); - - timer = new Timer(); - TimerTask task = new TimerTask() { - public final Timer thisTimer = timer; - - public final boolean isSingleFrame = singleFrame; - - @Override - public void run() { - try { - synchronized (ImagePanel.class) { - if (timer != thisTimer) { - return; - } - } - - if (isSingleFrame) { - drawFrame(thisTimer); - synchronized (ImagePanel.class) { - thisTimer.cancel(); - if (timer == thisTimer) { - timer = null; - } - } - - fireMediaDisplayStateChanged(); - } else { - nextFrame(thisTimer); - } - } catch (Exception ex) { - Logger.getLogger(ImagePanel.class.getName()).log(Level.SEVERE, null, ex); - } - } - }; - - if (singleFrame) { - timer.schedule(task, 0); - } else { - timer.schedule(task, 0, msPerFrame); - } - } - - @Override - public synchronized void rewind() { - frame = 0; - fireMediaDisplayStateChanged(); - } - - @Override - public synchronized boolean isPlaying() { - if (timelined == null || stillFrame) { - return false; - } - - return (timelined.getTimeline().getFrameCount() <= 1) || (timer != null); - } - - @Override - public void setLoop(boolean loop) { - this.loop = loop; - } - - @Override - public synchronized void gotoFrame(int frame) { - if (timelined == null) { - return; - } - Timeline timeline = timelined.getTimeline(); - if (frame >= timeline.getFrameCount()) { - return; - } - if (frame < 0) { - return; - } - - this.frame = frame; - stopInternal(); - redraw(); - fireMediaDisplayStateChanged(); - } - - @Override - public synchronized int getFrameRate() { - if (timelined == null) { - return 1; - } - if (stillFrame) { - return 1; - } - return timelined.getTimeline().frameRate; - } - - @Override - public synchronized boolean isLoaded() { - return loaded; - } - - @Override - public boolean loopAvailable() { - return false; - } - - @Override - public boolean screenAvailable() { - return true; - } - - @Override - public synchronized Zoom getZoom() { - return zoom; - } -} +/* + * 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 . + */ +package com.jpexs.decompiler.flash.gui; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.gui.player.MediaDisplay; +import com.jpexs.decompiler.flash.gui.player.MediaDisplayListener; +import com.jpexs.decompiler.flash.gui.player.Zoom; +import com.jpexs.decompiler.flash.tags.DefineButtonSoundTag; +import com.jpexs.decompiler.flash.tags.base.BoundedTag; +import com.jpexs.decompiler.flash.tags.base.ButtonTag; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.tags.base.DrawableTag; +import com.jpexs.decompiler.flash.tags.base.RenderContext; +import com.jpexs.decompiler.flash.tags.base.SoundTag; +import com.jpexs.decompiler.flash.tags.base.TextTag; +import com.jpexs.decompiler.flash.timeline.DepthState; +import com.jpexs.decompiler.flash.timeline.Timeline; +import com.jpexs.decompiler.flash.timeline.Timelined; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.ConstantColorColorTransform; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; +import com.jpexs.helpers.SerializableImage; +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionAdapter; +import java.awt.event.MouseMotionListener; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.imageio.ImageIO; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.UnsupportedAudioFileException; +import javax.swing.JLabel; +import javax.swing.JPanel; + +public final class ImagePanel extends JPanel implements MediaDisplay { + + private final List listeners = new ArrayList<>(); + + private Timelined timelined; + + private boolean stillFrame = false; + + private Timer timer; + + private int frame = -1; + + private boolean loop; + + private boolean zoomAvailable = false; + + private SWF swf; + + private boolean loaded; + + private int mouseButton; + + private final JLabel debugLabel = new JLabel("-"); + + private DepthState stateUnderCursor = null; + + private MouseEvent lastMouseEvent = null; + + private final List soundPlayers = new ArrayList<>(); + + private final IconPanel iconPanel; + + private int time = 0; + + private int selectedDepth = -1; + + private Zoom zoom = new Zoom(); + + private final Object delayObject = new Object(); + + private boolean drawReady; + + private final int drawWaitLimit = 50; // ms + + private TextTag textTag; + + private TextTag newTextTag; + + public synchronized void selectDepth(int depth) { + if (depth != selectedDepth) { + this.selectedDepth = depth; + } + + hideMouseSelection(); + } + + public void fireMediaDisplayStateChanged() { + for (MediaDisplayListener l : listeners) { + l.mediaDisplayStateChanged(this); + } + } + + @Override + public void addEventListener(MediaDisplayListener listener) { + listeners.add(listener); + } + + @Override + public void removeEventListener(MediaDisplayListener listener) { + listeners.remove(listener); + } + + private class IconPanel extends JPanel { + + private SerializableImage img; + + private Rectangle rect = null; + + private List dss; + + private List outlines; + + public BufferedImage getLastImage() { + return img.getBufferedImage(); + } + + public synchronized void setOutlines(List dss, List outlines) { + this.outlines = outlines; + this.dss = dss; + } + + public void setImg(SerializableImage img) { + this.img = img; + calcRect(); + repaint(); + } + + public synchronized List getObjectsUnderPoint(Point p) { + List ret = new ArrayList<>(); + for (int i = 0; i < outlines.size(); i++) { + if (outlines.get(i).contains(p)) { + ret.add(dss.get(i)); + } + } + return ret; + } + + public Rectangle getRect() { + return rect; + } + + public Point toImagePoint(Point p) { + if (img == null) { + return null; + } + return new Point((p.x - rect.x) * img.getWidth() / rect.width, (p.y - rect.y) * img.getHeight() / rect.height); + } + + private void calcRect() { + if (img != null) { + int w1 = img.getWidth(); + int h1 = img.getHeight(); + + int w2 = getWidth(); + int h2 = getHeight(); + + int w; + int h; + if (w1 <= w2 && h1 <= h2) { + w = w1; + h = h1; + } else { + + h = h1 * w2 / w1; + if (h > h2) { + w = w1 * h2 / h1; + h = h2; + } else { + w = w2; + } + } + + rect = new Rectangle(getWidth() / 2 - w / 2, getHeight() / 2 - h / 2, w, h); + } else { + rect = null; + } + } + + @Override + protected void paintComponent(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setPaint(View.transparentPaint); + g2d.fill(new Rectangle(0, 0, getWidth(), getHeight())); + g2d.setComposite(AlphaComposite.SrcOver); + g2d.setPaint(View.getSwfBackgroundColor()); + g2d.fill(new Rectangle(0, 0, getWidth(), getHeight())); + if (img != null) { + calcRect(); + g2d.setComposite(AlphaComposite.SrcOver); + g2d.drawImage(img.getBufferedImage(), rect.x, rect.y, rect.x + rect.width, rect.y + rect.height, 0, 0, img.getWidth(), img.getHeight(), null); + } + + } + } + + @Override + public void setBackground(Color bg) { + if (iconPanel != null) { + iconPanel.setBackground(bg); + } + super.setBackground(bg); + } + + @Override + public synchronized void addMouseListener(MouseListener l) { + iconPanel.addMouseListener(l); + } + + @Override + public synchronized void removeMouseListener(MouseListener l) { + iconPanel.removeMouseListener(l); + } + + @Override + public synchronized void addMouseMotionListener(MouseMotionListener l) { + iconPanel.addMouseMotionListener(l); + } + + @Override + public synchronized void removeMouseMotionListener(MouseMotionListener l) { + iconPanel.removeMouseMotionListener(l); + } + + private void updatePos(Timelined timelined, MouseEvent lastMouseEvent, Timer thisTimer) { + boolean handCursor = false; + DepthState newStateUnderCursor = null; + if (timelined != null) { + + Timeline tim = ((Timelined) timelined).getTimeline(); + BoundedTag bounded = (BoundedTag) timelined; + RECT rect = bounded.getRect(); + int width = rect.getWidth(); + double scale = 1.0; + /*if (width > swf.displayRect.getWidth()) { + scale = (double) swf.displayRect.getWidth() / (double) width; + }*/ + Matrix m = new Matrix(); + m.translate(-rect.Xmin, -rect.Ymin); + m.scale(scale); + + Point p = lastMouseEvent == null ? null : lastMouseEvent.getPoint(); + List objs = new ArrayList<>(); + String ret = ""; + + synchronized (ImagePanel.class) { + if (timer == thisTimer) { + p = p == null ? null : iconPanel.toImagePoint(p); + if (p != null) { + int x = p.x; + int y = p.y; + objs = iconPanel.getObjectsUnderPoint(p); + + ret += " [" + x + "," + y + "] : "; + } + } + } + + boolean first = true; + for (int i = 0; i < objs.size(); i++) { + DepthState ds = objs.get(i); + if (!first) { + ret += ", "; + } + first = false; + CharacterTag c = tim.swf.getCharacter(ds.characterId); + if (c instanceof ButtonTag) { + newStateUnderCursor = ds; + handCursor = true; + } + ret += c.toString(); + if (timelined instanceof ButtonTag) { + handCursor = true; + } + } + if (first) { + ret += " - "; + } + + synchronized (ImagePanel.class) { + if (timer == thisTimer) { + debugLabel.setText(ret); + + if (handCursor) { + iconPanel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + } else { + iconPanel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + if (newStateUnderCursor != stateUnderCursor) { + stateUnderCursor = newStateUnderCursor; + } + } + } + } + } + + private void showSelectedName() { + if (selectedDepth > -1 && frame > -1) { + DepthState ds = timelined.getTimeline().getFrame(frame).layers.get(selectedDepth); + if (ds != null) { + CharacterTag cht = timelined.getTimeline().swf.getCharacter(ds.characterId); + if (cht != null) { + debugLabel.setText(cht.getName()); + } + } + } + } + + public void hideMouseSelection() { + if (selectedDepth > -1) { + showSelectedName(); + } else { + debugLabel.setText(" - "); + } + } + + public ImagePanel() { + super(new BorderLayout()); + //iconPanel.setHorizontalAlignment(JLabel.CENTER); + setOpaque(true); + setBackground(View.getDefaultBackgroundColor()); + + loop = true; + iconPanel = new IconPanel(); + //labelPan.add(label, new GridBagConstraints()); + add(iconPanel, BorderLayout.CENTER); + add(debugLabel, BorderLayout.NORTH); + iconPanel.addMouseListener(new MouseAdapter() { + + @Override + public void mouseEntered(MouseEvent e) { + synchronized (ImagePanel.class) { + lastMouseEvent = e; + redraw(); + } + } + + @Override + public void mouseExited(MouseEvent e) { + synchronized (ImagePanel.class) { + stateUnderCursor = null; + lastMouseEvent = null; + hideMouseSelection(); + redraw(); + } + } + + @Override + public void mousePressed(MouseEvent e) { + synchronized (ImagePanel.class) { + mouseButton = e.getButton(); + lastMouseEvent = e; + redraw(); + if (stateUnderCursor != null) { + ButtonTag b = (ButtonTag) swf.getCharacter(stateUnderCursor.characterId); + DefineButtonSoundTag sounds = b.getSounds(); + if (sounds != null && sounds.buttonSoundChar2 != 0) { //OverUpToOverDown + playSound((SoundTag) swf.getCharacter(sounds.buttonSoundChar2), timer); + } + } + } + } + + @Override + public void mouseReleased(MouseEvent e) { + synchronized (ImagePanel.class) { + mouseButton = 0; + lastMouseEvent = e; + redraw(); + if (stateUnderCursor != null) { + ButtonTag b = (ButtonTag) swf.getCharacter(stateUnderCursor.characterId); + DefineButtonSoundTag sounds = b.getSounds(); + if (sounds != null && sounds.buttonSoundChar3 != 0) { //OverDownToOverUp + playSound((SoundTag) swf.getCharacter(sounds.buttonSoundChar3), timer); + } + } + } + } + + }); + iconPanel.addMouseMotionListener(new MouseMotionAdapter() { + @Override + public void mouseMoved(MouseEvent e) { + synchronized (ImagePanel.class) { + lastMouseEvent = e; + redraw(); + DepthState lastUnderCur = stateUnderCursor; + if (stateUnderCursor != null) { + if (lastUnderCur == null || lastUnderCur.instanceId != stateUnderCursor.instanceId) { + // New mouse entered + ButtonTag b = (ButtonTag) swf.getCharacter(stateUnderCursor.characterId); + DefineButtonSoundTag sounds = b.getSounds(); + if (sounds != null && sounds.buttonSoundChar1 != 0) { //IddleToOverUp + playSound((SoundTag) swf.getCharacter(sounds.buttonSoundChar1), timer); + } + } + } + if (lastUnderCur != null) { + if (stateUnderCursor == null || stateUnderCursor.instanceId != lastUnderCur.instanceId) { + // Old mouse leave + ButtonTag b = (ButtonTag) swf.getCharacter(lastUnderCur.characterId); + DefineButtonSoundTag sounds = b.getSounds(); + if (sounds != null && sounds.buttonSoundChar0 != 0) { //OverUpToIddle + playSound((SoundTag) swf.getCharacter(sounds.buttonSoundChar0), timer); + } + } + } + } + } + + @Override + public void mouseDragged(MouseEvent e) { + synchronized (ImagePanel.class) { + lastMouseEvent = e; + redraw(); + } + } + + }); + } + + private synchronized void redraw() { + if (timer == null && timelined != null) { + startTimer(timelined.getTimeline(), false); + } + } + + @Override + public synchronized void zoom(Zoom zoom) { + boolean modified = this.zoom.value != zoom.value || this.zoom.fit != zoom.fit; + if (modified) { + this.zoom = zoom; + redraw(); + if (textTag != null) { + setText(textTag, newTextTag); + } + + fireMediaDisplayStateChanged(); + } + } + + @Override + public synchronized BufferedImage printScreen() { + return iconPanel.getLastImage(); + } + + @Override + public synchronized double getZoomToFit() { + if (timelined instanceof BoundedTag) { + RECT bounds = ((BoundedTag) timelined).getRect(); + double w1 = bounds.getWidth() / SWF.unitDivisor; + double h1 = bounds.getHeight() / SWF.unitDivisor; + + double w2 = getWidth(); + double h2 = getHeight(); + + double w; + double h; + h = h1 * w2 / w1; + if (h > h2) { + w = w1 * h2 / h1; + } else { + w = w2; + } + + if (w1 <= Double.MIN_NORMAL) { + return 1.0; + } + + return (double) w / (double) w1; + } + + return 1; + } + + public void setImage(byte[] data) { + try { + setImage(new SerializableImage(ImageIO.read(new ByteArrayInputStream(data)))); + } catch (IOException ex) { + Logger.getLogger(ImagePanel.class.getName()).log(Level.SEVERE, null, ex); + } + } + + @Override + public synchronized boolean zoomAvailable() { + return zoomAvailable; + } + + public void setTimelined(final Timelined drawable, final SWF swf, int frame) { + synchronized (ImagePanel.class) { + stopInternal(); + if (drawable instanceof ButtonTag) { + frame = ButtonTag.FRAME_UP; + } + + this.timelined = drawable; + this.swf = swf; + zoomAvailable = true; + timer = null; + if (frame > -1) { + this.frame = frame; + this.stillFrame = true; + } else { + this.frame = 0; + this.stillFrame = false; + } + + loaded = true; + + if (drawable.getTimeline().getFrameCount() == 0) { + clearImagePanel(); + return; + } + + time = 0; + drawReady = false; + redraw(); + play(); + } + + synchronized (delayObject) { + try { + delayObject.wait(drawWaitLimit); + } catch (InterruptedException ex) { + Logger.getLogger(ImagePanel.class.getName()).log(Level.SEVERE, null, ex); + } + } + + synchronized (ImagePanel.class) { + if (!drawReady) { + clearImagePanel(); + } + } + + fireMediaDisplayStateChanged(); + } + + public synchronized void setImage(SerializableImage image) { + setBackground(View.getSwfBackgroundColor()); + clear(); + + timelined = null; + loaded = true; + stillFrame = true; + zoomAvailable = false; + iconPanel.setImg(image); + iconPanel.setOutlines(new ArrayList<>(), new ArrayList<>()); + drawReady = true; + + fireMediaDisplayStateChanged(); + } + + public synchronized void setText(TextTag textTag, TextTag newTextTag) { + setBackground(View.getSwfBackgroundColor()); + clear(); + + timelined = null; + loaded = true; + stillFrame = true; + zoomAvailable = true; + + this.textTag = textTag; + this.newTextTag = newTextTag; + + double zoomDouble = zoom.fit ? getZoomToFit() : zoom.value; + + RECT rect = textTag.getRect(); + int width = (int) (rect.getWidth() * zoomDouble); + int height = (int) (rect.getHeight() * zoomDouble); + SerializableImage image = new SerializableImage((int) (width / SWF.unitDivisor) + 1, + (int) (height / SWF.unitDivisor) + 1, SerializableImage.TYPE_INT_ARGB); + image.fillTransparent(); + Matrix m = new Matrix(); + m.translate(-rect.Xmin * zoomDouble, -rect.Ymin * zoomDouble); + m.scale(zoomDouble); + textTag.toImage(0, 0, 0, new RenderContext(), image, m, new ConstantColorColorTransform(0xFFC0C0C0)); + + if (newTextTag != null) { + newTextTag.toImage(0, 0, 0, new RenderContext(), image, m, new ConstantColorColorTransform(0xFF000000)); + } + + iconPanel.setImg(image); + iconPanel.setOutlines(new ArrayList<>(), new ArrayList<>()); + drawReady = true; + + fireMediaDisplayStateChanged(); + } + + private synchronized void clearImagePanel() { + iconPanel.setImg(null); + iconPanel.setOutlines(new ArrayList<>(), new ArrayList<>()); + } + + @Override + public synchronized int getCurrentFrame() { + return frame; + } + + @Override + public synchronized int getTotalFrames() { + if (timelined == null) { + return 0; + } + if (stillFrame) { + return 0; + } + return timelined.getTimeline().getFrameCount(); + } + + @Override + public void pause() { + stopInternal(); + redraw(); + } + + @Override + public void stop() { + stopInternal(); + rewind(); + redraw(); + } + + @Override + public void close() throws IOException { + stopInternal(); + } + + private void stopAllSounds() { + for (int i = soundPlayers.size() - 1; i >= 0; i--) { + SoundTagPlayer pl = soundPlayers.get(i); + pl.close(); + } + soundPlayers.clear(); + } + + private void clear() { + if (timer != null) { + timer.cancel(); + timer = null; + fireMediaDisplayStateChanged(); + } + + textTag = null; + newTextTag = null; + } + + private void nextFrame(Timer thisTimer) { + drawFrame(thisTimer); + synchronized (ImagePanel.class) { + if (timelined != null && timer == thisTimer) { + int frameCount = timelined.getTimeline().getFrameCount(); + + if (!stillFrame && frame == frameCount - 1 && !loop) { + stopInternal(); + return; + } + + int newframe; + if (frameCount > 0) { + newframe = (frame + 1) % frameCount; + } else { + newframe = frame; + } + + if (stillFrame) { + newframe = frame; + } + if (newframe != frame) { + if (newframe == 0) { + stopAllSounds(); + } + frame = newframe; + time = 0; + } else { + time++; + } + } + } + + fireMediaDisplayStateChanged(); + } + + private static SerializableImage getFrame(SWF swf, int frame, int time, Timelined drawable, DepthState stateUnderCursor, int mouseButton, int selectedDepth, double zoom) { + Timeline timeline = drawable.getTimeline(); + String key = "drawable_" + frame + "_" + drawable.hashCode() + "_" + mouseButton + "_depth" + selectedDepth + "_" + (stateUnderCursor == null ? "out" : stateUnderCursor.hashCode()) + "_" + zoom + "_" + timeline.fontFrameNum; + SerializableImage img = swf.getFromCache(key); + if (img == null) { + boolean shouldCache = timeline.isSingleFrame(frame); + if (drawable instanceof BoundedTag) { + BoundedTag bounded = (BoundedTag) drawable; + RECT rect = bounded.getRect(); + + int width = (int) (rect.getWidth() * zoom); + int height = (int) (rect.getHeight() * zoom); + SerializableImage image = new SerializableImage((int) Math.ceil(width / SWF.unitDivisor), + (int) Math.ceil(height / SWF.unitDivisor), SerializableImage.TYPE_INT_ARGB); + image.fillTransparent(); + Matrix m = new Matrix(); + m.translate(-rect.Xmin * zoom, -rect.Ymin * zoom); + m.scale(zoom); + RenderContext renderContext = new RenderContext(); + renderContext.stateUnderCursor = stateUnderCursor; + renderContext.mouseButton = mouseButton; + timeline.toImage(frame, time, frame, renderContext, image, m, new ColorTransform()); + + Graphics2D gg = (Graphics2D) image.getGraphics(); + gg.setStroke(new BasicStroke(3)); + gg.setPaint(Color.green); + gg.setTransform(AffineTransform.getTranslateInstance(0, 0)); + List dss = new ArrayList<>(); + List os = new ArrayList<>(); + DepthState ds = null; + if (timeline.getFrameCount() > frame) { + ds = timeline.getFrame(frame).layers.get(selectedDepth); + } + + if (ds != null) { + CharacterTag cht = swf.getCharacter(ds.characterId); + if (cht != null) { + if (cht instanceof DrawableTag) { + DrawableTag dt = (DrawableTag) cht; + Shape outline = dt.getOutline(0, ds.time, ds.ratio, renderContext, new Matrix(ds.matrix)); + Rectangle bounds = outline.getBounds(); + bounds.x *= zoom; + bounds.y *= zoom; + bounds.width *= zoom; + bounds.height *= zoom; + bounds.x /= 20; + bounds.y /= 20; + bounds.width /= 20; + bounds.height /= 20; + bounds.x -= rect.Xmin / 20; + bounds.y -= rect.Ymin / 20; + gg.setStroke(new BasicStroke(2.0f, + BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER, + 10.0f, new float[]{10.0f}, 0.0f)); + gg.setPaint(Color.red); + gg.draw(bounds); + } + } + } + + img = image; + } + + if (shouldCache) { + swf.putToCache(key, img); + } + } + return img; + } + + private void drawFrame(Timer thisTimer) { + Timelined timelined; + MouseEvent lastMouseEvent; + int frame; + int time; + DepthState stateUnderCursor; + int mouseButton; + int selectedDepth; + Zoom zoom; + SWF swf; + + synchronized (ImagePanel.class) { + timelined = this.timelined; + lastMouseEvent = this.lastMouseEvent; + } + + synchronized (ImagePanel.class) { + frame = this.frame; + time = this.time; + stateUnderCursor = this.stateUnderCursor; + mouseButton = this.mouseButton; + selectedDepth = this.selectedDepth; + zoom = this.zoom; + swf = this.swf; + } + + if (timelined == null) { + return; + } + + SerializableImage img; + try { + Timeline timeline = timelined.getTimeline(); + if (frame >= timeline.getFrameCount()) { + return; + } + + double zoomDouble = zoom.fit ? getZoomToFit() : zoom.value; + getOutlines(timelined, frame, time, zoomDouble, stateUnderCursor, mouseButton, thisTimer); + updatePos(timelined, lastMouseEvent, thisTimer); + + Matrix mat = new Matrix(); + mat.translateX = swf.displayRect.Xmin; + mat.translateY = swf.displayRect.Ymin; + + img = getFrame(swf, frame, time, timelined, stateUnderCursor, mouseButton, selectedDepth, zoomDouble); + + List sounds = new ArrayList<>(); + List soundClasses = new ArrayList<>(); + timeline.getSounds(frame, time, stateUnderCursor, mouseButton, sounds, soundClasses); + for (int cid : swf.getCharacters().keySet()) { + CharacterTag c = swf.getCharacter(cid); + for (String cls : soundClasses) { + if (cls.equals(c.getClassName())) { + sounds.add(cid); + } + } + } + + for (int sndId : sounds) { + CharacterTag c = swf.getCharacter(sndId); + if (c instanceof SoundTag) { + SoundTag st = (SoundTag) c; + playSound(st, thisTimer); + } + } + } catch (Throwable ex) { + // swf was closed during the rendering probably + return; + } + + synchronized (ImagePanel.class) { + if (timer == thisTimer) { + iconPanel.setImg(img); + drawReady = true; + synchronized (delayObject) { + delayObject.notify(); + } + } + } + } + + private void playSound(SoundTag st, Timer thisTimer) { + final SoundTagPlayer sp; + try { + sp = new SoundTagPlayer(st, 1, false); + sp.addEventListener(new MediaDisplayListener() { + + @Override + public void mediaDisplayStateChanged(MediaDisplay source) { + } + + @Override + public void playingFinished(MediaDisplay source) { + synchronized (ImagePanel.class) { + sp.close(); + soundPlayers.remove(sp); + } + } + }); + + synchronized (ImagePanel.class) { + if (timer != null && timer == thisTimer) { + soundPlayers.add(sp); + sp.play(); + } else { + sp.close(); + } + } + } catch (LineUnavailableException | IOException | UnsupportedAudioFileException ex) { + Logger.getLogger(ImagePanel.class.getName()).log(Level.SEVERE, "Error during playing sound", ex); + } + } + + private List getOutlines(Timelined timelined, int frame, int time, double zoom, DepthState stateUnderCursor, int mouseButton, Timer thisTimer) { + List objs = new ArrayList<>(); + List outlines = new ArrayList<>(); + Matrix m = new Matrix(); + Timeline timeline = timelined.getTimeline(); + RECT rect = timeline.displayRect; + m.translate(-rect.Xmin * zoom, -rect.Ymin * zoom); + m.scale(zoom); + + timeline.getObjectsOutlines(frame, time, frame, stateUnderCursor, mouseButton, m, objs, outlines); + for (int i = 0; i < outlines.size(); i++) { + outlines.set(i, SHAPERECORD.twipToPixelShape(outlines.get(i))); + } + + synchronized (ImagePanel.class) { + if (timer == thisTimer) { + iconPanel.setOutlines(objs, outlines); + } + } + + return outlines; + } + + public synchronized void clearAll() { + stopInternal(); + clearImagePanel(); + timelined = null; + swf = null; + + fireMediaDisplayStateChanged(); + } + + private synchronized void stopInternal() { + clear(); + stopAllSounds(); + } + + @Override + public synchronized void play() { + stopInternal(); + if (timelined != null) { + Timeline timeline = timelined.getTimeline(); + if (!stillFrame && frame == timeline.getFrameCount() - 1) { + frame = 0; + } + + startTimer(timeline, true); + } + } + + private void startTimer(Timeline timeline, boolean playing) { + + int frameRate = timeline.frameRate; + int msPerFrame = frameRate == 0 ? 1000 : 1000 / frameRate; + final boolean singleFrame = !playing || (timeline.getRealFrameCount() <= 1 && timeline.isSingleFrame()); + + timer = new Timer(); + TimerTask task = new TimerTask() { + public final Timer thisTimer = timer; + + public final boolean isSingleFrame = singleFrame; + + @Override + public void run() { + try { + synchronized (ImagePanel.class) { + if (timer != thisTimer) { + return; + } + } + + if (isSingleFrame) { + drawFrame(thisTimer); + synchronized (ImagePanel.class) { + thisTimer.cancel(); + if (timer == thisTimer) { + timer = null; + } + } + + fireMediaDisplayStateChanged(); + } else { + nextFrame(thisTimer); + } + } catch (Exception ex) { + Logger.getLogger(ImagePanel.class.getName()).log(Level.SEVERE, null, ex); + } + } + }; + + if (singleFrame) { + timer.schedule(task, 0); + } else { + timer.schedule(task, 0, msPerFrame); + } + } + + @Override + public synchronized void rewind() { + frame = 0; + fireMediaDisplayStateChanged(); + } + + @Override + public synchronized boolean isPlaying() { + if (timelined == null || stillFrame) { + return false; + } + + return (timelined.getTimeline().getFrameCount() <= 1) || (timer != null); + } + + @Override + public void setLoop(boolean loop) { + this.loop = loop; + } + + @Override + public synchronized void gotoFrame(int frame) { + if (timelined == null) { + return; + } + Timeline timeline = timelined.getTimeline(); + if (frame >= timeline.getFrameCount()) { + return; + } + if (frame < 0) { + return; + } + + this.frame = frame; + stopInternal(); + redraw(); + fireMediaDisplayStateChanged(); + } + + @Override + public synchronized int getFrameRate() { + if (timelined == null) { + return 1; + } + if (stillFrame) { + return 1; + } + return timelined.getTimeline().frameRate; + } + + @Override + public synchronized boolean isLoaded() { + return loaded; + } + + @Override + public boolean loopAvailable() { + return false; + } + + @Override + public boolean screenAvailable() { + return true; + } + + @Override + public synchronized Zoom getZoom() { + return zoom; + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 444350c89..b873c218f 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -2243,6 +2243,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se dumpViewPanel.clear(); previewPanel.clear(); headerPanel.clear(); + folderPreviewPanel.clear(); if (abcPanel != null) { abcPanel.clearSwf(); } @@ -2644,7 +2645,6 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se if (flashPanel != null) { try { flashPanel.close(); - flashPanel.unload(); } catch (IOException ex) { // ignore } @@ -2826,7 +2826,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se preferScript = true; } - folderPreviewPanel.setItems(new ArrayList<>()); + folderPreviewPanel.clear(); previewPanel.clear(); stopFlashPlayer(); diff --git a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java index 1272ecac9..bf20b1b08 100644 --- a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java @@ -522,7 +522,11 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel public void clear() { imagePanel.clearAll(); if (media != null) { - media.pause(); + try { + media.close(); + } catch (IOException ex) { + // ignore + } } binaryPanel.setBinaryData(null); diff --git a/src/com/jpexs/decompiler/flash/gui/SoundTagPlayer.java b/src/com/jpexs/decompiler/flash/gui/SoundTagPlayer.java index 4bc83eedd..76ef02d6e 100644 --- a/src/com/jpexs/decompiler/flash/gui/SoundTagPlayer.java +++ b/src/com/jpexs/decompiler/flash/gui/SoundTagPlayer.java @@ -1,322 +1,335 @@ -/* - * 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 . - */ -package com.jpexs.decompiler.flash.gui; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.gui.player.MediaDisplay; -import com.jpexs.decompiler.flash.gui.player.MediaDisplayListener; -import com.jpexs.decompiler.flash.gui.player.Zoom; -import com.jpexs.decompiler.flash.tags.Tag; -import com.jpexs.decompiler.flash.tags.base.SoundTag; -import java.awt.Color; -import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.Clip; -import javax.sound.sampled.Line; -import javax.sound.sampled.LineEvent; -import javax.sound.sampled.LineListener; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.UnsupportedAudioFileException; - -/** - * - * @author JPEXS - */ -public class SoundTagPlayer implements MediaDisplay { - - private final Clip clip; - - private int loopCount; - - private boolean paused = false; - - private final Object playLock = new Object(); - - private final SoundTag tag; - - private final Timer timer; - - private final List listeners = new ArrayList<>(); - - private boolean rewindAfterStop = false; - - @Override - public void addEventListener(MediaDisplayListener listener) { - listeners.add(listener); - } - - @Override - public void removeEventListener(MediaDisplayListener listener) { - listeners.remove(listener); - } - - public void fireMediaDisplayStateChanged() { - for (MediaDisplayListener l : listeners) { - l.mediaDisplayStateChanged(this); - } - } - - private void firePlayingFinished() { - for (MediaDisplayListener l : listeners) { - l.playingFinished(this); - } - } - - private static final int FRAME_DIVISOR = 8000; - - public SoundTagPlayer(final SoundTag tag, int loops, boolean async) throws LineUnavailableException, IOException, UnsupportedAudioFileException { - this.tag = tag; - this.loopCount = loops; - clip = (Clip) AudioSystem.getLine(new Line.Info(Clip.class)); - clip.addLineListener(new LineListener() { - - @Override - public void update(LineEvent event) { - if (event.getType() == LineEvent.Type.STOP) { - synchronized (playLock) { - if (!paused) { - decreaseLoopCount(); - - if (loopCount > 0) { - clip.setFramePosition(0); - clip.start(); - } else { - firePlayingFinished(); - } - } - } - - if (rewindAfterStop) { - rewind(); - rewindAfterStop = false; - } - } - - fireMediaDisplayStateChanged(); - } - }); - - timer = new Timer(); - timer.schedule(new TimerTask() { - - @Override - public void run() { - - try { - fireMediaDisplayStateChanged(); - } catch (Exception ex) { - // ignore - cancel(); - } - } - }, 100, 100); - - if (!async) { - paused = true; - openSound(tag); - } else { - new Thread() { - - @Override - public void run() { - try { - openSound(tag); - } catch (IOException | LineUnavailableException | UnsupportedAudioFileException ex) { - Logger.getLogger(SoundTagPlayer.class.getName()).log(Level.SEVERE, null, ex); - } - synchronized (playLock) { - if (!paused) { - play(); - } - } - } - - }.start(); - } - } - - private void openSound(SoundTag tag) throws IOException, LineUnavailableException, UnsupportedAudioFileException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - List soundData = tag.getRawSoundData(); - SWF swf = ((Tag) tag).getSwf(); - List siss = new ArrayList<>(); - for (byte[] data : soundData) { - siss.add(new SWFInputStream(swf, data)); - } - - tag.getSoundFormat().createWav(siss, baos); - byte[] wavData = baos.toByteArray(); - - synchronized (playLock) { - clip.open(AudioSystem.getAudioInputStream(new ByteArrayInputStream(wavData))); - } - } - - @Override - public int getCurrentFrame() { - - synchronized (playLock) { - return (int) (clip.getMicrosecondPosition() / FRAME_DIVISOR); - } - } - - @Override - public int getTotalFrames() { - - synchronized (playLock) { - return (int) (clip.getMicrosecondLength() / FRAME_DIVISOR); - } - } - - @Override - public void pause() { - - synchronized (playLock) { - paused = true; - clip.stop(); - } - } - - @Override - public void stop() { - rewindAfterStop = true; - pause(); - rewind(); - } - - @Override - public void play() { - synchronized (playLock) { - paused = false; - if (!clip.isActive()) { - if (clip.getMicrosecondLength() == clip.getMicrosecondPosition()) { - decreaseLoopCount(); - clip.setFramePosition(0); - } - - clip.start(); - } - } - - fireMediaDisplayStateChanged(); - } - - @Override - public void rewind() { - gotoFrame(0); - } - - @Override - public boolean isPlaying() { - synchronized (playLock) { - return clip.isActive(); - } - } - - @Override - public boolean loopAvailable() { - return true; - } - - @Override - public boolean screenAvailable() { - return false; - } - - @Override - public void zoom(Zoom zoom) { - } - - @Override - public boolean zoomAvailable() { - return false; - } - - @Override - public double getZoomToFit() { - return 1; - } - - @Override - public Zoom getZoom() { - return null; - } - - @Override - public void setLoop(boolean loop) { - loopCount = loop ? Integer.MAX_VALUE : 1; - } - - @Override - public void gotoFrame(int frame) { - synchronized (playLock) { - clip.setMicrosecondPosition((long) frame * FRAME_DIVISOR); - } - - fireMediaDisplayStateChanged(); - } - - @Override - public void setBackground(Color color) { - - } - - @Override - public int getFrameRate() { - return (int) (1000000L / FRAME_DIVISOR); - } - - @Override - public boolean isLoaded() { - return true; - } - - @Override - public BufferedImage printScreen() { - return null; - } - - @Override - protected void finalize() throws Throwable { - try { - timer.cancel(); - - if (clip != null) { - clip.close(); - } - } finally { - super.finalize(); - } - } - - private void decreaseLoopCount() { - // this method should be called from synchronized (playLock) block - if (loopCount > 0 && loopCount != Integer.MAX_VALUE) { - loopCount--; - } - } -} +/* + * 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 . + */ +package com.jpexs.decompiler.flash.gui; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.gui.player.MediaDisplay; +import com.jpexs.decompiler.flash.gui.player.MediaDisplayListener; +import com.jpexs.decompiler.flash.gui.player.Zoom; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.SoundTag; +import com.jpexs.helpers.ByteArrayRange; +import java.awt.Color; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.Line; +import javax.sound.sampled.LineEvent; +import javax.sound.sampled.LineListener; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.UnsupportedAudioFileException; + +/** + * + * @author JPEXS + */ +public class SoundTagPlayer implements MediaDisplay { + + private final Clip clip; + + private int loopCount; + + private boolean paused = false; + + private final Object playLock = new Object(); + + private final SoundTag tag; + + private final Timer timer; + + private final List listeners = new ArrayList<>(); + + private boolean rewindAfterStop = false; + + @Override + public void addEventListener(MediaDisplayListener listener) { + listeners.add(listener); + } + + @Override + public void removeEventListener(MediaDisplayListener listener) { + listeners.remove(listener); + } + + public void fireMediaDisplayStateChanged() { + for (MediaDisplayListener l : listeners) { + l.mediaDisplayStateChanged(this); + } + } + + private void firePlayingFinished() { + for (MediaDisplayListener l : listeners) { + l.playingFinished(this); + } + } + + private static final int FRAME_DIVISOR = 8000; + + public SoundTagPlayer(final SoundTag tag, int loops, boolean async) throws LineUnavailableException, IOException, UnsupportedAudioFileException { + this.tag = tag; + this.loopCount = loops; + clip = (Clip) AudioSystem.getLine(new Line.Info(Clip.class)); + clip.addLineListener(new LineListener() { + + @Override + public void update(LineEvent event) { + if (event.getType() == LineEvent.Type.STOP) { + synchronized (playLock) { + if (!paused) { + decreaseLoopCount(); + + if (loopCount > 0) { + clip.setFramePosition(0); + clip.start(); + } else { + firePlayingFinished(); + } + } + } + + if (rewindAfterStop) { + rewind(); + rewindAfterStop = false; + } + } + + fireMediaDisplayStateChanged(); + } + }); + + timer = new Timer(); + timer.schedule(new TimerTask() { + + @Override + public void run() { + + try { + fireMediaDisplayStateChanged(); + } catch (Exception ex) { + // ignore + cancel(); + } + } + }, 100, 100); + + if (!async) { + paused = true; + openSound(tag); + } else { + new Thread() { + + @Override + public void run() { + try { + openSound(tag); + } catch (IOException | LineUnavailableException | UnsupportedAudioFileException ex) { + Logger.getLogger(SoundTagPlayer.class.getName()).log(Level.SEVERE, null, ex); + } + synchronized (playLock) { + if (!paused) { + play(); + } + } + } + + }.start(); + } + } + + private void openSound(SoundTag tag) throws IOException, LineUnavailableException, UnsupportedAudioFileException { + SWF swf = ((Tag) tag).getSwf(); + byte[] wavData = swf.getFromCache(tag); + if (wavData == null) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + List soundData = tag.getRawSoundData(); + List siss = new ArrayList<>(); + for (ByteArrayRange data : soundData) { + SWFInputStream sis = new SWFInputStream(swf, data.getArray(), 0, data.getPos() + data.getLength()); + sis.seek(data.getPos()); + siss.add(sis); + } + + tag.getSoundFormat().createWav(siss, baos); + wavData = baos.toByteArray(); + swf.putToCache(tag, wavData); + } + + synchronized (playLock) { + clip.open(AudioSystem.getAudioInputStream(new ByteArrayInputStream(wavData))); + } + } + + @Override + public int getCurrentFrame() { + + synchronized (playLock) { + return (int) (clip.getMicrosecondPosition() / FRAME_DIVISOR); + } + } + + @Override + public int getTotalFrames() { + + synchronized (playLock) { + return (int) (clip.getMicrosecondLength() / FRAME_DIVISOR); + } + } + + @Override + public void pause() { + + synchronized (playLock) { + paused = true; + clip.stop(); + } + } + + @Override + public void stop() { + rewindAfterStop = true; + pause(); + rewind(); + } + + @Override + public void close() { + stop(); + timer.cancel(); + } + + @Override + public void play() { + synchronized (playLock) { + paused = false; + if (!clip.isActive()) { + if (clip.getMicrosecondLength() == clip.getMicrosecondPosition()) { + decreaseLoopCount(); + clip.setFramePosition(0); + } + + clip.start(); + } + } + + fireMediaDisplayStateChanged(); + } + + @Override + public void rewind() { + gotoFrame(0); + } + + @Override + public boolean isPlaying() { + synchronized (playLock) { + return clip.isActive(); + } + } + + @Override + public boolean loopAvailable() { + return true; + } + + @Override + public boolean screenAvailable() { + return false; + } + + @Override + public void zoom(Zoom zoom) { + } + + @Override + public boolean zoomAvailable() { + return false; + } + + @Override + public double getZoomToFit() { + return 1; + } + + @Override + public Zoom getZoom() { + return null; + } + + @Override + public void setLoop(boolean loop) { + loopCount = loop ? Integer.MAX_VALUE : 1; + } + + @Override + public void gotoFrame(int frame) { + synchronized (playLock) { + clip.setMicrosecondPosition((long) frame * FRAME_DIVISOR); + } + + fireMediaDisplayStateChanged(); + } + + @Override + public void setBackground(Color color) { + + } + + @Override + public int getFrameRate() { + return (int) (1000000L / FRAME_DIVISOR); + } + + @Override + public boolean isLoaded() { + return true; + } + + @Override + public BufferedImage printScreen() { + return null; + } + + @Override + protected void finalize() throws Throwable { + try { + timer.cancel(); + + if (clip != null) { + clip.close(); + } + } finally { + super.finalize(); + } + } + + private void decreaseLoopCount() { + // this method should be called from synchronized (playLock) block + if (loopCount > 0 && loopCount != Integer.MAX_VALUE) { + loopCount--; + } + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties index 67fa71980..2b9b34cd5 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties @@ -1,352 +1,355 @@ -# 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 . - -advancedSettings.dialog.title = Advanced Settings -advancedSettings.restartConfirmation = You must restart the program for some modifications to take effect. Do you want to restart it now? -advancedSettings.columns.name = Name -advancedSettings.columns.value = Value -advancedSettings.columns.description = Description -default = default - -config.group.name.export = Export -config.group.description.export = Configuration of exports - -config.group.name.script = Scripts -config.group.description.script = ActionScript decompilation related - -config.group.name.update = Updates -config.group.description.update = Checking for updates - -config.group.name.format = Formatting -config.group.description.format = ActionScript code formatting - -config.group.name.limit = Limits -config.group.description.limit = Decompilation limits for obfuscated code, etc. - -config.group.name.ui = Interface -config.group.description.ui = User intercace configuration - -config.group.name.debug = Debug -config.group.description.debug = Debugging settings - -config.group.name.display = Display -config.group.description.display = Flash objects display, etc. - -config.group.name.decompilation = Decompilation -config.group.description.decompilation = Global decompilation related functions - -config.group.name.other = Other -config.group.description.other = Other uncategorized configs - -config.name.openMultipleFiles = Open multiple files -config.description.openMultipleFiles = Allows opening multiple files at once in one window - -config.name.decompile = Show ActionScript source -config.description.decompile = You can disable AS decompilation, then only P-code is shown - -config.name.dumpView = Dump View -config.description.dumpView = View raw data dump - -config.name.useHexColorFormat = Hex color format -config.description.useHexColorFormat = Show the colors in hex format - -config.name.parallelSpeedUp = Parallel SpeedUp -config.description.parallelSpeedUp = Parallelism can speed up decompilation - -config.name.parallelThreadCount = Number of threads -config.description.parallelThreadCount = Number of threads for parallel speedup - -config.name.autoDeobfuscate = Automatic deobfuscation -config.description.autoDeobfuscate = Run deobfuscation on every file before ActionScript decompilation - -config.name.cacheOnDisk = Use caching on disk -config.description.cacheOnDisk = Cache already decompiled parts on hard drive instead of memory - -config.name.internalFlashViewer = Use own Flash viewer -config.description.internalFlashViewer = Use JPEXS Flash Viewer instead of standard Flash Player for flash parts display - -config.name.gotoMainClassOnStartup = Go to main class on startup (AS3) -config.description.gotoMainClassOnStartup = Navigates to document class of AS3 file on SWF opening - -config.name.autoRenameIdentifiers = Automatic rename identifiers -config.description.autoRenameIdentifiers = Automatically rename invalid indentifiers on SWF load - -config.name.offeredAssociation = (Internal) Association with SWF files displayed -config.description.offeredAssociation = Dialog about file association was already displayed - -config.name.decimalAddress = Use decimal addresses -config.description.decimalAddress = Use decimal addresses instead of hexadecimal - -config.name.showAllAddresses = Show all addresses -config.description.showAllAddresses = Display all ActionScript instruction addresses - -config.name.useFrameCache = Use frame cache -config.description.useFrameCache = Cache frames before rendering again - -config.name.useRibbonInterface = Ribbon interface -config.description.useRibbonInterface = Uncheck to use classic interface without ribbon menu - -config.name.openFolderAfterFlaExport = Open folder after FLA export -config.description.openFolderAfterFlaExport = Display output directory after exporting FLA file - -config.name.useDetailedLogging = Detailed Logging -config.description.useDetailedLogging = Log detailed error messages and info for debugging purposes - -config.name.debugMode = Debug mode -config.description.debugMode = Mode for debugging. Turns on debug menu. - -config.name.resolveConstants = Resolve constants in AS1/2 p-code -config.description.resolveConstants = Turn this off to show 'constantxx' instead of real values in P-code window - -config.name.sublimiter = Limit of code subs -config.description.sublimiter = Limit of code subs for obfuscated code. - -config.name.exportTimeout = Total export timeout (seconds) -config.description.exportTimeout = Decompiler will stop exporting after reaching this time - -config.name.decompilationTimeoutFile = Single file decompilation timeout (seconds) -config.description.decompilationTimeoutFile = Decompiler will stop ActionScript decompilation after reaching this time in one file - -config.name.paramNamesEnable = Enable parameter names in AS3 -config.description.paramNamesEnable = Using parameter names in decompiling may cause problems because official programs like Flash CS 5.5 inserts wrong parameter names indices - -config.name.displayFileName = Show SWF name in title -config.description.displayFileName = Display SWF file/url name in the window title (You can make screenshots then) - -config.name.debugCopy = Debug recompile -config.description.debugCopy = Tries to compile SWF file again just after opening to ensure it produces same binary code. Use for DEBUGGING only! - -config.name.dumpTags = Dump tags to console -config.description.dumpTags = Dump tags to console on reading SWF file - -config.name.decompilationTimeoutSingleMethod = AS3: Single method decompilation timeout (seconds) -config.description.decompilationTimeoutSingleMethod = Decompiler will stop ActionScript decompilation after reaching this time in one method - -config.name.lastRenameType = (Internal) Last rename type -config.description.lastRenameType = Last used rename identifiers type - -config.name.lastSaveDir = (Internal) Last save directory -config.description.lastSaveDir = Last used save directory - -config.name.lastOpenDir = (Internal) Last open directory -config.description.lastOpenDir = Last used open directory - -config.name.lastExportDir = (Internal) Last export directory -config.description.lastExportDir = Last used export directory - -config.name.locale = Language -config.description.locale = Locales identifier - -config.name.registerNameFormat = Register variable format -config.description.registerNameFormat = Format of local register variable names. Use %d for register number. - -config.name.maxRecentFileCount = Max recent count -config.description.maxRecentFileCount = Maximum number of recent files - -config.name.recentFiles = (Internal) Recent files -config.description.recentFiles = Recent opened files - -config.name.fontPairing = (Internal) Font pairs for import -config.description.fontPairing = Font pairs for importing new characters - -config.name.lastUpdatesCheckDate = (Internal) Last update check date -config.description.lastUpdatesCheckDate = Date of last checking for updates on server - -config.name.gui.window.width = (Internal) Last window width -config.description.gui.window.width = Last saved window width - -config.name.gui.window.height = (Internal) Last window height -config.description.gui.window.height = Last saved window height - -config.name.gui.window.maximized.horizontal = (Internal) Window maximized horizontally -config.description.gui.window.maximized.horizontal = Last window state - maximized horizontally - -config.name.gui.window.maximized.vertical = (Internal) Window maximized vertically -config.description.gui.window.maximized.vertical = Last window state - maximized vertically - -config.name.gui.avm2.splitPane.dividerLocationPercent = (Internal) AS3 Splitter location -config.description.gui.avm2.splitPane.dividerLocationPercent = - -config.name.gui.actionSplitPane.dividerLocationPercent = (Internal) AS1/2 splitter location -config.description.gui.actionSplitPane.dividerLocationPercent = - -config.name.gui.previewSplitPane.dividerLocationPercent = (Internal) Preview splitter location -config.description.gui.previewSplitPane.dividerLocationPercent = - -config.name.gui.splitPane1.dividerLocationPercent = (Internal) Splitter location 1 -config.description.gui.splitPane1.dividerLocationPercent = - -config.name.gui.splitPane2.dividerLocationPercent = (Internal) Splitter location 2 -config.description.gui.splitPane2.dividerLocationPercent = - -config.name.saveAsExeScaleMode = Save as EXE scale mode -config.description.saveAsExeScaleMode = Scaling mode for EXE export - -config.name.syntaxHighlightLimit = Syntax hilight max chars -config.description.syntaxHighlightLimit = Maximum number of characters to run syntax hilight on - -config.name.guiFontPreviewSampleText = (Internal) Last font preview sample text -config.description.guiFontPreviewSampleText = Last font preview sample text list index - -config.name.gui.fontPreviewWindow.width = (Internal) Last font preview window width -config.description.gui.fontPreviewWindow.width = - -config.name.gui.fontPreviewWindow.height = (Internal) Last font preview window height -config.description.gui.fontPreviewWindow.height = - -config.name.gui.fontPreviewWindow.posX = (Internal) Last font preview window X -config.description.gui.fontPreviewWindow.posX = - -config.name.gui.fontPreviewWindow.posY = (Internal) Last font preview window Y -config.description.gui.fontPreviewWindow.posY = - -config.name.formatting.indent.size = Characters per indent -config.description.formatting.indent.size = Number or spaces(or tabs) for one indentation - -config.name.formatting.indent.useTabs = Tabs for indent -config.description.formatting.indent.useTabs = Use tabs instead of spaces for indentation - -config.name.beginBlockOnNewLine = Curly brace on new line -config.description.beginBlockOnNewLine = Begin block with curly brace on new line - -config.name.check.updates.delay = Updates check delay -config.description.check.updates.delay = Minimum time between automatic checks for updates on application start - -config.name.check.updates.stable = Check for stable versions -config.description.check.updates.stable = Checking for stable version updates - -config.name.check.updates.nightly = Check for nightly versions -config.description.check.updates.nightly = Checking for nightly version updates - -config.name.check.updates.enabled = Updates check enabled -config.description.check.updates.enabled = Automatic checking for updates on application start - -config.name.export.formats = (Internal) Export formats -config.description.export.formats = Last used export formats - -config.name.textExportSingleFile = Export texts to single file -config.description.textExportSingleFile = Exporting texts to one file instead of multiple - -config.name.textExportSingleFileSeparator = Separator of texts in one file text export -config.description.textExportSingleFileSeparator = Text to insert between texts in single file text export - -config.name.textExportSingleFileRecordSeparator = Separator of records in one file text export -config.description.textExportSingleFileRecordSeparator = Text to insert between text records in single file text export - -config.name.warning.experimental.as12edit = Warn on AS1/2 direct edit -config.description.warning.experimental.as12edit = Show warning on AS1/2 experimental direct editation - -config.name.warning.experimental.as3edit = Warn on AS3 direct edit -config.description.warning.experimental.as3edit = Show warning on AS3 experimental direct editation - -config.name.packJavaScripts = Pack JavaScripts -config.description.packJavaScripts = Run JavaScript packer on scripts created on Canvas Export. - -config.name.textExportExportFontFace = Use font-face in SVG export -config.description.textExportExportFontFace = Embed font files in SVG using font-face instead of shapes - -config.name.lzmaFastBytes = LZMA fast bytes (valid values: 5-255) -config.description.lzmaFastBytes = Fast bytes parameter of the LZMA encoder - -#temporary setting, do not translate it -config.name.pluginPath = Plugin Path -config.description.pluginPath = - - -config.name.deobfuscationMode = Deobfuscation mode -config.description.deobfuscationMode = Run deobfuscation on every file before ActionScript decompilation - -config.name.showMethodBodyId = Show method body id -config.description.showMethodBodyId = Shows the id of the methodbody for commandline import - -config.name.export.zoom = (Internal) Export zoom -config.description.export.zoom = Last used export zoom - -config.name.debuggerPort = Debugger port -config.description.debuggerPort = Port used for socket debugging - -config.name.displayDebuggerInfo = (Internal) Display debugger info -config.description.displayDebuggerInfo = Display info about debugger before switching it - -config.name.randomDebuggerPackage = Use random package name for Debugger -config.description.randomDebuggerPackage = This renames Debugger package to random string which makes debugger presence harder to detect by ActionScript - -config.name.lastDebuggerReplaceFunction = (Internal) Last selected trace replacement -config.description.lastDebuggerReplaceFunction = Function name which was last selected in replace trace function with debugger - -config.name.getLocalNamesFromDebugInfo = AS3: Get local register names from debug info -config.description.getLocalNamesFromDebugInfo = If debug info present, renames local registers from _loc_x_ to real names. This can be turned off because some obfuscators use invalid register names there. - -config.name.tagTreeShowEmptyFolders = Show empty folders -config.description.tagTreeShowEmptyFolders = Show empty folders in tag tree. - -config.name.autoLoadEmbeddedSwfs = Auto load embedded SWFs -config.description.autoLoadEmbeddedSwfs = Automaticaly load the embedded SWFs from DefineBinaryData tags. - -config.name.overrideTextExportFileName = Override text export filename -config.description.overrideTextExportFileName = You can customize the filename of the exported text. Use {filename} placeholder to use the filename of current SWF. - -config.name.showOldTextDuringTextEditing = Show old text during text editing -config.description.showOldTextDuringTextEditing = Shows the original text of the text tag with gray color in the preview area. - -config.group.name.import = Import -config.group.description.import = Configuration of imports - -config.name.textImportResizeTextBoundsMode = Text bounds resize mode -config.description.textImportResizeTextBoundsMode = Text bounds resize mode after text editing. - -config.name.showCloseConfirmation = Show again SWF close confirmation -config.description.showCloseConfirmation = Show again SWF close confirmation for modified files. - -config.name.showCodeSavedMessage = Show again code saved message -config.description.showCodeSavedMessage = Show again code saved message - -config.name.showTraitSavedMessage = Show again trait saved message -config.description.showTraitSavedMessage = Show again trait saved message - -config.name.updateProxyAddress = Http Proxy address for checking updates -config.description.updateProxyAddress = Http Proxy address for checking updates. Format: example.com:8080 - -config.name.editorMode = Editor Mode -config.description.editorMode = Make text areas edittable automatically when you select a Text or Script node - -config.name.autoSaveTagModifications = Auto save tag modificatios -config.description.autoSaveTagModifications = Save the changes when you select a new tag in the tree - -config.name.saveSessionOnExit = Save session on exit -config.description.saveSessionOnExit = Save the current session and reopens it after FFDec restart (works only with real files) - -config.name.showDebugMenu = Show debug menu -config.description.showDebugMenu = Shows debug menu in the ribbon - -config.name.allowOnlyOneInstance = Allow only one FFDec instance (Only Windows OS) -config.description.allowOnlyOneInstance = FFDec can be then run only once, all files opened will be added to one window. It works only with Windows operating system. - -config.name.scriptExportSingleFile = Export scripts to single file -config.description.scriptExportSingleFile = Exporting texts to one file instead of multiple - -config.name.setFFDecVersionInExportedFont = Set FFDec version number in exported font -config.description.setFFDecVersionInExportedFont = When this setting is disabled, FFDec won't add the current FFDec version number to the exported font. - -config.name.gui.skin = User Interface Skin -config.description.gui.skin = Look and feel skin - -config.name.lastSessionData = Last session data -config.description.lastSessionData = Contains the opened files from the last session - -config.name.loopMedia = Loop sounds and sprites -config.description.loopMedia = Automatically restarts the playing of the sounds and sprites - -config.name.gui.timeLineSplitPane.dividerLocationPercent = (Internal) Timeline Splitter location -config.description.gui.timeLineSplitPane.dividerLocationPercent = +# 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 . + +advancedSettings.dialog.title = Advanced Settings +advancedSettings.restartConfirmation = You must restart the program for some modifications to take effect. Do you want to restart it now? +advancedSettings.columns.name = Name +advancedSettings.columns.value = Value +advancedSettings.columns.description = Description +default = default + +config.group.name.export = Export +config.group.description.export = Configuration of exports + +config.group.name.script = Scripts +config.group.description.script = ActionScript decompilation related + +config.group.name.update = Updates +config.group.description.update = Checking for updates + +config.group.name.format = Formatting +config.group.description.format = ActionScript code formatting + +config.group.name.limit = Limits +config.group.description.limit = Decompilation limits for obfuscated code, etc. + +config.group.name.ui = Interface +config.group.description.ui = User intercace configuration + +config.group.name.debug = Debug +config.group.description.debug = Debugging settings + +config.group.name.display = Display +config.group.description.display = Flash objects display, etc. + +config.group.name.decompilation = Decompilation +config.group.description.decompilation = Global decompilation related functions + +config.group.name.other = Other +config.group.description.other = Other uncategorized configs + +config.name.openMultipleFiles = Open multiple files +config.description.openMultipleFiles = Allows opening multiple files at once in one window + +config.name.decompile = Show ActionScript source +config.description.decompile = You can disable AS decompilation, then only P-code is shown + +config.name.dumpView = Dump View +config.description.dumpView = View raw data dump + +config.name.useHexColorFormat = Hex color format +config.description.useHexColorFormat = Show the colors in hex format + +config.name.parallelSpeedUp = Parallel SpeedUp +config.description.parallelSpeedUp = Parallelism can speed up decompilation + +config.name.parallelThreadCount = Number of threads +config.description.parallelThreadCount = Number of threads for parallel speedup + +config.name.autoDeobfuscate = Automatic deobfuscation +config.description.autoDeobfuscate = Run deobfuscation on every file before ActionScript decompilation + +config.name.cacheOnDisk = Use caching on disk +config.description.cacheOnDisk = Cache already decompiled parts on hard drive instead of memory + +config.name.internalFlashViewer = Use own Flash viewer +config.description.internalFlashViewer = Use JPEXS Flash Viewer instead of standard Flash Player for flash parts display + +config.name.gotoMainClassOnStartup = Go to main class on startup (AS3) +config.description.gotoMainClassOnStartup = Navigates to document class of AS3 file on SWF opening + +config.name.autoRenameIdentifiers = Automatic rename identifiers +config.description.autoRenameIdentifiers = Automatically rename invalid indentifiers on SWF load + +config.name.offeredAssociation = (Internal) Association with SWF files displayed +config.description.offeredAssociation = Dialog about file association was already displayed + +config.name.decimalAddress = Use decimal addresses +config.description.decimalAddress = Use decimal addresses instead of hexadecimal + +config.name.showAllAddresses = Show all addresses +config.description.showAllAddresses = Display all ActionScript instruction addresses + +config.name.useFrameCache = Use frame cache +config.description.useFrameCache = Cache frames before rendering again + +config.name.useRibbonInterface = Ribbon interface +config.description.useRibbonInterface = Uncheck to use classic interface without ribbon menu + +config.name.openFolderAfterFlaExport = Open folder after FLA export +config.description.openFolderAfterFlaExport = Display output directory after exporting FLA file + +config.name.useDetailedLogging = Detailed Logging +config.description.useDetailedLogging = Log detailed error messages and info for debugging purposes + +config.name.debugMode = Debug mode +config.description.debugMode = Mode for debugging. Turns on debug menu. + +config.name.resolveConstants = Resolve constants in AS1/2 p-code +config.description.resolveConstants = Turn this off to show 'constantxx' instead of real values in P-code window + +config.name.sublimiter = Limit of code subs +config.description.sublimiter = Limit of code subs for obfuscated code. + +config.name.exportTimeout = Total export timeout (seconds) +config.description.exportTimeout = Decompiler will stop exporting after reaching this time + +config.name.decompilationTimeoutFile = Single file decompilation timeout (seconds) +config.description.decompilationTimeoutFile = Decompiler will stop ActionScript decompilation after reaching this time in one file + +config.name.paramNamesEnable = Enable parameter names in AS3 +config.description.paramNamesEnable = Using parameter names in decompiling may cause problems because official programs like Flash CS 5.5 inserts wrong parameter names indices + +config.name.displayFileName = Show SWF name in title +config.description.displayFileName = Display SWF file/url name in the window title (You can make screenshots then) + +config.name.debugCopy = Debug recompile +config.description.debugCopy = Tries to compile SWF file again just after opening to ensure it produces same binary code. Use for DEBUGGING only! + +config.name.dumpTags = Dump tags to console +config.description.dumpTags = Dump tags to console on reading SWF file + +config.name.decompilationTimeoutSingleMethod = AS3: Single method decompilation timeout (seconds) +config.description.decompilationTimeoutSingleMethod = Decompiler will stop ActionScript decompilation after reaching this time in one method + +config.name.lastRenameType = (Internal) Last rename type +config.description.lastRenameType = Last used rename identifiers type + +config.name.lastSaveDir = (Internal) Last save directory +config.description.lastSaveDir = Last used save directory + +config.name.lastOpenDir = (Internal) Last open directory +config.description.lastOpenDir = Last used open directory + +config.name.lastExportDir = (Internal) Last export directory +config.description.lastExportDir = Last used export directory + +config.name.locale = Language +config.description.locale = Locales identifier + +config.name.registerNameFormat = Register variable format +config.description.registerNameFormat = Format of local register variable names. Use %d for register number. + +config.name.maxRecentFileCount = Max recent count +config.description.maxRecentFileCount = Maximum number of recent files + +config.name.recentFiles = (Internal) Recent files +config.description.recentFiles = Recent opened files + +config.name.fontPairing = (Internal) Font pairs for import +config.description.fontPairing = Font pairs for importing new characters + +config.name.lastUpdatesCheckDate = (Internal) Last update check date +config.description.lastUpdatesCheckDate = Date of last checking for updates on server + +config.name.gui.window.width = (Internal) Last window width +config.description.gui.window.width = Last saved window width + +config.name.gui.window.height = (Internal) Last window height +config.description.gui.window.height = Last saved window height + +config.name.gui.window.maximized.horizontal = (Internal) Window maximized horizontally +config.description.gui.window.maximized.horizontal = Last window state - maximized horizontally + +config.name.gui.window.maximized.vertical = (Internal) Window maximized vertically +config.description.gui.window.maximized.vertical = Last window state - maximized vertically + +config.name.gui.avm2.splitPane.dividerLocationPercent = (Internal) AS3 Splitter location +config.description.gui.avm2.splitPane.dividerLocationPercent = + +config.name.gui.actionSplitPane.dividerLocationPercent = (Internal) AS1/2 splitter location +config.description.gui.actionSplitPane.dividerLocationPercent = + +config.name.gui.previewSplitPane.dividerLocationPercent = (Internal) Preview splitter location +config.description.gui.previewSplitPane.dividerLocationPercent = + +config.name.gui.splitPane1.dividerLocationPercent = (Internal) Splitter location 1 +config.description.gui.splitPane1.dividerLocationPercent = + +config.name.gui.splitPane2.dividerLocationPercent = (Internal) Splitter location 2 +config.description.gui.splitPane2.dividerLocationPercent = + +config.name.saveAsExeScaleMode = Save as EXE scale mode +config.description.saveAsExeScaleMode = Scaling mode for EXE export + +config.name.syntaxHighlightLimit = Syntax hilight max chars +config.description.syntaxHighlightLimit = Maximum number of characters to run syntax hilight on + +config.name.guiFontPreviewSampleText = (Internal) Last font preview sample text +config.description.guiFontPreviewSampleText = Last font preview sample text list index + +config.name.gui.fontPreviewWindow.width = (Internal) Last font preview window width +config.description.gui.fontPreviewWindow.width = + +config.name.gui.fontPreviewWindow.height = (Internal) Last font preview window height +config.description.gui.fontPreviewWindow.height = + +config.name.gui.fontPreviewWindow.posX = (Internal) Last font preview window X +config.description.gui.fontPreviewWindow.posX = + +config.name.gui.fontPreviewWindow.posY = (Internal) Last font preview window Y +config.description.gui.fontPreviewWindow.posY = + +config.name.formatting.indent.size = Characters per indent +config.description.formatting.indent.size = Number or spaces(or tabs) for one indentation + +config.name.formatting.indent.useTabs = Tabs for indent +config.description.formatting.indent.useTabs = Use tabs instead of spaces for indentation + +config.name.beginBlockOnNewLine = Curly brace on new line +config.description.beginBlockOnNewLine = Begin block with curly brace on new line + +config.name.check.updates.delay = Updates check delay +config.description.check.updates.delay = Minimum time between automatic checks for updates on application start + +config.name.check.updates.stable = Check for stable versions +config.description.check.updates.stable = Checking for stable version updates + +config.name.check.updates.nightly = Check for nightly versions +config.description.check.updates.nightly = Checking for nightly version updates + +config.name.check.updates.enabled = Updates check enabled +config.description.check.updates.enabled = Automatic checking for updates on application start + +config.name.export.formats = (Internal) Export formats +config.description.export.formats = Last used export formats + +config.name.textExportSingleFile = Export texts to single file +config.description.textExportSingleFile = Exporting texts to one file instead of multiple + +config.name.textExportSingleFileSeparator = Separator of texts in one file text export +config.description.textExportSingleFileSeparator = Text to insert between texts in single file text export + +config.name.textExportSingleFileRecordSeparator = Separator of records in one file text export +config.description.textExportSingleFileRecordSeparator = Text to insert between text records in single file text export + +config.name.warning.experimental.as12edit = Warn on AS1/2 direct edit +config.description.warning.experimental.as12edit = Show warning on AS1/2 experimental direct editation + +config.name.warning.experimental.as3edit = Warn on AS3 direct edit +config.description.warning.experimental.as3edit = Show warning on AS3 experimental direct editation + +config.name.packJavaScripts = Pack JavaScripts +config.description.packJavaScripts = Run JavaScript packer on scripts created on Canvas Export. + +config.name.textExportExportFontFace = Use font-face in SVG export +config.description.textExportExportFontFace = Embed font files in SVG using font-face instead of shapes + +config.name.lzmaFastBytes = LZMA fast bytes (valid values: 5-255) +config.description.lzmaFastBytes = Fast bytes parameter of the LZMA encoder + +#temporary setting, do not translate it +config.name.pluginPath = Plugin Path +config.description.pluginPath = - + +config.name.deobfuscationMode = Deobfuscation mode +config.description.deobfuscationMode = Run deobfuscation on every file before ActionScript decompilation + +config.name.showMethodBodyId = Show method body id +config.description.showMethodBodyId = Shows the id of the methodbody for commandline import + +config.name.export.zoom = (Internal) Export zoom +config.description.export.zoom = Last used export zoom + +config.name.debuggerPort = Debugger port +config.description.debuggerPort = Port used for socket debugging + +config.name.displayDebuggerInfo = (Internal) Display debugger info +config.description.displayDebuggerInfo = Display info about debugger before switching it + +config.name.randomDebuggerPackage = Use random package name for Debugger +config.description.randomDebuggerPackage = This renames Debugger package to random string which makes debugger presence harder to detect by ActionScript + +config.name.lastDebuggerReplaceFunction = (Internal) Last selected trace replacement +config.description.lastDebuggerReplaceFunction = Function name which was last selected in replace trace function with debugger + +config.name.getLocalNamesFromDebugInfo = AS3: Get local register names from debug info +config.description.getLocalNamesFromDebugInfo = If debug info present, renames local registers from _loc_x_ to real names. This can be turned off because some obfuscators use invalid register names there. + +config.name.tagTreeShowEmptyFolders = Show empty folders +config.description.tagTreeShowEmptyFolders = Show empty folders in tag tree. + +config.name.autoLoadEmbeddedSwfs = Auto load embedded SWFs +config.description.autoLoadEmbeddedSwfs = Automaticaly load the embedded SWFs from DefineBinaryData tags. + +config.name.overrideTextExportFileName = Override text export filename +config.description.overrideTextExportFileName = You can customize the filename of the exported text. Use {filename} placeholder to use the filename of current SWF. + +config.name.showOldTextDuringTextEditing = Show old text during text editing +config.description.showOldTextDuringTextEditing = Shows the original text of the text tag with gray color in the preview area. + +config.group.name.import = Import +config.group.description.import = Configuration of imports + +config.name.textImportResizeTextBoundsMode = Text bounds resize mode +config.description.textImportResizeTextBoundsMode = Text bounds resize mode after text editing. + +config.name.showCloseConfirmation = Show again SWF close confirmation +config.description.showCloseConfirmation = Show again SWF close confirmation for modified files. + +config.name.showCodeSavedMessage = Show again code saved message +config.description.showCodeSavedMessage = Show again code saved message + +config.name.showTraitSavedMessage = Show again trait saved message +config.description.showTraitSavedMessage = Show again trait saved message + +config.name.updateProxyAddress = Http Proxy address for checking updates +config.description.updateProxyAddress = Http Proxy address for checking updates. Format: example.com:8080 + +config.name.editorMode = Editor Mode +config.description.editorMode = Make text areas edittable automatically when you select a Text or Script node + +config.name.autoSaveTagModifications = Auto save tag modificatios +config.description.autoSaveTagModifications = Save the changes when you select a new tag in the tree + +config.name.saveSessionOnExit = Save session on exit +config.description.saveSessionOnExit = Save the current session and reopens it after FFDec restart (works only with real files) + +config.name.showDebugMenu = Show debug menu +config.description.showDebugMenu = Shows debug menu in the ribbon + +config.name.allowOnlyOneInstance = Allow only one FFDec instance (Only Windows OS) +config.description.allowOnlyOneInstance = FFDec can be then run only once, all files opened will be added to one window. It works only with Windows operating system. + +config.name.scriptExportSingleFile = Export scripts to single file +config.description.scriptExportSingleFile = Exporting texts to one file instead of multiple + +config.name.setFFDecVersionInExportedFont = Set FFDec version number in exported font +config.description.setFFDecVersionInExportedFont = When this setting is disabled, FFDec won't add the current FFDec version number to the exported font. + +config.name.gui.skin = User Interface Skin +config.description.gui.skin = Look and feel skin + +config.name.lastSessionData = Last session data +config.description.lastSessionData = Contains the opened files from the last session + +config.name.loopMedia = Loop sounds and sprites +config.description.loopMedia = Automatically restarts the playing of the sounds and sprites + +config.name.gui.timeLineSplitPane.dividerLocationPercent = (Internal) Timeline Splitter location +config.description.gui.timeLineSplitPane.dividerLocationPercent = + +config.name.cacheOnDisk = Cache images +config.description.cacheOnDisk = Cache the decoded image objects diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_hu.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_hu.properties index 0fa163fa1..35f8db2f2 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_hu.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_hu.properties @@ -1,352 +1,355 @@ -# 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 . - -advancedSettings.dialog.title = Halad\u00f3 be\u00e1ll\u00edt\u00e1sok -advancedSettings.restartConfirmation = N\u00e9h\u00e1ny m\u00f3dos\u00edt\u00e1s \u00e9rv\u00e9nybel\u00e9p\u00e9s\u00e9hez a programot \u00fajra kell ind\u00edtani. Szeretn\u00e9 \u00fajraind\u00edtani most? -advancedSettings.columns.name = N\u00e9v -advancedSettings.columns.value = \u00c9rt\u00e9k -advancedSettings.columns.description = Le\u00edr\u00e1s -default = alap\u00e9rt\u00e9k - -config.group.name.export = Export\u00e1l\u00e1s -config.group.description.export = Export\u00e1l\u00e1s be\u00e1ll\u00edt\u00e1sai - -config.group.name.script = Szkriptek -config.group.description.script = ActionScript visszaford\u00edt\u00e1ssal kapcsolatos - -config.group.name.update = Friss\u00edt\u00e9sek -config.group.description.update = Friss\u00edt\u00e9sek keres\u00e9se - -config.group.name.format = Form\u00e1z\u00e1s -config.group.description.format = ActionScript k\u00f3d form\u00e1z\u00e1s - -config.group.name.limit = Korl\u00e1tok -config.group.description.limit = Visszaford\u00edt\u00e1si korl\u00e1tok obfuszk\u00e1lt k\u00f3dokra, stb. - -config.group.name.ui = Fel\u00fclet -config.group.description.ui = Felhaszn\u00e1l\u00f3i fel\u00fclet be\u00e1ll\u00edt\u00e1sai - -config.group.name.debug = Hibakeres\u00e9s -config.group.description.debug = Hibakeres\u00e9si be\u00e1ll\u00edt\u00e1sok - -config.group.name.display = Megjelen\u00edt\u00e9s -config.group.description.display = Flash objektum megjelen\u00edt\u00e9s, stb. - -config.group.name.decompilation = Visszaford\u00edt\u00e1s -config.group.description.decompilation = Glob\u00e1lis visszaford\u00edt\u00e1ssal kapcsolatos funkci\u00f3k - -config.group.name.other = Egy\u00e9b -config.group.description.other = Egy\u00e9b kategoriz\u00e1latlan be\u00e1ll\u00edt\u00e1sok - -config.name.openMultipleFiles = T\u00f6bb f\u00e1jl megnyit\u00e1sa -config.description.openMultipleFiles = Enged\u00e9lyezi t\u00f6bb f\u00e1jl megnyit\u00e1s\u00e1t egy ablakban - -config.name.decompile = ActionScript forr\u00e1s mutat\u00e1sa -config.description.decompile = Kikapcsolhatja az AS visszaford\u00edt\u00e1s\u00e1t, ekkor a P-k\u00f3d jelenik meg - -config.name.dumpView = Dump N\u00e9zet -config.description.dumpView = Nyers adatok mutat\u00e1sa - -config.name.useHexColorFormat = Hexa sz\u00edn form\u00e1tum -config.description.useHexColorFormat = A sz\u00ednek hexa form\u00e1tum\u00fa mutat\u00e1sa - -config.name.parallelSpeedUp = P\u00e1rhuzamos gyors\u00edt\u00e1s -config.description.parallelSpeedUp = P\u00e1rhuzamos\u00edt\u00e1s fel tudja gyors\u00edtani a visszaford\u00edt\u00e1st - -config.name.parallelThreadCount = Sz\u00e1lak sz\u00e1ma -config.description.parallelThreadCount = Sz\u00e1lak sz\u00e1ma a p\u00e1rhuzamos gyors\u00edt\u00e1sn\u00e1l - -config.name.autoDeobfuscate = Automatikus deobfuszk\u00e1l\u00e1s -config.description.autoDeobfuscate = Futtassa a deobfuszk\u00e1l\u00e1st minden f\u00e1jlon az ActionScript visszaford\u00edt\u00e1sa el\u0151tt - -config.name.cacheOnDisk = Lemez gyors\u00edt\u00f3t\u00e1r haszn\u00e1lata -config.description.cacheOnDisk = Gyors\u00edt\u00f3t\u00e1razza a m\u00e1r visszaford\u00edtott r\u00e9szeket a merevlemezre a mem\u00f3ria helyett - -config.name.internalFlashViewer = Saj\u00e1t Flash n\u00e9z\u0151ke haszn\u00e1lata -config.description.internalFlashViewer = JPEXS Flash N\u00e9z\u0151ke haszn\u00e1lata a standard Flash Player helyett a flash r\u00e9szek megjelen\u00edt\u00e9s\u00e9re - -config.name.gotoMainClassOnStartup = F\u0151 oszt\u00e1lyhoz ugr\u00e1s ind\u00edt\u00e1skor (AS3) -config.description.gotoMainClassOnStartup = A dokumentum oszt\u00e1lyhoz navig\u00e1l\u00e1s AS3 f\u00e1jl eset\u00e9n az SWF megnyit\u00e1sakor - -config.name.autoRenameIdentifiers = Azonos\u00edt\u00f3k automatikus \u00e1tnevez\u00e9se -config.description.autoRenameIdentifiers = Automatikusan \u00e1tnevezi az \u00e9rv\u00e9nytelen azonos\u00edt\u00f3kat az SWF bet\u00f6lt\u00e9sekor - -config.name.offeredAssociation = (Bels\u0151) SWF f\u00e1jlok t\u00e1rs\u00edt\u00e1sa megjelen\u00edtve -config.description.offeredAssociation = Dial\u00f3gus ablak a f\u00e1jl t\u00e1rs\u00edt\u00e1s\u00e1r\u00f3l m\u00e1r meg lett jelen\u00edtve - -config.name.decimalAddress = Decim\u00e1lis c\u00edmek haszn\u00e1lata -config.description.decimalAddress = Decim\u00e1lis c\u00edmek haszn\u00e1lata a hexadecim\u00e1lisok helyett - -config.name.showAllAddresses = Minden c\u00edm mutat\u00e1sa -config.description.showAllAddresses = Minden ActionScript utas\u00edt\u00e1s c\u00edm mutat\u00e1sa - -config.name.useFrameCache = Keret gyors\u00edt\u00f3t\u00e1r haszn\u00e1lata -config.description.useFrameCache = Keretek gyors\u00edt\u00f3t\u00e1rba helyez\u00e9se az \u00fajb\u00f3li renderel\u00e9s megel\u0151z\u00e9s\u00e9hez - -config.name.useRibbonInterface = Szalag fel\u00fclet -config.description.useRibbonInterface = Kapcsolja ki a klasszikus fel\u00fclet haszn\u00e1lat\u00e1hoz szalagos men\u00fc n\u00e9lk\u00fcl - -config.name.openFolderAfterFlaExport = Mappa megnyit\u00e1sa FLA export\u00e1l\u00e1s ut\u00e1n -config.description.openFolderAfterFlaExport = A kimeneti k\u00f6nyvt\u00e1r megnyit\u00e1sa az FLA f\u00e1jl export\u00e1l\u00e1sa ut\u00e1n - -config.name.useDetailedLogging = R\u00e9szletes napl\u00f3z\u00e1s -config.description.useDetailedLogging = R\u00e9szletes hiba\u00fczenetek \u00e9s inform\u00e1ci\u00f3k napl\u00f3z\u00e1sa hibakeres\u00e9ssi c\u00e9lb\u00f3l - -config.name.debugMode = Hibakeres\u00e9si m\u00f3d -config.description.debugMode = M\u00f3d a hibakeres\u00e9shez. Bekapcsolja a hibakeres\u00e9si men\u00fct. - -config.name.resolveConstants = \u00c1lland\u00f3k felold\u00e1sa AS1/2 p-k\u00f3d eset\u00e9n -config.description.resolveConstants = Kapcsolja ezt ki a 'constantxx' \u00e9rt\u00e9kek mutat\u00e1s\u00e1hoz a val\u00f3s \u00e9rt\u00e9kek helyett a P-k\u00f3d ablakban - -config.name.sublimiter = K\u00f3d sub korl\u00e1t -config.description.sublimiter = K\u00f3d sub korl\u00e1t obfuszk\u00e1lt k\u00f3dn\u00e1l. - -config.name.exportTimeout = Teljes export\u00e1l\u00e1si id\u0151korl\u00e1t (m\u00e1sodperc) -config.description.exportTimeout = A visszaford\u00edt\u00f3 le\u00e1ll\u00edtja az export\u00e1l\u00e1st miut\u00e1n el\u00e9ri ezt az id\u0151t - -config.name.decompilationTimeoutFile = F\u00e1jl visszaford\u00edt\u00e1si id\u0151korl\u00e1t (m\u00e1sodperc) -config.description.decompilationTimeoutFile = A visszaford\u00edt\u00f3 le\u00e1ll\u00edtja az ActionScript visszaford\u00edt\u00e1s\u00e1t mitu\u00e1n el\u00e9ri ezt az id\u0151t - -config.name.paramNamesEnable = Param\u00e9ter nevek enged\u00e9lyez\u00e9se AS3 eset\u00e9n -config.description.paramNamesEnable = Param\u00e9ter nevek haszn\u00e1lata a visszaford\u00edt\u00e1sn\u00e1l probl\u00e9m\u00e1khoz vezethet mivel a hivatalos programok mint pl. Flash CS 5.5 rossz param\u00e9ter n\u00e9v indexeket sz\u00far be - -config.name.displayFileName = SWF n\u00e9v mutat\u00e1sa a c\u00edmsorban -config.description.displayFileName = SWF f\u00e1jl/url n\u00e9v mutat\u00e1sa az ablak c\u00edmsor\u00e1ban (Ut\u00e1na k\u00e9sz\u00edthet k\u00e9perny\u0151k\u00e9peket) - -config.name.debugCopy = \u00dajraford\u00edt\u00e1s hibakeres\u00e9s -config.description.debugCopy = Megpr\u00f3b\u00e1lja \u00fajraford\u00edtani az SWF f\u00e1jlt megnyit\u00e1s ut\u00e1n hogy megbizonyosodjon arr\u00f3l, hogy ugyanazt a bin\u00e1ris k\u00f3dot \u00e1ll\u00edtja el\u0151. Csak HIBAKERES\u00c9SHEZ haszn\u00e1lja! - -config.name.dumpTags = Tagek ki\u00edr\u00e1sa a parancssorra -config.description.dumpTags = Tagek ki\u00edr\u00e1sa a parancssorra az SWF f\u00e1jl olvas\u00e1sakor - -config.name.decompilationTimeoutSingleMethod = AS3: Egyedi met\u00f3dus visszaford\u00edt\u00e1si id\u0151korl\u00e1t (m\u00e1sodperc) -config.description.decompilationTimeoutSingleMethod = A visszaford\u00edt\u00f3 le\u00e1ll\u00edtja az ActionScript visszaford\u00edt\u00e1s\u00e1t miut\u00e1n el\u00e9ri ezt az id\u0151t egy met\u00f3dusn\u00e1l - -config.name.lastRenameType = (Bels\u0151) Utols\u00f3 \u00e1tevez\u00e9si t\u00edpus -config.description.lastRenameType = Utolj\u00e1ra haszn\u00e1lt t\u00edpus az azonos\u00edt\u00f3k \u00e1tnevez\u00e9s\u00e9re - -config.name.lastSaveDir = (Bels\u0151) Utols\u00f3 ment\u00e9si k\u00f6nyvt\u00e1r -config.description.lastSaveDir = Utolj\u00e1ra haszn\u00e1lt ment\u00e9si k\u00f6nyvt\u00e1r - -config.name.lastOpenDir = (Bels\u0151) Utols\u00f3 megnyit\u00e1si k\u00f6nyvt\u00e1r -config.description.lastOpenDir = Utolj\u00e1ra haszn\u00e1lt megnyit\u00e1si k\u00f6nyvt\u00e1r - -config.name.lastExportDir = (Bels\u0151) Utols\u00f3 export\u00e1l\u00e1si k\u00f6nyvt\u00e1r -config.description.lastExportDir = Utolj\u00e1ra haszn\u00e1lt export\u00e1l\u00e1si k\u00f6nyvt\u00e1r - -config.name.locale = Nyelv -config.description.locale = Helysz\u00edn azonos\u00edt\u00f3 - -config.name.registerNameFormat = Regiszter v\u00e1ltoz\u00f3 form\u00e1tum -config.description.registerNameFormat = Helyi regiszter v\u00e1ltoz\u00f3n\u00e9v form\u00e1tum. Haszn\u00e1lja a %d-t a regiszter sz\u00e1m\u00e1hoz. - -config.name.maxRecentFileCount = Utolj\u00e1ra haszn\u00e1lt f\u00e1jlok maxim\u00e1lis sz\u00e1ma -config.description.maxRecentFileCount = Utolj\u00e1ra haszn\u00e1lt f\u00e1jlok maxim\u00e1lis sz\u00e1ma - -config.name.recentFiles = (Bels\u0151) Utolj\u00e1ra haszn\u00e1lt f\u00e1jlok -config.description.recentFiles = Utolj\u00e1ra megnyitott f\u00e1jlok - -config.name.fontPairing = (Bels\u0151) Bet\u0171t\u00edpus p\u00e1rok import\u00e1l\u00e1shoz -config.description.fontPairing = Bet\u0171t\u00edpus p\u00e1rok \u00faj karakterek import\u00e1l\u00e1s\u00e1hoz - -config.name.lastUpdatesCheckDate = (Bels\u0151) Utols\u00f3 friss\u00edt\u00e9s keres\u00e9s\u00e9nek d\u00e1tuma -config.description.lastUpdatesCheckDate = Utols\u00f3 friss\u00edt\u00e9s keres\u00e9s\u00e9nek d\u00e1tuma a kiszolg\u00e1l\u00f3r\u00f3l - -config.name.gui.window.width = (Bels\u0151) Legut\u00f3bbi ablak sz\u00e9less\u00e9g -config.description.gui.window.width = Legut\u00f3bb mentett ablak sz\u00e9less\u00e9ge - -config.name.gui.window.height = (Bels\u0151) Legut\u00f3bbi ablak magass\u00e1ga -config.description.gui.window.height = Legut\u00f3bb mentett ablak magass\u00e1ga - -config.name.gui.window.maximized.horizontal = (Bels\u0151) Az ablak v\u00edzszintesen maxim\u00e1lis m\u00e9ret\u0171 -config.description.gui.window.maximized.horizontal = Ablak utols\u00f3 \u00e1llapota - v\u00edzszintesen maxim\u00e1lis - -config.name.gui.window.maximized.vertical = (Bels\u0151) Az ablak f\u00fcgg\u0151legesen maxim\u00e1lis m\u00e9ret\u0171 -config.description.gui.window.maximized.vertical = Ablak utols\u00f3 \u00e1llapota - f\u00fcgg\u0151legesen maxim\u00e1lis - -config.name.gui.avm2.splitPane.dividerLocationPercent = (Bels\u0151) AS3 oszt\u00f3 helyzete -config.description.gui.avm2.splitPane.dividerLocationPercent = - -config.name.gui.actionSplitPane.dividerLocationPercent = (Bels\u0151) AS1/2 oszt\u00f3 helyzete -config.description.gui.actionSplitPane.dividerLocationPercent = - -config.name.gui.previewSplitPane.dividerLocationPercent = (Bels\u0151) El\u0151n\u00e9zet oszt\u00f3 helyzete -config.description.gui.previewSplitPane.dividerLocationPercent = - -config.name.gui.splitPane1.dividerLocationPercent = (Bels\u0151) Oszt\u00f3 helyzete 1 -config.description.gui.splitPane1.dividerLocationPercent = - -config.name.gui.splitPane2.dividerLocationPercent = (Bels\u0151) Oszt\u00f3 helyzete 2 -config.description.gui.splitPane2.dividerLocationPercent = - -config.name.saveAsExeScaleMode = Ment\u00e9s EXE-k\u00e9nt nagy\u00edt\u00e1s m\u00f3dja -config.description.saveAsExeScaleMode = Nagy\u00edt\u00e1s m\u00f3dja EXE export eset\u00e9n - -config.name.syntaxHighlightLimit = Szintaxis kiemel\u00e9s maxim\u00e1lis karakter sz\u00e1m -config.description.syntaxHighlightLimit = Maxim\u00e1lis karakter sz\u00e1m a szintaxis kiemel\u00e9s futtat\u00e1s\u00e1hoz - -config.name.guiFontPreviewSampleText = (Bels\u0151) Utols\u00f3 bet\u0171t\u00edpus el\u0151n\u00e9zet p\u00e9lda sz\u00f6veg -config.description.guiFontPreviewSampleText = Utols\u00f3 bet\u0171t\u00edpus p\u00e9lda sz\u00f6veg indexe a list\u00e1ban - -config.name.gui.fontPreviewWindow.width = (Bels\u0151) Bet\u0171t\u00edpus el\u0151n\u00e9zet ablak utols\u00f3 sz\u00e9less\u00e9ge -config.description.gui.fontPreviewWindow.width = - -config.name.gui.fontPreviewWindow.height = (Bels\u0151) Bet\u0171t\u00edpus el\u0151n\u00e9zet ablak utols\u00f3 magass\u00e1ga -config.description.gui.fontPreviewWindow.height = - -config.name.gui.fontPreviewWindow.posX = (Bels\u0151) Bet\u0171t\u00edpus el\u0151n\u00e9zet ablak utols\u00f3 X poz\u00edci\u00f3ja -config.description.gui.fontPreviewWindow.posX = - -config.name.gui.fontPreviewWindow.posY = (Bels\u0151) Bet\u0171t\u00edpus el\u0151n\u00e9zet ablak utols\u00f3 Y poz\u00edci\u00f3ja -config.description.gui.fontPreviewWindow.posY = - -config.name.formatting.indent.size = Karakterek sz\u00e1ma beh\u00faz\u00e1sonk\u00e9nt -config.description.formatting.indent.size = Sz\u00f3k\u00f6z\u00f6k (vagy tab-ok) sz\u00e1ma egy beh\u00faz\u00e1sn\u00e1l - -config.name.formatting.indent.useTabs = Tab-ok beh\u00faz\u00e1shoz -config.description.formatting.indent.useTabs = Tab-ok haszn\u00e1lata sz\u00f3k\u00f6z\u00f6k helyett beh\u00faz\u00e1sokn\u00e1l - -config.name.beginBlockOnNewLine = Kapcsos z\u00e1r\u00f3jel \u00faj sorban -config.description.beginBlockOnNewLine = Blokk kezdeti kapcsos z\u00e1r\u00f3jel \u00faj sorban - -config.name.check.updates.delay = Friss\u00edt\u00e9s keres\u00e9si v\u00e1rakoz\u00e1s -config.description.check.updates.delay = Minim\u00e1lis id\u0151 az automatikus friss\u00edt\u00e9sek keres\u00e9s\u00e9hez az alkalmaz\u00e1s ind\u00edt\u00e1sakor - -config.name.check.updates.stable = Stabil verzi\u00f3k ellen\u0151rz\u00e9se -config.description.check.updates.stable = Stabil verzi\u00f3 friss\u00edt\u00e9sek keres\u00e9se - -config.name.check.updates.nightly = \u00c9jszakai verzi\u00f3k ellen\u0151rz\u00e9se -config.description.check.updates.nightly = \u00c9jszakai verzi\u00f3 friss\u00edt\u00e9sek keres\u00e9se - -config.name.check.updates.enabled = Friss\u00edt\u00e9sek keres\u00e9se enged\u00e9lyezve -config.description.check.updates.enabled = Friss\u00edt\u00e9sek automatikus keres\u00e9se az alkalmaz\u00e1s ind\u00edt\u00e1sakor - -config.name.export.formats = (Bels\u0151) Export\u00e1l\u00e1si form\u00e1tumok -config.description.export.formats = Utolj\u00e1ra haszn\u00e1lt export\u00e1l\u00e1si form\u00e1tumok - -config.name.textExportSingleFile = Sz\u00f6vegek export\u00e1l\u00e1sa egy f\u00e1jlba -config.description.textExportSingleFile = Sz\u00f6vegek export\u00e1l\u00e1sa egyetlen f\u00e1jlba t\u00f6bb f\u00e1jl helyett - -config.name.textExportSingleFileSeparator = Sz\u00f6vegek elv\u00e1laszt\u00e1sa egy f\u00e1jlba t\u00f6rt\u00e9n\u0151 export\u00e1l\u00e1s eset\u00e9n -config.description.textExportSingleFileSeparator = Sz\u00f6veg, melyet besz\u00far a sz\u00f6vegek k\u00f6z\u00e9 egyetlen f\u00e1jlba t\u00f6rt\u00e9n\u0151 sz\u00f6veg export\u00e1l\u00e1skor - -config.name.textExportSingleFileRecordSeparator = Rekordok elv\u00e1laszt\u00e1sa egy f\u00e1jlba t\u00f6rt\u00e9n\u0151 export\u00e1l\u00e1s eset\u00e9n -config.description.textExportSingleFileRecordSeparator = Sz\u00f6veg, melyet besz\u00far a rekordok k\u00f6z\u00e9 egyetlen f\u00e1jlba t\u00f6rt\u00e9n\u0151 sz\u00f6veg export\u00e1l\u00e1skor - -config.name.warning.experimental.as12edit = Figyelmeztet\u00e9s AS1/2 direkt szerkeszt\u00e9se eset\u00e9n -config.description.warning.experimental.as12edit = Figyelmeztet\u00e9s megjelen\u00edt\u00e9se AS1/2 k\u00eds\u00e9rleti szerkeszt\u00e9se eset\u00e9n - -config.name.warning.experimental.as3edit = Figyelmeztet\u00e9s AS3 direkt szerkeszt\u00e9se eset\u00e9n -config.description.warning.experimental.as3edit = Figyelmeztet\u00e9s megjelen\u00edt\u00e9se AS3 k\u00eds\u00e9rleti szerkeszt\u00e9se eset\u00e9n - -config.name.packJavaScripts = JavaScripts csomagol\u00e1s -config.description.packJavaScripts = JavaScript csomagol\u00f3 futtat\u00e1sa V\u00e1szon Export\u00e1l\u00e1skor l\u00e9trehozott szkriptekre. - -config.name.textExportExportFontFace = Font-face haszn\u00e1lata SVG export\u00e1l\u00e1skor -config.description.textExportExportFontFace = Bet\u0171t\u00edpus f\u00e1jlok be\u00e1gyaz\u00e1sa az SVG f\u00e1jlokba \u00e9s font-face haszn\u00e1lata alakzatok helyett - -config.name.lzmaFastBytes = LZMA fast bytes (\u00e9rv\u00e9nyes \u00e9rt\u00e9kek: 5-255) -config.description.lzmaFastBytes = Az LZMA t\u00f6m\u00f6r\u00edt\u0151 "Fast bytes" param\u00e9tere - -#temporary setting, do not translate it -config.name.pluginPath = Plugin Path -config.description.pluginPath = - - -config.name.deobfuscationMode = Deobfuszk\u00e1l\u00e1si m\u00f3d -config.description.deobfuscationMode = Futtassa a deobfuszk\u00e1l\u00e1st minden f\u00e1jlon az ActionScript visszaford\u00edt\u00e1sa el\u0151tt - -config.name.showMethodBodyId = Method body azonos\u00edt\u00f3 mutat\u00e1sa -config.description.showMethodBodyId = Megmutatja a methodbody azonos\u00edt\u00f3t a parancssori import\u00e1l\u00e1shoz - -config.name.export.zoom = (Bels\u0151) Export zoom -config.description.export.zoom = Utolj\u00e1ra haszn\u00e1lt export zoom - -config.name.debuggerPort = Debugger port -config.description.debuggerPort = Socket hibakeres\u00e9shez haszn\u00e1lt port - -config.name.displayDebuggerInfo = (Bels\u0151) Hibakeres\u00e9si inform\u00e1ci\u00f3 mutat\u00e1sa -config.description.displayDebuggerInfo = Hibakeres\u00e9si inform\u00e1ci\u00f3 mutat\u00e1sa bekapcsol\u00e1s el\u0151tt - -config.name.randomDebuggerPackage = V\u00e9letlen csomag n\u00e9v haszn\u00e1lata hibakeres\u00e9sn\u00e9l -config.description.randomDebuggerPackage = \u00c1Tnevezi a hibakeres\u00e9si csomag nev\u00e9t v\u00e9letlen n\u00e9vre hogy nehezebben lehessen detekt\u00e1lni ActionScript-b\u0151l - -config.name.lastDebuggerReplaceFunction = (Bels\u0151) Utolj\u00e1ra kiv\u00e1laszott "trace" helyettes\u00edt\u00e9s -config.description.lastDebuggerReplaceFunction = Utolj\u00e1ra kiv\u00e1laszott f\u00fcggv\u00e9ny n\u00e9v a "trace" helyettes\u00edts\u00e9re hibakeres\u00e9skor - -config.name.getLocalNamesFromDebugInfo = AS3: Helyi regiszter nevek a hibakeres\u00e9si inform\u00e1ci\u00f3b\u00f3l -config.description.getLocalNamesFromDebugInfo = Ha a hibakeres\u00e9si inform\u00e1ci\u00f3 el\u00e9rhet\u0151, akkor \u00e1tnevezi a helyi regisztereket _loc_x_r\u0151l a val\u00f3s n\u00e9vre. Ez kikapcsolhat\u00f3, mert n\u00e9h\u00e1ny obfuszk\u00e1tor \u00e9rv\u00e9nytelen regiszter neveket haszn\u00e1l. - -config.name.tagTreeShowEmptyFolders = \u00dcres mapp\u00e1k mutat\u00e1sa -config.description.tagTreeShowEmptyFolders = \u00dcres mapp\u00e1k mutat\u00e1sa a tag f\u00e1ban. - -config.name.autoLoadEmbeddedSwfs = Be\u00e1gyazott SWFek automatikus bet\u00f6lt\u00e9se -config.description.autoLoadEmbeddedSwfs = Aut\u00f3matikusan bet\u00f6lti a be\u00e1gyazott SWF-eket a DefineBinaryData tagekb\u0151l. - -config.name.overrideTextExportFileName = Sz\u00f6veg export\u00e1l\u00e1s f\u00e1jlnev\u00e9nek fel\u00fcl\u00edr\u00e1sa -config.description.overrideTextExportFileName = Szem\u00e9lyre szabhatod a nev\u00e9t az export\u00e1lt sz\u00f6vegf\u00e1jlnak. Haszn\u00e1ld a {filename} helykit\u00f6lt\u0151t az aktu\u00e1lis SWF nev\u00e9hez. - -config.name.showOldTextDuringTextEditing = R\u00e9gi sz\u00f6veg mutat\u00e1sa sz\u00f6veg szerkeszt\u00e9sekor -config.description.showOldTextDuringTextEditing = Mutatja az eredeti sz\u00f6veget sz\u00fcrke sz\u00ednnel az el\u0151n\u00e9zeti ablakban szerkeszt\u00e9s k\u00f6zben. - -config.group.name.import = Import\u00e1l\u00e1s -config.group.description.import = Import\u00e1l\u00e1s be\u00e1ll\u00edt\u00e1sai - -config.name.textImportResizeTextBoundsMode = Sz\u00f6veg hat\u00e1r \u00e1tm\u00e9retez\u00e9se -config.description.textImportResizeTextBoundsMode = Sz\u00f6veg hat\u00e1r \u00e1tm\u00e9retez\u00e9se sz\u00f6veg m\u00f3dos\u00edt\u00e1sa ut\u00e1n. - -config.name.showCloseConfirmation = SWF bez\u00e1r\u00e1si meger\u0151s\u00edt\u00e9s \u00fajb\u00f3li mutat\u00e1sa -config.description.showCloseConfirmation = SWF bez\u00e1r\u00e1si meger\u0151s\u00edt\u00e9s \u00fajb\u00f3li mutat\u00e1sa m\u00f3dosult f\u00e1jlok eset\u00e9n. - -config.name.showCodeSavedMessage = K\u00f3d mentve \u00fczenet \u00fajra mutat\u00e1sa -config.description.showCodeSavedMessage = K\u00f3d mentve \u00fczenet \u00fajra mutat\u00e1sa - -config.name.showTraitSavedMessage = Trait mentve \u00fczenet \u00fajra mutat\u00e1sa -config.description.showTraitSavedMessage = Trait mentve \u00fczenet \u00fajra mutat\u00e1sa - -config.name.updateProxyAddress = Http Proxy c\u00edm a friss\u00edt\u00e9sek keres\u00e9s\u00e9hez -config.description.updateProxyAddress = Http Proxy c\u00edm a friss\u00edt\u00e9sek keres\u00e9s\u00e9hez. Form\u00e1tum: example.com:8080 - -config.name.editorMode = Szerkeszt\u0151 m\u00f3d -config.description.editorMode = A sz\u00f6veget tartalmaz\u00f3 mez\u0151 szerkeszthet\u0151v\u00e9 t\u00e9tele automatikusan a sz\u00f6veg vagy szkript kiv\u00e1laszt\u00e1sa eset\u00e9n - -config.name.autoSaveTagModifications = Tag m\u00f3dos\u00edt\u00e1sainak automatikus ment\u00e9se -config.description.autoSaveTagModifications = V\u00e1ltoz\u00e1sok ment\u00e9se amikor \u00faj tag-et v\u00e1laszt ki a f\u00e1ban - -config.name.saveSessionOnExit = Munkamenet ment\u00e9se kil\u00e9p\u00e9skor -config.description.saveSessionOnExit = Elmenti az aktu\u00e1lis munkamenetet \u00e9s vissza\u00e1ll\u00edtja azt az FFDec \u00fajraind\u00edt\u00e1sa ut\u00e1n (csak igazi f\u00e1jlokkal m\u0171k\u00f6dik) - -config.name.showDebugMenu = Hibakeres\u00e9si men\u00fc mutat\u00e1sa -config.description.showDebugMenu = Hibakeres\u00e9si men\u00fc mutat\u00e1sa a szalagon - -config.name.allowOnlyOneInstance = Csak egy FFDec p\u00e9ld\u00e1ny enged\u00e9lyez\u00e9se (Csak Windows OS-en) -config.description.allowOnlyOneInstance = FFDec csak egy p\u00e9ld\u00e1nyban futhat, minden f\u00e1jl egy ablakban lesz megnyitva. Csak Windows oper\u00e1ci\u00f3s rendszeren m\u0171k\u00f6dik. - -config.name.scriptExportSingleFile = Szkriptek export\u00e1l\u00e1sa egy f\u00e1jlba -config.description.scriptExportSingleFile = Szkriptek export\u00e1l\u00e1sa egyetlen f\u00e1jlba t\u00f6bb f\u00e1jl helyett - -config.name.setFFDecVersionInExportedFont = FFDec verzi\u00f3sz\u00e1m be\u00e1ll\u00edt\u00e1sa az export\u00e1lt bet\u0171t\u00edpusban -config.description.setFFDecVersionInExportedFont = Ha ez a be\u00e1ll\u00edt\u00e1s ki van kapcsolva, az FFDec nem fogja be\u00edrni az aktu\u00e1lis FFDec verzi\u00f3sz\u00e1m\u00e1t az export\u00e1lt bet\u0171t\u00edpus f\u00e1jlba. - -config.name.gui.skin = Felhaszn\u00e1l\u00f3i fel\u00fclet b\u0151r -config.description.gui.skin = Kin\u00e9zet - -config.name.lastSessionData = Utols\u00f3 munkamenet adatai -config.description.lastSessionData = Az legut\u00f3bbi munkamenetben megnyitott f\u00e1jlokat tartalmazza - -config.name.loopMedia = Zen\u00e9k \u00e9s szpr\u00e1jtok -config.description.loopMedia = Aut\u00f3matikusan \u00fajraind\u00edtja a zen\u00e9k \u00e9s szpr\u00e1jtok lej\u00e1tsz\u00e1s\u00e1t - -config.name.gui.timeLineSplitPane.dividerLocationPercent = (Internal) Timeline oszt\u00f3 helyzete -config.description.gui.timeLineSplitPane.dividerLocationPercent = +# 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 . + +advancedSettings.dialog.title = Halad\u00f3 be\u00e1ll\u00edt\u00e1sok +advancedSettings.restartConfirmation = N\u00e9h\u00e1ny m\u00f3dos\u00edt\u00e1s \u00e9rv\u00e9nybel\u00e9p\u00e9s\u00e9hez a programot \u00fajra kell ind\u00edtani. Szeretn\u00e9 \u00fajraind\u00edtani most? +advancedSettings.columns.name = N\u00e9v +advancedSettings.columns.value = \u00c9rt\u00e9k +advancedSettings.columns.description = Le\u00edr\u00e1s +default = alap\u00e9rt\u00e9k + +config.group.name.export = Export\u00e1l\u00e1s +config.group.description.export = Export\u00e1l\u00e1s be\u00e1ll\u00edt\u00e1sai + +config.group.name.script = Szkriptek +config.group.description.script = ActionScript visszaford\u00edt\u00e1ssal kapcsolatos + +config.group.name.update = Friss\u00edt\u00e9sek +config.group.description.update = Friss\u00edt\u00e9sek keres\u00e9se + +config.group.name.format = Form\u00e1z\u00e1s +config.group.description.format = ActionScript k\u00f3d form\u00e1z\u00e1s + +config.group.name.limit = Korl\u00e1tok +config.group.description.limit = Visszaford\u00edt\u00e1si korl\u00e1tok obfuszk\u00e1lt k\u00f3dokra, stb. + +config.group.name.ui = Fel\u00fclet +config.group.description.ui = Felhaszn\u00e1l\u00f3i fel\u00fclet be\u00e1ll\u00edt\u00e1sai + +config.group.name.debug = Hibakeres\u00e9s +config.group.description.debug = Hibakeres\u00e9si be\u00e1ll\u00edt\u00e1sok + +config.group.name.display = Megjelen\u00edt\u00e9s +config.group.description.display = Flash objektum megjelen\u00edt\u00e9s, stb. + +config.group.name.decompilation = Visszaford\u00edt\u00e1s +config.group.description.decompilation = Glob\u00e1lis visszaford\u00edt\u00e1ssal kapcsolatos funkci\u00f3k + +config.group.name.other = Egy\u00e9b +config.group.description.other = Egy\u00e9b kategoriz\u00e1latlan be\u00e1ll\u00edt\u00e1sok + +config.name.openMultipleFiles = T\u00f6bb f\u00e1jl megnyit\u00e1sa +config.description.openMultipleFiles = Enged\u00e9lyezi t\u00f6bb f\u00e1jl megnyit\u00e1s\u00e1t egy ablakban + +config.name.decompile = ActionScript forr\u00e1s mutat\u00e1sa +config.description.decompile = Kikapcsolhatja az AS visszaford\u00edt\u00e1s\u00e1t, ekkor a P-k\u00f3d jelenik meg + +config.name.dumpView = Dump N\u00e9zet +config.description.dumpView = Nyers adatok mutat\u00e1sa + +config.name.useHexColorFormat = Hexa sz\u00edn form\u00e1tum +config.description.useHexColorFormat = A sz\u00ednek hexa form\u00e1tum\u00fa mutat\u00e1sa + +config.name.parallelSpeedUp = P\u00e1rhuzamos gyors\u00edt\u00e1s +config.description.parallelSpeedUp = P\u00e1rhuzamos\u00edt\u00e1s fel tudja gyors\u00edtani a visszaford\u00edt\u00e1st + +config.name.parallelThreadCount = Sz\u00e1lak sz\u00e1ma +config.description.parallelThreadCount = Sz\u00e1lak sz\u00e1ma a p\u00e1rhuzamos gyors\u00edt\u00e1sn\u00e1l + +config.name.autoDeobfuscate = Automatikus deobfuszk\u00e1l\u00e1s +config.description.autoDeobfuscate = Futtassa a deobfuszk\u00e1l\u00e1st minden f\u00e1jlon az ActionScript visszaford\u00edt\u00e1sa el\u0151tt + +config.name.cacheOnDisk = Lemez gyors\u00edt\u00f3t\u00e1r haszn\u00e1lata +config.description.cacheOnDisk = Gyors\u00edt\u00f3t\u00e1razza a m\u00e1r visszaford\u00edtott r\u00e9szeket a merevlemezre a mem\u00f3ria helyett + +config.name.internalFlashViewer = Saj\u00e1t Flash n\u00e9z\u0151ke haszn\u00e1lata +config.description.internalFlashViewer = JPEXS Flash N\u00e9z\u0151ke haszn\u00e1lata a standard Flash Player helyett a flash r\u00e9szek megjelen\u00edt\u00e9s\u00e9re + +config.name.gotoMainClassOnStartup = F\u0151 oszt\u00e1lyhoz ugr\u00e1s ind\u00edt\u00e1skor (AS3) +config.description.gotoMainClassOnStartup = A dokumentum oszt\u00e1lyhoz navig\u00e1l\u00e1s AS3 f\u00e1jl eset\u00e9n az SWF megnyit\u00e1sakor + +config.name.autoRenameIdentifiers = Azonos\u00edt\u00f3k automatikus \u00e1tnevez\u00e9se +config.description.autoRenameIdentifiers = Automatikusan \u00e1tnevezi az \u00e9rv\u00e9nytelen azonos\u00edt\u00f3kat az SWF bet\u00f6lt\u00e9sekor + +config.name.offeredAssociation = (Bels\u0151) SWF f\u00e1jlok t\u00e1rs\u00edt\u00e1sa megjelen\u00edtve +config.description.offeredAssociation = Dial\u00f3gus ablak a f\u00e1jl t\u00e1rs\u00edt\u00e1s\u00e1r\u00f3l m\u00e1r meg lett jelen\u00edtve + +config.name.decimalAddress = Decim\u00e1lis c\u00edmek haszn\u00e1lata +config.description.decimalAddress = Decim\u00e1lis c\u00edmek haszn\u00e1lata a hexadecim\u00e1lisok helyett + +config.name.showAllAddresses = Minden c\u00edm mutat\u00e1sa +config.description.showAllAddresses = Minden ActionScript utas\u00edt\u00e1s c\u00edm mutat\u00e1sa + +config.name.useFrameCache = Keret gyors\u00edt\u00f3t\u00e1r haszn\u00e1lata +config.description.useFrameCache = Keretek gyors\u00edt\u00f3t\u00e1rba helyez\u00e9se az \u00fajb\u00f3li renderel\u00e9s megel\u0151z\u00e9s\u00e9hez + +config.name.useRibbonInterface = Szalag fel\u00fclet +config.description.useRibbonInterface = Kapcsolja ki a klasszikus fel\u00fclet haszn\u00e1lat\u00e1hoz szalagos men\u00fc n\u00e9lk\u00fcl + +config.name.openFolderAfterFlaExport = Mappa megnyit\u00e1sa FLA export\u00e1l\u00e1s ut\u00e1n +config.description.openFolderAfterFlaExport = A kimeneti k\u00f6nyvt\u00e1r megnyit\u00e1sa az FLA f\u00e1jl export\u00e1l\u00e1sa ut\u00e1n + +config.name.useDetailedLogging = R\u00e9szletes napl\u00f3z\u00e1s +config.description.useDetailedLogging = R\u00e9szletes hiba\u00fczenetek \u00e9s inform\u00e1ci\u00f3k napl\u00f3z\u00e1sa hibakeres\u00e9ssi c\u00e9lb\u00f3l + +config.name.debugMode = Hibakeres\u00e9si m\u00f3d +config.description.debugMode = M\u00f3d a hibakeres\u00e9shez. Bekapcsolja a hibakeres\u00e9si men\u00fct. + +config.name.resolveConstants = \u00c1lland\u00f3k felold\u00e1sa AS1/2 p-k\u00f3d eset\u00e9n +config.description.resolveConstants = Kapcsolja ezt ki a 'constantxx' \u00e9rt\u00e9kek mutat\u00e1s\u00e1hoz a val\u00f3s \u00e9rt\u00e9kek helyett a P-k\u00f3d ablakban + +config.name.sublimiter = K\u00f3d sub korl\u00e1t +config.description.sublimiter = K\u00f3d sub korl\u00e1t obfuszk\u00e1lt k\u00f3dn\u00e1l. + +config.name.exportTimeout = Teljes export\u00e1l\u00e1si id\u0151korl\u00e1t (m\u00e1sodperc) +config.description.exportTimeout = A visszaford\u00edt\u00f3 le\u00e1ll\u00edtja az export\u00e1l\u00e1st miut\u00e1n el\u00e9ri ezt az id\u0151t + +config.name.decompilationTimeoutFile = F\u00e1jl visszaford\u00edt\u00e1si id\u0151korl\u00e1t (m\u00e1sodperc) +config.description.decompilationTimeoutFile = A visszaford\u00edt\u00f3 le\u00e1ll\u00edtja az ActionScript visszaford\u00edt\u00e1s\u00e1t mitu\u00e1n el\u00e9ri ezt az id\u0151t + +config.name.paramNamesEnable = Param\u00e9ter nevek enged\u00e9lyez\u00e9se AS3 eset\u00e9n +config.description.paramNamesEnable = Param\u00e9ter nevek haszn\u00e1lata a visszaford\u00edt\u00e1sn\u00e1l probl\u00e9m\u00e1khoz vezethet mivel a hivatalos programok mint pl. Flash CS 5.5 rossz param\u00e9ter n\u00e9v indexeket sz\u00far be + +config.name.displayFileName = SWF n\u00e9v mutat\u00e1sa a c\u00edmsorban +config.description.displayFileName = SWF f\u00e1jl/url n\u00e9v mutat\u00e1sa az ablak c\u00edmsor\u00e1ban (Ut\u00e1na k\u00e9sz\u00edthet k\u00e9perny\u0151k\u00e9peket) + +config.name.debugCopy = \u00dajraford\u00edt\u00e1s hibakeres\u00e9s +config.description.debugCopy = Megpr\u00f3b\u00e1lja \u00fajraford\u00edtani az SWF f\u00e1jlt megnyit\u00e1s ut\u00e1n hogy megbizonyosodjon arr\u00f3l, hogy ugyanazt a bin\u00e1ris k\u00f3dot \u00e1ll\u00edtja el\u0151. Csak HIBAKERES\u00c9SHEZ haszn\u00e1lja! + +config.name.dumpTags = Tagek ki\u00edr\u00e1sa a parancssorra +config.description.dumpTags = Tagek ki\u00edr\u00e1sa a parancssorra az SWF f\u00e1jl olvas\u00e1sakor + +config.name.decompilationTimeoutSingleMethod = AS3: Egyedi met\u00f3dus visszaford\u00edt\u00e1si id\u0151korl\u00e1t (m\u00e1sodperc) +config.description.decompilationTimeoutSingleMethod = A visszaford\u00edt\u00f3 le\u00e1ll\u00edtja az ActionScript visszaford\u00edt\u00e1s\u00e1t miut\u00e1n el\u00e9ri ezt az id\u0151t egy met\u00f3dusn\u00e1l + +config.name.lastRenameType = (Bels\u0151) Utols\u00f3 \u00e1tevez\u00e9si t\u00edpus +config.description.lastRenameType = Utolj\u00e1ra haszn\u00e1lt t\u00edpus az azonos\u00edt\u00f3k \u00e1tnevez\u00e9s\u00e9re + +config.name.lastSaveDir = (Bels\u0151) Utols\u00f3 ment\u00e9si k\u00f6nyvt\u00e1r +config.description.lastSaveDir = Utolj\u00e1ra haszn\u00e1lt ment\u00e9si k\u00f6nyvt\u00e1r + +config.name.lastOpenDir = (Bels\u0151) Utols\u00f3 megnyit\u00e1si k\u00f6nyvt\u00e1r +config.description.lastOpenDir = Utolj\u00e1ra haszn\u00e1lt megnyit\u00e1si k\u00f6nyvt\u00e1r + +config.name.lastExportDir = (Bels\u0151) Utols\u00f3 export\u00e1l\u00e1si k\u00f6nyvt\u00e1r +config.description.lastExportDir = Utolj\u00e1ra haszn\u00e1lt export\u00e1l\u00e1si k\u00f6nyvt\u00e1r + +config.name.locale = Nyelv +config.description.locale = Helysz\u00edn azonos\u00edt\u00f3 + +config.name.registerNameFormat = Regiszter v\u00e1ltoz\u00f3 form\u00e1tum +config.description.registerNameFormat = Helyi regiszter v\u00e1ltoz\u00f3n\u00e9v form\u00e1tum. Haszn\u00e1lja a %d-t a regiszter sz\u00e1m\u00e1hoz. + +config.name.maxRecentFileCount = Utolj\u00e1ra haszn\u00e1lt f\u00e1jlok maxim\u00e1lis sz\u00e1ma +config.description.maxRecentFileCount = Utolj\u00e1ra haszn\u00e1lt f\u00e1jlok maxim\u00e1lis sz\u00e1ma + +config.name.recentFiles = (Bels\u0151) Utolj\u00e1ra haszn\u00e1lt f\u00e1jlok +config.description.recentFiles = Utolj\u00e1ra megnyitott f\u00e1jlok + +config.name.fontPairing = (Bels\u0151) Bet\u0171t\u00edpus p\u00e1rok import\u00e1l\u00e1shoz +config.description.fontPairing = Bet\u0171t\u00edpus p\u00e1rok \u00faj karakterek import\u00e1l\u00e1s\u00e1hoz + +config.name.lastUpdatesCheckDate = (Bels\u0151) Utols\u00f3 friss\u00edt\u00e9s keres\u00e9s\u00e9nek d\u00e1tuma +config.description.lastUpdatesCheckDate = Utols\u00f3 friss\u00edt\u00e9s keres\u00e9s\u00e9nek d\u00e1tuma a kiszolg\u00e1l\u00f3r\u00f3l + +config.name.gui.window.width = (Bels\u0151) Legut\u00f3bbi ablak sz\u00e9less\u00e9g +config.description.gui.window.width = Legut\u00f3bb mentett ablak sz\u00e9less\u00e9ge + +config.name.gui.window.height = (Bels\u0151) Legut\u00f3bbi ablak magass\u00e1ga +config.description.gui.window.height = Legut\u00f3bb mentett ablak magass\u00e1ga + +config.name.gui.window.maximized.horizontal = (Bels\u0151) Az ablak v\u00edzszintesen maxim\u00e1lis m\u00e9ret\u0171 +config.description.gui.window.maximized.horizontal = Ablak utols\u00f3 \u00e1llapota - v\u00edzszintesen maxim\u00e1lis + +config.name.gui.window.maximized.vertical = (Bels\u0151) Az ablak f\u00fcgg\u0151legesen maxim\u00e1lis m\u00e9ret\u0171 +config.description.gui.window.maximized.vertical = Ablak utols\u00f3 \u00e1llapota - f\u00fcgg\u0151legesen maxim\u00e1lis + +config.name.gui.avm2.splitPane.dividerLocationPercent = (Bels\u0151) AS3 oszt\u00f3 helyzete +config.description.gui.avm2.splitPane.dividerLocationPercent = + +config.name.gui.actionSplitPane.dividerLocationPercent = (Bels\u0151) AS1/2 oszt\u00f3 helyzete +config.description.gui.actionSplitPane.dividerLocationPercent = + +config.name.gui.previewSplitPane.dividerLocationPercent = (Bels\u0151) El\u0151n\u00e9zet oszt\u00f3 helyzete +config.description.gui.previewSplitPane.dividerLocationPercent = + +config.name.gui.splitPane1.dividerLocationPercent = (Bels\u0151) Oszt\u00f3 helyzete 1 +config.description.gui.splitPane1.dividerLocationPercent = + +config.name.gui.splitPane2.dividerLocationPercent = (Bels\u0151) Oszt\u00f3 helyzete 2 +config.description.gui.splitPane2.dividerLocationPercent = + +config.name.saveAsExeScaleMode = Ment\u00e9s EXE-k\u00e9nt nagy\u00edt\u00e1s m\u00f3dja +config.description.saveAsExeScaleMode = Nagy\u00edt\u00e1s m\u00f3dja EXE export eset\u00e9n + +config.name.syntaxHighlightLimit = Szintaxis kiemel\u00e9s maxim\u00e1lis karakter sz\u00e1m +config.description.syntaxHighlightLimit = Maxim\u00e1lis karakter sz\u00e1m a szintaxis kiemel\u00e9s futtat\u00e1s\u00e1hoz + +config.name.guiFontPreviewSampleText = (Bels\u0151) Utols\u00f3 bet\u0171t\u00edpus el\u0151n\u00e9zet p\u00e9lda sz\u00f6veg +config.description.guiFontPreviewSampleText = Utols\u00f3 bet\u0171t\u00edpus p\u00e9lda sz\u00f6veg indexe a list\u00e1ban + +config.name.gui.fontPreviewWindow.width = (Bels\u0151) Bet\u0171t\u00edpus el\u0151n\u00e9zet ablak utols\u00f3 sz\u00e9less\u00e9ge +config.description.gui.fontPreviewWindow.width = + +config.name.gui.fontPreviewWindow.height = (Bels\u0151) Bet\u0171t\u00edpus el\u0151n\u00e9zet ablak utols\u00f3 magass\u00e1ga +config.description.gui.fontPreviewWindow.height = + +config.name.gui.fontPreviewWindow.posX = (Bels\u0151) Bet\u0171t\u00edpus el\u0151n\u00e9zet ablak utols\u00f3 X poz\u00edci\u00f3ja +config.description.gui.fontPreviewWindow.posX = + +config.name.gui.fontPreviewWindow.posY = (Bels\u0151) Bet\u0171t\u00edpus el\u0151n\u00e9zet ablak utols\u00f3 Y poz\u00edci\u00f3ja +config.description.gui.fontPreviewWindow.posY = + +config.name.formatting.indent.size = Karakterek sz\u00e1ma beh\u00faz\u00e1sonk\u00e9nt +config.description.formatting.indent.size = Sz\u00f3k\u00f6z\u00f6k (vagy tab-ok) sz\u00e1ma egy beh\u00faz\u00e1sn\u00e1l + +config.name.formatting.indent.useTabs = Tab-ok beh\u00faz\u00e1shoz +config.description.formatting.indent.useTabs = Tab-ok haszn\u00e1lata sz\u00f3k\u00f6z\u00f6k helyett beh\u00faz\u00e1sokn\u00e1l + +config.name.beginBlockOnNewLine = Kapcsos z\u00e1r\u00f3jel \u00faj sorban +config.description.beginBlockOnNewLine = Blokk kezdeti kapcsos z\u00e1r\u00f3jel \u00faj sorban + +config.name.check.updates.delay = Friss\u00edt\u00e9s keres\u00e9si v\u00e1rakoz\u00e1s +config.description.check.updates.delay = Minim\u00e1lis id\u0151 az automatikus friss\u00edt\u00e9sek keres\u00e9s\u00e9hez az alkalmaz\u00e1s ind\u00edt\u00e1sakor + +config.name.check.updates.stable = Stabil verzi\u00f3k ellen\u0151rz\u00e9se +config.description.check.updates.stable = Stabil verzi\u00f3 friss\u00edt\u00e9sek keres\u00e9se + +config.name.check.updates.nightly = \u00c9jszakai verzi\u00f3k ellen\u0151rz\u00e9se +config.description.check.updates.nightly = \u00c9jszakai verzi\u00f3 friss\u00edt\u00e9sek keres\u00e9se + +config.name.check.updates.enabled = Friss\u00edt\u00e9sek keres\u00e9se enged\u00e9lyezve +config.description.check.updates.enabled = Friss\u00edt\u00e9sek automatikus keres\u00e9se az alkalmaz\u00e1s ind\u00edt\u00e1sakor + +config.name.export.formats = (Bels\u0151) Export\u00e1l\u00e1si form\u00e1tumok +config.description.export.formats = Utolj\u00e1ra haszn\u00e1lt export\u00e1l\u00e1si form\u00e1tumok + +config.name.textExportSingleFile = Sz\u00f6vegek export\u00e1l\u00e1sa egy f\u00e1jlba +config.description.textExportSingleFile = Sz\u00f6vegek export\u00e1l\u00e1sa egyetlen f\u00e1jlba t\u00f6bb f\u00e1jl helyett + +config.name.textExportSingleFileSeparator = Sz\u00f6vegek elv\u00e1laszt\u00e1sa egy f\u00e1jlba t\u00f6rt\u00e9n\u0151 export\u00e1l\u00e1s eset\u00e9n +config.description.textExportSingleFileSeparator = Sz\u00f6veg, melyet besz\u00far a sz\u00f6vegek k\u00f6z\u00e9 egyetlen f\u00e1jlba t\u00f6rt\u00e9n\u0151 sz\u00f6veg export\u00e1l\u00e1skor + +config.name.textExportSingleFileRecordSeparator = Rekordok elv\u00e1laszt\u00e1sa egy f\u00e1jlba t\u00f6rt\u00e9n\u0151 export\u00e1l\u00e1s eset\u00e9n +config.description.textExportSingleFileRecordSeparator = Sz\u00f6veg, melyet besz\u00far a rekordok k\u00f6z\u00e9 egyetlen f\u00e1jlba t\u00f6rt\u00e9n\u0151 sz\u00f6veg export\u00e1l\u00e1skor + +config.name.warning.experimental.as12edit = Figyelmeztet\u00e9s AS1/2 direkt szerkeszt\u00e9se eset\u00e9n +config.description.warning.experimental.as12edit = Figyelmeztet\u00e9s megjelen\u00edt\u00e9se AS1/2 k\u00eds\u00e9rleti szerkeszt\u00e9se eset\u00e9n + +config.name.warning.experimental.as3edit = Figyelmeztet\u00e9s AS3 direkt szerkeszt\u00e9se eset\u00e9n +config.description.warning.experimental.as3edit = Figyelmeztet\u00e9s megjelen\u00edt\u00e9se AS3 k\u00eds\u00e9rleti szerkeszt\u00e9se eset\u00e9n + +config.name.packJavaScripts = JavaScripts csomagol\u00e1s +config.description.packJavaScripts = JavaScript csomagol\u00f3 futtat\u00e1sa V\u00e1szon Export\u00e1l\u00e1skor l\u00e9trehozott szkriptekre. + +config.name.textExportExportFontFace = Font-face haszn\u00e1lata SVG export\u00e1l\u00e1skor +config.description.textExportExportFontFace = Bet\u0171t\u00edpus f\u00e1jlok be\u00e1gyaz\u00e1sa az SVG f\u00e1jlokba \u00e9s font-face haszn\u00e1lata alakzatok helyett + +config.name.lzmaFastBytes = LZMA fast bytes (\u00e9rv\u00e9nyes \u00e9rt\u00e9kek: 5-255) +config.description.lzmaFastBytes = Az LZMA t\u00f6m\u00f6r\u00edt\u0151 "Fast bytes" param\u00e9tere + +#temporary setting, do not translate it +config.name.pluginPath = Plugin Path +config.description.pluginPath = - + +config.name.deobfuscationMode = Deobfuszk\u00e1l\u00e1si m\u00f3d +config.description.deobfuscationMode = Futtassa a deobfuszk\u00e1l\u00e1st minden f\u00e1jlon az ActionScript visszaford\u00edt\u00e1sa el\u0151tt + +config.name.showMethodBodyId = Method body azonos\u00edt\u00f3 mutat\u00e1sa +config.description.showMethodBodyId = Megmutatja a methodbody azonos\u00edt\u00f3t a parancssori import\u00e1l\u00e1shoz + +config.name.export.zoom = (Bels\u0151) Export zoom +config.description.export.zoom = Utolj\u00e1ra haszn\u00e1lt export zoom + +config.name.debuggerPort = Debugger port +config.description.debuggerPort = Socket hibakeres\u00e9shez haszn\u00e1lt port + +config.name.displayDebuggerInfo = (Bels\u0151) Hibakeres\u00e9si inform\u00e1ci\u00f3 mutat\u00e1sa +config.description.displayDebuggerInfo = Hibakeres\u00e9si inform\u00e1ci\u00f3 mutat\u00e1sa bekapcsol\u00e1s el\u0151tt + +config.name.randomDebuggerPackage = V\u00e9letlen csomag n\u00e9v haszn\u00e1lata hibakeres\u00e9sn\u00e9l +config.description.randomDebuggerPackage = \u00c1Tnevezi a hibakeres\u00e9si csomag nev\u00e9t v\u00e9letlen n\u00e9vre hogy nehezebben lehessen detekt\u00e1lni ActionScript-b\u0151l + +config.name.lastDebuggerReplaceFunction = (Bels\u0151) Utolj\u00e1ra kiv\u00e1laszott "trace" helyettes\u00edt\u00e9s +config.description.lastDebuggerReplaceFunction = Utolj\u00e1ra kiv\u00e1laszott f\u00fcggv\u00e9ny n\u00e9v a "trace" helyettes\u00edts\u00e9re hibakeres\u00e9skor + +config.name.getLocalNamesFromDebugInfo = AS3: Helyi regiszter nevek a hibakeres\u00e9si inform\u00e1ci\u00f3b\u00f3l +config.description.getLocalNamesFromDebugInfo = Ha a hibakeres\u00e9si inform\u00e1ci\u00f3 el\u00e9rhet\u0151, akkor \u00e1tnevezi a helyi regisztereket _loc_x_r\u0151l a val\u00f3s n\u00e9vre. Ez kikapcsolhat\u00f3, mert n\u00e9h\u00e1ny obfuszk\u00e1tor \u00e9rv\u00e9nytelen regiszter neveket haszn\u00e1l. + +config.name.tagTreeShowEmptyFolders = \u00dcres mapp\u00e1k mutat\u00e1sa +config.description.tagTreeShowEmptyFolders = \u00dcres mapp\u00e1k mutat\u00e1sa a tag f\u00e1ban. + +config.name.autoLoadEmbeddedSwfs = Be\u00e1gyazott SWFek automatikus bet\u00f6lt\u00e9se +config.description.autoLoadEmbeddedSwfs = Aut\u00f3matikusan bet\u00f6lti a be\u00e1gyazott SWF-eket a DefineBinaryData tagekb\u0151l. + +config.name.overrideTextExportFileName = Sz\u00f6veg export\u00e1l\u00e1s f\u00e1jlnev\u00e9nek fel\u00fcl\u00edr\u00e1sa +config.description.overrideTextExportFileName = Szem\u00e9lyre szabhatod a nev\u00e9t az export\u00e1lt sz\u00f6vegf\u00e1jlnak. Haszn\u00e1ld a {filename} helykit\u00f6lt\u0151t az aktu\u00e1lis SWF nev\u00e9hez. + +config.name.showOldTextDuringTextEditing = R\u00e9gi sz\u00f6veg mutat\u00e1sa sz\u00f6veg szerkeszt\u00e9sekor +config.description.showOldTextDuringTextEditing = Mutatja az eredeti sz\u00f6veget sz\u00fcrke sz\u00ednnel az el\u0151n\u00e9zeti ablakban szerkeszt\u00e9s k\u00f6zben. + +config.group.name.import = Import\u00e1l\u00e1s +config.group.description.import = Import\u00e1l\u00e1s be\u00e1ll\u00edt\u00e1sai + +config.name.textImportResizeTextBoundsMode = Sz\u00f6veg hat\u00e1r \u00e1tm\u00e9retez\u00e9se +config.description.textImportResizeTextBoundsMode = Sz\u00f6veg hat\u00e1r \u00e1tm\u00e9retez\u00e9se sz\u00f6veg m\u00f3dos\u00edt\u00e1sa ut\u00e1n. + +config.name.showCloseConfirmation = SWF bez\u00e1r\u00e1si meger\u0151s\u00edt\u00e9s \u00fajb\u00f3li mutat\u00e1sa +config.description.showCloseConfirmation = SWF bez\u00e1r\u00e1si meger\u0151s\u00edt\u00e9s \u00fajb\u00f3li mutat\u00e1sa m\u00f3dosult f\u00e1jlok eset\u00e9n. + +config.name.showCodeSavedMessage = K\u00f3d mentve \u00fczenet \u00fajra mutat\u00e1sa +config.description.showCodeSavedMessage = K\u00f3d mentve \u00fczenet \u00fajra mutat\u00e1sa + +config.name.showTraitSavedMessage = Trait mentve \u00fczenet \u00fajra mutat\u00e1sa +config.description.showTraitSavedMessage = Trait mentve \u00fczenet \u00fajra mutat\u00e1sa + +config.name.updateProxyAddress = Http Proxy c\u00edm a friss\u00edt\u00e9sek keres\u00e9s\u00e9hez +config.description.updateProxyAddress = Http Proxy c\u00edm a friss\u00edt\u00e9sek keres\u00e9s\u00e9hez. Form\u00e1tum: example.com:8080 + +config.name.editorMode = Szerkeszt\u0151 m\u00f3d +config.description.editorMode = A sz\u00f6veget tartalmaz\u00f3 mez\u0151 szerkeszthet\u0151v\u00e9 t\u00e9tele automatikusan a sz\u00f6veg vagy szkript kiv\u00e1laszt\u00e1sa eset\u00e9n + +config.name.autoSaveTagModifications = Tag m\u00f3dos\u00edt\u00e1sainak automatikus ment\u00e9se +config.description.autoSaveTagModifications = V\u00e1ltoz\u00e1sok ment\u00e9se amikor \u00faj tag-et v\u00e1laszt ki a f\u00e1ban + +config.name.saveSessionOnExit = Munkamenet ment\u00e9se kil\u00e9p\u00e9skor +config.description.saveSessionOnExit = Elmenti az aktu\u00e1lis munkamenetet \u00e9s vissza\u00e1ll\u00edtja azt az FFDec \u00fajraind\u00edt\u00e1sa ut\u00e1n (csak igazi f\u00e1jlokkal m\u0171k\u00f6dik) + +config.name.showDebugMenu = Hibakeres\u00e9si men\u00fc mutat\u00e1sa +config.description.showDebugMenu = Hibakeres\u00e9si men\u00fc mutat\u00e1sa a szalagon + +config.name.allowOnlyOneInstance = Csak egy FFDec p\u00e9ld\u00e1ny enged\u00e9lyez\u00e9se (Csak Windows OS-en) +config.description.allowOnlyOneInstance = FFDec csak egy p\u00e9ld\u00e1nyban futhat, minden f\u00e1jl egy ablakban lesz megnyitva. Csak Windows oper\u00e1ci\u00f3s rendszeren m\u0171k\u00f6dik. + +config.name.scriptExportSingleFile = Szkriptek export\u00e1l\u00e1sa egy f\u00e1jlba +config.description.scriptExportSingleFile = Szkriptek export\u00e1l\u00e1sa egyetlen f\u00e1jlba t\u00f6bb f\u00e1jl helyett + +config.name.setFFDecVersionInExportedFont = FFDec verzi\u00f3sz\u00e1m be\u00e1ll\u00edt\u00e1sa az export\u00e1lt bet\u0171t\u00edpusban +config.description.setFFDecVersionInExportedFont = Ha ez a be\u00e1ll\u00edt\u00e1s ki van kapcsolva, az FFDec nem fogja be\u00edrni az aktu\u00e1lis FFDec verzi\u00f3sz\u00e1m\u00e1t az export\u00e1lt bet\u0171t\u00edpus f\u00e1jlba. + +config.name.gui.skin = Felhaszn\u00e1l\u00f3i fel\u00fclet b\u0151r +config.description.gui.skin = Kin\u00e9zet + +config.name.lastSessionData = Utols\u00f3 munkamenet adatai +config.description.lastSessionData = Az legut\u00f3bbi munkamenetben megnyitott f\u00e1jlokat tartalmazza + +config.name.loopMedia = Zen\u00e9k \u00e9s szpr\u00e1jtok +config.description.loopMedia = Aut\u00f3matikusan \u00fajraind\u00edtja a zen\u00e9k \u00e9s szpr\u00e1jtok lej\u00e1tsz\u00e1s\u00e1t + +config.name.gui.timeLineSplitPane.dividerLocationPercent = (Internal) Timeline oszt\u00f3 helyzete +config.description.gui.timeLineSplitPane.dividerLocationPercent = + +config.name.cacheOnDisk = K\u00e9pek gyors\u00edt\u00f3t\u00e1rba helyez\u00e9se +config.description.cacheOnDisk = A dek\u00f3dolt k\u00e9peket gyors\u00edt\u00f3t\u00e1rba helyezi diff --git a/src/com/jpexs/decompiler/flash/gui/player/FlashPlayerPanel.java b/src/com/jpexs/decompiler/flash/gui/player/FlashPlayerPanel.java index 511e0a636..c0b735305 100644 --- a/src/com/jpexs/decompiler/flash/gui/player/FlashPlayerPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/player/FlashPlayerPanel.java @@ -252,10 +252,6 @@ public final class FlashPlayerPanel extends Panel implements Closeable, MediaDis @Override public void close() throws IOException { - - } - - public void unload() { timer.cancel(); } diff --git a/src/com/jpexs/decompiler/flash/gui/player/MediaDisplay.java b/src/com/jpexs/decompiler/flash/gui/player/MediaDisplay.java index 3c6aff1b1..335384619 100644 --- a/src/com/jpexs/decompiler/flash/gui/player/MediaDisplay.java +++ b/src/com/jpexs/decompiler/flash/gui/player/MediaDisplay.java @@ -1,69 +1,70 @@ -/* - * 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 . - */ -package com.jpexs.decompiler.flash.gui.player; - -import java.awt.Color; -import java.awt.image.BufferedImage; - -/** - * - * @author JPEXS - */ -public interface MediaDisplay { - - public int getCurrentFrame(); - - public int getTotalFrames(); - - public void zoom(Zoom zoom); - - public void pause(); - - public void stop(); - - public void play(); - - public void rewind(); - - public boolean isPlaying(); - - public void setLoop(boolean loop); - - public void gotoFrame(int frame); - - public void setBackground(Color color); - - public int getFrameRate(); - - public boolean isLoaded(); - - public BufferedImage printScreen(); - - public boolean loopAvailable(); - - public boolean screenAvailable(); - - public boolean zoomAvailable(); - - public double getZoomToFit(); - - public Zoom getZoom(); - - public void addEventListener(MediaDisplayListener listener); - - public void removeEventListener(MediaDisplayListener listener); -} +/* + * 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 . + */ +package com.jpexs.decompiler.flash.gui.player; + +import java.awt.Color; +import java.awt.image.BufferedImage; +import java.io.Closeable; + +/** + * + * @author JPEXS + */ +public interface MediaDisplay extends Closeable { + + public int getCurrentFrame(); + + public int getTotalFrames(); + + public void zoom(Zoom zoom); + + public void pause(); + + public void stop(); + + public void play(); + + public void rewind(); + + public boolean isPlaying(); + + public void setLoop(boolean loop); + + public void gotoFrame(int frame); + + public void setBackground(Color color); + + public int getFrameRate(); + + public boolean isLoaded(); + + public BufferedImage printScreen(); + + public boolean loopAvailable(); + + public boolean screenAvailable(); + + public boolean zoomAvailable(); + + public double getZoomToFit(); + + public Zoom getZoom(); + + public void addEventListener(MediaDisplayListener listener); + + public void removeEventListener(MediaDisplayListener listener); +}